老接口:register_chrdev//注册设备驱动(实现注册设备号和相应的file_operation操作结构体)
//缺点:只有自定义设置主设备号,无法指定次设备号
新接口:
register_chrdev_region(注册设备号)/alloc_chrdev_region(自动分配设备号) + cdev
cdev结构体及相关函数(每一个驱动文件,都有一个它私有的cdev结构体,来建立设备号、设备操作函数的关系)
结构体: struct cdev { struct kobject kobj; struct module *owner; const struct file_operations *ops;//包含具体可用的操作函数 struct list_head list; dev_t dev;//主、次设备号 unsigned int count; };
相关函数:
cdev_alloc(为cdev结构体分配内存空间)、cdev_init、
cdev_add(向驱动注册函数)、cdev_del
设备号相关的宏:MKDEV、MAJOR、MINOR
新的接口注册字符设备驱动步骤:
1、注册/自动分配主次设备号
register_chrdev_region(注册设备号)/alloc_chrdev_region(自动分配设备号)
2、注册字符设备驱动
cdev_init
cdev_add
新的接口注销字符设备驱动步骤:
1、注销字符设备驱动
cdev_del
2、注销申请的主次设备号
unregister_chrdev_region
中途出错的倒影式错误处理方法
(1).内核中很多函数包含了很多的操作,这些操作每一步都可能出错,而且出错
后面的步骤就没有进行下去的必要了。
(2).将容易出错的地方分别做顺序标记,一旦出错,按顺序回滚错误处理。比如,第三步出错了,则利用goto跳转到相应的出错标记flag处,
处理第一、二步成功执行后产生的东西(比如分配的设备号进行注销)
使用cdev_alloc函数:
实现功能:使用kalloc分配一个cdev结构体堆内存空间给一个cdev结构体指针变量
目的:减少.data数据段大小(仅占用一个指针的数据段),方便内存的按需释放
(结构体指针变量仅占用一个指针的大小,而结构体变量占用一个结构体的大小)
程序使用内存的情况:
全局变量 .data数据段
局部变量 栈
malloc 堆
附注:使用cdev_alloc函数时,cdev_init函数可以使用一句代码替代:如
pcdev = cdev_alloc(); pcdev->owner = THIS_MODULE //cdev_init(pcdev,&test_fops); pcdev->ops = &test_fops;