0
点赞
收藏
分享

微信扫一扫

【C语言】linux内核pci_register_driver

一世独秀 04-04 17:00 阅读 2

一、注释

以下是对源代码中英文注释的中文翻译,可能会略去一些编程上的专有词汇(例如函数名、类型名等),以使翻译更易理解。

// drivers\pci\pci-driver.c
/**
 * __pci_register_driver - 注册一个新的PCI驱动
 * @drv: 需要注册的驱动结构体
 * @owner: 拥有该drv的模块
 * @mod_name: 模块的名称字符串
 *
 * 将驱动结构体添加到已注册驱动的列表中。
 * 注册失败时返回负值,否则返回0。
 * 如果没有发生错误,即使在注册期间没有设备被认领,
 * 驱动仍然会保持注册状态。
 */
int __pci_register_driver(struct pci_driver *drv, struct module *owner,
                          const char *mod_name)
{
    /* 初始化通用驱动字段 */
    drv->driver.name = drv->name;
    drv->driver.bus = &pci_bus_type;
    drv->driver.owner = owner;
    drv->driver.mod_name = mod_name;
    drv->driver.groups = drv->groups;

    // 初始化动态ID锁和列表
    spin_lock_init(&drv->dynids.lock);
    INIT_LIST_HEAD(&drv->dynids.list);

    /* 在核心层注册 */
    return driver_register(&drv->driver);
}
EXPORT_SYMBOL(__pci_register_driver);

// include\linux\pci.h
/* 支持可热插拔设备的正确探测 */
int __must_check __pci_register_driver(struct pci_driver *, struct module *,
                                       const char *mod_name);

/* pci_register_driver() 必须是一个宏,这样才能扩展 KBUILD_MODNAME */
#define pci_register_driver(driver)        \
    __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)


/**
 * module_pci_driver() - 用于注册PCI驱动的辅助宏
 * @__pci_driver: pci_driver结构体
 *
 * 这是一个辅助宏,用于PCI驱动,如果在模块的初始化/退出中没有特殊操作。
 * 这个宏可以简化很多代码。每个模块只能使用这个宏一次,且使用后会替代
 * module_init() 和 module_exit()。
 */
#define module_pci_driver(__pci_driver) \
    module_driver(__pci_driver, pci_register_driver, pci_unregister_driver)

/**
 * builtin_pci_driver() - 注册PCI驱动的辅助宏
 * @__pci_driver: pci_driver结构体
 *
 * 这是一个辅助宏,用于PCI驱动,如果在它们的初始化代码中没有特殊操作。
 * 这个宏可以简化很多代码。每个驱动只能使用这个宏一次,且使用后将替代
 * device_initcall(...)。
 */
#define builtin_pci_driver(__pci_driver) \
    builtin_driver(__pci_driver, pci_register_driver)

在源代码注释中,它描述了如何在Linux内核中注册一个PCI设备驱动。提供了一些宏来简化驱动注册和初始化过程。这些宏对于不需要复杂初始化和退出函数的标准PCI驱动来说是非常有用的,可以减少代码冗余。

二、讲解

这些代码片段主要来自于 Linux 内核源码,涉及到 PCI(Peripheral Component Interconnect)驱动程序的注册和管理。PCI 是一种连接计算机外围设备的总线标准。

第一段代码是 __pci_register_driver 函数的实现。这个函数用来注册一个新的 PCI 驱动程序。让我们逐行解释:

int __pci_register_driver(struct pci_driver *drv, struct module *owner, const char *mod_name)

这个函数接受3个参数:要注册的驱动程序结构体,驱动程序所属的模块以及模块的名称字符串。

drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
drv->driver.mod_name = mod_name;
drv->driver.groups = drv->groups;

这部分代码初始化了 pci_driver 结构体的一些成员字段。这包括驱动程序的名称、它所属的总线类型(在这里是 PCI 总线)、它的拥有者(通常是加载它的模块)、模块名称以及属性组。

spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);

这两行代码初始化了用于动态设备 ID 管理的自旋锁和链表头。

return driver_register(&drv->driver);

最终调用了 driver_register 函数,该函数将 pci_driver 结构体添加到内核的驱动程序列表中。如果注册成功,返回0,否则返回负值错误码。

EXPORT_SYMBOL(__pci_register_driver);

这行代码导出上面定义的 __pci_register_driver 函数,使得其他内核模块可以调用它。

-----

第二段代码中 pci_register_driver 是一个宏定义,其作用是将驱动程序注册到PCI子系统。它封装了 __pci_register_driver 函数,将当前模块(`THIS_MODULE`)和模块名称(通过 KBUILD_MODNAME 宏定义)作为参数传递。

#define pci_register_driver(driver) \
    __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

-----

第三段代码包含了两个辅助宏:`module_pci_driver` 和 builtin_pci_driver。这些宏简化了驱动程序的初始化和退出代码。

#define module_pci_driver(__pci_driver) \
  module_driver(__pci_driver, pci_register_driver, pci_unregister_driver)

module_pci_driver 宏定义用于注册和注销驱动程序,它用来替代 module_init 和 module_exit 宏。这使得不需要显式定义初始化和清理函数的 PCI 驱动程序可以更简洁地编写。

#define builtin_pci_driver(__pci_driver) \
  builtin_driver(__pci_driver, pci_register_driver)

builtin_pci_driver 宏是类似的,但是用于内建驱动程序的注册。调用它会替代典型的 device_initcall 宏。这主要用于那些编译到内核本身,而不是作为模块加载的驱动程序。

总结而言,这些代码片段涵盖了 Linux 内核中 PCI 驱动程序注册的不同方面,从注册具体的驱动到提供宏简化驱动程序模块的编写。这些机制都是 Linux 设备驱动框架的一部分,用于确保各种设备的驱动程序可以被正确识别、加载和管理。

通义灵码

在Linux内核中,pci_register_driver() 是一个用于注册PCI(Peripheral Component Interconnect)设备驱动程序的关键函数。它允许驱动程序声明自己能够支持特定类型的PCI设备,以便当系统检测到匹配的PCI设备插入时,能够自动加载并初始化相应的驱动。

#include <linux/pci.h>

static struct pci_driver my_pci_driver = {
    .name     = "my_pci_drv",
    .id_table = my_pci_ids,
    .probe    = my_pci_probe,
    .remove   = my_pci_remove,
    /* 其他可能的回调函数 */
};

static int __init my_pci_init(void)
{
    return pci_register_driver(&my_pci_driver);
}

static void __exit my_pci_exit(void)
{
    pci_unregister_driver(&my_pci_driver);
}

module_init(my_pci_init);
module_exit(my_pci_exit);

上面的示例展示了如何使用 pci_register_driver() 函数:

  • my_pci_driver 是一个 struct pci_driver 类型的变量,其中包含了驱动程序的相关信息:

    • .name 是驱动程序的名字,用于标识和调试。
    • .id_table 是一个包含一组PCI设备ID列表的表,每个设备ID定义了驱动程序所支持的设备范围。
    • .probe 是一个回调函数,当发现新的PCI设备并且其ID与.id_table中定义的ID相匹配时,系统将调用这个函数来初始化设备。
    • .remove 是一个在设备被移除或驱动程序卸载时调用的清理函数。
  • my_pci_init() 是模块的初始化函数,在模块被加载时调用,它调用 pci_register_driver() 注册驱动程序。

  • my_pci_exit() 是模块的退出函数,在模块被卸载时调用,它调用 pci_unregister_driver() 取消注册驱动程序。

通过这样的机制,Linux内核能够灵活管理各种PCI设备的动态插拔,实现了设备驱动的即插即用(Plug-and-Play)。

举报

相关推荐

0 条评论