device_register和驱动driver_register先后注册的影响和关系

来源:互联网 发布:高顿网校cpa价格知乎 编辑:程序博客网 时间:2024/06/06 00:38

开始我的博文之前,最近一天来的感受,我只想说一下,Linux的世界,玩在表面是轻松的,但是玩在内部那就是找死。佩服那些写源码的人。真的佩服。

 

 这段世界大概半个月了,开始linux驱动的真正开发,也是从基层开始看的。相比以为linux下的驱动就是点灯之类的Led来说,现在我的感受就是,那些完全就是表面的东西。核心层次的驱动,完全不是这么随随便便写出来的。也正好说明现在很多公司正在写驱动的不多,完全独立写的也不多,因为实在太复杂。只能靠着源码或者BSP来修改。半个多月来看了linux2.6.10下面的音频驱动OSS架构,不是一般的复杂。熟悉了I2C驱动的整个架构(之前写了一下博文)。

     今天为何再写这个内容,因为最近开始看linux下面的视频架构。恍惚间看到device_register和driver_register,这两个对驱动真正核心的东西,让我察觉到这两个到底谁需要先执行,还是没关系。百度了很多,都说的是表面文章,去qq上也是一肚子的灰,因此我依旧独立解决,虽然我知道这个问题基本没人去思考(除了写内核的大神们),因为这块内容和内核走的很近很近,代码量也大。所以基本可见的分析都在表面。故把我这次的分析总结写在这里,供大家借鉴,不对之处也请多指正。

      从函数driver_register和device_register在源码中来看,这两个函数的执行顺序前后都有出现,但是之前都活在表面,没有深入的看过,因为知道内核在深入下去就是很复杂的东西。但为了解决问题只会硬着头皮去看。下面是我的一些分析,主要涉及到的是链表,kobject,kset,bus,device,device_driver几个结构体。

1. 先从driver_register的调用流程说起,主要介绍核心的调用,其间的某些函数不做解析。

driver_register->bus_add_driver->

[plain] view plaincopy
  1. int bus_add_driver(struct device_driver * drv)  
  2. {  
  3.     struct bus_type * bus = get_bus(drv->bus);  
  4.     int error = 0;  
  5.   
  6.     if (bus) {  
  7.         pr_debug("bus %s: add driver %s\n", bus->name, drv->name);  
  8.         error = kobject_set_name(&drv->kobj, "%s", drv->name);  //给kobj赋予名字  
  9.         if (error) {  
  10.             put_bus(bus);  
  11.             return error;  
  12.         }  
  13.         drv->kobj.kset = &bus->drivers;  //kset指向bus->drivers(类型为kset)  
  14.         if ((error = kobject_register(&drv->kobj))) {  
  15.             put_bus(bus);  
  16.             return error;  
  17.         }  
  18.   
  19.         down_read(&bus->subsys.rwsem);  
  20.         driver_attach(drv);  
  21.         up_read(&bus->subsys.rwsem);  
  22.         module_add_driver(drv->owner, drv);  
  23.   
  24.         driver_add_attrs(bus, drv);  
  25.     }  
  26.     return error;  
  27. }  

在这个函数中,我觉得核心的是语句 drv->kobj.kset = &bus->drivers;,为何会这样说。因为实际上在设备和驱动在注册的过程中,都会将自己结构体的链表成员添加到bus->drivers和bus->devices为链表头的链表中去。最后都根据这些链表遍历所在成员的地址,然后找到设备和驱动依次执行是否probe。

所以 drv->kobj.kset = &bus->drivers;这个做的事情需要结合函数 kobject_register->kobject_add函数中去

[plain] view plaincopy
  1. static void unlink(struct kobject * kobj)  
  2. {  
  3.     if (kobj->kset) {  
  4.         down_write(&kobj->kset->subsys->rwsem);  
  5.         list_del_init(&kobj->entry);  
  6.         up_write(&kobj->kset->subsys->rwsem);  
  7.     }  
  8.     kobject_put(kobj);  
  9. }  
  10.   
  11. /**  
  12.  *  kobject_add - add an object to the hierarchy.  
  13.  *  @kobj:  object.  
  14.  */  
  15.   
  16. int kobject_add(struct kobject * kobj)  
  17. {  
  18.     int error = 0;  
  19.     struct kobject * parent;  
  20.   
  21.     if (!(kobj = kobject_get(kobj)))  
  22.         return -ENOENT;  
  23.     if (!kobj->k_name)  
  24.         kobj->k_name = kobj->name;  
  25.     parent = kobject_get(kobj->parent);  
  26.   
  27.     pr_debug("kobject %s: registering. parent: %s, set: %s\n",  
  28.          kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",   
  29.          kobj->kset ? kobj->kset->kobj.name : "<NULL>" );  
  30.   
  31.     if (kobj->kset) {  
  32.         down_write(&kobj->kset->subsys->rwsem);  
  33.   
  34.         if (!parent)  
  35.             parent = kobject_get(&kobj->kset->kobj);  
  36.   
  37.         list_add_tail(&kobj->entry,&kobj->kset->list);  //kobj的list_head内容加到bus->drivers的list链表中  
  38.         up_write(&kobj->kset->subsys->rwsem);  
  39.     }  
  40.     kobj->parent = parent;  
  41.   
  42.     error = create_dir(kobj);  
  43.     if (error) {  
  44.         /* unlink does the kobject_put() for us */  
  45.         unlink(kobj);  
  46.         if (parent)  
  47.             kobject_put(parent);  
  48.     } else {  
  49.         kobject_hotplug(kobj, KOBJ_ADD);  
  50.     }  
  51.   
  52.     return error;  
  53. }  

在这里有这么一个list_add_tail宏来完成device_driver中将成员kobject的kset链表头加入到kobj->kset->list中去,实际是drv->kobj.kset = &bus->drivers,也就是加入到链表头bus->drivers->list中去。这样就顺利完成了在设备注册时,可以遍历到这个链表头下面的驱动。

总结一下的话,其实devices和driver在注册中,最终都会挂接到bus下面,类型是kset(device和driver)下的list。最终都去遍历这个链表头下面对应的驱动和设备。而我们知道一个驱动可以有多个设备,因此device下的driver_list会添加到driver下面的链表头中去。

 

相对于driver_register的实现,device_register这方面的实现,就简单多了,一句list_add_tail(&dev->bus_list, &dev->bus->devices.list);    //将设备的bus_list加入到devoces.list的链表头中,这个简单了很多很多。很明了,而不需要像驱动那样将kobj下面的链表加入到Bus下面去用于遍历。

         总之,这个问题很小,但是和内核走的很近很近,所以,遇到这个问题我想必须解决,这样可以带给我对驱动很深入的理解。继续努力,走在linux的世界里