Skip to content
  • 首页
  • PHP源码
  • html5网页模板
  • js特效
  • Window软件
  • Mac软件
  • 服务器
  • 其他
Search
源码巴士
  • Sample Page

linux下的usb驱动框架

一、linux 下的usb驱动框架

在linux系统中,usb驱动可以从两个角度去观察,一个是主机侧,一个是设备侧。linux usb 驱动的总体框架如下图所示:

  从主机侧看usb驱动可分为四层:usb主机控制器硬件底层、usb主机控制器驱动、usb核心和usb设备驱动。

在主机侧要实现的驱动主要分为两类:usb主机控制器驱动和usb设备驱动。主机控制器驱动负责控制插入其中的usb设备,usb设备驱动主要负责usb设备和主机的通信。

usb核心向上为设备驱动提供编程接口,向下为usb控制器驱动提供编程口,维护整个usb设备信息,完成设备热插拔控制,总线数据传输控制。

可以看到这种设备驱动、核心层、主机控制器驱动这种三层结构的驱动框架,与之前分析过linux系统下i2c子系统的驱动架构有异曲同工之处。linux内核中将主机控制器的驱动和外设端的驱动分离,通过一个核心层将某种总线的协议进行抽象,外设端的驱动调用核心层API间接过渡到主机驱动传输函数的调用。

这里借助一张图来对比linux下,i2c、spi、usb三个子系统的相似之处。

这样一对比,就能比较清晰的分析usb主机控制器驱动与usb设备驱动。

二、usb总线驱动程序分析

主机控制器中重要的数据结构:

usb_hcd:描述了USB主机控制器驱动,包含主机控制器的信息

hc_driver:用于操作主机控制器的驱动,该结构体在usb_hcd 中

   ohci_hcd: 是usb_hcd 结构体中的私有数据

在主机控制驱动中还是通过平台设备驱动来注册platform_device和platform_driver,然后用平台总线进行匹配,匹配成功之后调用probe函数,在probe函数中做j进一步的操作。

probe函数:

复制代码
static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
                  struct platform_device *dev)
{
    struct usb_hcd *hcd = NULL;
    int retval;
    // dev->dev.platform_data == NULL,因此这里不会不用set_power
    s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
    s3c2410_usb_set_power(dev->dev.platform_data, 2, 1);
    // 创建一个hcd结构体,并做一些设置
    hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
    if (hcd == NULL)
        return -ENOMEM;
    // 设置内存和IO资源的开始位置
    hcd->rsrc_start = dev->resource[0].start;
    //  设置内存和IO资源的长度
    hcd->rsrc_len   = dev->resource[0].end - dev->resource[0].start + 1;
    // 申请一块内存资源
    if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
        dev_err(&dev->dev, "request_mem_region failed\n");
        retval = -EBUSY;
        goto err_put;
    }
    //  在clock.c中找到"usb-host"对应的clk结构体
    clk = clk_get(&dev->dev, "usb-host");
    if (IS_ERR(clk)) {
        dev_err(&dev->dev, "cannot get usb-host clock\n");
        retval = -ENOENT;
        goto err_mem;
    }
     //  在clock.c中找到"usb-bus-host"对应的clk结构体   
    usb_clk = clk_get(&dev->dev, "usb-bus-host");
    if (IS_ERR(usb_clk)) {
        dev_err(&dev->dev, "cannot get usb-bus-host clock\n");
        retval = -ENOENT;
        goto err_clk;
    }
    //  使能时钟  使能过流检查
    s3c2410_start_hc(dev, hcd);
    //  io端口重映射
    hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
    if (!hcd->regs) {
        dev_err(&dev->dev, "ioremap failed\n");
        retval = -ENOMEM;
        goto err_ioremap;
    }
    // 初始化ohci_hcd 结构体ohci->next_statechange = jiffies
    ohci_hcd_init(hcd_to_ohci(hcd));
    // 这个函数下边分析 一个usb主机控制器对应一个usb_hcd,对应一条usb总线,集成一个root_hub
    retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
    if (retval != 0)
        goto err_ioremap;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;

err_ioremap:
s3c2410_stop_hc(dev);
iounmap(hcd->regs);
clk_put(usb_clk);

err_clk:
clk_put(clk);

err_mem:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

err_put:
usb_put_hcd(hcd);
return retval;
}

复制代码

在probe函数中主要的任务如下:

(1)创建一个usb_hcd结构体===>和i2c控制器驱动中的中分配一个i2c_adapter一样

(2)设置这个这个usb_hcd结构体(设置操作主机控制器的hc_driver)===>设置i2c_adapter结构体(设置操作i2c_adapter的transfer函数)

