linux usb gadget

本文介绍了Linux系统中USB Gadget的架构,包括composite framework和UDC core两个核心抽象层。composite framework处理gadget driver的公共部分,如EP0管理和descriptor获取。UDC core则关注与硬件相关的部分。以Android为例,详细阐述了gadget驱动的注册和配置过程,以及如何处理endpoint。文章以ADB功能的配置为例,展示了endpoint的分配和request的设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇谈到了usb host以及usb core,这一篇来介绍下usb gadget,usb gadget较usb host出现较晚,随着linux越来越用作嵌入式设备而出现,是一套独立的架构,独立于usb core。




由上图可以看出gadget架构有两个核心抽象层,composite framework和udc core。

composite framework: 由写一个gadget driver需要处理的一些common部分抽象而成,如:ep0 common部分处理(与硬件无关的部分),get descriptor,set configuration等。

由于要处理set configuration,所以composite framework需要知道usb的config以及添加进来的function(usb interface)。

核心函数如下:

usb_compostie_probe: 提供给上层的接口,用来注册一个usb composite driver,上图中的android, serial, usb massstorage都是composite driver

usb_add_config: 添加一个config

usb_add_function: 添加一个function(interface), 如adb,mass storage,serial,rndis。

composite_setup: 处理ep0的setup请求


udc core: 由每一个usd device controller需要提供给composite framework的接口抽象而成,这样usb devcie controller部分就只需要focus在与硬件相关的部分


下面我们以android为例来追一下具体的调用流程

android的init模块会调用 usb_composite_probe(&android_usb_driver, android_bind);

1772 int usb_composite_probe(struct usb_composite_driver *driver,
1773                    int (*bind)(struct usb_composite_dev *cdev))
1774 {
1775     int rc;
1776     if (!driver || !driver->dev || !bind || composite)
1777         return -EINVAL;
1778 
1779     if (!driver->name)
1780         driver->name = "composite";
1781     if (!driver->iProduct)
1782         driver->iProduct = driver->name;
1783     composite_driver.function =  (char *) driver->name;
1784     composite_driver.driver.name = driver->name;
1785     composite_driver.max_speed =
1786         min_t(u8, composite_driver.max_speed, driver->max_speed);
1787     composite = driver;
1788     composite_gadget_bind = bind;
1789     rc = switch_dev_register(&compositesdev);
1790     INIT_WORK(&cdusbcmdwork, ctusbcmd_do_work);
1791     if (rc < 0)
1792         pr_err("%s: switch_dev_register fail", __func__);
1793 
1794     return usb_gadget_probe_driver(&composite_driver, composite_bind);
1795 }

从代码中可以看出,usb_composite_probe主要是将注册进来的usb_composite_driver(这里是android_usb_driver)与usb_gadget_driver(这里是composite_driver)联系起来,然后调用udc core提供的函数:usb_gadget_probe_driver,并提供callback function: composite_bind给udc core.

先来看composite_bind

