从USB设备插上到驱动probe调用流程分析

本文将详细讲述 2.6.22 下 的一个 USB 设备插上 linux 系 统 PC 后是如何一步一步调到我们的 usb 设 备驱动的 probe 函数的 , 我们知道我们的 USB 驱 动的 probe 函数中的一个参数是 interface 结 构 , 因此一般来说 ,  一 个 USB 设备中的任何一个接口都应该有对应的一个驱动程序 , 当 然也有例外 ( cdc-acm).

我们知道 USB 设备都是通过插入上层 HUB 的 一个 Port 来连入系统并进而被系统发现的 , USB 设 备插入一个 HUB , HUB 的 那个 port 的状态就会改变 , 从而系统就会 知道这个改变 , 此时会调用 hub_port_connect_change()  /*driver/usb/core/hub.c*/

static void hub_connect_change(struct usb_hub *hub, int portl, u16 portstatus, u16 portchange)

{

….

usb_new_device(udev);

}

该函数创建一个 usb_device 的对象 udev, 并 初始化它 , 接着调用 usb_new_device() 来 获取这个 usb 设备的各种描述符并为每个 interface 找 到对用的 driver.

int usb_new_device(struct usb_device *udev)

{

  ….

err = usb_get_configuration(udev);

  ….

device_add(&udev->dev);

}

该函数首先调用 usb_get_configuration() 来 获取设备的各种描述符 ( 设备描述符 , 配置描 述符等 ), 接着调用 device_add() 来 把这个 USB 设备添加到 USB 系统中去 , 也 就是在这个过程中系统回去为这个设备找到相应的驱动 . 2.6 的 早期的一些版本中在分析配置描述符后得到 interface 的同时把 interface 作 为设备来调用 device_add()

int device_add(struct device *dev)

{

….

if((error = bus_add_device(dev)))

bus_attach_device(dev);

}

这个函数是个通用的设备管 理 函数 , 它会为每个设备调用 bus_add_device 来 把这个设备添加到相应 bus 的设备列表中去 . 接 着调用 bus_attach_device() 来匹配对应的驱动程序 , 对 于 USB 设备来说第一次调用 bus_attach_device() 时 的参数 dev 代表的是整个 usb 设备 ( 以 后 usb 设备中的 interface 也会作 为设备调用这个函数 ).

int bus_attach_device(struct device *dev)

{

ret = device_attach(dev);

}

这个函数就是用来为设备找到相应的设备驱动程序的 ( 通过调 用 device_attach() 实现 ).

int device_attach(struct device *dev)

{

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

}

该函数调用 bus_for_each_drv() 来从总线 上已注册的所有驱动中找出匹配的驱动程序 .

int bus_for_each_drv(struct bus_type *bus,

struct device_driver *start,

void *data,

int (*fn)(struct device_driver *, void *))

{

       ….

while((drv = next_driver(&i)) && !error)

error = fn(drv, data);  // 返回 0 将 继续搜索 , 返回错误值将停止搜索 .

}

该函数遍历 bus 上 的所有驱动程序 , 并为每个驱动调用 fn() 来 查看是否匹配 . 这里的 fn 就是 __device_attach.

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

{

struct device *dev = data;

return driver_probe_device(drv, dev);

}

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

{

  

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

  

 

   ret = really_probe(dev, drv);

}

    对 于 usb 驱动来说 , 我们通过 usb_registe()r 来 注册我们的驱动程序 , 这个函数会为我们的驱动程序对象 (usb_driver) 中 的 bus 指定为 usb_bus_type:

   Struct bus_type usb_bus_type = {

  

   .match = usb_device_match,

   ….

}

因此对于 usb 驱动会首先调用 usb_device_match().

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

{

     if(is_usb_device(dev)) {  /*dev 代 表整个 usb 设备 */

          ….

}

else   /*dev 代表一个 usb 设 备 interface*/

{

  

   usb_match_id();

  

   usb_match_dynamic_id();

  

}

}

这个函数只是做一些粗略的匹配 , 如果匹配成功则返回 1, 然 后由 really_probe 来做进一步的匹配 , 如 果匹配失败则返回 0, 并且 really_probe 也 不会在执行 . 这个函数的调用保证了 dev, drv 要 么都是设备级别的 ( dev 代表 usb 设 备 ,drv 代表 usb 设备驱动 ), 要 么都是接口级别的 ( dev 代表 usb 设 备的一个 interface,drv 代表 usb 接 口驱动 ).

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

{

  

   dev->driver = drv;  // 先 赋值 , 以后的 probe 过程中会用到

   else if(drv->probe)

           ret = drv->probe(dev);

probe_failed:

   dev->drvier = NULL;  //probe 失 败 , 重设它

  

}

对于 usb 来说这个函数的调用有 2 种 分支 , 1: dev,drv 代表的是设备级别的 , 2 dev,drv 代表的是接口级别的 . 其他情况组合在 usb_device_match 中 被过滤掉了 ,

分支 1: dev,drv 代表的是设备级别 :

此时的 drv 肯定是 usb_generic_driver. 因 为在当前的 usb 系统中只有这个 driver 是 代表整个设备的驱动 , 它是在 usb_init 中 被注册的 , 而我们通常写的 usb 驱动都是代 表一个 interface .

struct usb_device_driver usb_generic_driver = {

  

   .probe = generic_probe,

  

}

因此 , 此时的 drv->probe 将 调用 generic_probe().

static int generic_probe(struct usb_device *udev)

{

  

   c = choose_configuration(dev);

   if(c >= 0) {

   err = usb_set_configuration(udev, c);  // 设 置 配置 , 并注册 interface.

  

}

}

该函数为这个 usb 设备选择一个合适的配置 , 并 注册这个配置下面的 interface.

int usb_set_configuration(struct usb_device *dev, int configuration)

{

  

   for(I = 0; I < nintf; i++) {

   struct usb_interface *intf = cp->interface[i];

  

   device_add(&intf->dev);

  

}

  

}

该函数比较重要 , 但我们只关心 probe 过 程因此省掉了很多东西 . 它为当前配置下的每个 interface 调 用 device_add() 函数 , 根据前面 的分析可知 , 这个过程将会走到接下来我们要分析的分支 2.

分支 2: dev,drv 代表的是 interface 级 别 :

此时的 dev 代表着一个 interface, drv 就 代表了我们自己的 usb 驱动 . 但是我们应当 看到 drv device_driver 类 型 , 而我们写的 usb 驱动的类型一般是 usb_driver, 因 此这里的 probe 和我们自己写的 probe 显 然不是同一个 . 实际上这里的 drv 是我们的 驱动对象里内嵌的一个子对象 ( 因为 linux 下 所以的驱动都必须用 device_driver 来代表 ,). 那 这个子对象的 probe 函数是在哪里赋值的呢 ? 这 就要看 usb_register 函数了 ,

跟踪这个函数 我们可以看到这里的 probe 函数实际上是 usb_probe_interface( 所 有的 usb interface 驱动都是一样的 ).

  static int usb_probe_interface(struct device *dev)

{

  struct driver = to_usb_driver(dev->driver);  //dev->driver  really_probe 中 设置 .

 

  error = driver->probe(intf, id);   // 这 个就是我们自己写的 probe 函数了 .

 

}

  driver->probe(intf, id); 这就调用到我们自己写的代码里面了 ,

 

整个流程大概 就是这样 :

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章