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