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

全部博文(166)

文章存档

2012年(3)

2011年(7)

2010年(18)

2009年(59)

2008年(79)

我的朋友

分类: LINUX

2008-04-17 19:22:29

三、设备的注册过程

当一个PCI设备热插拔,或是系统初启时,它会遍历这个总线的已经注册进内核里的驱动链表。当找到匹配的时候,它就将这个设备绑定。



它首先会执行一个注册函数:

int device_register(struct device *dev)

{

       device_initialize(dev);

       return device_add(dev);

}



int device_add(struct device *dev)

{

       struct device *parent = NULL;

       char *class_name = NULL;

       struct class_interface *class_intf;

       int error = -EINVAL;



       dev = get_device(dev);

       if (!dev || !strlen(dev->bus_id))

              goto Error;



       pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);



       parent = get_device(dev->parent);



       error = setup_parent(dev, parent);

       if (error)

              goto Error;



       /* first, register with generic layer. */

       kobject_set_name(&dev->kobj, "%s", dev->bus_id);

       error = kobject_add(&dev->kobj);

       if (error)

              goto Error;



       /* notify platform of device entry */

       if (platform_notify)

              platform_notify(dev);



       /* notify clients of device entry (new way) */

       if (dev->bus) //通知链表

              blocking_notifier_call_chain(&dev->bus->bus_notifier,

                                        BUS_NOTIFY_ADD_DEVICE, dev);



       dev->uevent_attr.attr.name = "uevent";

       dev->uevent_attr.attr.mode = S_IWUSR;

       if (dev->driver)

              dev->uevent_attr.attr.owner = dev->driver->owner;

       dev->uevent_attr.store = store_uevent;

       error = device_create_file(dev, &dev->uevent_attr);

       if (error)

              goto attrError;



       if (MAJOR(dev->devt)) { //属性处理

              struct device_attribute *attr;

              attr = kzalloc(sizeof(*attr), GFP_KERNEL);

              if (!attr) {

                     error = -ENOMEM;

                     goto ueventattrError;

              }

              attr->attr.name = "dev";

              attr->attr.mode = S_IRUGO;

              if (dev->driver)

                     attr->attr.owner = dev->driver->owner;

              attr->show = show_dev;

              error = device_create_file(dev, attr);

              if (error) {

                     kfree(attr);

                     goto ueventattrError;

              }



              dev->devt_attr = attr;

       }



       if (dev->class) { //设备类型处理

              sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,

                              "subsystem");

              /* If this is not a "fake" compatible device, then create the

               * symlink from the class to the device. */

              if (dev->kobj.parent != &dev->class->subsys.kset.kobj)

                     sysfs_create_link(&dev->class->subsys.kset.kobj,

                                     &dev->kobj, dev->bus_id);

              if (parent) {

                     sysfs_create_link(&dev->kobj, &dev->parent->kobj,

                                                 "device");

#ifdef CONFIG_SYSFS_DEPRECATED

                     class_name = make_class_name(dev->class->name,

                                                 &dev->kobj);

                     if (class_name)

                            sysfs_create_link(&dev->parent->kobj,

                                            &dev->kobj, class_name);

#endif

              }

       }



       if ((error = device_add_attrs(dev)))

              goto AttrsError;

       if ((error = device_add_groups(dev)))

              goto GroupError;

       if ((error = device_pm_add(dev)))

              goto PMError;

       if ((error = bus_add_device(dev)))

              goto BusError;

       if (!dev->uevent_suppress)

              kobject_uevent(&dev->kobj, KOBJ_ADD);

       if ((error = bus_attach_device(dev))) //将设备于驱动绑定

              goto AttachError;

       if (parent) //加入链表

              klist_add_tail(&dev->knode_parent, &parent->klist_children);



       if (dev->class) {

              down(&dev->class->sem);

              /* tie the class to the device */

              list_add_tail(&dev->node, &dev->class->devices);



              /* notify any interfaces that the device is here */

              list_for_each_entry(class_intf, &dev->class->interfaces, node)

                     if (class_intf->add_dev)

                            class_intf->add_dev(dev, class_intf);

              up(&dev->class->sem);

       }

Done:

      kfree(class_name);

       put_device(dev);

       return error;

……

}



int bus_add_device(struct device * dev)

{

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

       int error = 0;



       if (bus) {

              pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);

              error = device_add_attrs(bus, dev);

              if (error)

                     goto out_put;

              error = sysfs_create_link(&bus->devices.kobj,

                                          &dev->kobj, dev->bus_id);

              if (error)

                     goto out_id;

              error = sysfs_create_link(&dev->kobj,

                            &dev->bus->subsys.kset.kobj, "subsystem");

              if (error)

                     goto out_subsys;

              error = make_deprecated_bus_links(dev);

              if (error)

                     goto out_deprecated;

       }

       return 0;



out_deprecated:

       sysfs_remove_link(&dev->kobj, "subsystem");

out_subsys:

       sysfs_remove_link(&bus->devices.kobj, dev->bus_id);

out_id:

       device_remove_attrs(bus, dev);

out_put:

       put_bus(dev->bus);

       return error;

}





/**

*    bus_attach_device - add device to bus

*    @dev:     device tried to attach to a driver

*

*    - Add device to bus's list of devices.

*    - Try to attach to driver.

*/

int bus_attach_device(struct device * dev)

{

       struct bus_type *bus = dev->bus;

       int ret = 0;



       if (bus) {

              dev->is_registered = 1;

              ret = device_attach(dev);

              if (ret >= 0) {

                     klist_add_tail(&dev->knode_bus, &bus->klist_devices);

                     ret = 0;

              } else

                     dev->is_registered = 0;

       }

       return ret;

}



int device_attach(struct device * dev)

{

       int ret = 0;



       down(&dev->sem);

       if (dev->driver) {

              ret = device_bind_driver(dev);

              if (ret == 0)

                     ret = 1;

       } else

              ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

       up(&dev->sem);

       return ret;

}



static int __device_attach(struct device_driver * drv, void * data)

{

       struct device * dev = data;

       return driver_probe_device(drv, dev);

}



接下来的代码就跟上面的驱动注册一样了。

声明:转的
阅读(1957) | 评论(0) | 转发(0) |
0

上一篇: PCI设备的注册过程分析1

下一篇:(1)引言

给主人留下些什么吧!~~