USB Gadget
+ -

gadget probe过程-以g_audio为例

2025-08-14 本文链接为:http://www.usbzh.com/article/detail-1558.html ,欢迎转载,转载请附上本文链接。

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;
}
本文链接为:http://www.usbzh.com/article/detail-1558.html ,欢迎转载,转载请附上本文链接。

0 篇笔记 写笔记

USB Gadget CDC-ECM网卡实例
ECM和NCM网卡类似,也需要安装ECM驱动设备兼容ID为:USBClass_02&SubClass_06&Prot_00USBClass_02&SubClass_06USBClass_02创建脚本:#!/bin/bashmodprobe libcompos......
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", ......
configfs文件系统
Linux内核使用CONFIGFS配置项支持可以通过用户创建USB Compoiste Gadget。CONFIG_CONFIGFS_FS项用于支持配置文件系统。Menconfig -> FileSystems -> Psuedo File System -> {M}User......
Gadget legacy和Gadget Function的区别
在 Linux 的 USB Gadget 子系统中,Legacy Gadget 和 Gadget Function(FunctionFS 或 configfs) 是两种不同的实现方式,用于将 Linux 设备配置为 USB 外设(如 U 盘、网卡、串口等)。它们的区别主要体现在架构、使用方式和灵活性......
usb_gadget复合HID键盘和U盘实例
#!/bin/bash# 加载模块modprobe libcompositemodprobe usb_f_hidmodprobe usb_f_mass_storage.komount -t configfs none /sys/kernel/config# 创建 Gadgetcd......
usb gadget创建uvc相机脚本实例
#!/bin/bashmodprobe libcompositemodprobe usb_f_uvcmount -t configfs none /sys/kernel/configmkdir -p /sys/kernel/config/usb_gadget/g1cd /sys/kern......
USB Gadget CDC-ACM串口实例
符合USB ACM规范的设备由Windows提供其驱动程序usbser.sysuserser.infLinux Gadget对应的ACM驱动依赖为root@ATK-IMX6U:/sys/kernel/config/usb_gadget/g1# lsmodModule ......
USB Gadget CDC-NCM网卡实例
USG Gadget也提供了CDC-NCM网卡驱动程序,使用USB Gadget CDC-NCM驱动,这样在Windows主机端和Linux设备端都会创建一个USB网卡设备。root@ATK-IMX6U:/lib/modules/4.1.15# ifconfig -ausb0 Lin......
USB Gadget 打印机实例
打印机这一块应该要与实例相连,具体这一块没有研究过。生成的设备如下:设备模块如下:root@ATK-IMX6U:/lib/modules/4.1.15# lsmodModule Size Used byusb_f_printer 1137......
USB Gadget CDC-EEM网卡实例
从理论上来讲,EEM网卡Windows是应该支持的,实际上也确实不用像NCM、ECM需要手动安装驱动,系统会自动匹配兼容ID来进行安装驱动,但是驱动启动失败,这个Linux系统下就没有问题。#!/bin/bashmodprobe libcompositemodprobe usb_f_eemm......
USB Gadget LoopBack实例
Loopback Function 提供的功能简单,它分配了两个 bulk endpoint,所做的就是把 out_ep 接收到的数据转发到 in_ep。#!/bin/bashmodprobe libcompositemodprobe usb_f_ss_lbmount -t configfs......
USB Gadget RNDIS网络适配器实列
和NCM一样,由于兼容ID的问题,RNDIS网络适配器也需要手动安装驱动。其对应的驱动为:netrndis.infrndismp6.sys其创建脚本如下:#!/bin/bashmodprobe libcompositemodprobe usb_f_rndismount -t conf......
USB Gadget实例分析usb_function_instance和usb_function
linux usb gadtet的设备类驱动有两个很重要的概念:usb_function_instance和usb_function从名来上看,usb_function_instance像是usb_function的实例化,但实际是恰恰相反。这里以f_loopback为示例解释:USB设备信息执......
USB Gadget数据收发-批量传输
当执行命令ln -s functions/Loopback.0 configs/c.1之后,会调用loopback_alloc函数创建usb_functionstruct f_loopback { struct usb_function function; struct......
关注公众号
  • HID人机交互
  • Linux&USB
  • UAC音频
  • CDC
  • TYPE-C
  • USB规范
  • USB大容量存储
  • USB百科
  • USB周边
  • UVC摄像头
  • Windows系统USB
  • 音视频博客
  • 取消
    感谢您的支持,我会继续努力的!
    扫码支持
    扫码打赏,你说多少就多少

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

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