Linux 字符设备驱动框架详细介绍

2019-10-13 12:59:02王旭

我们可以将驱动设计的命令包含在一个头文件中,记录用户程序和驱动程序的命令约定,下面是一个简单的例子

//mycmd.h
...
#include <asm/ioctl.h>
#define CMDT 'A'
#define KARG_SIZE 36
struct karg{
  int kval;
  char kbuf[KARG_SIZE];
};
#define CMD_OFF _IO(CMDT,0)
#define CMD_ON _IO(CMDT,1)
#define CMD_R  _IOR(CMDT,2,struct karg)
#define CMD_W  _IOW(CMDT,3,struct karg)
...
//chrdev.c
static long demo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  static struct karg karg = {
    .kval = 0,
    .kbuf = {0},
  };
  struct karg *usr_arg;

  switch(cmd){
  case CMD_ON:
    /* 开灯 */
    break;
  case CMD_OFF:
    /* 关灯 */
    break;
  case CMD_R:
    if(_IOC_SIZE(cmd) != sizeof(karg)){
      return -EINVAL;
    }
    usr_arg = (struct karg *)arg;
    if(copy_to_user(usr_arg, &karg, sizeof(karg))){
      return -EAGAIN;
    }
    break;
  case CMD_W:   
    if(_IOC_SIZE(cmd) != sizeof(karg)){
      return -EINVAL;
    }
    usr_arg = (struct karg *)arg;
    if(copy_from_user(&karg, usr_arg, sizeof(karg))){
      return -EAGAIN;
    }
    break;
  default:
    ;
  };
  return 0;
}

创建设备文件

插入的设备模块,我们就可以使用cat /proc/devices命令查看当前系统注册的设备,但是我们还没有创建相应的设备文件,用户也就不能通过文件访问这个设备。设备文件的inode应该是包含了这个设备的设备号,操作方法集指针等信息,这样我们就可以通过设备文件找到相应的inode进而访问设备。创建设备文件的方法有两种,手动创建或自动创建,手动创建设备文件就是使用mknod /dev/xxx 设备类型 主设备号 次设备号的命令创建,所以首先需要使用cat /proc/devices查看设备的主设备号并通过源码找到设备的次设备号,需要注意的是,理论上设备文件可以放置在任何文件加夹,但是放到"/dev"才符合Linux的设备管理机制,这里面的devtmpfs是专门设计用来管理设备文件的文件系统。设备文件创建好之后就会和创建时指定的设备绑定,即使设备已经被卸载了,如要删除设备文件,只需要像删除普通文件一样rm即可。理论上模块名(lsmod),设备名(/proc/devices),设备文件名(/dev)并没有什么关系,完全可以不一样,但是原则上还是建议将三者进行统一,便于管理。

除了使用蹩脚的手动创建设备节点的方式,我们还可以在设备源码中使用相应的措施使设备一旦被加载就自动创建设备文件,自动创建设备文件需要我们在编译内核的时候或制作根文件系统的时候就好相应的配置:

Device Drivers --->
    Generic Driver Options --->
      [*]Maintain a devtmpfs filesystem to mount at /dev
      [*] Automount devtmpfs at /dev,after the kernel mounted the rootfs
OR

制作根文件系统的启动脚本写入