Linux驱动 probe函数调用

本文详细解析了Linux中驱动注册的过程,从driver_register函数开始,深入介绍了如何将驱动注册到总线,包括bus_add_driver、driver_attach等关键函数的作用及其实现细节。此外,还特别分析了针对PCI Express设备的匹配函数pcie_port_bus_match的具体实现。
ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

参考:

http://blog.chinaunix.net/space.php?uid=15887868&do=blog&id=2758294

http://www.cnblogs.com/hoys/archive/2011/04/01/2002299.html
1,driver_register把驱动注册到总线 

/**
 * driver_register - register driver with bus
 * @drv: driver to register
 * We pass off most of the work to the bus_add_driver() call,
 * since most of the things we have to do deal with the bus
 * structures.
 */
int driver_register(struct device_driver *drv)
{
……………………
	if ((drv->bus->probe && drv->probe) ||
	    (drv->bus->remove && drv->remove) ||
	    (drv->bus->shutdown && drv->shutdown))

	ret = bus_add_driver(drv);//把drv驱动,注册到总线
……………………
}

2,驱动注册到总线的实现函数
/**
 * bus_add_driver - Add a driver to the bus.        -----在总线上加入一个驱动
 * @drv: driver.
 */
int bus_add_driver(struct device_driver *drv)
{
………………
	if (drv->bus->p->drivers_autoprobe) {
		error = driver_attach(drv);      //驱动的匹配函数
………………
}
3,driver_attach()
/**
 * driver_attach - try to bind driver to devices.
 * @drv: driver.
 *
 * Walk the list of devices that the bus has on it and try to
 * match the driver with each one.  If driver_probe_device()
 * returns 0 and the @dev->driver is set, we've found a
 * compatible pair.
 */
int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//注意这里的__driver_attach
}
EXPORT_SYMBOL_GPL(driver_attach);
上面真正起作用的是__driver_attach:
static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	/*
	 * Lock device and try to bind to it. We drop the error
	 * here and always return 0, because we need to keep trying
	 * to bind to devices and some drivers will return an error
	 * simply if it didn't support the device.
	 *
	 * driver_probe_device() will spit a warning if there
	 * is an error.
	 */

	if (!driver_match_device(drv, dev))
		return 0;

	if (dev->parent)	/* Needed for USB */
		device_lock(dev->parent);
	device_lock(dev);
	if (!dev->driver)
		driver_probe_device(drv, dev);//看下这个函数的实现过程
	device_unlock(dev);
	if (dev->parent)
		device_unlock(dev->parent);

	return 0;
}
int driver_probe_device(structdevice_driver *drv, struct device *dev)
{
...
//1.先是判断bus是否match:
if (drv->bus->match && !drv->bus->match(dev, drv))
   goto done;
//2.再具体执行probe:
ret = really_probe(dev, drv);
...
}
4,really_probe是我们真正要找的函数
static int really_probe(struct device *dev, struct device_driver *drv)
{
……………………
//1.先是调用的驱动所属总线的probe函数:
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} 
//2.再调用的驱动中的probe函数:
	else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}

	driver_bound(dev);
	ret = 1;
	pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
		 drv->bus->name, __func__, dev_name(dev), drv->name);//这个信息可以看到我们注册的总 驱动、设备和总线  信息
	goto done;
………………
}

5.drv->bus->match(dev, drv)

driver_probe_device(struct device_driver *drv, struct device *dev)会通过drv->bus->match()来匹配PCIE设备与相应的设备驱动。对于内核为2.6.27的bus驱动“pci_express”来说,是通过调用pcie_port_bus_match()实现驱动match的。

 

static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
{
	struct pcie_device *pciedev;
	struct pcie_port_service_driver *driver;

	if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type)
		return 0;
	
	pciedev = to_pcie_device(dev);
	driver = to_service_driver(drv);
	if (   (driver->id_table->vendor != PCI_ANY_ID && 
		driver->id_table->vendor != pciedev->id.vendor) ||
	       (driver->id_table->device != PCI_ANY_ID &&
		driver->id_table->device != pciedev->id.device) ||	
	       (driver->id_table->port_type != PCIE_ANY_PORT &&
		driver->id_table->port_type != pciedev->id.port_type) ||
		driver->id_table->service_type != pciedev->id.service_type )
		return 0; 
         // driver与pciedev的id_table匹配成功,才match成功;
	return 1;
}
// id_table的结构定义如下,match时只关注vendor,device,port_type,service_type
struct pcie_port_service_id {
	__u32 vendor, device;		/* Vendor and device ID or PCI_ANY_ID*/
	__u32 subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
	__u32 class, class_mask;	/* (class,subclass,prog-if) triplet */
	__u32 port_type, service_type;	/* Port Entity */
	kernel_ulong_t driver_data;
};

 

打印出的驱动设备信息如:

………………

