《Linux4.0设备驱动开发详解》笔记--第六章:Linux字符设备驱动

时间:2023-01-19 17:54:18

6.1 linux字符设备驱动结构

6.1.1 cdev结构体

  • cdev结构体描述一个字符设备
struct cdev { 
struct kobject kobj; //内嵌的kobject对象
struct module *owner; //所属模块
const struct file_operations *ops;//文件操作结构
struct list_head list;
dev_t dev; //设备号,int 类型
unsigned int count;
};
  • cdev的dev_t成员定义了设备号,高12位为主设备号,低20位为次设备号
    • 获取主、次设备号:
      • MAJOR(dev_t dev)
      • MINOR(dev_t dev)
    • 主次设备号生成dev_t:MKDEV(int major,int minor)
  • cdev结构体相关的操作函数
void cdev_init(struct cdev *, const struct file_operations *);//建立cdev和file_operation之间的连接
struct cdev *cdev_alloc(void); //动态申请一个cdev内存
void cdev_put(struct cdev *p); //释放
int cdev_add(struct cdev *, dev_t, unsigned); //注册设备
void cdev_del(struct cdev *);//注销设备

6.1.2 分配和释放设备号

  • 在注册设备之前应该先申请设备号
    • register_chrdev_region()用于已知设备号
    • register_chrdev_region()用于动态申请
int register_chrdev_region(dev_t from,unsigned count,const char *name)

int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count,const char *name)
  • 释放设备号
void unregister_chrdev_region(dev_t from,unsigned count)
  • 注册与注销字符设备顺序关系如下:
register_chrdev_region()-->cdev_add()     //此过程在加载模块中 
cdev_del()-->unregister_chrdev_region() //此过程在卸载模块中

6.1.3 字符设备驱动组成

  • 字符设备的模块加载与卸载函数
  • 字符设备驱动的file_operation结构体中的成员函数,大多数实现以下函数
    • read()
    • write()
    • ioctl()
  • copy_from_user():用户空间缓冲区到内核空间
  • copy_to_user():内核空间到用户空间缓冲区
    • 返回0:成功
    • 返回正数:不能被复制的字节数
    • 负数:操作失败
  • 复制的内容是简单的类型,如int、char、long等,则可以用以下函数
    • put_user、get_user
    • 上述函数中_user是一个宏,表示其后的指针指向用户空间
  • 内核空间访问用户空间缓存时需要合法性检查
    • access_ok(type, add, size):确认缓存区确实属于用户空间
  • ioctl函数
    • 设备类型字段为一个幻数,可以使0-0xff的值,内核中的ioctl-number.txt有推荐的已经存在的幻数,新设备区应该避免与其冲突
    • 方向字段表示数据传输的方向
      • _IOC_NONE:无数据传输
      • _IOC_READ:读
      • _IOC_WRITE:写
      • _IOC_READ|_IOC_WRITE:双向
设备类型 序列号 方向 数据尺寸
8位 8位 2位 13/14位
  • 预定义命令:内核中预定了一些I/O控制命令,如果某设备中抱哈没了与预定义命令一样的命令码,则这些命令会作为预定义命令被内核处理而不是被设备驱动处理

    • FIOCLEX:通知内核当exec()系统调用发生时,自动关闭打开的文件
    • FIONCLEX:与FIOCLEX相反,清除由FIOCLEX命令设置的标志
    • FIOQSIZE:获得一个文件和目录的大小,当用于设备文件时返回一个ENOTTY错误
    • FIONBIO:修改在filp->f_flags中的O_NONBLOCK标志