Linux中probe何时被调用

本文深入探讨了PCI总线驱动模型的实现机制,详细分析了从pci_driver结构注册到设备探测的整个流程,包括pci_device_probe和driver_probe_device函数的作用及调用过程。
摘要由CSDN通过智能技术生成

// 以PCI总线驱动模型, XDMA设备源码, 2.6.26内核源码为例

// 网上通用解释如下:

  static const struct pci_device_id cpi_ids[] = {
    	{PCI_DEVICE(0x10ee, 0x903f), },
    	{PCI_DEVICE(0x10ee, 0x9038), },
    	……
    	{0,},
    };

static struct pci_driver pci_driver = {
	.name = DRV_MODULE_NAME,
	.id_table = pci_ids,
	.probe = probe_one,
	.remove = remove_one,
	.err_handler = &xdma_err_handler,
};

// 初始化入口函数
static int __init xdma_mod_init(void)
{
	int rv;
	extern unsigned int desc_blen_max;
	extern unsigned int sgdma_timeout;
	pr_info("%s", version);
	if(desc_blen_max > XDMA_DESC_BLEN_MAX)
		desc_blen_max = XDMA_DESC_BLEN_MAX;
	pr_info("desc_blen_max: 0x%x/%u, sgdma_timeout: %u sec.\n",
		desc_blen_max, desc_blen_max, sgdma_timeout);
	rv = xdma_cdev_init();
	if(rv < 0)
		return rv;
	return pci_register_driver(&pci_driver);
}

static inline int __must_check pci_register_driver(struct pci_driver *driver)
{
	return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}

int __pci_register_driver(struct pci_driver *drv, struct module *owner,
			  const char *mod_name)
{
	int error;
	/* initialize common driver fields */
	drv->driver.name = drv->name;
	drv->driver.bus = &pci_bus_type;
	drv->driver.owner = owner;
	drv->driver.mod_name = mod_name;
	……
	error = driver_register(&drv->driver);
	……
}

int driver_register(struct device_driver *drv)
{
	……
	ret = bus_add_driver(drv);
	……
}			 

int bus_add_driver(struct device_driver *drv)
{
	……
	driver_attach(drv);
	……
}

int driver_attach(struct device_driver *drv)
{
	return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}

int bus_for_each_dev(struct bus_type *bus, struct device *start,
		     void *data, int (*fn)(struct device *, void *))
{
	struct klist_iter i;
	struct device *dev;
	int error = 0;

	if (!bus)
		return -EINVAL;

	klist_iter_init_node(&bus->p->klist_devices, &i,
			     (start ? &start->knode_bus : NULL));
	while ((dev = next_device(&i)) && !error)
		error = fn(dev, data);	//这里调用__driver_attach
	klist_iter_exit(&i);
	return error;
}


static int __driver_attach(struct device *dev, void *data)
{
	struct device_driver *drv = data;

	if (dev->parent)	/* Needed for USB */
		down(&dev->parent->sem);
	down(&dev->sem);
	if (!dev->driver)
		driver_probe_device(drv, dev);
	up(&dev->sem);
	if (dev->parent)
		up(&dev->parent->sem);

	return 0;
}

int driver_probe_device(struct device_driver *drv, struct device *dev)
{
	int ret = 0;

	if (!device_is_registered(dev))
		return -ENODEV;
	if (drv->bus->match && !drv->bus->match(dev, drv))
		goto done;

	pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
		 drv->bus->name, __func__, dev->bus_id, drv->name);

	ret = really_probe(dev, drv);

done:
	return ret;
}

static int really_probe(struct device *dev, struct device_driver *drv)
{
	……
	dev->driver = drv;	//将device_driver结构赋值到device中
	……
	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev);	//此处调用驱动中的probe函数
		if (ret)
			goto probe_failed;
	}
	……
}
  • 解释到这里就结束了,可我注册的驱动函数为pci_driver.probe,

  • 此处调用的是pci_driver.driver.probe

  • 这两个貌似并没有联系,且参数也不一样,怎么解释?

  • 查看源码之后解释如下:

  • 在really_probe()函数中, 先判断dev->bus->probe是否存在,

  • 实际PCI、USB、IIC等标准总线,这个函数是存在的,

  • 所以此处并不会执行下面的else语句,

  • dev->bus在__pci_register_driver函数中赋值为&pci_bus_type.

// pci_bus_type结构如下:

 struct bus_type pci_bus_type = {
	.name		= "pci",
	.match		= pci_bus_match,
	.uevent		= pci_uevent,
	.probe		= pci_device_probe,
	.remove		= pci_device_remove,
	.suspend	= pci_device_suspend,
	.suspend_late	= pci_device_suspend_late,
	.resume_early	= pci_device_resume_early,
	.resume		= pci_device_resume,
	.shutdown	= pci_device_shutdown,
	.dev_attrs	= pci_dev_attrs,
};

// 所以在really_probe中实际调用的是pci_device_probe函数。

static int pci_device_probe(struct device * dev)
{
	int error = 0;
	struct pci_driver *drv;
	struct pci_dev *pci_dev;

	drv = to_pci_driver(dev->driver);	//通过device结构得到pci_driver
	pci_dev = to_pci_dev(dev);
	pci_dev_get(pci_dev);
	error = __pci_device_probe(drv, pci_dev);
	if (error)
		pci_dev_put(pci_dev);

	return error;
}
 
 
 static int
__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
{
	const struct pci_device_id *id;
	int error = 0;

	if (!pci_dev->driver && drv->probe) {
		error = -ENODEV;

		id = pci_match_device(drv, pci_dev);
		if (id)
			error = pci_call_probe(drv, pci_dev, id);
		if (error >= 0) {
			pci_dev->driver = drv;
			error = 0;
		}
	}
	return error;
}


static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
			  const struct pci_device_id *id)
{
	int error;
	……
	error = drv->probe(dev, id);			//此处调用驱动中的probe函数
	……
	return error;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值