Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1057471
  • 博文数量: 166
  • 博客积分: 10217
  • 博客等级: 上将
  • 技术积分: 2133
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-09 19:45
文章分类

全部博文(166)

文章存档

2012年(3)

2011年(7)

2010年(18)

2009年(59)

2008年(79)

我的朋友

分类: LINUX

2008-04-17 19:20:31

PCI设备的注册过程分析(1)
R.wen

一、驱动与设备注册过程总述。

在2.6设备模型下,当一个驱动程序模块挂入内核(insmod),它会遍历所有在这个总线(BUS)上注册的设备链表,并且对每个被遍历的设备调用 match()函数,直到找到匹配的为止。第二种情况是,当一个设备被插入到系统总线上的时候(或系统初起),它会遍历枚举这个总线上的所有注册过的驱 动,并且对每个驱动调用match()函数,直到找到匹配的驱动为止。

之后,上两种情况都会调用probe函数,进行设备的初始化。



二、驱动注册过程。

首先是驱动的注册,以e100为例:



static struct pci_driver e100_driver = {

       .name =         DRV_NAME,

       .id_table =     e100_id_table,

       .probe =        e100_probe,

       .remove =       __devexit_p(e100_remove),

       .shutdown =     e100_shutdown,

……

};



static int __init e100_init_module(void)

{

       return pci_register_driver(&e100_driver);

}



我们看到,它先初始化一个pci_driver结构,然后以这个结构为参数调用pci_register_driver(),它其实是:

static inline int __must_check pci_register_driver(struct pci_driver *driver)

{

       return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);

}



/**

* __pci_register_driver - register a new pci driver

* @drv: the driver structure to register

* @owner: owner module of drv

* @mod_name: module name string

*

* Adds the driver structure to the list of registered drivers.

* Returns a negative value on error, otherwise 0.

* If no error occurred, the driver remains registered even if

* no device was claimed during registration.

*/

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;

       drv->driver.kobj.ktype = &pci_driver_kobj_type;



       //是否使用多线程来进行probe

       if (pci_multithread_probe)

              drv->driver.multithread_probe = pci_multithread_probe;

       else

              drv->driver.multithread_probe = drv->multithread_probe;



       spin_lock_init(&drv->dynids.lock);

       INIT_LIST_HEAD(&drv->dynids.list);



       /* register with core */

       error = driver_register(&drv->driver); //上面是PCI驱动的注册,这里是通用设备的注册

       if (error)

              return error;



       //在sysfs中建立文件项

       error = pci_create_newid_file(drv);

       if (error)

              driver_unregister(&drv->driver);



       return error;

}





/**

*    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.

*

*    The one interesting aspect is that we setup @drv->unloaded

*    as a completion that gets complete when the driver reference

*    count reaches 0.

*/

int driver_register(struct device_driver * drv)

{

       if ((drv->bus->probe && drv->probe) ||

           (drv->bus->remove && drv->remove) ||

           (drv->bus->shutdown && drv->shutdown)) {

              printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);

       }

       klist_init(&drv->klist_devices, NULL, NULL);

       init_completion(&drv->unloaded);

       return bus_add_driver(drv); //这个函数将驱动加入BUS链表

}



/**

*    bus_add_driver - Add a driver to the bus.

*    @drv:     driver.

*/

int bus_add_driver(struct device_driver *drv)

{

       struct bus_type * bus = get_bus(drv->bus);

       int error = 0;



       if (!bus)

              return 0;



       pr_debug("bus %s: add driver %s\n", bus->name, drv->name);

       error = kobject_set_name(&drv->kobj, "%s", drv->name);

       if (error)

              goto out_put_bus;

       drv->kobj.kset = &bus->drivers;

       if ((error = kobject_register(&drv->kobj)))

              goto out_put_bus;

     

       //将这个驱动与可能的设备捆绑起来

       error = driver_attach(drv);

       if (error)

              goto out_unregister;

       klist_add_tail(&drv->knode_bus, &bus->klist_drivers); //加入链表

       module_add_driver(drv->owner, drv);



       error = driver_add_attrs(bus, drv); //注册属性

       ……

return error;

}