(3)从platform_device中获取到硬件资源,进行内存映射

(4)使能时钟

(5)usb_add_hcd

usb_create_hcd函数:

复制代码
struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
        struct device *dev, const char *bus_name)
{
    struct usb_hcd *hcd;
    hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
    dev_set_drvdata(dev, hcd);
        ...
        // 初始化hcd下边的usb_bus,为后边将其加入到usb_bus 中做准备:    
            //bus->devnum_next = 1;  bus->root_hub = NULL;  bus->busnum = -1;
            //bus->bandwidth_allocated = 0;  bus->bandwidth_int_reqs  = 0;
            //bus->bandwidth_isoc_reqs = 0;
    usb_bus_init(&hcd->self);
    hcd->self.controller = dev;
    hcd->self.bus_name = bus_name;
    hcd->self.uses_dma = (dev->dma_mask != NULL);
        // 初始定时器用来轮询控制器的root_hub的状态改变
    init_timer(&hcd->rh_timer);
        // 注册定时器中断服务函数
    hcd->rh_timer.function = rh_timer_func;
    hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_USB_SUSPEND
    INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
    mutex_init(&hcd->bandwidth_mutex);
        // 给hcd添加主机控制器驱动函数    driver==ohci_s3c2410_hc_driver
    hcd->driver = driver;
    hcd->product_desc = (driver->product_desc) ? driver->product_desc :
            "USB Host Controller";
    return hcd;
}
复制代码

 usb_add_hcd函数:一个usb主机控制器对应一条usb总线,集成一个root_hub,对应一个usb_hcd。

