Linux驱动中常用的宏
1. module_i2c_driver(adxl34x_driver)
//展开为: static int __int adxl34x_driver_init(void) { return i2c_register_driver(&adxl34x_driver); } module_init(adxl34x_driver_init); static void __exit adxl34x_driver_exit(void) { return i2c_del_driver(&adxl34x_driver); } module_exit(adxl34x_driver_exit);
作用: 代替注册初始化函数和module_init()和module_exit(),如果在初始化函数中什么也不做的话就可以用此来替换。
2. module_platform_driver
//module_platform_driver(gpio_led_driver) 展开后: static int __init gpio_led_driver_init(void) { return platform_driver_register(&gpio_led_driver); } module_init(gpio_led_driver_init); static void __exit gpio_led_driver_exit(void) { platform_driver_unregister(&gpio_led_driver); } module_exit(gpio_led_driver_exit);
作用: 当在 module_init/module_exit 中不做其它任何事的时候方便使用。
3. MODULE_DEVICE_TABLE (usb, skel_table);
//在linux/module.h中定义为: #define MODULE_DEVICE_TABLE(usb, skel_table) \ extern const typeof(name) __mod_##type##__##name##_device_table \ __attribute__ ((unused, alias(__stringify(name))))
该宏生成一个名为__mod_pci_device_table的局部变量,该变量指向第二个参数。内核构建时,depmod程序会在所有模块中搜索符号__mod_pci_device_table,把数据(设备列表)从模块中抽出,添加到映射文件/lib/modules/KERNEL_VERSION/modules.pcimap中,当depmod结束之后,所有的PCI设备连同他们的模块名字都被该文件列出。当内核告知热插拔系统一个新的PCI设备被发现时,热插拔系统使用modules.pcimap文件来找寻恰当的驱动程序。
MODULE_DEVICE_TABLE的第一个参数是设备的类型,如果是USB设备,那自然是usb(如果是PCI设备,那将是pci,这两个子系统用同一个宏来注册所支持的设备)。后面一个参数是设备表,这个设备表的最后一个元素是空的,用于标识结束。例:假如代码定义了USB_SKEL_VENDOR_ID是 0xfff0, USB_SKEL_PRODUCT_ID是0xfff0,也就是说,当有一个设备接到集线器时,usb子系统就会检查这个设备的 vendor ID和product ID,如果他们的值是0xfff0时,那么子系统就会调用这个模块作为设备的驱动。
4. IS_ERR()
它就是判断返回的指针是否有错,如果指针并不是指向最后一个page,那么没有问题,申请成功了,如果指针指向了最后一个page,那么说明实际上这不是一个有效的指针,这个指针里保存的实际上是一种错误代码.而通常很常用的方法就是先用IS_ERR()来判断是否是错误,然后如果是,那么就调用PTR_ERR()来返回这个错误代码,也就是提供一个信息给调用者,如果你只需要知道是否出错,而不在乎因为什么而出错,那你当然不用调用PTR_ERR()了。
5. LIST_HEAD LIST_HEAD_INIT
LIST_HEAD(name) == struct list_head name = { &(name), &(name) } #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
6. container_of
#define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); })
已有ptr指针,执行type类型的member成员,返回指向包含member成员的type类型的指针。
若ptr执行的成员不是实体成员,而是指针实体,那么可以使用如下变体:
#define container_of_ptr(ptr, type, member) ({ \ const typeof(((type *)0)->member) __mptr = (ptr); \ (type *)((char *)__mptr - offsetof(type, member)); })
7. list_for_each_entry(pos, head, member)
#define list_for_each_entry(pos, head, member) \ for (pos = __container_of((head)->next, pos, member); \ &pos->member != (head); \ pos = __container_of(pos->member.next, pos, member))
pos 是类型为单元类型的游标
head 是链表头,从链表头开始遍历
member head->next成员是指向member成员的,即单元是通过member成员挂载在链表上的
举例:
//module.c print_unload_info() struct module_use *use; list_for_each_entry(use, &mod->source_list, source_list) { //使用 use 指针 }
6. list_for_each_entry_safe(pos, n, head, member)
#define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member), \ n = list_next_entry(pos, member); \ &pos->member != (head); \ pos = n, n = list_next_entry(n, member))
所谓的safe就是提前取了下一个成员,因此在使用pos指针后可以删除pos所在的节点,而不影响继续遍历。
举例:
//of_irq_init() struct of_intc_desc *desc, *temp_desc; list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { //使用 desc 指针 list_del(&desc->list); }
posted on 2017-08-30 16:56 Hello-World3 阅读(943) 评论(0) 编辑 收藏 举报