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