复制代码
int usb_add_hcd(struct usb_hcd *hcd,
        unsigned int irqnum, unsigned long irqflags)
{
        // 初始化缓存池
    if ((retval = hcd_buffer_create(hcd)) != 0) {
        dev_dbg(hcd->self.controller, "pool alloc failed\n");
        return retval;
    }
        //设置hcd下usb_bus的busnum并将其挂到usb_bus_list这个链表中 hcd->self 在usb_create_hcd 中已经初始化了  (注册完之后hcd->self.busnum = 1)
    if ((retval = usb_register_bus(&hcd->self)) < 0)
        goto err_register_bus;
        // 创建一个root_hub
    if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
        dev_err(hcd->self.controller, "unable to allocate root hub\n");
        retval = -ENOMEM;
        goto err_allocate_root_hub;
    }
      // 将上边分配好的usb_device挂在主机控制的usb_bus下
    hcd->self.root_hub = rhdev;
        // 根据ohci_s3c2410_hc_driver(HCD_USB11 | HCD_MEMORY,)下的flag 选择 root_hub 的speed
    switch (hcd->driver->flags & HCD_MASK) {
    case HCD_USB11:
        rhdev->speed = USB_SPEED_FULL;
        break;
    case HCD_USB2:
        rhdev->speed = USB_SPEED_HIGH;
        break;
    case HCD_USB3:
        rhdev->speed = USB_SPEED_SUPER;
        break;
    default:
        goto err_set_rh_speed;
    }
    device_init_wakeup(&rhdev->dev, 1);
    if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
        dev_err(hcd->self.controller, "can't setup\n");
        goto err_hcd_driver_setup;
    }
    hcd->rh_pollable = 1;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> NOTE: root hub and controller capabilities may not be the same </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (device_can_wakeup(hcd-&gt;<span style="color: rgba(0, 0, 0, 1)">self.controller)
        </span>&amp;&amp; device_can_wakeup(&amp;hcd-&gt;self.root_hub-&gt;<span style="color: rgba(0, 0, 0, 1)">dev))
    dev_dbg(hcd</span>-&gt;self.controller, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">supports USB remote wakeup\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> enable irqs just before we start the controller </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 接下来使能中断
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 接下来执行主机控制器的启动函数</span>

<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> starting here, usbcore will pay attention to this root hub </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
rhdev</span>-&gt;bus_mA = min(<span style="color: rgba(128, 0, 128, 1)">500u</span>, hcd-&gt;<span style="color: rgba(0, 0, 0, 1)">power_budget);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> ((retval = <span style="background-color: rgba(255, 102, 0, 1)">register_root_hub(hcd)</span>) != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> err_register_root_hub;

retval </span>= sysfs_create_group(&amp;rhdev-&gt;dev.kobj, &amp;<span style="color: rgba(0, 0, 0, 1)">usb_bus_attr_group);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (retval &lt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
    printk(KERN_ERR </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Cannot register USB bus sysfs attributes: %d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
           retval);
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> error_create_attr_group;
}
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (hcd-&gt;uses_new_polling &amp;&amp;<span style="color: rgba(0, 0, 0, 1)"> HCD_POLL_RH(hcd))
    usb_hcd_poll_rh_status(hcd);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> retval;
...

}

复制代码

在usb_add_hcd中,最主要干的一件事是创建一个root_hub,这个root_hub的数据类型是一个usb_device,并将这个root_hub注册到usb总线中。

这里大概解释一下什么是root_hub。在我们的电脑上通常有几个usb端口,这些端口可以用来连接一个普通的usb设备,或者一个hub,hub是一个usb设备,可以用来扩展连接usb设备的端口数量。通常情况下主机控制器的物理端口由一个虚拟的root_hub来管理。这个hub是主机控制器的设备驱动虚拟的,用来统一管理总线拓扑。用一张图说明usb系统的拓扑结构。

 

register_root_hub函数的调用太复杂了,这里先抽象出其函数调用过程如下:

为了分析清楚root_hub下的dev到底与总线上的哪一个device_driver匹配需要分析usb总线上的match函数

复制代码
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
    // 需要匹配的是usb_device时的情况
    if (is_usb_device(dev)) {
    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> interface drivers never match devices </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">is_usb_device_driver(drv))
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> TODO: Add real matching code </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
} 
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 需要匹配的是接口的情况</span>

else if (is_usb_interface(dev)) {
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 </span>= usb_match_id(intf, usb_drv-&gt;<span style="color: rgba(0, 0, 0, 1)">id_table);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (id)
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
    id </span>=<span style="color: rgba(0, 0, 0, 1)"> usb_match_dynamic_id(intf, usb_drv);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (id)
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;

}

复制代码

对于传入的match函数的dev其dev->type是usb_device_type(在分配usb_alloc_dev中已经设置了)。

现在看usb总线上有哪些device_driver:在/core/usb.c中我们可以看到已经注册了两个usb_driver结构体 usbfs_driver和hub_driver 

                                                                                                                          一个usb_device_driver结构体  usb_generic_driver

(这里跳转的比较突然,这三个结构体的注册是在usb_init函数中进行的)

所以match函数中传入的dev会和这三个已经注册到usb_bus上的device_driver进行匹配,这里看哪一个usb_driver下的device_driver会匹配成功,也就是看usbdrv_wrap->for_devices的值,这个值需要在usb_register函数中查看,这里给出结果。其实从driver的名字就可以看出只有usb_device_driver (usb设备驱动)是能够和device(设备)进行匹配的。

 

因此root_hub->dev会和usb_generic_driver->drvwrap.driver进行匹配,匹配完成之后会执行probe函数。那么这个probe函数有是哪一个呢?probe函数肯定是usb_generic_driver->drvwrap.driver.probe

这个函数在usb_register_device_driver(&usb_generic_driver, THIS_MODULE)中进行了设置usb_generic_driver->drvwrap.driver.probe = usb_probe_device

usb_probe_device函数的分析:

复制代码
static int usb_probe_device(struct device *dev)
{
        // 这里通过container_of 找到usb_device_driver  和 usb_device 
        // 注意在really_probe 函数中已经将dev->driver 挂上了 device_driver ,所以这个地方才能找到usb_device_driver 
    struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
    struct usb_device *udev = to_usb_device(dev);
    int error = 0;
dev_dbg(dev, </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, __func__);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> TODO: Add real matching code </span><span style="color: rgba(0, 128, 0, 1)">*/</span>

<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> The device should always appear to be in use
 * unless the driver suports autosuspend.
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (!udriver-&gt;<span style="color: rgba(0, 0, 0, 1)">supports_autosuspend)
    error </span>=<span style="color: rgba(0, 0, 0, 1)"> usb_autoresume_device(udev);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 程序执行到这里可以看到饶了一大圈的probe函数就是usb_generic_driver-&gt;probe函数  也就是generic_probe 函数<br></span>    <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">error)
    error </span>= udriver-&gt;<span style="color: rgba(0, 0, 0, 1)">probe(udev);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> error;

}

复制代码

因此接下分析generic_probe 函数:

复制代码
static int generic_probe(struct usb_device *udev)
{
    int err, c;
    if (usb_device_is_owned(udev)) 
        ;        /* Don't configure if the device is owned */
        // 在创建root_hub 时分配usb_device时已经设置了dev->authorized = 1
    else 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);
            }
        }
    }
    /* USB device state == configured ... usable */
    usb_notify_add_device(udev);
    return 0;
}
复制代码

在这里我们可以看一下到底对着root->hub选择了什么配置,设置了什么配置

