Linux USB驱动源代码分析
+ -

gadget probe过程-以g_audio为例

2025-08-14 0 0

g_audio中通过如下代码调用usb_composite_probe,其中入参为audio_driver

static struct usb_composite_driver audio_driver = {
    .name        = "g_audio",
    .dev        = &device_desc,
    .strings    = audio_strings,
    .max_speed    = USB_SPEED_HIGH,
    .bind        = audio_bind,
    .unbind        = audio_unbind,
};
static int __init audio_driver_init(void)
{
    return usb_composite_probe(&audio_driver);
}
module_init(audio_driver_init);

static void __exit audio_driver_exit(void)
{
    usb_composite_unregister(&audio_driver);
}
module_exit(audio_driver_exit);

然后在composite层

static const struct usb_gadget_driver composite_driver_template = {
    .bind        = composite_bind, //中创建usb_compoiste_device,并再调用usb_composite_driver:bind,即audio_bind
    .unbind        = composite_unbind,

    .setup        = composite_setup,
    .reset        = composite_disconnect,
    .disconnect    = composite_disconnect,

    .suspend    = composite_suspend,
    .resume        = composite_resume,

    .driver    = {
        .owner        = THIS_MODULE,
    },
};

int usb_composite_probe(struct usb_composite_driver *driver)
{
    struct usb_gadget_driver *gadget_driver;

    if (!driver || !driver->dev || !driver->bind)
        return -EINVAL;

    if (!driver->name)
        driver->name = "composite";

    driver->gadget_driver = composite_driver_template;// 复制模板驱动(默认方法)
    gadget_driver = &driver->gadget_driver;

    //根据 usb_composite_driver 定义针对性的修改: function、driver.name、max_speed
    gadget_driver->function =  (char *) driver->name;
    gadget_driver->driver.name = driver->name;
    gadget_driver->max_speed = driver->max_speed;

 //将usb_composite_driver 转换为 usb_gadget_driver 对象进行 probe
    return usb_gadget_probe_driver(gadget_driver);
}

并进入udc-core.c调用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);
    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 && !udc->driver)
            goto found;
    } else {
        list_for_each_entry(udc, &udc_list, list) {
            /* For now we take the first one */
            if (!udc->driver)
                goto found;
        }
    }

    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);
    mutex_unlock(&udc_lock);
    return 0;
found:
    ret = udc_bind_to_driver(udc, driver);
    mutex_unlock(&udc_lock);
    return ret;
}

对于list_for_each_entry(udc, &udc_list, list),从udc_list中找到相应的udc,然后调用udc_bind_to_driver

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);

    udc->driver = driver;//实际为复制的composite_driver_template指针
    udc->dev.driver = &driver->driver;
    udc->gadget->dev.driver = &driver->driver;

//Bind阶段:composite_driver_template 模板驱动中的 bind 方法:composite_bind
    ret = driver->bind(udc->gadget, driver);
    if (ret)
        goto err1;

    //start阶段:实际指向 UDC 设备 OPS 能力集中的 udc_start 方法
    ret = usb_gadget_udc_start(udc);
    if (ret) {
        driver->unbind(udc->gadget);
        goto err1;
    }

    //Connect 阶段 实际指向 UDC 设备 OPS 能力集中的 pullup 方法,控制上拉电阻连接
    usb_udc_connect_control(udc);

    //OTG 相关,暂且忽略
    kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
    return 0;
err1:
    if (ret != -EISNAM)
        dev_err(&udc->dev, "failed to start %s: %d\n",
            udc->driver->function, ret);
    udc->driver = NULL;
    udc->dev.driver = NULL;
    udc->gadget->dev.driver = NULL;
    return ret;
}

udc_bind_to_driver中调用composite_bind

static int composite_bind(struct usb_gadget *gadget,
        struct usb_gadget_driver *gdriver)
{
    struct usb_composite_dev    *cdev;
    struct usb_composite_driver    *composite = to_cdriver(gdriver);
    int                status = -ENOMEM;

    cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
    if (!cdev)
        return status;

