Edit online

Gadget Bus

3 Apr 2024
Read time: 5 minute(s)

Gadget Layer 层没有定义一个标准的 Bus 总线,而是自定义了两条链表来分别存储 Device 和 Driver:

type list escript
Device udc_list 所有 Device 全集
Driver gadget_driver_pending_list 只包含没有适配 Device 的 Driver

它们的使用场景如下:

  • 在 Gadget Device 创建时,首先把 Device 加入到 udc_list 链表,然后尝试和 gadget_driver_pending_list 链表中的 Driver 进行 match():
    usb_add_gadget_udc() → usb_add_gadget_udc_release() → usb_add_gadget():
    
    int usb_add_gadget(struct usb_gadget *gadget)
    {
    
        /* (1) 将 device 加入全局链表 */
        list_add_tail(&udc->list, &udc_list);
    
        /* pick up one of pending gadget drivers */
        /* (2) 尝试 match gadget 的 device 和 driver */
        ret = check_pending_gadget_drivers(udc);
        if (ret)
            goto err_del_udc;
    
        mutex_unlock(&udc_lock);
    }
    
    ↓
    
    static int check_pending_gadget_drivers(struct usb_udc *udc)
    {
        struct usb_gadget_driver *driver;
        int ret = 0;
    
        /* (2.1) 遍历 `gadget_driver_pending_list` 链表中的 Driver,和 Device 进行 match()
                且一个 Driver 只能 match 一个 Device,Driver match 成功后会从链表删除
        */
        list_for_each_entry(driver, &gadget_driver_pending_list, pending)
            if (!driver->udc_name || strcmp(driver->udc_name,
                            dev_name(&udc->dev)) == 0) {
                /* (2.2) Match 成功,对 Device 和 Driver 进行 bind() */
                ret = udc_bind_to_driver(udc, driver);
                if (ret != -EPROBE_DEFER)
                    /* (2.3) Driver Match 成功后,从 pending 链表删除 */
                    list_del_init(&driver->pending);
                break;
            }
    
        return ret;
    }
    
  • 在 Gadget Driver 创建时,首先尝试和 udc_list 链表中的 Device 进行 match(),match() 不成功则把 Driver 加入到 gadget_driver_pending_list 链表中:
    gadget_dev_desc_UDC_store() → usb_gadget_probe_driver():
    
    int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
    {
        struct usb_udc          *udc = NULL;
        int                     ret = -ENODEV;
    
        if (!driver || !driver->bind || !driver->setup)
            return -EINVAL;
    
        mutex_lock(&udc_lock);
        /* (1.1) 如果 Driver 有 udc_name,尝试和 udc_list 链表中 Device 的 Name 进行 match()  */
        if (driver->udc_name) {
            list_for_each_entry(udc, &udc_list, list) {
                ret = strcmp(driver->udc_name, dev_name(&udc->dev));
                if (!ret)
                    break;
            }
            if (ret)
                ret = -ENODEV;
            else if (udc->driver)
                ret = -EBUSY;
            else
                goto found;
        /* (1.2) 如果 Driver 没有 udc_name,尝试适配 udc_list 链表中第一个没有适配的 Device */
        } else {
            list_for_each_entry(udc, &udc_list, list) {
                /* For now we take the first one */
                if (!udc->driver)
                    goto found;
            }
        }
    
        if (!driver->match_existing_only) {
            /* (2) 如果没有 match() 成功,则把 Driver 加入到 pending 链表 */
            list_add_tail(&driver->pending, &gadget_driver_pending_list);
            pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
                driver->function);
            ret = 0;
        }
    
        mutex_unlock(&udc_lock);
        if (ret)
            pr_warn("udc-core: couldn't find an available UDC or it's busy\n");
        return ret;
    found:
        /* (3) 如果 Match 成功,对 Device 和 Driver 进行 bind() */
        ret = udc_bind_to_driver(udc, driver);
        mutex_unlock(&udc_lock);
        return ret;
    }
    
  • 在 Device 和 Driver Match 成功时的 bind() 动作:
    static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
    {
        int ret;
    
        dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
                driver->function);
    
        /* (1) 数据成员的赋值 */
        udc->driver = driver;
        udc->dev.driver = &driver->driver;
        udc->gadget->dev.driver = &driver->driver;
    
        usb_gadget_udc_set_speed(udc, driver->max_speed);
    
        /* (2) 调用 Gadget Driver 的 bind() 函数 */
        ret = driver->bind(udc->gadget, driver);
        if (ret)
            goto err1;
    
        /* (3) 调用 Gadget Device 的 start() 函数
                udc->gadget->ops->udc_start(udc->gadget, udc->driver);
        */
        ret = usb_gadget_udc_start(udc);
        if (ret) {
            driver->unbind(udc->gadget);
            goto err1;
        }
    
        /* (4) 调用 Gadget Device 的 pullup() 函数
                gadget->ops->pullup(gadget, 1/0);
        */
        usb_udc_connect_control(udc);
    
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
        return 0;
    
    }
注: 这里和一般的 Device 和 Driver 的适配规则有些不一样。一般的规则是一个 Dirver 可以适配多个 Device,而一个 Device 只能适配一个 Driver。而这里的规则是一个 Gadget Device 只能适配一个 Gadget Driver,而一个 Gadget Driver 只能适配一个 Gadget Device。 Gadget Driver 代表的是一个 Composite Device