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编辑  收藏  举报

导航