Linux设备驱动之USB hub驱动

it2022-05-09  23

------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ ------------------------------------------ 一:前言 继UHCI的驱动之后,我们对USB Control的运作有了一定的了解.在接下来的分析中,我们对USB设备的驱动做一个全面的分析,我们先从HUB的驱动说起.关于HUB,usb2.0 spec上有详细的定义,基于这部份的代码位于linux-2.6.25/drivers/usb/core下,也就是说,这部份代码是位于core下, 和具体设备是无关的,因为各厂商的hub都是按照spec的要求来设计的. 二:UHCI驱动中的root hub 记得在分析UHCI驱动的时候,曾详细分析过root hub的初始化操作.为了分析方便,将代码片段列出如下: usb_add_hcd() à usb_alloc_dev(): struct usb_device *usb_alloc_dev(struct usb_device *parent,                struct usb_bus *bus, unsigned port1) {     ……     ……     //usb_device,内嵌有struct device结构,对这个结构进行初始化     device_initialize(&dev->dev);     dev->dev.bus = &usb_bus_type;     dev->dev.type = &usb_device_type;     ……     …… } 一看到前面对dev的赋值,根据我们对设备模型的理解,一旦这个device进行注册,就会发生driver和device的匹配过程了. 不过,现在还不是分析这个过程的时候,我们先来看一下,USB子系统中的两种驱动.   三:USB子系统中的两种驱动 linux-2.6.25/drivers/usb/core/driver.c中,我们可以找到两种 register driver的方式,分别为usb_register_driver()和usb_register_device_driver().分别来分析一下这 两个接口.   usb_register_device_driver()接口的代码如下: int usb_register_device_driver(struct usb_device_driver *new_udriver,         struct module *owner) {     int retval = 0;       if (usb_disabled())         return -ENODEV;       new_udriver->drvwrap.for_devices = 1;     new_udriver->drvwrap.driver.name = (char *) new_udriver->name;     new_udriver->drvwrap.driver.bus = &usb_bus_type;     new_udriver->drvwrap.driver.probe = usb_probe_device;     new_udriver->drvwrap.driver.remove = usb_unbind_device;     new_udriver->drvwrap.driver.owner = owner;       retval = driver_register(&new_udriver->drvwrap.driver);       if (!retval) {         pr_info("%s: registered new device driver %s\n",             usbcore_name, new_udriver->name);         usbfs_update_special();     } else {         printk(KERN_ERR "%s: error %d registering device "             "   driver %s\n",             usbcore_name, retval, new_udriver->name);     }       return retval; } 首先,通过usb_disabled()来判断一下usb是否被禁用,如果被禁用,当然就不必执行下面的流程了,直接退出即可. 从上面的代码,很明显可以看到, struct usb_device_driver 对struct device_driver进行了一次封装,我们注意一下这里的赋值操作:new_udriver->drvwrap.for_devices = 1.等等.这些在后面都是用派上用场的.   usb_register_driver()的代码如下: int usb_register_driver(struct usb_driver *new_driver, struct module *owner,             const char *mod_name) {     int retval = 0;       if (usb_disabled())         return -ENODEV;       new_driver->drvwrap.for_devices = 0;     new_driver->drvwrap.driver.name = (char *) new_driver->name;     new_driver->drvwrap.driver.bus = &usb_bus_type;     new_driver->drvwrap.driver.probe = usb_probe_interface;     new_driver->drvwrap.driver.remove = usb_unbind_interface;     new_driver->drvwrap.driver.owner = owner;     new_driver->drvwrap.driver.mod_name = mod_name;     spin_lock_init(&new_driver->dynids.lock);     INIT_LIST_HEAD(&new_driver->dynids.list);       retval = driver_register(&new_driver->drvwrap.driver);       if (!retval) {         pr_info("%s: registered new interface driver %s\n",             usbcore_name, new_driver->name);         usbfs_update_special();         usb_create_newid_file(new_driver);     } else {         printk(KERN_ERR "%s: error %d registering interface "             "   driver %s\n",             usbcore_name, retval, new_driver->name);     }       return retval; } 很明显,在这里接口里,将new_driver->drvwrap.for_devices设为了0.而且两个接口的porbe()函数也不一样. 其实,对于usb_register_driver()可以看作是usb设备中的接口驱动,而usb_register_device_driver()是一个单纯的USB设备驱动.   四: hub的驱动分析 4.1: usb_bus_type->match()的匹配过程 usb_bus_type->match()用来判断驱动和设备是否匹配,它的代码如下: static int usb_device_match(struct device *dev, struct device_driver *drv) {     /* devices and interfaces are handled separately */       //usb device的情况     if (is_usb_device(dev)) {           /* interface drivers never match devices */         if (!is_usb_device_driver(drv))             return 0;           /* TODO: Add real matching code */         return 1;       }     //interface的情况     else {         struct usb_interface *intf;         struct usb_driver *usb_drv;         const struct usb_device_id *id;           /* device drivers never match interfaces */         if (is_usb_device_driver(drv))             return 0;           intf = to_usb_interface(dev);         usb_drv = to_usb_driver(drv);           id = usb_match_id(intf, usb_drv->id_table);         if (id)             return 1;           id = usb_match_dynamic_id(intf, usb_drv);         if (id)             return 1;     }       return 0; } 这里的match会区分上面所说的两种驱动,即设备的驱动和接口的驱动. is_usb_device()的代码如下: static inline int is_usb_device(const struct device *dev) {     return dev->type == &usb_device_type; } 很明显,对于root hub来说,这个判断是肯定会满足的. static inline int is_usb_device_driver(struct device_driver *drv) {     return container_of(drv, struct usbdrv_wrap, driver)->             for_devices; } 回忆一下,我们在分析usb_register_device_driver()的时候,不是将 new_udriver->drvwrap.for_devices置为了1么?所以对于 usb_register_device_driver()注册的驱动来说,这里也是会满足的. 因此,对应root hub的情况,从第一个if就会匹配到usb_register_device_driver()注册的驱动. 对于接口的驱动,我们等遇到的时候再来进行分析.   4.2:root hub的驱动入口 既然我们知道,root hub会匹配到usb_bus_type->match()的驱动,那这个驱动到底是什么呢?我们从usb子系统的初始化开始说起. 在linux-2.6.25/drivers/usb/core/usb.c中.有这样的一段代码: subsys_initcall(usb_init); 对于subsys_initcall()我们已经不陌生了,在很多地方都会遇到它.在系统初始化的时候,会调用到它对应的函数.在这里,即为usb_init(). 在usb_init()中,有这样的代码片段: static int __init usb_init(void) {     ……     …… retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);     if (!retval)         goto out;     …… } 在这里终于看到usb_register_device_driver()了. usb_generic_driver会匹配到所有usb 设备.定义如下: struct usb_device_driver usb_generic_driver = {     .name = "usb",     .probe = generic_probe,     .disconnect = generic_disconnect, #ifdef  CONFIG_PM     .suspend = generic_suspend,     .resume = generic_resume, #endif     .supports_autosuspend = 1, }; 现在是到分析probe()的时候了.我们这里说的并不是usb_generic_driver中的probe,而是封装在struct usb_device_driver中的driver对应的probe函数. 在上面的分析, usb_register_device_driver()将封装的driver的probe()函数设置为了usb_probe_device().代码如下: static int usb_probe_device(struct device *dev) {     struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);     struct usb_device *udev;     int error = -ENODEV;       dev_dbg(dev, "%s\n", __FUNCTION__);       //再次判断dev是否是usb device     if (!is_usb_device(dev))    /* Sanity check */         return error;       udev = to_usb_device(dev);       /* TODO: Add real matching code */       /* The device should always appear to be in use      * unless the driver suports autosuspend.      */      //pm_usage_cnt: autosuspend计数.如果此计数为1,则不允许autosuspend     udev->pm_usage_cnt = !(udriver->supports_autosuspend);       error = udriver->probe(udev);     return error; } 首先,可以通过container_of()将封装的struct device, struct device_driver转换为struct usb_device和struct usb_device_driver. 然后,再执行一次安全检查,判断dev是否是属于一个usb device. 在这里,我们首次接触到了hub suspend.如果不支持suspend(udriver->supports_autosuspend为0),则 udev->pm_usage_cnt被设为1,也就是说,它不允许设备suspend.否则,将其初始化为0. 最后,正如你所看到的,流程转入到了usb_device_driver->probe(). 对应到root hub,流程会转入到generic_probe().代码如下:   static int generic_probe(struct usb_device *udev) {     int err, c;       /* put device-specific files into sysfs */     usb_create_sysfs_dev_files(udev);       /* Choose and set the configuration.  This registers the interfaces      * with the driver core and lets interface drivers bind to them.      */     if (udev->authorized == 0)         dev_err(&udev->dev, "Device is not authorized for usage\n");     else {         //选择和设定一个配置         c = usb_choose_configuration(udev);         if (c >= 0) {             err = usb_set_configuration(udev, c);             if (err) {                 dev_err(&udev->dev, "can't set config #%d, error %d\n",                     c, err);                 /* This need not be fatal.  The user can try to                  * set other configurations. */             }         }     }     /* USB device state == configured ... usable */     usb_notify_add_device(udev);       return 0; } usb_create_sysfs_dev_files()是在sysfs中显示几个属性文件,不进行详细分析,有兴趣的可以结合之前分析的<<linux设备模型详解>>来看下代码. usb_notify_add_device()是有关notify链表的操作,这里也不做详细分析. 至于udev->authorized,在root hub的初始化中,是会将其初始化为1的.后面的逻辑就更简单了.为root hub 选择一个配置然后再设定这个配置. 还记得我们在分析root hub的时候,在usb_new_device()中,会将设备的所有配置都取出来,然后将它们放到了usb_device-> config.现在这些信息终于会派上用场了.不太熟悉的,可以看下本站之前有关usb控制器驱动的文档.   Usb2.0 spec上规定,对于hub设备,只能有一个config,一个interface,一个endpoint.实际上,在这里,对hub的选择约束不大,反正就一个配置,不管怎么样,选择和设定都是这个配置. 不过,为了方便以后的分析,我们还是跟进去看下usb_choose_configuration()和usb_set_configuration()的实现. 实际上,经过这两个函数之后,设备的probe()过程也就会结束了.   4.2.1:usb_choose_configuration()函数分析 usb_choose_configuration()的代码如下: //为usb device选择一个合适的配置 int usb_choose_configuration(struct usb_device *udev) {     int i;     int num_configs;     int insufficient_power = 0;     struct usb_host_config *c, *best;       best = NULL;     //config数组     c = udev->config;     //config项数     num_configs = udev->descriptor.bNumConfigurations;     //遍历所有配置项     for (i = 0; i < num_configs; (i++, c++)) {         struct usb_interface_descriptor *desc = NULL;           /* It's possible that a config has no interfaces! */         //配置项的接口数目         //取配置项的第一个接口         if (c->desc.bNumInterfaces > 0)             desc = &c->intf_cache[0]->altsetting->desc;           /*          * HP's USB bus-powered keyboard has only one configuration          * and it claims to be self-powered; other devices may have          * similar errors in their descriptors.  If the next test          * were allowed to execute, such configurations would always          * be rejected and the devices would not work as expected.          * In the meantime, we run the risk of selecting a config          * that requires external power at a time when that power          * isn't available.  It seems to be the lesser of two evils.          *          * Bugzilla #6448 reports a device that appears to crash          * when it receives a GET_DEVICE_STATUS request!  We don't          * have any other way to tell whether a device is self-powered,          * but since we don't use that information anywhere but here,          * the call has been removed.          *          * Maybe the GET_DEVICE_STATUS call and the test below can          * be reinstated when device firmwares become more reliable.          * Don't hold your breath.          */ #if 0         /* Rule out self-powered configs for a bus-powered device */         if (bus_powered && (c->desc.bmAttributes &                     USB_CONFIG_ATT_SELFPOWER))             continue; #endif           /*          * The next test may not be as effective as it should be.          * Some hubs have errors in their descriptor, claiming          * to be self-powered when they are really bus-powered.          * We will overestimate the amount of current such hubs          * make available for each port.          *          * This is a fairly benign sort of failure.  It won't          * cause us to reject configurations that we should have          * accepted.          */           /* Rule out configs that draw too much bus current */         //电源不足.配置描述符中的电力是所需电力的1/2         if (c->desc.bMaxPower * 2 > udev->bus_mA) {             insufficient_power++;             continue;         }           /* When the first config's first interface is one of Microsoft's          * pet nonstandard Ethernet-over-USB protocols, ignore it unless          * this kernel has enabled the necessary host side driver.          */         if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) { #if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)             continue; #else             best = c; #endif         }           /* From the remaining configs, choose the first one whose          * first interface is for a non-vendor-specific class.          * Reason: Linux is more likely to have a class driver          * than a vendor-specific driver. */          //选择一个不是USB_CLASS_VENDOR_SPEC的配置         else if (udev->descriptor.bDeviceClass !=                         USB_CLASS_VENDOR_SPEC &&                 (!desc || desc->bInterfaceClass !=                         USB_CLASS_VENDOR_SPEC)) {             best = c;             break;         }           /* If all the remaining configs are vendor-specific,          * choose the first one. */         else if (!best)             best = c;     }       if (insufficient_power > 0)         dev_info(&udev->dev, "rejected %d configuration%s "             "due to insufficient available bus power\n",             insufficient_power, plural(insufficient_power));     //如果选择好了配置,返回配置的序号,否则,返回-1     if (best) {         i = best->desc.bConfigurationValue;         dev_info(&udev->dev,             "configuration #%d chosen from %d choice%s\n",             i, num_configs, plural(num_configs));     } else {         i = -1;         dev_warn(&udev->dev,             "no configuration chosen from %d choice%s\n",             num_configs, plural(num_configs));     }     return i; } Linux按照自己的喜好选择好了配置之后,返回配置的序号.不过对于HUB来说,它有且仅有一个配置.   4.2.2:usb_set_configuration()函数分析 既然已经选好配置了,那就告诉设备选好的配置,这个过程是在usb_set_configuration()中完成的.它的代码如下: int usb_set_configuration(struct usb_device *dev, int configuration) {     int i, ret;     struct usb_host_config *cp = NULL;     struct usb_interface **new_interfaces = NULL;     int n, nintf;       if (dev->authorized == 0 || configuration == -1)         configuration = 0;     else {         for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {             if (dev->config[i].desc.bConfigurationValue ==                     configuration) {                 cp = &dev->config[i];                 break;             }         }     }       if ((!cp && configuration != 0))         return -EINVAL;       /* The USB spec says configuration 0 means unconfigured.      * But if a device includes a configuration numbered 0,      * we will accept it as a correctly configured state.      * Use -1 if you really want to unconfigure the device.      */     if (cp && configuration == 0)         dev_warn(&dev->dev, "config 0 descriptor??\n"); 首先,根据选择好的配置号找到相应的配置,在这里要注意了, dev->config[]数组中的配置并不是按照配置的序号来存放的,而是按照遍历到顺序来排序的.因为有些设备在发送配置描述符的时候,并不是 按照配置序号来发送的,例如,配置2可能在第一次GET_CONFIGURATION就被发送了,而配置1可能是在第二次 GET_CONFIGURATION才能发送. 取得配置描述信息之后,要对它进行有效性判断,注意一下本段代码的最后几行代码:usb2.0 spec上规定,0号配置是无效配置,但是可能有些厂商的设备并末按照这一约定,所以在linux中,遇到这种情况只是打印出警告信息,然后尝试使用这一配置.     /* Allocate memory for new interfaces before doing anything else,      * so that if we run out then nothing will have changed. */       n = nintf = 0;     if (cp) {         //接口总数         nintf = cp->desc.bNumInterfaces;         //interface指针数组,         new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),                 GFP_KERNEL);         if (!new_interfaces) {             dev_err(&dev->dev, "Out of memory\n");             return -ENOMEM;         }           for (; n < nintf; ++n) {             new_interfaces[n] = kzalloc(                     sizeof(struct usb_interface),                     GFP_KERNEL);             if (!new_interfaces[n]) {                 dev_err(&dev->dev, "Out of memory\n");                 ret = -ENOMEM; free_interfaces:                 while (--n >= 0)                     kfree(new_interfaces[n]);                 kfree(new_interfaces);                 return ret;             }         }           //如果总电源小于所需电流,打印警告信息         i = dev->bus_mA - cp->desc.bMaxPower * 2;         if (i < 0)             dev_warn(&dev->dev, "new config #%d exceeds power "                     "limit by %dmA\n",                     configuration, -i);     } 在这里,注要是为new_interfaces分配空间,要这意的是, new_interfaces是一个二级指针,它的最终指向是struct usb_interface结构.特别的,如果总电流数要小于配置所需电流,则打印出警告消息.实际上,这种情况在 usb_choose_configuration()中已经进行了过滤.       /* Wake up the device so we can send it the Set-Config request */     //要对设备进行配置了,先唤醒它     ret = usb_autoresume_device(dev);     if (ret)         goto free_interfaces;       /* if it's already configured, clear out old state first.      * getting rid of old interfaces means unbinding their drivers.      */      //不是处于ADDRESS状态,先清除设备的状态     if (dev->state != USB_STATE_ADDRESS)         usb_disable_device(dev, 1); /* Skip ep0 */       //发送控制消息,选取配置     ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),                   USB_REQ_SET_CONFIGURATION, 0, configuration, 0,                   NULL, 0, USB_CTRL_SET_TIMEOUT);     if (ret < 0) {         /* All the old state is gone, so what else can we do?          * The device is probably useless now anyway.          */         cp = NULL;     }       //dev->actconfig存放的是当前设备选取的配置     dev->actconfig = cp;     if (!cp) {         usb_set_device_state(dev, USB_STATE_ADDRESS);         usb_autosuspend_device(dev);         goto free_interfaces;     }     //将状态设为CONFIGURED     usb_set_device_state(dev, USB_STATE_CONFIGURED); 接下来,就要对设备进行配置了,首先,将设备唤醒.回忆一下我们在分析UHCI驱动时,列出来的设备状态图.只 有在ADDRESS状态才能转入到CONFIG状态.(SUSPEND状态除外). 所以,如果设备当前不是处于ADDRESS状态,就需要将设备的状态初始化.usb_disable_device()函数是个比较重要的操作,在接下来 再对它进行详细分析. 接着,发送SET_CONFIGURATION的Control消息给设备,用来选择配置 最后,将dev->actconfig指向选定的配置,将设备状态设为CONFIG       /* Initialize the new interface structures and the      * hc/hcd/usbcore interface/endpoint state.      */      //遍历所有的接口     for (i = 0; i < nintf; ++i) {         struct usb_interface_cache *intfc;         struct usb_interface *intf;         struct usb_host_interface *alt;           cp->interface[i] = intf = new_interfaces[i];         intfc = cp->intf_cache[i];         intf->altsetting = intfc->altsetting;         intf->num_altsetting = intfc->num_altsetting;         //是否关联的接口描述符,定义在minor usb 2.0 spec中         intf->intf_assoc = find_iad(dev, cp, i);         kref_get(&intfc->ref);           //选择0号设置         alt = usb_altnum_to_altsetting(intf, 0);           /* No altsetting 0?  We'll assume the first altsetting.          * We could use a GetInterface call, but if a device is          * so non-compliant that it doesn't have altsetting 0          * then I wouldn't trust its reply anyway.          */           //如果0号设置不存在,选排在第一个设置         if (!alt)             alt = &intf->altsetting[0];           //当前的配置         intf->cur_altsetting = alt;         usb_enable_interface(dev, intf);         intf->dev.parent = &dev->dev;         intf->dev.driver = NULL;         intf->dev.bus = &usb_bus_type;         intf->dev.type = &usb_if_device_type;         intf->dev.dma_mask = dev->dev.dma_mask;         device_initialize(&intf->dev);         mark_quiesced(intf);         sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",             dev->bus->busnum, dev->devpath,             configuration, alt->desc.bInterfaceNumber);     }     kfree(new_interfaces);       if (cp->string == NULL)         cp->string = usb_cache_string(dev, cp->desc.iConfiguration); 之前初始化的new_interfaces在这里终于要派上用场了.初始化各接口,从上面的初始化过程中,我们可以看出: Intf->altsetting,表示接口的各种设置 Intf->num_altsetting:表示接口的设置数目 Intf->intf_assoc:接口的关联接口(定义于minor usb 2.0 spec) Intf->cur_altsetting:接口的当前设置. 结合之前在UHCI中的分析,我们总结一下: Usb_dev->config,其实是一个数组,存放设备的配置.usb_dev->config[m]-> interface[n]表示第m个配置的第n个接口的intercace结构.(m,n不是配置序号和接口序号 *^_^*). 注意这个地方对intf内嵌的struct devcie结构赋值,它的type被赋值为了usb_if_device_type.bus还是usb_bus_type.可能你已经反应过来了,要和这个device匹配的设备是interface的驱动. 特别的,这里的device的命名: sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",             dev->bus->busnum, dev->devpath,             configuration, alt->desc.bInterfaceNumber); dev指的是这个接口所属的usb_dev,结合我们之前在UHCI中关于usb设备命名方式的描述.可得出它的命令方式如下: USB总线号-设备路径:配置号.接口号. 例如,在我的虚拟机上: [root@localhost devices]# pwd /sys/bus/usb/devices [root@localhost devices]# ls 1-0:1.0  usb1 [root@localhost devices]# 可以得知,系统只有一个usb control. 1-0:1.0:表示,第一个usb control下的root hub的1号配置的0号接口. 那在插入U盘之后,会发生什么变化呢?不着急,我们等着往下面看,待分析到的时候,我自然就会列出来了 ^_^ usb_enable_interface()用来启用接口,也就是启用接口中的每一个endpoint.这个接口比较简单,其中调用的子函数usb_enable_endpoint()在分析UHCI的时候已经详细分析过了.在这里就不再赘述了. 在这里,还涉及到一个很有意思的函数, mark_quiesced().从字面意思上看来,它是标记接口为停止状态.它的”反函数”是mark_active().两个函数如下示: static inline void mark_active(struct usb_interface *f) {     f->is_active = 1;     f->dev.power.power_state.event = PM_EVENT_ON; }   static inline void mark_quiesced(struct usb_interface *f) {     f->is_active = 0;     f->dev.power.power_state.event = PM_EVENT_SUSPEND; } 从代码看来,它只是对接口的活动标志(is_active)进行了设置.       /* Now that all the interfaces are set up, register them      * to trigger binding of drivers to interfaces.  probe()      * routines may install different altsettings and may      * claim() any interfaces not yet bound.  Many class drivers      * need that: CDC, audio, video, etc.      */       //注册每一个接口?     for (i = 0; i < nintf; ++i) {         struct usb_interface *intf = cp->interface[i];           dev_dbg(&dev->dev,             "adding %s (config #%d, interface %d)\n",             intf->dev.bus_id, configuration,             intf->cur_altsetting->desc.bInterfaceNumber);         ret = device_add(&intf->dev);         if (ret != 0) {             dev_err(&dev->dev, "device_add(%s) --> %d\n",                 intf->dev.bus_id, ret);             continue;         }         usb_create_sysfs_intf_files(intf);     }       //使设备suspend     usb_autosuspend_device(dev);     return 0; } 最后,注册intf内嵌的device结构.设备配置完成了,为了省电,可以将设备置为SUSPEND状态.   这个函数中还有几个比较重要的子函数,依次分析如下: 1: usb_disable_device()函数. 顾名思义,这个函数是将设备disable掉.代码如下: void usb_disable_device(struct usb_device *dev, int skip_ep0) {     int i;       dev_dbg(&dev->dev, "%s nuking %s URBs\n", __FUNCTION__,         skip_ep0 ? "non-ep0" : "all");     for (i = skip_ep0; i < 16; ++i) {         usb_disable_endpoint(dev, i);         usb_disable_endpoint(dev, i + USB_DIR_IN);     }     dev->toggle[0] = dev->toggle[1] = 0;       /* getting rid of interfaces will disconnect      * any drivers bound to them (a key side effect)      */     if (dev->actconfig) {         for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {             struct usb_interface    *interface;               /* remove this interface if it has been registered */             interface = dev->actconfig->interface[i];             if (!device_is_registered(&interface->dev))                 continue;             dev_dbg(&dev->dev, "unregistering interface %s\n",                 interface->dev.bus_id);             usb_remove_sysfs_intf_files(interface);             device_del(&interface->dev);         }           /* Now that the interfaces are unbound, nobody should          * try to access them.          */         for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {             put_device(&dev->actconfig->interface[i]->dev);             dev->actconfig->interface[i] = NULL;         }         dev->actconfig = NULL;         if (dev->state == USB_STATE_CONFIGURED)             usb_set_device_state(dev, USB_STATE_ADDRESS);     } } 第二个参数是skip_ep0.是表示是否跳过ep0.为1表示跳过,为0表示清除掉设备中的所有endpoint. 这个函数可以分为两个部份,一部份是对usb_dev中的endpoint进行操作,一方面是释放usb_dev的选定配置项. 对于第一部份: 从代码中可能看到,如果skip_ep0为1,那就是从1开始循环,所以,就跳过了ep0.另外,一个端点号对应了两个端点,一个IN,一个OUT.IN端点比OUT端点要大USB_DIR_IN. 另外,既然设备都已经被禁用了,那toggle也应该回归原位了.因些将两个方向的toggle都设为0. usb_disable_endpoint()是一个很有意思的处理.它的代码如下: void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) {     unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;     struct usb_host_endpoint *ep;       if (!dev)         return;     //在dev->ep_out和dev->ep_in删除endpoint     if (usb_endpoint_out(epaddr)) {         ep = dev->ep_out[epnum];         dev->ep_out[epnum] = NULL;     } else {         ep = dev->ep_in[epnum];         dev->ep_in[epnum] = NULL;     }     //禁用掉此ep.包括删除ep上提交的urb 和ep上的QH     if (ep) {         ep->enabled = 0;         usb_hcd_flush_endpoint(dev, ep);         usb_hcd_disable_endpoint(dev, ep);     } } 在dev->ep_in[]/dev->ep_out[]中删除endpoint,这点很好理解. 比较难以理解的是后面的两个操作,即usb_hcd_flush_endpoint()和usb_hcd_disable_endpoint().根据之 前分析的UHCI的驱动,我们得知,对于每个endpoint都有一个传输的qh,这个qh上又挂上了要传输的urb.因此,这两个函数一个是删除 urb,一个是删除qh. usb_hcd_flush_endpoint()的代码如下: void usb_hcd_flush_endpoint(struct usb_device *udev,         struct usb_host_endpoint *ep) {     struct usb_hcd      *hcd;     struct urb      *urb;       if (!ep)         return;     might_sleep();     hcd = bus_to_hcd(udev->bus);       /* No more submits can occur */     //在提交urb时,将urb加到ep->urb_list上的时候要持锁     //因此,这里持锁的话,无法发生中断和提交urb     spin_lock_irq(&hcd_urb_list_lock); rescan: //将挂在ep->urb_list上的所有urb unlink.注意这里unlink一般只会设置urb->unlinked的 //值,不会将urb从ep->urb_list上删除.只有在UHCI的中断处理的时候,才会调用 //uhci_giveback_urb()将其从ep->urb_list中删除     list_for_each_entry (urb, &ep->urb_list, urb_list) {         int is_in;           if (urb->unlinked)             continue;         usb_get_urb (urb);         is_in = usb_urb_dir_in(urb);         spin_unlock(&hcd_urb_list_lock);           /* kick hcd */         unlink1(hcd, urb, -ESHUTDOWN);         dev_dbg (hcd->self.controller,             "shutdown urb %p ep%d%s%s\n",             urb, usb_endpoint_num(&ep->desc),             is_in ? "in" : "out",             ({  char *s;                    switch (usb_endpoint_type(&ep->desc)) {                  case USB_ENDPOINT_XFER_CONTROL:                     s = ""; break;                  case USB_ENDPOINT_XFER_BULK:                     s = "-bulk"; break;                  case USB_ENDPOINT_XFER_INT:                     s = "-intr"; break;                  default:                     s = "-iso"; break;                 };                 s;             }));         usb_put_urb (urb);           /* list contents may have changed */         //在这里解开锁了,对应ep->urb_list上又可以提交urb.         //这里释放释的话,主要是为了能够产生中断         spin_lock(&hcd_urb_list_lock);         goto rescan;     }     spin_unlock_irq(&hcd_urb_list_lock);       /* Wait until the endpoint queue is completely empty */       //等待urb被调度完     while (!list_empty (&ep->urb_list)) {         spin_lock_irq(&hcd_urb_list_lock);           /* The list may have changed while we acquired the spinlock */         urb = NULL;         if (!list_empty (&ep->urb_list)) {             urb = list_entry (ep->urb_list.prev, struct urb,                     urb_list);             usb_get_urb (urb);         }         spin_unlock_irq(&hcd_urb_list_lock);           if (urb) {             usb_kill_urb (urb);             usb_put_urb (urb);         }     } } 仔细体会这里的代码,为什么在前一个循环中,要使用goto rescan重新开始这个循环呢?这是因为在后面已经将自旋锁释放了,因此,就会有这样的可能,在函数中操作的urb,可能已经被调度完释放了.因此,再 对这个urb操作就会产生错误.所以,需要重新开始这个循环. 那后一个循环又是干什么的呢?后一个循环就是等待urb被调度完.有人就会有这样的疑问了,这里一边等待,然后endpoint一边还提交urb,那这个函数岂不是要耗掉很长时间? 在这里,不要忘记了前面的操作,在调这个函数之前, usb_disable_endpoint()已经将这个endpoint禁用了,也就是说该endpoint不会产生新的urb.因为,在后一个循环 中,只需要等待那些被unlink的urb调度完即可.在usb_kill_urb()中,会一直等待,直到这个urb被调度完成为止. 可能有人又会有这样的疑问: Usb_kill_urb()中也有unlink urb的操作,为什么这里要分做两个循环呢?     另外的一个函数是usb_hcd_disable_endpoint().代码如下: void usb_hcd_disable_endpoint(struct usb_device *udev,         struct usb_host_endpoint *ep) {     struct usb_hcd      *hcd;       might_sleep();     hcd = bus_to_hcd(udev->bus);     if (hcd->driver->endpoint_disable)         hcd->driver->endpoint_disable(hcd, ep); } 从上面的代码可以看到,操作转向了hcd->driver的endpoint_disable()接口. 以UHCI为例.在UHCI中,对应的接口为: static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,         struct usb_host_endpoint *hep) {     struct uhci_hcd *uhci = hcd_to_uhci(hcd);     struct uhci_qh *qh;       spin_lock_irq(&uhci->lock);     qh = (struct uhci_qh *) hep->hcpriv;     if (qh == NULL)         goto done;       while (qh->state != QH_STATE_IDLE) {         ++uhci->num_waiting;         spin_unlock_irq(&uhci->lock);         wait_event_interruptible(uhci->waitqh,                 qh->state == QH_STATE_IDLE);         spin_lock_irq(&uhci->lock);         --uhci->num_waiting;     }       uhci_free_qh(uhci, qh); done:     spin_unlock_irq(&uhci->lock); } 这个函数没啥好说的,就是在uhci->waitqh上等待队列状态变为QH_STATE_IDLE.来回忆一下,qh在什么情况下才会变为QH_STATE_IDLE呢? 是在qh没有待传输的urb的时候. 然后,将qh释放.   现在我们来接着看usb_disable_device()的第二个部份. 第二部份主要是针对dev->actconfig进行的操作, dev->actconfig存放的是设备当前的配置,现在要将设备设回Address状态.就些东西当然是用不了上的了.释放 dev->actconfig->interface[]中的各元素,注意不要将 dev->actconfig->interface[]所指向的信息释放了,它都是指向dev->config[]-> intf_cache[]中的东西,这些东西一释放,usb device在Get_ Configure所获得的信息就会部丢失了. 就这样, usb_disable_device()函数也走到了尾声.   2: usb_cache_string()函数 这个函数我们在分析UHCI的时候已经接触过,但末做详细的分析. 首先了解一下这个函数的作用,有时候,为了形象的说明,会提供一个字符串形式的说明.例如,对于配置描述符来 说,它的iConfiguration就表示一个字符串索引,然后用Get_String就可以取得这个索引所对应的字串了.不过,事情并不是这么简单. 因为字符串对应不同的编码,所以这里还会对应有编码的处理.来看具体的代码: char *usb_cache_string(struct usb_device *udev, int index) {     char *buf;     char *smallbuf = NULL;     int len;       if (index <= 0)         return NULL;       //不知道字符到底有多长,就按最长256字节处理     buf = kmalloc(256, GFP_KERNEL);     if (buf) {         len = usb_string(udev, index, buf, 256);         //取到字符了,分配合适的长度         if (len > 0) {             smallbuf = kmalloc(++len, GFP_KERNEL);             if (!smallbuf)                 return buf;             //将字符copy过去             memcpy(smallbuf, buf, len);         }         //释放旧空间         kfree(buf);     }     return smallbuf; } 这个函数没啥好说的,流程转入到usb_string中.代码如下: int usb_string(struct usb_device *dev, int index, char *buf, size_t size) {     unsigned char *tbuf;     int err;     unsigned int u, idx;       if (dev->state == USB_STATE_SUSPENDED)         return -EHOSTUNREACH;     if (size <= 0 || !buf || !index)         return -EINVAL;     buf[0] = 0;     tbuf = kmalloc(256, GFP_KERNEL);     if (!tbuf)         return -ENOMEM;       /* get langid for strings if it's not yet known */     //先取得设备支持的编码ID     if (!dev->have_langid) {         //以0号序号和编码0,Get_String就可得到设备所支持的编码列表         err = usb_string_sub(dev, 0, 0, tbuf);         //如果发生了错误,或者是取得的数据超短(最短为4字节)         if (err < 0) {             dev_err(&dev->dev,                 "string descriptor 0 read error: %d\n",                 err);             goto errout;         } else if (err < 4) {             dev_err(&dev->dev, "string descriptor 0 too short\n");             err = -EINVAL;             goto errout;         }         //取设备支持的第一个编码         else {             dev->have_langid = 1;             dev->string_langid = tbuf[2] | (tbuf[3] << 8);             /* always use the first langid listed */             dev_dbg(&dev->dev, "default language 0xx\n",                 dev->string_langid);         }     }       //以编码ID和序号Index作为参数Get_String取得序号对应的字串     err = usb_string_sub(dev, dev->string_langid, index, tbuf);     if (err < 0)         goto errout;       //空一个字符来用来存放结束符     size--;     /* leave room for trailing NULL char in output buffer */     //两字节一组,(Unicode编码的)     for (idx = 0, u = 2; u < err; u += 2) {         if (idx >= size)             break;         //如果高字节有值,说明它不是ISO-8859-1编码的,将它置为?         //否则,就将低位的值存放到buf中         if (tbuf[u+1])          /* high byte */             buf[idx++] = '?';  /* non ISO-8859-1 character */         else             buf[idx++] = tbuf[u];     }     //在最后一位赋0,字串结尾     buf[idx] = 0;     //返回字串的长度,(算上了最后的结尾字符)     err = idx;     //如果该描述符不是STRING描述符,打印出错误提示     if (tbuf[1] != USB_DT_STRING)         dev_dbg(&dev->dev,             "wrong descriptor type x for string %d (\"%s\")\n",             tbuf[1], index, buf);    errout:     //释放空间,返回长度     kfree(tbuf);     return err; } 结合代码中的注释,就很容易理解这一函数了,在此不对这一函数做详细分析. 跟踪进usb_string_sub().代码如下: static int usb_string_sub(struct usb_device *dev, unsigned int langid,               unsigned int index, unsigned char *buf) {     int rc;       /* Try to read the string descriptor by asking for the maximum      * possible number of bytes */      //如果设备不需要Fixup 就发出Get_String     if (dev->quirks & USB_QUIRK_STRING_FETCH_255)         rc = -EIO;     else         rc = usb_get_string(dev, langid, index, buf, 255);       /* If that failed try to read the descriptor length, then      * ask for just that many bytes */      //如果Get_String失败或者取得长度有问题.就先取字符描述符的头部      //再以实际的长度和参数,再次Get_String     if (rc < 2) {         rc = usb_get_string(dev, langid, index, buf, 2);         if (rc == 2)             rc = usb_get_string(dev, langid, index, buf, buf[0]);     }       //如果成功     if (rc >= 2) {         //如果前两个字节为空.则需要找到数据的有效起始位置         if (!buf[0] && !buf[1])             usb_try_string_workarounds(buf, &rc);           /* There might be extra junk at the end of the descriptor */         //整调一下描述符的长度         if (buf[0] < rc)             rc = buf[0];         //将rc置为了一个偶数.         rc = rc - (rc & 1); /* force a multiple of two */     }       //长度最终小于2.返回错误值     if (rc < 2)         rc = (rc < 0 ? rc : -EINVAL);       return rc; } 在这个地方,有个错误处理,可能有的设备你一次用255的长度去取它对字符串会返回一个错误,所以,在用255长度返回错误的时候,先以2为长度取它的描述符头度,再以描述符的实际长度去取字符串描述符串. 另外,在描述符的前两个字节都为空的情况下,就需要计算它的有效长度.在代码中,这一工作是由usb_try_string_workarounds()完成的. static void usb_try_string_workarounds(unsigned char *buf, int *length) {     int newlength, oldlength = *length;     //前两个字节是描述符头部,所以从2开始循环.     //Unicode编码用两个字节来表示一个字符. 所以每次循环完了之后要+2     for (newlength = 2; newlength + 1 < oldlength; newlength += 2)         //低字节是不可打印字符,或者高字节不为空(不是ISO-8859-1), 就退出循环.         if (!isprint(buf[newlength]) || buf[newlength + 1])             break;       //修正字符串描述符的实际长度.     //如果newlength 等于2.说明字符中描述符没有带字串     if (newlength > 2) {         buf[0] = newlength;         *length = newlength;     } } 这个函数涉及到编码方面的东东,建议参阅fudan_abc的<< Linux那些事儿之我是USB core >>,上面的较详细的描述. 至此, usb_cache_string()完分析完了. 到这里,usb device driver的probe过程也就完成了.   五:hub接口驱动分析 5.1:接口驱动架构 是时候来分析接口驱动的架构了. 我们在上面看到了接口设备的注册.在开篇的时候分析了接口驱动的注册.我们首先来分析接口驱备和接口驱动的匹配. 代码还是在usb_bus_type->match().只不过是对应另外的一种情况了.将相关代码列出: static int usb_device_match(struct device *dev, struct device_driver *drv) {     ……     if (is_usb_device(dev)) {         …… }     //interface的情况     else {         struct usb_interface *intf;         struct usb_driver *usb_drv;         const struct usb_device_id *id;           /* device drivers never match interfaces */         if (is_usb_device_driver(drv))             return 0;           intf = to_usb_interface(dev);         usb_drv = to_usb_driver(drv);           id = usb_match_id(intf, usb_drv->id_table);         if (id)             return 1;           id = usb_match_dynamic_id(intf, usb_drv);         if (id)             return 1;     }       return 0; } 经过前面的分析,因为在注册接口设备的时候,是将type设为usb_if_device_type,因此,这个函数第一个if是不会满足的. 首先,将struct device和struct device_driver转换为被封装的struct usb_interface和struct usb_driver.紧接着,我们看到了两个匹配,一个是usb_match_id().另外一个是usb_match_dynamic_id().后 者只有在前者没有匹配成功的情况下才能调用.我们也可以看到, struct usb_driver中一个struct usb_device_id类型的数组(id_table字段)和一个dynids链表.哪id和dyname_id有什么区别呢? 一般来说,id_table是usb 接口驱动静态定义的可以和此驱动匹配设备的一些参数.而dyname_id是可以动态调整的. 你可以通过写/sys/bus/usb/drivers/XXX/new_id来设置驱动的dyname_id.其中,XXX表示驱动的名称. 这两个函数的逻辑都差不多,我们以usb_match_id()为例进行分析.代码如下: const struct usb_device_id *usb_match_id(struct usb_interface *interface,                      const struct usb_device_id *id) {     /* proc_connectinfo in devio.c may call us with id == NULL. */     //如果driver中没有定义符合条件的id_talbe.则不能静态匹配所有设备     if (id == NULL)         return NULL;       /* It is important to check that id->driver_info is nonzero,        since an entry that is all zeroes except for a nonzero        id->driver_info is the way to create an entry that        indicates that the driver want to examine every        device and interface. */        //如果id_talbe中,有定义的匹配项,则调用usb_match_one_id()进行匹配测试        //如果成功,则返回匹配成功的id_talbe 项数.否则,继续下一项     for (; id->idVendor || id->idProduct || id->bDeviceClass ||            id->bInterfaceClass || id->driver_info; id++) {         if (usb_match_one_id(interface, id))             return id;     }       //如果没有匹配成功,则返回NULL     return NULL; } Id_talbe所属的结构如下示: struct usb_device_id {     /* which fields to match against? */     __u16       match_flags;       /* Used for product specific matches; range is inclusive */     __u16       idVendor;     __u16       idProduct;     __u16       bcdDevice_lo;     __u16       bcdDevice_hi;       /* Used for device class matches */     __u8        bDeviceClass;     __u8        bDeviceSubClass;     __u8        bDeviceProtocol;       /* Used for interface class matches */     __u8        bInterfaceClass;     __u8        bInterfaceSubClass;     __u8        bInterfaceProtocol;       /* not matched against */     kernel_ulong_t  driver_info; }; match_flags是一个匹配标志,表示要匹配哪一项.而后面的成员,例如idVendor, idProduct.表示具体要匹配项的值. usb_match_one_id()的代码如下: int usb_match_one_id(struct usb_interface *interface,              const struct usb_device_id *id) {     struct usb_host_interface *intf;     struct usb_device *dev;       /* proc_connectinfo in devio.c may call us with id == NULL. */     //再次判断id是否为空     if (id == NULL)         return 0;       //接口听当前匹配     intf = interface->cur_altsetting;     //转换为所属的usb_dev     dev = interface_to_usbdev(interface);       //关于设备参数的匹配.只有在设备参数符合的情况下,才会进行接口     //参数的匹配.     if (!usb_match_device(dev, id))         return 0;         //下面是关于接口参数的匹配     /* The interface class, subclass, and protocol should never be      * checked for a match if the device class is Vendor Specific,      * unless the match record specifies the Vendor ID. */  //当设备是厂商自定义类型时(Vendor Specific).除非定义了//USB_DEVICE_ID_MATCH_VENDOR      //否则是不需要匹配的     if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&             !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&             (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |                 USB_DEVICE_ID_MATCH_INT_SUBCLASS |                 USB_DEVICE_ID_MATCH_INT_PROTOCOL)))         return 0;     //如果要匹配interface class     if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&         (id->bInterfaceClass != intf->desc.bInterfaceClass))         return 0;     //如果要匹配interface subclass     if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&         (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))         return 0;     //如果要匹配interface protocol     if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&         (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))         return 0;       return 1; } 这个函数逻辑比较简单.它先检测所属设备参数的匹配项.再检查接口参数的匹配项.由于这个函数比较简单,就不对它多费舌去解释了. 简单的说一下关于Vendor Specific class的设备,这个类型在USB Class Codes被定义如下: This base class is defined for vendors to use as they please.  These class codes can be used in both Device and Interface Descriptors.     也就是说,这个类型是被厂商自定义的.它主要是靠SubClass和protocol来区分设备的.这些都是非标准定义的.   如果被这个match匹配成功的话,就会转入probe()了,由于bus中没有probe()函数,因此,流程转入到了与之匹配的驱动的probe函数. 记得在开篇的时候,分析过接口驱动,它的probe函数被设置为了usb_cache_string().代码如下: static int usb_probe_interface(struct device *dev) {     struct usb_driver *driver = to_usb_driver(dev->driver);     struct usb_interface *intf;     struct usb_device *udev;     const struct usb_device_id *id;     int error = -ENODEV;       dev_dbg(dev, "%s\n", __FUNCTION__);     //如果是一个usb 设备,退出     if (is_usb_device(dev))     /* Sanity check */         return error;       intf = to_usb_interface(dev);     udev = interface_to_usbdev(intf);       //如果所属设备的authorized 为0.错误,退出     if (udev->authorized == 0) {         dev_err(&intf->dev, "Device is not authorized for usage\n");         return -ENODEV;     }       //再确认一下设备和驱动是否匹配     id = usb_match_id(intf, driver->id_table);     if (!id)         id = usb_match_dynamic_id(intf, driver);     //如果匹配     if (id) {         dev_dbg(dev, "%s - got id\n", __FUNCTION__);           //使设备resume         error = usb_autoresume_device(udev);         if (error)             return error;           /* Interface "power state" doesn't correspond to any hardware          * state whatsoever.  We use it to record when it's bound to          * a driver that may start I/0:  it's not frozen/quiesced.          */          //将接口标志为active         mark_active(intf);         //intf->condition:接口的状态         //USB_INTERFACE_BINDING:正在绑定         intf->condition = USB_INTERFACE_BINDING;           /* The interface should always appear to be in use          * unless the driver suports autosuspend.          */          //intf->pm_usage_cnt:如果为1,接口不会autosuspend         intf->pm_usage_cnt = !(driver->supports_autosuspend);         //调用挂装结构的probe         error = driver->probe(intf, id);         //如果发生了错误,将接口标记成不活动的,接口状态设为USB_INTERFACE_UNBOUND         if (error) {             mark_quiesced(intf);             intf->needs_remote_wakeup = 0;             intf->condition = USB_INTERFACE_UNBOUND;         }         //如果成功,将接口状态设为USB_INTERFACE_BOUND         else             intf->condition = USB_INTERFACE_BOUND;           //使设备suspend         usb_autosuspend_device(udev);     }       return error; } 至此为至,我们遇到了大量的usb_autoresume_device()/usb_autosuspend_device().先将它们放到一边,等以后再来详细分析他们的操作. 还记得,在usb_set_configuration()中,为每一个接口调用了mark_quiesced().所以在这个probe里,将正确匹配的接口调用mark_active(),将其标记为Active. 另外,我们来看一下,intf-> condition的几种情况,在代码中, condition属于enum usb_interface_condition结构.如下示: enum usb_interface_condition {     USB_INTERFACE_UNBOUND = 0,     USB_INTERFACE_BINDING,     USB_INTERFACE_BOUND,     USB_INTERFACE_UNBINDING, }; 分别表示,没有绑定,正在绑定,已经绑定,正在解除绑定. 从上面的代码中可以看出.最后的流程会回溯到usb_driver的probe.   5.2:hub的接口驱动 经过上面的分析,我们知道,接口驱动和接口的匹配主要是根据接口的一些信息来判断的.那对于hub的接口,它的标志信息是什么呢? 在usb2.0 spec上,规定了hub的设备class和接口class都为0x9.也就是代码中定义的USB_CLASS_HUB. 同时,我们注意到,在usb_init()àusb_hub_init()中: int usb_hub_init(void) {     if (usb_register(&hub_driver) < 0) {         printk(KERN_ERR "%s: can't register hub driver\n",             usbcore_name);         return -1;     }       khubd_task = kthread_run(hub_thread, NULL, "khubd");     if (!IS_ERR(khubd_task))         return 0;       /* Fall through if kernel_thread failed */     usb_deregister(&hub_driver);     printk(KERN_ERR "%s: can't start khubd\n", usbcore_name);       return -1; } 这个函数注册了hub_driver对应的接口驱动,还启动了一个内核线程.在这里,我们注意到, hub_driver的定义如下: static struct usb_driver hub_driver = {     .name =     "hub",     .probe =    hub_probe,     .disconnect =   hub_disconnect,     .suspend =  hub_suspend,     .resume =   hub_resume,     .reset_resume = hub_reset_resume,     .pre_reset =    hub_pre_reset,     .post_reset =   hub_post_reset,     .ioctl =    hub_ioctl,     .id_table = hub_id_table,     .supports_autosuspend = 1, }; Hub_id_talbe被定义为: static struct usb_device_id hub_id_table [] = {     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,       .bDeviceClass = USB_CLASS_HUB},     { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,       .bInterfaceClass = USB_CLASS_HUB},     { }                      /* Terminating entry */ }; 看到了没,这些信息就是hub 的接口class信息. 也就是说, hub_driver就是为们要找的hub 接口的驱动. 根据上面的分析,流程最终会到hub_driver->probe中,对应的接口为hub_probe().   5.2.1:接口驱动的probe过程 Hub_probe()的代码如下: static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) {     struct usb_host_interface *desc;     struct usb_endpoint_descriptor *endpoint;     struct usb_device *hdev;     struct usb_hub *hub;       desc = intf->cur_altsetting;     hdev = interface_to_usbdev(intf);   #ifdef  CONFIG_USB_OTG_BLACKLIST_HUB     if (hdev->parent) {         dev_warn(&intf->dev, "ignoring external hub\n");         return -ENODEV;     } #endif       /* Some hubs have a subclass of 1, which AFAICT according to the */     /*  specs is not defined, but it works */     //spec上规定接口的subclass为0.但为1时,也能工作     if ((desc->desc.bInterfaceSubClass != 0) &&         (desc->desc.bInterfaceSubClass != 1)) { descriptor_error:         dev_err (&intf->dev, "bad descriptor, ignoring hub\n");         return -EIO;     }       /* Multiple endpoints? What kind of mutant ninja-hub is this? */     //spec上规定hub interface的endpoint数目为1,这里的数目没有包括ep0     if (desc->desc.bNumEndpoints != 1)         goto descriptor_error;     //端点描述符     endpoint = &desc->endpoint[0].desc;       /* If it's not an interrupt in endpoint, we'd better punt! */     //不是IN方向的中断传输端点,有错误     if (!usb_endpoint_is_int_in(endpoint))         goto descriptor_error;       /* We found a hub */     dev_info (&intf->dev, "USB hub found\n");       //初始化一个struct usb_hub结构     hub = kzalloc(sizeof(*hub), GFP_KERNEL);     if (!hub) {         dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");         return -ENOMEM;     }     //初始化引用计数     kref_init(&hub->kref);     //初始化event_list     INIT_LIST_HEAD(&hub->event_list);     //hub->intfdev:指向接口封装的dev      hub->intfdev = &intf->dev;     //hub->hdev:hub所属的usb_dev     hub->hdev = hdev;     //初始化一个延时工作队列,用来管理hub LED的     INIT_DELAYED_WORK(&hub->leds, led_work);     //增加intf->dev的引用计数     usb_get_intf(intf);     //intf->dev的私有结构指和hub     usb_set_intfdata (intf, hub);     //接口需要远程唤醒     intf->needs_remote_wakeup = 1;       //如果是一个高速设备,增加highspeed_hubs  计数     if (hdev->speed == USB_SPEED_HIGH)         highspeed_hubs++;       //配置hub     if (hub_configure(hub, endpoint) >= 0)         return 0;       hub_disconnect (intf);     return -ENODEV; } 这个函数前一部份进行一些有效性检查,后半部份分配并初始化一个struct usb_hub结构.然后流程就转入了hub_configure(). hub_configure()函数是一个很重要的操作,它的代码如下: static int hub_configure(struct usb_hub *hub,     struct usb_endpoint_descriptor *endpoint) {     struct usb_device *hdev = hub->hdev;     struct device *hub_dev = hub->intfdev;     u16 hubstatus, hubchange;     u16 wHubCharacteristics;     unsigned int pipe;     int maxp, ret;     char *message;       //为buffer分配空间,DMA分配,其物理地址存放在hub->buffer_dma中     //buffer是一个指向数组的指针     hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,             &hub->buffer_dma);     if (!hub->buffer) {         message = "can't allocate hub irq buffer";         ret = -ENOMEM;         goto fail;     }       //为status分配空间     hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);     if (!hub->status) {         message = "can't kmalloc hub status buffer";         ret = -ENOMEM;         goto fail;     }     mutex_init(&hub->status_mutex);       //为hub->descriptor分配空间     hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);     if (!hub->descriptor) {         message = "can't kmalloc hub descriptor";         ret = -ENOMEM;         goto fail;     }       /* Request the entire hub descriptor.      * hub->descriptor can handle USB_MAXCHILDREN ports,      * but the hub can/will return fewer bytes here.      */      //取得hub描述符     ret = get_hub_descriptor(hdev, hub->descriptor,             sizeof(*hub->descriptor));     //如果Get_Descriptor失败或者hub端口超多     if (ret < 0) {         message = "can't read hub descriptor";         goto fail;     }     //协议上规定hub最多有255个接口,但Linux认为31个接口已经够多了     else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {         message = "hub has too many ports!";         ret = -ENODEV;         goto fail;     }       //hdev->maxchild: hub的端口数目     hdev->maxchild = hub->descriptor->bNbrPorts;     dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,         (hdev->maxchild == 1) ? "" : "s");       //wHubCharacteristics字段     wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);       //是否是一个复合设备     if (wHubCharacteristics & HUB_CHAR_COMPOUND) {         int i;         char    portstr [USB_MAXCHILDREN + 1];           for (i = 0; i < hdev->maxchild; i++)             //找到数组中的所在项和数组项中的位置             portstr[i] = hub->descriptor->DeviceRemovable                     [((i + 1) / 8)] & (1 << ((i + 1) % 8))                 ? 'F' : 'R';         //以\0 结尾         portstr[hdev->maxchild] = 0;         dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);     } else         dev_dbg(hub_dev, "standalone hub\n");       //电源开关模式     switch (wHubCharacteristics & HUB_CHAR_LPSM) {         //ganged 电源开关,所有连接端口同时开机         case 0x00:             dev_dbg(hub_dev, "ganged power switching\n");             break;         //端口有单独的电源开关         case 0x01:             dev_dbg(hub_dev, "individual port power switching\n");             break;         //1X:保留, 表示没有电源开关            case 0x02:         case 0x03:             dev_dbg(hub_dev, "no power switching (usb 1.0)\n");             break;     }       //过电流保护模式     switch (wHubCharacteristics & HUB_CHAR_OCPM) {         //全部电流保护         case 0x00:             dev_dbg(hub_dev, "global over-current protection\n");             break;         //个别连接端口电源保护         case 0x08:             dev_dbg(hub_dev, "individual port over-current protection\n");             break;         //没有过电流保护         case 0x10:         case 0x18:             dev_dbg(hub_dev, "no over-current protection\n");                         break;     }       //初始化TT相关的东西     spin_lock_init (&hub->tt.lock);     INIT_LIST_HEAD (&hub->tt.clear_list);     INIT_WORK (&hub->tt.kevent, hub_tt_kevent);     //设备描述符的bDeviceProtocol 字段     switch (hdev->descriptor.bDeviceProtocol) {         //HUB是一个低速/全速设备         case 0:             break;         //只有一个TT         case 1:             dev_dbg(hub_dev, "Single TT\n");             hub->tt.hub = hdev;             break;         //多个TT            case 2:             //为接口选取1号设置             ret = usb_set_interface(hdev, 0, 1);             if (ret == 0) {                 dev_dbg(hub_dev, "TT per port\n");                 hub->tt.multi = 1;             } else                 dev_err(hub_dev, "Using single TT (err %d)\n",                     ret);             hub->tt.hub = hdev;             break;         default:             dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",                 hdev->descriptor.bDeviceProtocol);             break;     }       /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */     //TT think time,     switch (wHubCharacteristics & HUB_CHAR_TTTT) {         case HUB_TTTT_8_BITS:             if (hdev->descriptor.bDeviceProtocol != 0) {                 hub->tt.think_time = 666;                 dev_dbg(hub_dev, "TT requires at most %d "                         "FS bit times (%d ns)\n",                     8, hub->tt.think_time);             }             break;         case HUB_TTTT_16_BITS:             hub->tt.think_time = 666 * 2;             dev_dbg(hub_dev, "TT requires at most %d "                     "FS bit times (%d ns)\n",                 16, hub->tt.think_time);             break;         case HUB_TTTT_24_BITS:             hub->tt.think_time = 666 * 3;             dev_dbg(hub_dev, "TT requires at most %d "                     "FS bit times (%d ns)\n",                 24, hub->tt.think_time);             break;         case HUB_TTTT_32_BITS:             hub->tt.think_time = 666 * 4;             dev_dbg(hub_dev, "TT requires at most %d "                     "FS bit times (%d ns)\n",                 32, hub->tt.think_time);             break;     }       /* probe() zeroes hub->indicator[] */     //是否支持连接端口LED     if (wHubCharacteristics & HUB_CHAR_PORTIND) {         hub->has_indicators = 1;         dev_dbg(hub_dev, "Port indicators are supported\n");     }     //bPwrOn2PwrGood字段表示连接端口从开机到准备好的时间     dev_dbg(hub_dev, "power on to power good time: %dms\n",         hub->descriptor->bPwrOn2PwrGood * 2);       /* power budgeting mostly matters with bus-powered hubs,      * and battery-powered root hubs (may provide just 8 mA).      */      //Get_Status 设备     ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);     //Get_Status失败     if (ret < 2) {         message = "can't get hub status";         goto fail;     }     //设备的status包含两个部份:bit 0 表示使用自身电源bit 1是远程唤醒字段     le16_to_cpus(&hubstatus);     //如果是root hub     if (hdev == hdev->bus->root_hub) {         //如果电流没有限制         if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)             hub->mA_per_port = 500;         //有限制的情况下         else {             hub->mA_per_port = hdev->bus_mA;             hub->limited_power = 1;         }     }     //如果使用总线电流     else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {         dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",             hub->descriptor->bHubContrCurrent);         hub->limited_power = 1;         if (hdev->maxchild > 0) {             int remaining = hdev->bus_mA -                     hub->descriptor->bHubContrCurrent;               if (remaining < hdev->maxchild * 100)                 dev_warn(hub_dev,                     "insufficient power available "                     "to use all downstream ports\n");             hub->mA_per_port = 100;     /* 7.2.1.1 */         }     }     // 如果使用本身电流     else {  /* Self-powered external hub */         /* FIXME: What about battery-powered external hubs that          * provide less current per port? */         hub->mA_per_port = 500;     }     if (hub->mA_per_port < 500)         dev_dbg(hub_dev, "%umA bus power budget for each child\n",                 hub->mA_per_port);     //Get hub status     //hub 状态位和改变位     ret = hub_hub_status(hub, &hubstatus, &hubchange);     if (ret < 0) {         message = "can't get hub status";         goto fail;     }       /* local power status reports aren't always correct */     //自身供电     if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER)         dev_dbg(hub_dev, "local power source is %s\n",             (hubstatus & HUB_STATUS_LOCAL_POWER)             ? "lost (inactive)" : "good");     //不支持过电流保护     if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)         dev_dbg(hub_dev, "%sover-current condition exists\n",             (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");       /* set up the interrupt endpoint      * We use the EP's maxpacket size instead of (PORTS+1+7)/8      * bytes as USB2.0[11.12.3] says because some hubs are known      * to send more data (and thus cause overflow). For root hubs,      * maxpktsize is defined in hcd.c's fake endpoint descriptors      * to be big enough for at least USB_MAXCHILDREN ports. */            //设备中断控制传输的urb      //通道和最大包长度     pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);     maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));       if (maxp > sizeof(*hub->buffer))         maxp = sizeof(*hub->buffer);     //分配urb     hub->urb = usb_alloc_urb(0, GFP_KERNEL);     if (!hub->urb) {         message = "couldn't allocate interrupt urb";         ret = -ENOMEM;         goto fail;     }     //填充urb     usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,         hub, endpoint->bInterval);     hub->urb->transfer_dma = hub->buffer_dma;     hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;       /* maybe cycle the hub leds */     if (hub->has_indicators && blinkenlights)         hub->indicator [0] = INDICATOR_CYCLE;     //驱动hub     hub_power_on(hub);     //激活hub     hub_activate(hub);     return 0;   fail:     dev_err (hub_dev, "config failed, %s (err %d)\n",             message, ret);     /* hub_disconnect() frees urb and descriptor */     return ret; } 这个函数先初始化struct usb_hub中的几个指针,为之分配空间,然后,取得hub的描述符,再根据取得的描述符信息再初始化和显示一些调试信息.其中的一些成员赋值等我们用 到的时候再来进行分析.这个函数的后面关于urb部份和后面调用的两个子函数才是我们要分析的重点. 在这里,顺带提一下HUB的指示灯问题. Hub描述符的wHubCharacteristics的bit7来描述设备是否支持显示灯.为1表示在下游的连接端口上支持显示灯,为0则不支持. 如果Hub支持指示灯,则将hub->has_indicators置为1.另外,HUB的指示灯是否起作用,还由一个参数决定,在代码中,大家也看到,这个参数是blinkenlights.这个参数定义如下: static int blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); 这是一个可调的模块参数.如果要显示灯起作用,必须要将其置为1才可以.我们可以用下面两种方法来设置这个参数: 1:如果模块没有编译进kernel,可以在插入模块的时候,加上这个参数:     modprobe usbcore blinkenlights=1 2:如果模块已经编进kernel,那在kernel的启动参数上加上如下参数:     usbcore.blinkenlights=1 在usb2.0 spec中,对不同情况下的灯颜色都做了定义. 在代码中,灯的显示交给了一延迟的工作队列进行处理,初始化如下所示: INIT_DELAYED_WORK(&hub->leds, led_work); (在hub_probe()函数中) 在这里,并不打算详细分析这一部份,有兴趣的可以跟踪下去看下.   那函数后面初始化的URB是用来干什么的呢?我们将这个URB的初始化部份单独列出如下: pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress);     maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe));     if (maxp > sizeof(*hub->buffer))         maxp = sizeof(*hub->buffer); 我们从此可以看出,这个URB是作用于ep0之外的另一个端点,而且传输数据的长度最大为sizeof(*hub->buffer) Hub->buffer被定义如下: struct usb_hub {     ……     char            (*buffer)[8];     …… } 由此可以看出buffer是指向一个8元素字符数组的指针,sizeof(*hub->buffer)等于0. 关于传输的数据长度,代码中有一段注释,这段注释说,spec上规定的长度是(PORTS+1+7)/8.而linux中,对每个hub上挂有认为最多的端口进行处理,因些,就是(31+1+7)/8 = 5 为什么这里要是8呢? 因为usb2.0 spec上规定,ep0的最大发包长度,可能为8.16.32.64.512.所以选择比5要大的最小值8. 另外,我们注意到,URB完成之后,所要调用的函数是hub_irq().如下所示: usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,         hub, endpoint->bInterval); UHCI必须要知道HUB的端口的一些连接状态,因此,需要HUB周期性的上报它的端口连接状态.这个URB就是用来做这个用途的.UHCI周期性的发送IN方向中断传输传输给HUB.HUB就会通过这个URB将端口信息发送给HUB. 那这个轮询周期是多长呢?根据我们之前分析的UHCI的知识,它的调度周期是由endpoint的bInterval 字段所决定的.   现在,我们慢慢来接触到hub的一些核心处理了.整理一下心情,继续看代码.^_^ 接下来,我们要看到的第一个函数是hub_power_on().代码如下: static void hub_power_on(struct usb_hub *hub) {     int port1;     //从连接端口从开机到准备好的时间     unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;     //wHubCharacteristics字段     u16 wHubCharacteristics =             le16_to_cpu(hub->descriptor->wHubCharacteristics);       /* Enable power on each port.  Some hubs have reserved values      * of LPSM (> 2) in their descriptors, even though they are      * USB 2.0 hubs.  Some hubs do not implement port-power switching      * but only emulate it.  In all cases, the ports won't work      * unless we send these messages to the hub.      */      //开关模式     if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2)         dev_dbg(hub->intfdev, "enabling power on all ports\n");     else         dev_dbg(hub->intfdev, "trying to enable port power on "                 "non-switchable hub\n");     //给每一个端口发送PORT_POWER的Set_Feature消息     for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)         set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);       /* Wait at least 100 msec for power to become stable */     //等待端口可以正常工作,至少100 ms     msleep(max(pgood_delay, (unsigned) 100)); } 这里就是给每个接口发送PORT_POWER的Set_Feature消息,告之可起来工作了,然后等待端口可以工作.   另外要分析的函数是hub_activate().代码如下: static void hub_activate(struct usb_hub *hub) {     int status;       hub->quiescing = 0;     hub->activating = 1;       //提交urb     status = usb_submit_urb(hub->urb, GFP_NOIO);     if (status < 0)         dev_err(hub->intfdev, "activate --> %d\n", status);     if (hub->has_indicators && blinkenlights)         schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD);       /* scan all ports ASAP */     kick_khubd(hub); } 首先 ,是在hub的两个字段进行赋值操作,hub-> quiescing 和 hub->activating表示分别表示hub处理暂停和活跃状态.注意,在这里,不要和接口的mark_active()设置的intf->is_active相混淆. 然后,将hub->urb提交.开始调度Led的工作队列. 最后,流程转入kick_khubd().代码如下: static void kick_khubd(struct usb_hub *hub) {     unsigned long   flags;       /* Suppress autosuspend until khubd runs */     //pm_usage_cnt设置为1,防止autosuspend     to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;       spin_lock_irqsave(&hub_event_lock, flags);     if (!hub->disconnected && list_empty(&hub->event_list)) {         list_add_tail(&hub->event_list, &hub_event_list);         wake_up(&khubd_wait);     }     spin_unlock_irqrestore(&hub_event_lock, flags); } 在这个函数中,先将接口的pm_usage_cnt置1,此后,该接口就不能SUSPEND. 然后,将该hub添加进hub_event_list链表,并唤醒Khubd_wait等待队列. hub_event_list和Khubd_wait到底代表着什么呢?它后面的参数又是什么呢?接着往下看…

转载于:https://www.cnblogs.com/sdphome/archive/2011/09/29/2195789.html

相关资源:数据结构—成绩单生成器

最新回复(0)