linux 源码 网络驱动,Linux网络驱动源码分析(一)

功能:注册PCI驱动,参数为要注册的pci驱动的结构体。

下面来详细的分析以下这个函数,如此,才能更清楚的了解驱动和设备的匹配过程。

pci_register_driver->driver_register(&drv->driver);->bus_add_driver->driver_attach->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

在这个过程中有涉及到一个更为抽象的结构体struct device_driver,它是pci_driver的更高级的抽象,即下层是pci_driver,其上是device_driver,这符合通常的程序设计逻辑,越往上层抽象级别越高,因为在操作系统看来,它并不需要知道具体是什么设备,所有的设备对操作系统来说都是相同的,即都用struct device_driver来表示。

在driver_register中先调用driver_find(drv->name, drv->bus),首先在相应的总线上查找drv->name的驱动是否已经被注册过,如果被注册过则返回,否则进行注册过程,即调用bus_add_driver(drv)。

int bus_add_driver(struct device_driver *drv)函数首先判断当前总线是否支持自动探测,如果执行则执行探测函数driver_attach(drv)。

if (drv->bus->p->drivers_autoprobe) {

error = driver_attach(drv);

if (error)

goto out_unregister;

}int driver_attach(struct device_driver *drv)

{

return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

这个函数对PCI总线的上所有已经连接的PCI设备与当前的PCI驱动进程一次匹配的过程,即对每一个PCI设备都调用匹配函数__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;

}

该函数首先判断总线提供的match函数是否为空,如果非空则执行总线提供的match函数,在rtl8139网络驱动中,match非空,参见代码:

drv->driver.bus = &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,

.shutdown = pci_device_shutdown,

.dev_attrs = pci_dev_attrs,

.bus_attrs = pci_bus_attrs,

.pm = PCI_PM_OPS_PTR,

};

这里将match函数即pci_bus_match,最后该函数调用到

static inline const struct pci_device_id *

pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)

{

if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&

(id->device == PCI_ANY_ID || id->device == dev->device) &&

(id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&

(id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&

!((id->class ^ dev->class) & id->class_mask))

return id;

return NULL;

}

在这里进行了pci_driver和pci_dev的匹配,如果匹配成功,则返回pci_device_id。如果匹配不成功,而且当前设备还没有驱动,则调用driver_probe_device(drv,dev)。

int driver_probe_device(struct device_driver *drv, struct device *dev)

{

int ret = 0;

if (!device_is_registered(dev))

return -ENODEV;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",

drv->bus->name, __func__, dev_name(dev), drv->name);

pm_runtime_get_noresume(dev);

pm_runtime_barrier(dev);

ret = really_probe(dev, drv);

pm_runtime_put_sync(dev);

return ret;

}

执行到这里说明,说明PCI总线没有提供match函数或者总线提供的match函数返回非空。还需要进行更深层次的探测,至少在总线提供的match函数中仅仅是进行了匹配,并没有将驱动和设备关联起来,这些操作就是在下面的函数中实现的。

int driver_probe_device(struct device_driver *drv, struct device *dev)

{

int ret = 0;

if (!device_is_registered(dev))

return -ENODEV;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",

drv->bus->name, __func__, dev_name(dev), drv->name);

pm_runtime_get_noresume(dev);

pm_runtime_barrier(dev);

ret = really_probe(dev, drv);

pm_runtime_put_sync(dev);

return ret;

}

重点看really_probe函数:

static int really_probe(struct device *dev, struct device_driver *drv)

{

int ret = 0;

atomic_inc(&probe_count);

pr_debug("bus: '%s': %s: probing driver %s with device %s\n",

drv->bus->name, __func__, drv->name, dev_name(dev));

WARN_ON(!list_empty(&dev->devres_head));

dev->driver = drv;

if (driver_sysfs_add(dev)) {

printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",

__func__, dev_name(dev));

goto probe_failed;

}

if (dev->bus->probe) {

ret = dev->bus->probe(dev);

if (ret)

goto probe_failed;

} 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;

probe_failed:

devres_release_all(dev);

driver_sysfs_remove(dev);

dev->driver = NULL;

if (ret != -ENODEV && ret != -ENXIO) {

/* driver matched but the probe failed */

printk(KERN_WARNING

"%s: probe of %s failed with error %d\n",

drv->name, dev_name(dev), ret);

}

/*

* Ignore errors returned by ->probe so that the next driver can try

* its luck.

*/

ret = 0;

done:

atomic_dec(&probe_count);

wake_up(&probe_waitqueue);

return ret;

}

在此函数中,首先将驱动和设备关联起来,即红色代码dev->driver = drv; 指明了当前设备的驱动。按照常规的程序设计思想,驱动和设备关联后是否还需要做一些其他工作才能是设备在相应的驱动下正常工作呢,这就是probe函数实现的功能了,很明显设备和驱动获取都需要做一些工作,因此这里分别留出设备和驱动的probe函数。其中设备的probe即设备所在总线的probe,这里暂且不去分析,因为与网络驱动关系不大,都是PCI总线相关的东西,重点来看驱动的probe,在前面提到的pci_driver结构体中,对于rtl8139驱动来说,其pci_driver结构体被初始化为:

static struct pci_driver rtl8139_pci_driver = {

.name = DRV_NAME,

.id_table = rtl8139_pci_tbl,

.probe = rtl8139_init_one,

.remove = __devexit_p(rtl8139_remove_one),

#ifdef CONFIG_PM

.suspend = rtl8139_suspend,

.resume = rtl8139_resume,

#endif /* CONFIG_PM */

};

这里即调用rtl8139_init_one,经过上面的逐层分析,我们从pci核心驱动一步一步的走到了rtl8139网络设备的驱动,豁然开朗了,以后看网络驱动的时候就不会感到开始的地方有点迷糊了。代码分析重在代码之间的过渡,如果衔接不好,很多地方都会产生疑问。在下一篇文章中,将会详细分析rtl8139网络驱动的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值