概述
转自:http://blog.csdn.net/wbcuc/article/details/8618363
参考:
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驱动,注册到总线
- ……………………
- }
/**
* 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); //驱动的匹配函数
- ………………
- }
/**
* 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 - 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);
- ...
- }
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 %sn",
- drv->bus->name, __func__, dev_name(dev), drv->name);//这个信息可以看到我们注册的总 驱动、设备和总线 信息
- goto done;
- ………………
- }
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 %sn",
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;
- }
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;
- };
// 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
最后
以上就是单身小松鼠为你收集整理的Linux驱动probe函数调用的全部内容,希望文章能够帮你解决Linux驱动probe函数调用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复