【Linux设备驱动读书笔记】 -- 02、字符驱动

1. 驱动的设计

  • 本章目标:设计驱动scull操作内存,就像操作一个设备
  • 驱动的第一步是定义驱动将要提供给用户程序的能力
  • 4个设备:scull0~scull3,每个由一个全局永久的内存区组成,可共享,数据不丢失
  • 4个FIFO设备:scullpipe0~scullpipe3,一个进程读来自另一个进程写,多个设备会竞争数据
  •                         scullpipe内部有阻塞和非阻塞读写的具体实现
  • 以下这些设备与scull0相似:
  • scullsingle:一次只允许一个进程使用驱动
  • scullpriv:对每个虚拟终端(或x终端会话)是私有的
  • sculluid:可多次打开,但是一次只能是一个用户,另一用户锁着设备,返回设备忙错误
  • scullwuid:可多次打开,但是一次只能是一个用户,另一用户锁着设备,实现阻塞打开

2. 主次编号

  • 设备文件存位于 /dev
  • 字符设备标志是 c,快设备的标志是 b
  • 主设备号标识设备相连的驱动,linux允许多个驱动共享主编号
  • 次编号被用来决定引用哪个设备
  • dev_t 用来表示设备号(包括主次设备号,主12bit,次20bit)
  • <linux/kdev_t.h>定义的宏表示主次设备号,MAJOR(dev_t dev),MINOR(dev_t dev)
  • 若直接有主次编号,需要调用 MKDEV(int major, int minor)

   分配和释放设备编号

  • 获取设备编号来使用,在 <linux/fs.h>中声明:

        int  register_chrdev_region(dev_t first,  unsigned int count,  char *name);

  • first 是起始设备编号,first的次设备标号通常是0
  • count 是请求链接设备编号的总数
  • name 是应当来链接到这个设备的设备名字,它出现在 /proc/devices 和 sysfs 中
  • 成功返回0,错误返回错误码

  

  • 动态分配一个主编号:

         int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned count, char *name);

  • dev 在函数成功返回分配的第一个数
  • firstminor 请求的第一个要用的次编号,通常是0
  • count 和 name 同上一个函数

 

  • 设备编号的释放:

       void unregister_chrdev_region(dev_t first, unsigned int count); 

  • 该函数通常在模块cleanup的函数内

    重要的数据结构file_operation

  • file_operation 结构,定义在 <linux/fs.h>,是一个函数指针的集合,负责实现系统调用,有open、read等
  • 常遇到 __user,是一种文档形式,可以被外部检查软件使用来找出对用户空间地址的错误使用
  • struct module *owner;                              // 是一个指向拥有这个结构的模块的指针,用来在它正在被使用时阻止模块被卸载
  •                                                                 // 几乎都被初始化为 THIS_MODULE,一个定义在 <linux/module.h> 中的宏
  • loff_t (*llseek) (struct file *, lott_t, int);     // 用作改变文件中的当前读/写位置,新位置(正)作为返回值,lott_t 类型是 long offset(32位系统至少有64位宽)
  •                                                                // 错误返回负数,若该函数指针时NULL,seek调用会无法预知地改变file结构中的位置计数器
  • ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
  •                                                                // 用作从设备中读取数据,若该指针为NULL,则read系统调用以 -EINVAL 失败
  •                                                                // 非负的返回值,代表成功读取的字节数(signed size类型,目标平台的整数类型)
  • size_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
  •                                                               // 初始化一个异步读,可能在函数返回前不结束读操作,若为NULL,所有读操作会被read(同步读)代替
  • ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
  •                                                               // 发送数据给设备,若为NULL,write系统调用会返回 -EINVAL
  •                                                               // 非负的返回值,代表成功写的字节数
  • ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t *);
  •                                                               // 初始化设备上一个异步写
  • int (*readdir) (struct file *, void *, filldir_t); // 对于设备文件这个成员应当为NULL,用它来读取目录,并且对文件系统有用
  • unsigned int (*poll) (struct file *, struct poll_table_struct *);
  •                                                              // 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值