【吃灰板子捡起来】字符设备驱动开发实验


该实验与正点原子教程一致,先将该实验视频过一遍,然后根据文档进行实验。

一、驱动框架

(1)注册驱动

//include/linux/fs.h
static int __init xxx_init(void){ 
  /* 注册模块 */
  int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops);
  return 0;
}
static void __exit xxx_exit(void){
  /* 卸载模块*/
  void unregister_chrdev(unsigned int major, const char *name);
}
module_init(xxx_init); //注册模块加载函数
module_exit(xxx_exit); //注册模块卸载函数

(2)操作函数集合

//include/linux/fs.h
/* 文件打开 */
static int xxx_open(struct inode *, struct file *){
  
}
/* 文件释放 */
static int xxx_release(struct inode *, struct file *){
  
}
/* 文件读 */
static ssize_t xxx_read(struct file *, char __user *, size_t, loff_t *){
  
}
/* 文件写 */
static ssize_t xxx_write(struct file *, const char __user *, size_t, loff_t *){

}
/* 文件操作函数集合 */
static struct file_operations  xxx_fops = {
  .owner   = THGIS_MODULE,
  .open    = xxx_open,
  .release = xxx_release,
  .read    = xxx_read,
  .write   = xxx_write,
  }

(3)数据操作

#include <asm/uaccess.h>

long copy_to_user(void __user *to, const void *from, long n)

long copy_from_user(void *to, const void __user *from, long n)

(4)开源协议

MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");

二、Makefile

在这里插入图片描述

三、测试程序

1 NAME 简短的指令、数据名称说明;

2 SYNOPSIS 简短的指令下达语法(Syntax)简介

3 Description 较为完整的说明,这部分最好仔细看看;

4 Options 针对SYNOPSIS 部分中,有列举的所有可用的选项和说明;

5 COMMANDS 当这个程序软件在执行的时候,可以在此程序中下达的指令;

6 FILES 这个程序或数据所使用或参考或连结到的某些档案;

7 SEE ALSO 可以参考的,跟这个指令或数据有相关的其他说明;

8 EXAMPLE 一些可以参考的范例;

9 BUGS 是否有相关的臭虫!

open:man 2 open

OPEN(2)                                Linux Programmer's Manual                               OPEN(2)

NAME
       open, creat - open and possibly create a file or device

SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);
       int open(const char *pathname, int flags, mode_t mode);

       int creat(const char *pathname, mode_t mode);

DESCRIPTION
       Given a pathname for a file, open() returns a file descriptor, a small, nonnegative integer for
       use in subsequent system  calls  (read(2),  write(2),  lseek(2),  fcntl(2),  etc.).   The  file
       descriptor  returned  by a successful call will be the lowest-numbered file descriptor not cur‐
       rently open for the process.

       By default, the new file descriptor is set to  remain  open  across  an  execve(2)  (i.e.,  the
       FD_CLOEXEC  file  descriptor  flag  described  in fcntl(2) is initially disabled; the O_CLOEXEC

write:man 2 write

WRITE(2)                               Linux Programmer's Manual                              WRITE(2)

NAME
       write - write to a file descriptor

SYNOPSIS
       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

DESCRIPTION
       write()  writes  up  to  count bytes from the buffer pointed buf to the file referred to by the
       file descriptor fd.

       The number of bytes written may be less than count if, for example, there is insufficient space
       on the underlying physical medium, or the RLIMIT_FSIZE resource limit is encountered (see setr‐
       limit(2)), or the call was interrupted by a signal handler after having written less than count
       bytes.  (See also pipe(7).)

       For  a  seekable file (i.e., one to which lseek(2) may be applied, for example, a regular file)
       writing takes place at the current file offset, and the file offset is incremented by the  num‐
       ber  of  bytes  actually  written.  If the file was open(2)ed with O_APPEND, the file offset is
       first set to the end of the file before writing.  The adjustment of the  file  offset  and  the
 Manual page write(2) line 1 (press h for help or q to quit)

read:man 2 read

READ(2)                                Linux Programmer's Manual                               READ(2)

NAME
       read - read from a file descriptor

SYNOPSIS
       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

DESCRIPTION
       read()  attempts  to read up to count bytes from file descriptor fd into the buffer starting at
       buf.

       If count is zero, read() returns zero and has no other  results.   If  count  is  greater  than
       SSIZE_MAX, the result is unspecified.

RETURN VALUE
       On  success,  the  number  of bytes read is returned (zero indicates end of file), and the file
       position is advanced by this number.  It is not an error if this number  is  smaller  than  the
       number  of bytes requested; this may happen for example because fewer bytes are actually avail‐
       able right now (maybe because we were close to end-of-file, or because we are  reading  from  a
       pipe,  or  from  a  terminal),  or because read() was interrupted by a signal.  On error, -1 is
 Manual page read(2) line 1 (press h for help or q to quit)

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"


static char usrdata[] = {"usr data!"};

int main(int argc, char *argv[])
{
  int fd,retvalue;
  char *filename;
  char readbuf[100],writebuf[100];

  if(argc != 3)
  {
    printf("Error Usage!\r\n");
    return -1;
  } 
  
  filename = argv[1];

  fd = open(filename,O_RDWR);
  if(fd < 0){
    printf("Can't open file %s\r\n",filename);
    return -1;
  }

  if(atoi(argv[2]) == 1){
    retvalue = read(fd,readbuf,50);
    if(retvalue < 0){
      printf("read file %s failed! \r\n",filename);
     }else{
       printf("read data:%s\r\n",readbuf);
     }
  }


  if(atoi(argv[2]) == 2){
    memcpy(writebuf,usrdata,sizeof(usrdata));
    retvalue = write(fd,writebuf,50);
    if(retvalue < 0){
      printf("write file %s failed!\r\n",filename);
    }
  }

  retvalue = close(fd);
  if(retvalue < 0){
    printf("Can't close file %s\r\n",filename);
    return -1;
  }
  
  return 0;
}

四、过程总结

(1)代码按照正点原子例程来敲的,编译的Makefile文件按照酷客开发板例程里敲的,后面再抽空研究Makefile吧,内容有点多,就暂时不深究了。

(2)编译应用程序的时候,电脑里没有arm-linux-gnueabihf-gcc这个命令,直接使用arm-linux-gcc进行编译,编译成功后,一样可以运行。

(3)modprobe这个指令有,但是depmod指令没有,busybox可能需要后期需要重新编译一下,把这个指令加进去,暂时使用insmod和rmmod指令。

(4)卸载的时候,发现卸载不了,最后发现是执行rmmod chrdevbase.ko卸载不了,执行rmmod chrdevbase指令可以卸载,卸载的时候,不加.ko。

(5)代码用vi写的,有点艰难。Linux下的VS Code还没搭建。
附上实验成功的截图:
在这里插入图片描述

                                                         记录自己的学习过程,2022.04.07
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值