/**

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

}

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; //总是返回0

}

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->klist_devices, &i,

                          (start ? &start->knode_bus : NULL));

       while ((dev = next_device(&i)) && !error) //由于error总是0,所以会遍历整个链表

              error = fn(dev, data);

       klist_iter_exit(&i);



       return error;

}



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,

};



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

{

       struct stupid_thread_structure *data;

       struct task_struct *probe_task;

       int ret = 0;



       if (!device_is_registered(dev)) //已经注册了

              return -ENODEV;

       if (drv->bus->match && !drv->bus->match(dev, drv))

              goto done; //调用match()函数,如果不匹配,则说明这个驱动不合适这个设备,跳过这个设备。由上面的结构可以看到,这个函数是pci_bus_match



       pr_debug("%s: Matched Device %s with Driver %s\n",

               drv->bus->name, dev->bus_id, drv->name);



       data = kmalloc(sizeof(*data), GFP_KERNEL);

       if (!data)

              return -ENOMEM;

       data->drv = drv;

       data->dev = dev;



       if (drv->multithread_probe) { //启动另一个线程来完成

              probe_task = kthread_run(really_probe, data,

                                    "probe-%s", dev->bus_id);

              if (IS_ERR(probe_task))

                     ret = really_probe(data);

       } else

              ret = really_probe(data);



done:

       return ret;

}



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

{

       struct pci_dev *pci_dev = to_pci_dev(dev);

       struct pci_driver *pci_drv = to_pci_driver(drv);

       const struct pci_device_id *found_id;



       found_id = pci_match_device(pci_drv, pci_dev);

       if (found_id)

              return 1;



       return 0; //不匹配

}

const struct pci_device_id *pci_match_device(struct pci_driver *drv,

                                        struct pci_dev *dev)

{

       struct pci_dynid *dynid;



       /* Look at the dynamic ids first, before the static ones */

       spin_lock(&drv->dynids.lock);

       list_for_each_entry(dynid, &drv->dynids.list, node) {

              if (pci_match_one_device(&dynid->id, dev)) {

                     spin_unlock(&drv->dynids.lock);

                     return &dynid->id;

              }

       }

       spin_unlock(&drv->dynids.lock);



//检查静态表,这个表来自于pc_driver中的id_table域。

       return pci_match_id(drv->id_table, dev);

}

const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,

                                    struct pci_dev *dev)

{

       if (ids) {

              while (ids->vendor || ids->subvendor || ids->class_mask) {

                     if (pci_match_one_device(ids, dev))

                            return ids;

                     ids++;

              }

       }

       return NULL;

}



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;

}



如果上面的match成功返回,下一步则执行以下这个函数了。

static int really_probe(void *void_data)

{

       struct stupid_thread_structure *data = void_data;

       struct device_driver *drv = data->drv;

       struct device *dev = data->dev;

       int ret = 0;



       atomic_inc(&probe_count);

       pr_debug("%s: Probing driver %s with device %s\n",

               drv->bus->name, drv->name, dev->bus_id);

       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",

                     __FUNCTION__, dev->bus_id);

              goto probe_failed;

       }



       if (dev->bus->probe) {

              ret = dev->bus->probe(dev); //执行总线的probe函数

              if (ret)

                     goto probe_failed;

       } else if (drv->probe) { //如果没有,则执行驱动的probe

              ret = drv->probe(dev);

              if (ret)

                     goto probe_failed;

       }



       driver_bound(dev);

       ret = 1;

       pr_debug("%s: Bound Device %s to Driver %s\n",

               drv->bus->name, dev->bus_id, drv->name);

       goto done;



probe_failed:

              …...

       ret = 0;

done:

       kfree(data);

       atomic_dec(&probe_count);

       wake_up(&probe_waitqueue);

       return ret;

}



由上面的结构可以看到,总线的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);

       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;

}



我们看到,总线的probe最终还是执行驱动程序提供的probe函数。至此,设备的注册过程已经完成。

static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,

                       const struct pci_device_id *id)

{

       int error;

#ifdef CONFIG_NUMA

……

#endif

       error = drv->probe(dev, id); //完成系统的初始化操作

#ifdef CONFIG_NUMA

       ……

#endif

       return error;

}

声明: 转的,为了容易找到,帖过来了
阅读(2609) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~