Chinaunix首页 | 论坛 | 博客
  • 博客访问: 525431
  • 博文数量: 51
  • 博客积分: 345
  • 博客等级: 民兵
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-21 12:02
个人简介

文章分类

全部博文(51)

文章存档

2023年(2)

2022年(1)

2021年(7)

2020年(10)

2019年(2)

2016年(20)

2015年(5)

2014年(1)

2011年(3)

我的朋友

分类: LINUX

2016-09-12 17:57:35

Atheros wifi驱动加载流程为例来说明PCI设备驱动加载流程

static struct pci_driver ath_pci_driver = {

    .name       = "ath_pci",

    .id_table   = ath_pci_id_table,      //列出支持的pci类型

    .probe      = ath_pci_probe,

    .remove     = ath_pci_remove,

#ifdef ATH_BUS_PM

    .suspend    = ath_pci_suspend,

    .resume     = ath_pci_resume,

#endif /* ATH_BUS_PM */

    /* Linux 2.4.6 has save_state and enable_wake that are not used here */

};

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,

};

 

pci_register_driver

-->__pci_register_driver          //register a new pci driverAdds the driver structure to the list of registered drivers.

int __pci_register_driver(struct pci_driver *drv, struct module *owner,

                              const char *mod_name)

{

         int error;

 

         /* initialize common driver fields */ pci设备驱动统一信息;

         drv->driver.name = drv->name;

         drv->driver.bus = &pci_bus_type;

         drv->driver.owner = owner;

         drv->driver.mod_name = mod_name;

 

         spin_lock_init(&drv->dynids.lock);

         INIT_LIST_HEAD(&drv->dynids.list);

 

         /* register with core */

         error = driver_register(&drv->driver);     //register driver with bus

         if (error)

                   goto out;

 

         error = pci_create_newid_files(drv);

         if (error)

                   goto out_newid;

out:

         return error;

 

out_newid:

         driver_unregister(&drv->driver);

         goto out;

}

 

driver_register-->bus_add_driver   //Add a driver to the bus.

-->初始化struct driver_private kobject相关;

-->driver_attach

         提取出drv_bus上的所有设备,依次调用__driver_attach

         -->__driver_attach

                   -->driver_match_device

                   调用pci_bus_match,通过比对id_table表项与设备信息来确认驱动是否支持该设备;

 

static int __driver_attach(struct device *dev, void *data)

{

         struct device_driver *drv = data;

 

         if (!driver_match_device(drv, dev))

                   return 0;

 

         if (dev->parent)  /* Needed for USB */

                   device_lock(dev->parent);

         device_lock(dev);

         if (!dev->driver)  //设备已经绑定驱动,则跳过probe流程;

                   driver_probe_device(drv, dev);       // attempt to bind device & driver together

         device_unlock(dev);

         if (dev->parent)

                   device_unlock(dev->parent);

 

         return 0;

}

 

--> 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;     //dev绑定driver

              if (driver_sysfs_add(dev)) {                //新建sysfs

                            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);             // pci_device_probe

                            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 == -EPROBE_DEFER) {

                            /* Driver requested deferred probing */

                            dev_info(dev, "Driver %s requests probe deferral\n", drv->name);

                            driver_deferred_probe_add(dev);

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

              } else {

                            pr_debug("%s: probe of %s rejects match %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;

}

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

              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);           //检查pci设备与驱动是否匹配;

                            if (id)

                                          error = pci_call_probe(drv, pci_dev, id);     //调用local_pci_probe

                            if (error >= 0) {

                                          pci_dev->driver = drv;

                                          error = 0;

                            }

              }

              return error;

}

static long local_pci_probe(void *_ddi)

{

              struct drv_dev_and_id *ddi = _ddi;

              struct device *dev = &ddi->dev->dev;

              int rc;

 

              /* Unbound PCI devices are always set to disabled and suspended.

               * During probe, the device is set to enabled and active and the

               * usage count is incremented.  If the driver supports runtime PM,

               * it should call pm_runtime_put_noidle() in its probe routine and

               * pm_runtime_get_noresume() in its remove routine.

               */

              pm_runtime_get_noresume(dev);

              pm_runtime_set_active(dev);

              pm_runtime_enable(dev);

 

              rc = ddi->drv->probe(ddi->dev, ddi->id);     //此处的probeAtherosath_pci_probe

              if (rc) {

                            pm_runtime_disable(dev);

                            pm_runtime_set_suspended(dev);

                            pm_runtime_put_noidle(dev);

              }

              return rc;

}

阅读(5120) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~