1576 static int composite_bind(struct usb_gadget *gadget)
1577 {
1578     struct usb_composite_dev    *cdev;
1579     int             status = -ENOMEM;
1580 
1581     cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
1582     if (!cdev)
1583         return status;
1584 
1585     spin_lock_init(&cdev->lock);
1586     cdev->gadget = gadget;
1587     set_gadget_data(gadget, cdev);
1588     INIT_LIST_HEAD(&cdev->configs);
1589 
1590     /* preallocate control response and buffer */
1591     cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
1592     if (!cdev->req)
1593         goto fail;
1594     cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
1595     if (!cdev->req->buf)
1596         goto fail;
1597     cdev->req->complete = composite_setup_complete;
1598     gadget->ep0->driver_data = cdev;
1599 
1600     cdev->bufsiz = USB_BUFSIZ;
1601     cdev->driver = composite;
1602 
1603     INIT_DELAYED_WORK(&cdev->request_reset, composite_request_reset);
1604     /*
1605      * As per USB compliance update, a device that is actively drawing
1606      * more than 100mA from USB must report itself as bus-powered in
1607      * the GetStatus(DEVICE) call.
1608      */
1609     if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
1610         usb_gadget_set_selfpowered(gadget);
1611 
1612     /* interface and string IDs start at zero via kzalloc.
1613      * we force endpoints to start unassigned; few controller
1614      * drivers will zero ep->driver_data.
1615      */
1616     usb_ep_autoconfig_reset(cdev->gadget);
1617 
1618     /* composite gadget needs to assign strings for whole device (like
1619      * serial number), register function drivers, potentially update
1620      * power state and consumption, etc
1621      */
1622     status = composite_gadget_bind(cdev);
1623     if (status < 0)
1624         goto fail;
1625 
1626     cdev->desc = *composite->dev;
1627 
1628     /* standardized runtime overrides for device ID data */
1629     if (idVendor)
1630         cdev->desc.idVendor = cpu_to_le16(idVendor);
1631     if (idProduct)
1632         cdev->desc.idProduct = cpu_to_le16(idProduct);
1633     if (bcdDevice)
1634         cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
1635 
1636     /* string overrides */
1637     if (iManufacturer || !cdev->desc.iManufacturer) {
1638         if (!iManufacturer && !composite->iManufacturer &&
1639             !*composite_manufacturer)
1640             snprintf(composite_manufacturer,
1641                  sizeof composite_manufacturer,
1642                  "%s %s with %s",
1643                  init_utsname()->sysname,
1644                  init_utsname()->release,
1645                  gadget->name);
1646 
1647         cdev->manufacturer_override =
1648             override_id(cdev, &cdev->desc.iManufacturer);
1649     }
1650 
1651     if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
1652         cdev->product_override =
1653             override_id(cdev, &cdev->desc.iProduct);
1654 
1655     if (iSerialNumber)
1656         cdev->serial_override =
1657             override_id(cdev, &cdev->desc.iSerialNumber);
1658 
1659     /* has userspace failed to provide a serial number? */
1660     if (composite->needs_serial && !cdev->desc.iSerialNumber)
1661         WARNING(cdev, "userspace failed to provide iSerialNumber\n");
1662 
1663     /* finish up */
1664     status = device_create_file(&gadget->dev, &dev_attr_suspended);
1665     if (status)
1666         goto fail;
1667 
1668     INFO(cdev, "%s ready\n", composite->name);
1669     return 0;
1670 
1671 fail:
1672     composite_unbind(gadget);
1673     return status;
1674 }

可以看出,composite_bind一开始就新建usb_composite_dev并建立usb_gadget与usb_composite_dev的关系。接下来,usb_ep_alloc_request(gadget->ep0) 分配ep0 usb request.

cdev->driver = composite, 这里指定usb_composite_dev的driver为usb_composite_probe注册进来的usb_composite_driver: android_usb_driver

status = composite_gadget_bind(cdev); 这里调用的是usb_composite_probe传进来的android_bind,android_bind会调用usb_add_config来添加config。具体的每一个function的添加会在调用usb_add_config时传进来的callback function中完成(这里是android_bind_config,这个函数会调用每一个需要添加的function的bind_config, 而bind_config调用的是usb_add_function)

接下来我们看 usb_gadget_probe_driver,这个函数主要调用usb_gadget_start