    spin_lock_init(&cdev->lock);
    cdev->gadget = gadget;
    set_gadget_data(gadget, cdev);
    INIT_LIST_HEAD(&cdev->configs);
    INIT_LIST_HEAD(&cdev->gstrings);

    status = composite_dev_prepare(composite, cdev);
    if (status)
        goto fail;

    /* composite gadget needs to assign strings for whole device (like
     * serial number), register function drivers, potentially update
     * power state and consumption, etc
     */
    status = composite->bind(cdev);//audio_bind
    if (status < 0)
        goto fail;

    if (cdev->use_os_string) {
        status = composite_os_desc_req_prepare(cdev, gadget->ep0);
        if (status)
            goto fail;
    }

    update_unchanged_dev_desc(&cdev->desc, composite->dev);

    /* has userspace failed to provide a serial number? */
    if (composite->needs_serial && !cdev->desc.iSerialNumber)
        WARNING(cdev, "userspace failed to provide iSerialNumber\n");

    INFO(cdev, "%s ready\n", composite->name);
    return 0;

fail:
    __composite_unbind(gadget, false);
    return status;
}

然后调用audio_bind

static int audio_bind(struct usb_composite_dev *cdev)
{
#ifndef CONFIG_GADGET_UAC1
    struct f_uac2_opts    *uac2_opts;
#else
    struct f_uac1_opts    *uac1_opts;
#endif
    int            status;

#ifndef CONFIG_GADGET_UAC1
    fi_uac2 = usb_get_function_instance("uac2");
    if (IS_ERR(fi_uac2))
        return PTR_ERR(fi_uac2);
#else
    // 申请Function实例
    fi_uac1 = usb_get_function_instance("uac1");
    if (IS_ERR(fi_uac1))
        return PTR_ERR(fi_uac1);
#endif

#ifndef CONFIG_GADGET_UAC1
    uac2_opts = container_of(fi_uac2, struct f_uac2_opts, func_inst);
    uac2_opts->p_chmask = p_chmask;
    uac2_opts->p_srate = p_srate;
    uac2_opts->p_ssize = p_ssize;
    uac2_opts->c_chmask = c_chmask;
    uac2_opts->c_srate = c_srate;
    uac2_opts->c_ssize = c_ssize;
#else
    uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst);
    uac1_opts->fn_play = fn_play;
    uac1_opts->fn_cap = fn_cap;
    uac1_opts->fn_cntl = fn_cntl;
    uac1_opts->req_buf_size = req_buf_size;
    uac1_opts->req_count = req_count;
    uac1_opts->audio_buf_size = audio_buf_size;
#endif

    status = usb_string_ids_tab(cdev, strings_dev);
    if (status < 0)
        goto fail;
    device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
    device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;

    if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) {
        struct usb_descriptor_header *usb_desc;

        usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
        if (!usb_desc)
            goto fail;
        usb_otg_descriptor_init(cdev->gadget, usb_desc);
        otg_desc[0] = usb_desc;
        otg_desc[1] = NULL;
    }

    status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
    if (status < 0)
        goto fail_otg_desc;
    usb_composite_overwrite_options(cdev, &coverwrite);

    INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
    return 0;

fail_otg_desc:
    kfree(otg_desc[0]);
    otg_desc[0] = NULL;
fail:
#ifndef CONFIG_GADGET_UAC1
    usb_put_function_instance(fi_uac2);
#else
    usb_put_function_instance(fi_uac1);
#endif
    return status;
}

0 篇笔记 写笔记

Linux Gadget驱动结构关系图
Linux Gadget驱动层级如下:Gadget Function驱动/gadget legacy驱动Gadget Compoiste驱动USB UDC驱动(USB Device Control)Gadget Function驱动/gadget legacy驱动function, 更加现代......
gadget probe过程-以g_audio为例
g_audio中通过如下代码调用usb_composite_probe,其中入参为audio_driverstatic struct usb_composite_driver audio_driver = { .name = "g_audio", ......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • CDC
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

    打开支付宝扫一扫,即可进行扫码打赏哦

    您的支持,是我们前进的动力!