[    0.588087] bus: 'platform': really_probe: bound device power.0to driver power  // 总线:platform  设备:power.0  驱动:power
[    0.661226] bus: 'platform': really_probe: bound device s3c24xx-pwm.0 to driver s3c24xx-pwm
[    0.678552] bus: 'platform': really_probe: bound device s3c24xx-pwm.1 to driver s3c24xx-pwm
[    0.695971] bus: 'platform': really_probe: bound device s3c24xx-pwm.2 to driver s3c24xx-pwm
[    0.713389 bus: 'platform': really_probe: bound device s3c24xx-pwm.3 to driver
……………………

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think> 我们正在处理一个关于Linux NVMe驱动的问题。用户询问“在Linux驱动调用nvme_probe的函数”是什么。根据提供的引用,我们可以从引用[2]和引用[4]中提取关键信息。 引用[2]提到:“文章目录 Nvme Probe概述1 Nvme Probe 流程 开胃前菜 主要数据结构介绍2 probe 流程详细介绍...”,并在其中提到了probe的流程。引用[4]则直接指出:“Linux NVMe Driver学习笔记之3:nvme_probe函数解析。从上面的代码中,我们可以了解到,nvme_init_ctrl的作用主要是...”,表明nvme_probe函数是在驱动中用于初始化NVMe控制器的。 在Linux设备驱动模型中,probe函数通常是在设备与驱动匹配时由总线核心调用的。对于PCI设备(NVMe设备通常是PCI设备),当PCI设备被检测到时,内核会调用与该设备匹配的驱动probe函数。 从引用[3]中我们得知,nvme_reset_work函数是在初始化时通过nvme_probe()赋值的。而引用[1]提到nvme_init_ctrl函数中设置了scan_work,并且引用了笔记3(即引用[4])中的内容。 具体到调用nvme_probe的函数,根据Linux PCI驱动的架构,通常是由PCI子系统在发现设备与驱动匹配后调用驱动probe函数。对于NVMe驱动,这个驱动结构体定义在驱动代码中,其中应该指定了probe函数为nvme_probe。 因此,我们可以推断,调用nvme_probe的函数是PCI总线核心的代码,具体来说,当PCI设备与nvme_driver(NVMe驱动pci_driver结构体)匹配时,PCI核心会调用驱动probe函数,即nvme_probe。 在引用[4]中,我们可以找到这样的信息:在nvme_probe函数中,进行了NVMe控制器的初始化。因此,调用nvme_probe的函数应该是PCI子系统中的某个函数,例如pci_device_probe。 但是,我们也可以从引用[2]中看到,probe流程中涉及了PCI设备的内存映射和设置,这进一步证实了nvme_probe作为PCI驱动probe函数被PCI核心调用。 因此,我们可以回答:在Linux驱动中,调用nvme_probe的函数是PCI总线核心在匹配设备与驱动调用的,通常是`pci_device_probe`函数(或类似机制)会调用驱动注册probe函数,即`nvme_probe`。 为了确保准确性,我们可以参考标准的Linux PCI驱动模型:驱动注册一个pci_driver结构体,其中包含.probe成员指向nvme_probe。当PCI设备与驱动匹配时,内核的PCI子系统会调用这个probe函数。 因此,直接调用nvme_probe的函数是PCI子系统中的函数(例如`driver_probe_device`),但触发调用的是设备与驱动匹配的过程。 总结:调用nvme_probe的函数是Linux内核PCI子系统中的函数,具体是当NVMe PCI设备与驱动匹配时,由PCI总线核心调用。 </think>在Linux NVMe驱动中,调用`nvme_probe`函数的主要入口点是**PCI子系统**。具体流程如下: 1. **驱动注册阶段** NVMe驱动初始化时,会向PCI子系统注册`struct pci_driver`结构体: ```c static struct pci_driver nvme_driver = { .name = "nvme", .id_table = nvme_id_table, // 设备ID匹配表 .probe = nvme_probe, // 指向nvme_probe函数 .remove = nvme_remove, .shutdown = nvme_shutdown, .driver.pm = &nvme_dev_pm_ops, }; ``` 2. **触发调用时机** 当内核检测到匹配的PCI设备时(如SSD控制器),PCI子系统通过以下路径调用`nvme_probe`: ``` pci_device_probe() → really_probe() → drv->probe(dev) // 即nvme_driver.probe → nvme_probe() // 最终执行 ``` 3. **关键引用证据** - 引用[2]明确指出:NVMe设备的初始化始于`nvme_probe`,该函数处理PCI设备映射、工作队列初始化和控制器复位[^2]。 - 引用[3]补充:`nvme_reset_work`(控制器复位函数)是在`nvme_probe()`执行过程中被赋值注册的[^3]。 - 引用[4]进一步验证:`nvme_init_ctrl`(创建字符设备的核心函数)由`nvme_probe`调用[^4]。 4. **调用关系示意** $$ \text{pci\_device\_probe()} \xrightarrow{\text{匹配设备}} \text{nvme\_probe()} \xrightarrow{\text{初始化}} \begin{cases} \text{nvme\_dev\_map()} & \text{(PCI资源映射)} \\ \text{nvme\_init\_ctrl()} & \text{(控制器初始化)} \\ \text{nvme\_setup\_prp\_pools()} & \text{(DMA内存池)} \end{cases} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值