复制代码
int usb_choose_configuration(struct usb_device *udev)
{
    int i;
    int num_configs;
    int insufficient_power = 0;
    struct usb_host_config *c, *best;
best </span>=<span style="color: rgba(0, 0, 0, 1)"> NULL;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> root_hub下的一些与配置有关的东西在usb_new_device中都读取出来然后放到了root_hub下的config中</span>
c = udev-&gt;<span style="color: rgba(0, 0, 0, 1)">config;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 有多少项配置</span>
num_configs = udev-&gt;<span style="color: rgba(0, 0, 0, 1)">descriptor.bNumConfigurations;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">  遍历所有的配置项</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> (i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; num_configs; (i++, c++<span style="color: rgba(0, 0, 0, 1)">)) {
    </span><span style="color: rgba(0, 0, 255, 1)">struct</span> usb_interface_descriptor    *desc =<span style="color: rgba(0, 0, 0, 1)"> NULL;

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> It's possible that a config has no interfaces! </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
            <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 有可能一个配置没有接口,所以要做判断</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (c-&gt;desc.bNumInterfaces &gt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">  取出配置下的第一个接口</span>
        desc = &amp;c-&gt;intf_cache[<span style="color: rgba(128, 0, 128, 1)">0</span>]-&gt;altsetting-&gt;<span style="color: rgba(0, 0, 0, 1)">desc;

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
     * 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.
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span>

#if 0
/ Rule out self-powered configs for a bus-powered device /
if (bus_powered && (c->desc.bmAttributes &
USB_CONFIG_ATT_SELFPOWER))
continue;
#endif

    <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
     * 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.
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span>

    <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Rule out configs that draw too much bus current </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (c-&gt;desc.bMaxPower * <span style="color: rgba(128, 0, 128, 1)">2</span> &gt; udev-&gt;<span style="color: rgba(0, 0, 0, 1)">bus_mA) {
        insufficient_power</span>++<span style="color: rgba(0, 0, 0, 1)">;
        </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 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.
     * But: Don't ignore it if it's the only config.
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (i == <span style="color: rgba(128, 0, 128, 1)">0</span> &amp;&amp; num_configs &gt; <span style="color: rgba(128, 0, 128, 1)">1</span> &amp;&amp; desc &amp;&amp;<span style="color: rgba(0, 0, 0, 1)">
            (is_rndis(desc) </span>||<span style="color: rgba(0, 0, 0, 1)"> is_activesync(desc))) {

#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else
best = c;
#endif
}

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 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. </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (udev-&gt;descriptor.bDeviceClass !=<span style="color: rgba(0, 0, 0, 1)">
                    USB_CLASS_VENDOR_SPEC </span>&amp;&amp;<span style="color: rgba(0, 0, 0, 1)">
            (desc </span>&amp;&amp; desc-&gt;bInterfaceClass !=<span style="color: rgba(0, 0, 0, 1)">
                    USB_CLASS_VENDOR_SPEC)) {
        best </span>=<span style="color: rgba(0, 0, 0, 1)"> c;
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    }

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> If all the remaining configs are vendor-specific,
     * choose the first one. </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">best)
        best </span>=<span style="color: rgba(0, 0, 0, 1)"> c;
}

</span><span style="color: rgba(0, 0, 255, 1)">if</span> (insufficient_power &gt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    dev_info(</span>&amp;udev-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">rejected %d configuration%s </span><span style="color: rgba(128, 0, 0, 1)">"</span>
        <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">due to insufficient available bus power\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
        insufficient_power, plural(insufficient_power));

</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (best) {
    i </span>= best-&gt;<span style="color: rgba(0, 0, 0, 1)">desc.bConfigurationValue;
    dev_dbg(</span>&amp;udev-&gt;<span style="color: rgba(0, 0, 0, 1)">dev,
        </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">configuration #%d chosen from %d choice%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
        i, num_configs, plural(num_configs));
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
    i </span>= -<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
    dev_warn(</span>&amp;udev-&gt;<span style="color: rgba(0, 0, 0, 1)">dev,
        </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">no configuration chosen from %d choice%s\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
        num_configs, plural(num_configs));
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> i;  <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 这里返回了一个系统觉得合适的配置项的编号</span>

}

复制代码

返回的这个最好的配置项的编号传入到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;
    struct usb_hcd *hcd = bus_to_hcd(dev->bus);
    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;
</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 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.
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当configuration==0 时发出警告,0是无效的配置,但仍然认为他是正确的</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (cp &amp;&amp; configuration == <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    dev_warn(</span>&amp;dev-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">config 0 descriptor??\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Allocate memory for new interfaces before doing anything else,
 * so that if we run out then nothing will have changed. </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
n </span>= nintf = <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 得到接口总数,并分配内存</span>
<span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (cp) {
    nintf </span>= cp-&gt;<span style="color: rgba(0, 0, 0, 1)">desc.bNumInterfaces;
    new_interfaces </span>= kmalloc(nintf * <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(*<span style="color: rgba(0, 0, 0, 1)">new_interfaces),
            GFP_NOIO);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">new_interfaces) {
        dev_err(</span>&amp;dev-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Out of memory\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(0, 0, 0, 1)">ENOMEM;
    }

    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (; n &lt; nintf; ++<span style="color: rgba(0, 0, 0, 1)">n) {
        new_interfaces[n] </span>=<span style="color: rgba(0, 0, 0, 1)"> kzalloc(
                </span><span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">struct</span><span style="color: rgba(0, 0, 0, 1)"> usb_interface),
                GFP_NOIO);
        </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">new_interfaces[n]) {
            dev_err(</span>&amp;dev-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Out of memory\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            ret </span>= -<span style="color: rgba(0, 0, 0, 1)">ENOMEM;

free_interfaces:
while (–n >= 0)
kfree(new_interfaces[n]);
kfree(new_interfaces);
return ret;
}
}

    i </span>= dev-&gt;bus_mA - cp-&gt;desc.bMaxPower * <span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (i &lt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
        dev_warn(</span>&amp;dev-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">new config #%d exceeds power </span><span style="color: rgba(128, 0, 0, 1)">"</span>
                <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">limit by %dmA\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                configuration, </span>-<span style="color: rgba(0, 0, 0, 1)">i);
}

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Wake up the device so we can send it the Set-Config request </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置前唤醒设备</span>
ret =<span style="color: rgba(0, 0, 0, 1)"> usb_autoresume_device(dev);
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (ret)
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> free_interfaces;

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> if it's already configured, clear out old state first.
 * getting rid of old interfaces means unbinding their drivers.
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (dev-&gt;state !=<span style="color: rgba(0, 0, 0, 1)"> USB_STATE_ADDRESS)
    usb_disable_device(dev, </span><span style="color: rgba(128, 0, 128, 1)">1</span>);    <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Skip ep0 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>

<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Get rid of pending async Set-Config requests for this device </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
cancel_async_set_config(dev);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Make sure we have bandwidth (and available HCD resources) for this
 * configuration.  Remove endpoints from the schedule if we're dropping
 * this configuration to set configuration 0.  After this point, the
 * host controller will not allow submissions to dropped endpoints.  If
 * this call fails, the device state is unchanged.
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
mutex_lock(</span>&amp;hcd-&gt;<span style="color: rgba(0, 0, 0, 1)">bandwidth_mutex);
ret </span>=<span style="color: rgba(0, 0, 0, 1)"> usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (ret &lt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
    mutex_unlock(</span>&amp;hcd-&gt;<span style="color: rgba(0, 0, 0, 1)">bandwidth_mutex);
    usb_autosuspend_device(dev);
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> free_interfaces;
}
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置配置</span>
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">),
              USB_REQ_SET_CONFIGURATION, </span><span style="color: rgba(128, 0, 128, 1)">0</span>, configuration, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,
              NULL, </span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">, USB_CTRL_SET_TIMEOUT);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (ret &lt; <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> All the old state is gone, so what else can we do?
     * The device is probably useless now anyway.
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
    cp </span>=<span style="color: rgba(0, 0, 0, 1)"> NULL;
}

dev</span>-&gt;actconfig =<span style="color: rgba(0, 0, 0, 1)"> cp;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">cp) {
    usb_set_device_state(dev, USB_STATE_ADDRESS);
    usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
    mutex_unlock(</span>&amp;hcd-&gt;<span style="color: rgba(0, 0, 0, 1)">bandwidth_mutex);
    usb_autosuspend_device(dev);
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> free_interfaces;
}
mutex_unlock(</span>&amp;hcd-&gt;<span style="color: rgba(0, 0, 0, 1)">bandwidth_mutex);
usb_set_device_state(dev, USB_STATE_CONFIGURED);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Initialize the new interface structures and the
 * hc/hcd/usbcore interface/endpoint state.
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 接下来设置这个配置的接口并将接口注册到usb总线下</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> (i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; nintf; ++<span style="color: rgba(0, 0, 0, 1)">i) {
    </span><span style="color: rgba(0, 0, 255, 1)">struct</span> usb_interface_cache *<span style="color: rgba(0, 0, 0, 1)">intfc;
    </span><span style="color: rgba(0, 0, 255, 1)">struct</span> usb_interface *<span style="color: rgba(0, 0, 0, 1)">intf;
    </span><span style="color: rgba(0, 0, 255, 1)">struct</span> usb_host_interface *<span style="color: rgba(0, 0, 0, 1)">alt;

    cp</span>-&gt;<span style="color: rgba(0, 0, 255, 1)">interface</span>[i] = intf =<span style="color: rgba(0, 0, 0, 1)"> new_interfaces[i];
    intfc </span>= cp-&gt;<span style="color: rgba(0, 0, 0, 1)">intf_cache[i];
    intf</span>-&gt;altsetting = intfc-&gt;<span style="color: rgba(0, 0, 0, 1)">altsetting;
    intf</span>-&gt;num_altsetting = intfc-&gt;<span style="color: rgba(0, 0, 0, 1)">num_altsetting;
    intf</span>-&gt;intf_assoc =<span style="color: rgba(0, 0, 0, 1)"> find_iad(dev, cp, i);
    kref_get(</span>&amp;intfc-&gt;<span style="color: rgba(0, 0, 255, 1)">ref</span><span style="color: rgba(0, 0, 0, 1)">);

    alt </span>= usb_altnum_to_altsetting(intf, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">);

    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 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.
     </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
    <span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">alt)
        alt </span>= &amp;intf-&gt;altsetting[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">];

    intf</span>-&gt;cur_altsetting =<span style="color: rgba(0, 0, 0, 1)"> alt;
    usb_enable_interface(dev, intf, </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
    intf</span>-&gt;dev.parent = &amp;dev-&gt;<span style="color: rgba(0, 0, 0, 1)">dev;
    intf</span>-&gt;dev.driver =<span style="color: rgba(0, 0, 0, 1)"> NULL;
    intf</span>-&gt;dev.bus = &amp;<span style="color: rgba(0, 0, 0, 1)">usb_bus_type;
    intf</span>-&gt;dev.type = &amp;<span style="color: rgba(0, 0, 0, 1)">usb_if_device_type;
    intf</span>-&gt;dev.groups =<span style="color: rgba(0, 0, 0, 1)"> usb_interface_groups;
    intf</span>-&gt;dev.dma_mask = dev-&gt;<span style="color: rgba(0, 0, 0, 1)">dev.dma_mask;
    INIT_WORK(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">reset_ws, __usb_queue_reset_device);
    intf</span>-&gt;minor = -<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;
    device_initialize(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev);
    pm_runtime_no_callbacks(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev);
    dev_set_name(</span>&amp;intf-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">%d-%s:%d.%d</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
        dev</span>-&gt;bus-&gt;busnum, dev-&gt;<span style="color: rgba(0, 0, 0, 1)">devpath,
        configuration, alt</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">desc.bInterfaceNumber);
}
kfree(new_interfaces);

</span><span style="color: rgba(0, 0, 255, 1)">if</span> (cp-&gt;<span style="color: rgba(0, 0, 255, 1)">string</span> == NULL &amp;&amp;
        !(dev-&gt;quirks &amp;<span style="color: rgba(0, 0, 0, 1)"> USB_QUIRK_CONFIG_INTF_STRINGS))
    cp</span>-&gt;<span style="color: rgba(0, 0, 255, 1)">string</span> = usb_cache_string(dev, cp-&gt;<span style="color: rgba(0, 0, 0, 1)">desc.iConfiguration);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 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.
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> (i = <span style="color: rgba(128, 0, 128, 1)">0</span>; i &lt; nintf; ++<span style="color: rgba(0, 0, 0, 1)">i) {
    </span><span style="color: rgba(0, 0, 255, 1)">struct</span> usb_interface *intf = cp-&gt;<span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)">[i];

    dev_dbg(</span>&amp;dev-&gt;<span style="color: rgba(0, 0, 0, 1)">dev,
        </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">adding %s (config #%d, interface %d)\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
        dev_name(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev), configuration,
        intf</span>-&gt;cur_altsetting-&gt;<span style="color: rgba(0, 0, 0, 1)">desc.bInterfaceNumber);
    device_enable_async_suspend(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev);
    ret </span>= device_add(&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev);
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ret != <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) {
        dev_err(</span>&amp;dev-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">device_add(%s) --&gt; %d\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            dev_name(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev), ret);
        </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
    }
    create_intf_ep_devs(intf);
}

usb_autosuspend_device(dev);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;

}

复制代码

简单看完usb_set_configuration之后,看一下此刻在/sys/bus/usb/device 路径存在的设备如下:

usb1这个设备是在之前一次register_root_hub中的device_add中添加的,而1-0:1.0是在sub_set_configuration中device_add添加的,对应表示 总线号-设备路径:配置号-接口号

1-0:1.0表示usb控制器1下的usb_hub下的1号配置的0号接口

  注意到这里有出现了device_add,这又是一长串的函数调用,但是还是向总线注册设备、与总线上的device_driver进行匹配,匹配成功之后执行probe函数的一系列套路。所以在这里又得分析usb_device_match函数和probe,重点是这个probe函数执行的是哪一个函数?

之前分析过usb_device_match函数,这次传入到usb_device_match中的dev是一个接口类型的,所以应该执行usb_device_match中的第二条分支,通过id来进行匹配。这次与root_hub下的接口匹配的应该是hub_driver->drvwrap.driver,通过静态id_table的匹配成功之后应该执行usb_probe_interface这个函数。

复制代码
static int usb_probe_interface(struct device *dev)
{
    struct usb_driver *driver = to_usb_driver(dev->driver);
    struct usb_interface *intf = to_usb_interface(dev);
    struct usb_device *udev = interface_to_usbdev(intf);
    const struct usb_device_id *id;
        ....
        // 执行到这里又回到了hub_driver下的hub_probe函数
        // 可以看到这里的probe函数的调用是一层套一层的,但最终都会执行到driver下的probe函数
    error = driver->probe(intf, id);
    if (error)
        goto err;
     .... }
复制代码

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 </span>= intf-&gt;<span style="color: rgba(0, 0, 0, 1)">cur_altsetting;
hdev </span>=<span style="color: rgba(0, 0, 0, 1)"> interface_to_usbdev(intf);

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Hubs have proper suspend/resume support </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
usb_enable_autosuspend(hdev);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> hub 只支持6层嵌套,在前边那张usb系统拓扑图中hub接hub最多接6层 </span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (hdev-&gt;level ==<span style="color: rgba(0, 0, 0, 1)"> MAX_TOPO_LEVEL) {
    dev_err(</span>&amp;intf-&gt;<span style="color: rgba(0, 0, 0, 1)">dev,
        </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Unsupported bus topology: hub nested too deep\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(0, 0, 0, 1)">E2BIG;
}

#ifdef CONFIG_USB_OTG_BLACKLIST_HUB
if (hdev->parent) {
dev_warn(&intf->dev, “ignoring external hub\n”);
return -ENODEV;
}
#endif

<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> Some hubs have a subclass of 1, which AFAICT according to the </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">  specs is not defined, but it works </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> ((desc-&gt;desc.bInterfaceSubClass != <span style="color: rgba(128, 0, 128, 1)">0</span>) &amp;&amp;<span style="color: rgba(0, 0, 0, 1)">
    (desc</span>-&gt;desc.bInterfaceSubClass != <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)) {

descriptor_error:
dev_err (&intf->dev, “bad descriptor, ignoring hub\n”);
return -EIO;
}

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">hub interface的endpoint数目为1,这里的数目没有包括ep0</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (desc-&gt;desc.bNumEndpoints != <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> descriptor_error;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取端点描述符</span>
endpoint = &amp;desc-&gt;endpoint[<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">].desc;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断端点是不是中断in类型的端点,</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">usb_endpoint_is_int_in(endpoint))
    </span><span style="color: rgba(0, 0, 255, 1)">goto</span><span style="color: rgba(0, 0, 0, 1)"> descriptor_error;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 在上述情况都满足的情况下才说明有一个hub存在</span>
<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> We found a hub </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
dev_info (</span>&amp;intf-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">USB hub found\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 分配一个usb_hub</span>
hub = kzalloc(<span style="color: rgba(0, 0, 255, 1)">sizeof</span>(*<span style="color: rgba(0, 0, 0, 1)">hub), GFP_KERNEL);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">hub) {
    dev_dbg (</span>&amp;intf-&gt;dev, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">couldn't kmalloc hub struct\n</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(0, 0, 0, 1)">ENOMEM;
}
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">初始化引用计数</span>
kref_init(&amp;hub-&gt;<span style="color: rgba(0, 0, 0, 1)">kref);
INIT_LIST_HEAD(</span>&amp;hub-&gt;<span style="color: rgba(0, 0, 0, 1)">event_list);
hub</span>-&gt;intfdev = &amp;intf-&gt;dev;<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 接口设备</span>
hub-&gt;hdev = hdev;         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> hub实体</span>
INIT_DELAYED_WORK(&amp;hub-&gt;<span style="color: rgba(0, 0, 0, 1)">leds, led_work);
INIT_DELAYED_WORK(</span>&amp;hub-&gt;<span style="color: rgba(0, 0, 0, 1)">init_work, NULL);
usb_get_intf(intf);

usb_set_intfdata (intf, hub);
intf</span>-&gt;needs_remote_wakeup = <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 0, 255, 1)">if</span> (hdev-&gt;speed ==<span style="color: rgba(0, 0, 0, 1)"> USB_SPEED_HIGH)
    highspeed_hubs</span>++<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 配置hub</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (hub_configure(hub, endpoint) &gt;= <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">;

hub_disconnect (intf);
</span><span style="color: rgba(0, 0, 255, 1)">return</span> -<span style="color: rgba(0, 0, 0, 1)">ENODEV;

}

复制代码

在hub_probe函数中创建了一个hub实例后,在hub_configure中配置这个hub。

复制代码
static int hub_configure(struct usb_hub *hub,
    struct usb_endpoint_descriptor *endpoint)
{
        ...
        // 为hub开辟缓冲区
    hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
    hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
    hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
        // 获取hub的描述符, 之前说过hub从本质上讲也是一种usb设备,只是其设备描述符与普通的usb设备不同
    ret = get_hub_descriptor(hdev, hub->descriptor,
            sizeof(*hub->descriptor));
hdev</span>-&gt;maxchild = hub-&gt;descriptor-&gt;<span style="color: rgba(0, 0, 0, 1)">bNbrPorts;
hub</span>-&gt;port_owners = kzalloc(hdev-&gt;maxchild * <span style="color: rgba(0, 0, 255, 1)">sizeof</span>(<span style="color: rgba(0, 0, 255, 1)">void</span> *<span style="color: rgba(0, 0, 0, 1)">), GFP_KERNEL);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取描述hub特性的信息</span>
wHubCharacteristics = le16_to_cpu(hub-&gt;descriptor-&gt;<span style="color: rgba(0, 0, 0, 1)">wHubCharacteristics);
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断hub是不是混合设备</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (wHubCharacteristics &amp;<span style="color: rgba(0, 0, 0, 1)"> HUB_CHAR_COMPOUND) {
              </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果是混合设备就需要存储其每一个下行端口是否可以被移除
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断hub的电源管理类型</span>
<span style="color: rgba(0, 0, 255, 1)">switch</span> (wHubCharacteristics &amp;<span style="color: rgba(0, 0, 0, 1)"> HUB_CHAR_LPSM) {
}
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断hub的过流保护类型</span>
<span style="color: rgba(0, 0, 255, 1)">switch</span> (wHubCharacteristics &amp;<span style="color: rgba(0, 0, 0, 1)"> HUB_CHAR_OCPM) {
}

spin_lock_init (</span>&amp;hub-&gt;tt.<span style="color: rgba(0, 0, 255, 1)">lock</span><span style="color: rgba(0, 0, 0, 1)">);
INIT_LIST_HEAD (</span>&amp;hub-&gt;<span style="color: rgba(0, 0, 0, 1)">tt.clear_list);
INIT_WORK(</span>&amp;hub-&gt;<span style="color: rgba(0, 0, 0, 1)">tt.clear_work, hub_tt_work);   
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">  根据设备描述符中bDeviceProtocol字段信息设置hub-&gt;tt</span>
<span style="color: rgba(0, 0, 255, 1)">switch</span> (hdev-&gt;<span style="color: rgba(0, 0, 0, 1)">descriptor.bDeviceProtocol) {
}
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">  设置usb-&gt;tt.think_time</span>
<span style="color: rgba(0, 0, 255, 1)">switch</span> (wHubCharacteristics &amp;<span style="color: rgba(0, 0, 0, 1)"> HUB_CHAR_TTTT) {
}
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 判断是否支持指示</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (wHubCharacteristics &amp;<span style="color: rgba(0, 0, 0, 1)"> HUB_CHAR_PORTIND) {

}
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">  获得hub的状态</span>
ret = usb_get_status(hdev, USB_RECIP_DEVICE, <span style="color: rgba(128, 0, 128, 1)">0</span>, &amp;<span style="color: rgba(0, 0, 0, 1)">hubstatus);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">  对hub的电源管理</span>

…
ret = hub_hub_status(hub, &hubstatus, &hubchange);
…
// 分配一个urb
hub->urb = usb_alloc_urb(0, GFP_KERNEL);
// 填充这个urb
usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval);
// 激活hub
hub_activate(hub, HUB_INIT);
}

复制代码

在hub_configure中填充了urb后,检测hub端口,如果状态发生变化,那么会调用hub_irq函数(这其中的过程需要后续的发现)

 

 

 

文章导航
←计算机毕业设计ssm基于ssm的高校党建平台f80yq系统+程序+源码+lw+远程部署
往模拟器SD卡中存文件时提示文件系统只读的解决方法→

Copyright © 2022 源码巴士  鲁ICP备19024253号-1