119 static inline int usb_gadget_start(struct usb_gadget *gadget,
120         struct usb_gadget_driver *driver,
121         int (*bind)(struct usb_gadget *))
122 {           
123     return gadget->ops->start(driver, bind);
124 

可以看出这个函数是udc core层实现的一个接口函数,具体实现在对应的usb device controller中

从参数可以看出,这个函数会将usb_gadget_driver和usb_gadget对应起来,并调用bind(这里为composite_bind,前面已经介绍过了他的作用)。


到这里,上图中的所有模块就已经介绍完了,对于整个gadget大体也有一个概念,不过疑问也来了,这里只涉及到了ep0,别的endpoind如何处理呢?

下面我们以adb为例做个简单的介绍

在composite_bind中有提到,他会调用到每一个需要添加的function的bind_config,adb算是其中一个function,那么我们从adb的bind_config看起。


629 static int adb_bind_config(struct usb_configuration *c)
630 {
631     struct adb_dev *dev = _adb_dev;
632    
633     printk(KERN_INFO "adb_bind_config\n");
634    
635     dev->cdev = c->cdev;  
636     dev->function.name = "adb";    
637     dev->function.descriptors = fs_adb_descs;
638     dev->function.hs_descriptors = hs_adb_descs;
639     dev->function.bind = adb_function_bind;
640     dev->function.unbind = adb_function_unbind;
641     dev->function.set_alt = adb_function_set_alt;
642     dev->function.disable = adb_function_disable;
643    
644     return usb_add_function(c, &dev->function);
645 }

可以看到正如我们前面所说,这里会调用usb_add_function,在usb_add_function中会调用function.bind,也就是adb_function_bind。

525 static int
526 adb_function_bind(struct usb_configuration *c, struct usb_function *f)
527 {
528     struct usb_composite_dev *cdev = c->cdev;
529     struct adb_dev  *dev = func_to_adb(f);
530     int         id;
531     int         ret;
532 
533     dev->cdev = cdev;
534     DBG(cdev, "adb_function_bind dev: %p\n", dev);
535 
536     /* allocate interface ID(s) */
537     id = usb_interface_id(c, f);
538     if (id < 0)
539         return id;
540     adb_interface_desc.bInterfaceNumber = id;
541 
542     /* allocate endpoints */
543     ret = adb_create_bulk_endpoints(dev, &adb_fullspeed_in_desc,
544             &adb_fullspeed_out_desc);
545     if (ret)
546         return ret;
547 
548     /* support high speed hardware */
549     if (gadget_is_dualspeed(c->cdev->gadget)) {
550         adb_highspeed_in_desc.bEndpointAddress =
551             adb_fullspeed_in_desc.bEndpointAddress;
552         adb_highspeed_out_desc.bEndpointAddress =
553             adb_fullspeed_out_desc.bEndpointAddress;
554     }
555 
556     DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
557             gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
558             f->name, dev->ep_in->name, dev->ep_out->name);
559     return 0;
560 }


可以看出主要的调用是 adb_create_bulk_endpoints

226 static int adb_create_bulk_endpoints(struct adb_dev *dev,
227                 struct usb_endpoint_descriptor *in_desc,
228                 struct usb_endpoint_descriptor *out_desc)
229 {
230     struct usb_composite_dev *cdev = dev->cdev;
231     struct usb_request *req;
232     struct usb_ep *ep;
233     int i;
234 
235     DBG(cdev, "create_bulk_endpoints dev: %p\n", dev);
236 
237     ep = usb_ep_autoconfig(cdev->gadget, in_desc);
238     if (!ep) {
239         DBG(cdev, "usb_ep_autoconfig for ep_in failed\n");
240         return -ENODEV;
241     }
242     DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name);
243     ep->driver_data = dev;      /* claim the endpoint */
244     dev->ep_in = ep;
245 
246     ep = usb_ep_autoconfig(cdev->gadget, out_desc);
247     if (!ep) {
248         DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
249         return -ENODEV;
250     }
251     DBG(cdev, "usb_ep_autoconfig for adb ep_out got %s\n", ep->name);
252     ep->driver_data = dev;      /* claim the endpoint */
253     dev->ep_out = ep;
254 
255     /* now allocate requests for our endpoints */
256     req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE);
257     if (!req)
258         goto fail;
259     req->complete = adb_complete_out;
260     dev->rx_req = req;
261 
262     for (i = 0; i < TX_REQ_MAX; i++) {
263         req = adb_request_new(dev->ep_in, ADB_BULK_BUFFER_SIZE);
264         if (!req)
265             goto fail;
266         req->complete = adb_complete_in;
267         adb_req_put(dev, &dev->tx_idle, req);
268     }
269 
270     return 0;
271 
272 fail:
273     printk(KERN_ERR "adb_bind() could not allocate requests\n");
274     return -1;
275 }

从这个函数可以看出function如何与gadget建立关系

1. 通过usb_ep_autoconfig(cdev->gadget, in_desc)分配gadget初始化注册的endpoint

2. 通过adb_request_new(主要调用usb_ep_alloc_request)来分配对应的endpoint的request

3. req->complete = adb_complete_out 指定request的complete函数,这个函数会在usb device controller对应的endpoint收发中断完成之后被调用

















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值