Linux驅動 probe函數調用

參考:

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 driverpower  //總線: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
……………………

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章