Linux 字符设备驱动结构
1 cdev结构体
struct cdev{ struct kobject kobj; /* 内嵌的kobject对象*/ 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)
而使用下列宏则可以通过主设备号和次设备号生成dev_t:
MKDEV(int major, int minor)
cdev 结构体的另一个重要成员file_operations定义了字符设备驱动提供给虚拟文件系统的接口函数。
Linux2.6 内核提供了一组函数用于操作cdev结构体:
void cdev_init(struct cdev *, struct file_operation *); struct cdev *cdev_alloc(void); void cdev_put(struct cdev *p); int cdev_add(struct cdev *, dev_t, unsigned); void cdev_del(struct cdev *);
cdev_init()函数用于初始化cdev的成员,并建立cdev和file_operations之间的链接,其源代码清单如下所示:
void cdev_init(struct cdev *cdev, struct file_operations *fops) { memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops; /* 将传入的文件操作结构指针赋值给cdev的ops */ }
cdev_alloc()函数用于动态申请一个cdev内存,其源代码如下所示
struct cdev *cdev_alloc(void) { struct cdev *p = kzalloc(sizeof(struct dev), GFP_KERNEL); if(p){ INIT_LIST_HEAD(&p->list); kobject_init(&p->kobj, &ktype_cdev_dynamic); } return p; }
cdev_add()函数和cdev_del()函数分别向系统添加和删除一个dev,完成字符设备的注册和注销。
对cdev_add()的调用通常发生在字符设备驱动模块加载函数中,而对cdev_del()函数的调用则通常发生在字符设备驱动模块卸载函数中。
2 分配和释放设备号
在调用cdev_add()函数向系统注册字符设备之前,应首先调用register_chrdev_region()或alloc_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);
register_chrdev_region()用于已知启示设备的设备号的情况,而alloc_chrdev_region()用于设备号未知,向系统动态申请未被占用的设备号的情况,函数调用成功以后,会把设备号放入第一个参数dev中。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。