Linux字符设备驱动结构:
1.cdev 结构体 linux内核中使用cdev结构体来描述一个字符设备;
Struct cdev {
Struct kobject kobj;
Struct module *owner;
Struct file_operations *ops; /*文件操作结构体*/
Struct list_head list;
Dev_t dev; // 设备号
Unsigned int count;
};
①cdev 结构体中的dev_t成员定义了设备号,为32位,其中12位为主设备号,后20位为次设备号;使用了两个宏可以从dev_t 获得主次设备号:MAJOR (dev_t dev) MINOR(dev_t dev)。。。。。。使用宏MKDEV(int major, int minor)生成主设备号;
②cdev结构体中定义的了一个重要的成员 file_operations 定义了字符设备提供给虚拟文件系统的接口函数。
③Linux2.6内核提供了一组函数用于操作cdev结构体:
Void cdev_init (struct cdev *, struct file_operations *);
Void cdev_add(struct cdev *,dev_t , unsigned);
Void cdev_del (struct cdev *);
Cdev_init 函数用于初始化cdev成员,建立cdev和file_operations之间的联系;
Cdev_add和cdev_del函数分别是向系统添加和删除一个cdev(字符设备),完成字符设备的注册和注销。对cdev_add函数的调用通常发生在字符设备驱动模块的加载函数中,相反,cdev_del函数发生在字符设备驱动模块的卸载模块函数中。
Cdev_add()函数分配设备号:在调用cdev_add()函数向系统注册设备号号,应该调用register_chrdev_region()或者alloc_chrdev_region()函数向系统申请设备号。。。 Register_chrdev_region(dev_t from,unsigned count,const char *name);
相反:在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该在被调用以释放原先申请的设备号;
Unsigned_chrdev_region(dev_t , number_of_dev);
④file_operations 结构体
File_operations结构中的成员函数是字符设备驱动与内核的接口,字符设备驱动程序的主题内容,这些函数实际上会在应用程序进行linux的open、read、write等系统调用时被调用;
Struct file_operations {
Struct module *owner;
/*拥有结构体的模块指针,一般为THIS_MODULES*/
Ssize_t (read *)(struct file *, ,, ,,);
};
Read()函数用来想设备中读取数据,成功时返回读取的字节数,出错时返回一个负数;
Ioctl() 提供设备相关的控制命令的实现,成功返回一个非负值;
Mmap()函数将设备内存映射到进程内存中,如果设备驱动未实现此函数,用户进行mmap()系统调用时将获得 -ENODEV返回值。这个函数对于帧缓冲等设备特别有意义??。
⑤ioctl()命令
字符类型 |
序列号 |
方向 |
数据尺寸 |
8bit |
8bit |
2bit |
13/14bit |
命令码的设备类型字段为一个“幻数”,可以是0~0xff之间的值,
命令码的序列号为8位宽;
命令码的方向字段为2位宽,该字段表示数据传送的方向,可能的值为_IOC_NONE(无数据传输) , _IOC_READ(读), _IOC_WRITE(写), _IOC_READ | _IOC_WRITE(双向);
命令码的数据长度字段,这个成员的宽度依赖与体系结构
#define _IO (type, nsize) 这个宏的作用是根据传入的type(设备类型字段),和nr (序列号字段)和宏隐含的方向字段移位生成命令码。。。。。