设备驱动模型之device-driver

前面我们分析了device、driver、bus三种类型,主要是三者的注册与注销,在sysfs中的目录与属性文件创建等内容。本节就来详细分析下,在设备注册到总线上时,总线是如何为其寻找对应的驱动的;在驱动注册到总线上时,总线又是如何为其寻找对应的设备的。

本节的实现代码集中在drivers/base/bus.c和drivers/base/dd.c中。

先来回忆下,在device_register()->device_add()中,先是调用bus_add_device()添加device与bus间的联系,并添加bus为device定义的属性,然后会调用bus_probe_device()。bus_probe_device()会试图为已挂在总线上的该设备寻找对应的驱动。我们的故事就从这里开始。

  1. /** 
  2.  * bus_probe_device - probe drivers for a new device 
  3.  * @dev: device to probe 
  4.  * 
  5.  * - Automatically probe for a driver if the bus allows it. 
  6.  */  
  7. void bus_probe_device(struct device *dev)  
  8. {  
  9.     struct bus_type *bus = dev->bus;  
  10.     int ret;  
  11.   
  12.     if (bus && bus->p->drivers_autoprobe) {  
  13.         ret = device_attach(dev);  
  14.         WARN_ON(ret < 0);  
  15.     }  
  16. }  
bus_probe_device()为总线上的设备寻找驱动。它先是检查bus->p->drivers_autoprobe,看是否允许自动探测。允许了才会调用device_attach()进行实际的寻找工作。

说到bus->p->drivers_autoprobe这个变量,它是在bus_type_private中的,在调用bus_register()前都初始化不了,在bus_register()中自动定为1。所以,除非是用户空间通过drivers_autoprobe属性文件主动禁止,bus总是允许自动探测的,所有的bus都是如此。

  1. /** 
  2.  * device_attach - try to attach device to a driver. 
  3.  * @dev: device. 
  4.  * 
  5.  * Walk the list of drivers that the bus has and call 
  6.  * driver_probe_device() for each pair. If a compatible 
  7.  * pair is found, break out and return. 
  8.  * 
  9.  * Returns 1 if the device was bound to a driver; 
  10.  * 0 if no matching driver was found; 
  11.  * -ENODEV if the device is not registered. 
  12.  * 
  13.  * When called for a USB interface, @dev->parent->sem must be held. 
  14.  */  
  15. int device_attach(struct device *dev)  
  16. {  
  17.     int ret = 0;  
  18.   
  19.     down(&dev->sem);  
  20.     if (dev->driver) {  
  21.         ret = device_bind_driver(dev);  
  22.         if (ret == 0)  
  23.             ret = 1;  
  24.         else {  
  25.             dev->driver = NULL;  
  26.             ret = 0;  
  27.         }  
  28.     } else {  
  29.         pm_runtime_get_noresume(dev);  
  30.         ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);  
  31.         pm_runtime_put_sync(dev);  
  32.     }  
  33.     up(&dev->sem);  
  34.     return ret;  
  35. }  

device_attach()在实际绑定之前,会用dev->sem进行加锁。不错,dev->sem几乎就是为了在设备与驱动绑定或者解除绑定时加锁用的。还没有看到它在其它地方被调用。

如果在调用device_attach()前就已经有了dev->driver(),就调用device_bind_driver()进行绑定,不然还要调用bus_for_each_drv()进行依次匹配。至于pm_runtime_get_noresume之类的函数,属于电源管理部分,我们现在先忽略。

  1. static void driver_bound(struct device *dev)  
  2. {  
  3.     if (klist_node_attached(&dev->p->knode_driver)) {  
  4.         printk(KERN_WARNING "%s: device %s already bound\n",  
  5.             __func__, kobject_name(&dev->kobj));  
  6.         return;  
  7.     }  
  8.   
  9.     pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),  
  10.          __func__, dev->driver->name);  
  11.   
  12.     if (dev->bus)  
  13.         blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  
  14.                          BUS_NOTIFY_BOUND_DRIVER, dev);  
  15.   
  16.     klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);  
  17. }  
  18.   
  19. static int driver_sysfs_add(struct device *dev)  
  20. {  
  21.     int ret;  
  22.   
  23.     ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,  
  24.               kobject_name(&dev->kobj));  
  25.     if (ret == 0) {  
  26.         ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,  
  27.                     "driver");  
  28.         if (ret)  
  29.             sysfs_remove_link(&dev->driver->p->kobj,  
  30.                     kobject_name(&dev->kobj));  
  31.     }  
  32.     return ret;  
  33. }  
  34.   
  35. static 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值