Linux-USB Gadget : Part 1: 简介
简介之简介
Linux-USB Gadget 驱动框架(以下简称 Gadget)实现了USB 协议定义的设备端的软件功能。相对于 Linux USB主机端(Host) 驱动而言, Gadget 驱动出现较晚,它出现在2.4.23 以后, (作者的第一次 announce:http://lwn.net/Articles/27352/或 http://kerneltrap.org/node/621), 如果需要在老的 2.4 内核上支持 Gadget, 可以移植 2.4.31 代码,工作量较小。另外,2.6 内核标准版本里的可能比最新版本要老一些。 “mm” 补丁中的版本会比较新。
Gadget 框架提出了一套标准 API, 在底层, USB 设备控制器(USB Device Controller, UDC)驱动则实现这一套 API,不同的 UDC (通常是 SOC 的一部分) 需要不同的驱动, 甚至基于同样的 UDC 的不同板子也需要进行代码修改。这一层我们可以称之为平台相关层。
基于 API, Gadget 驱动实现了一套硬件无关的功能,这基本上可以对应到 USB 协议里 的各种 USB Class, 也有比如 USB Gadget Generic Serial 驱动,没有对应的 Class。当然,Gadget 驱动还是受限于底层提供的功能的。比如某些 Class 需要 USB Isochronous 端点,这时我们就不能支持该 Class。
普通的 Gadget 驱动只实现一个功能(比如, u 盘,usb 网卡)。复合设备可以支持多个功能,后面将仔细研究一下复合设备的实现。像智能手机, PDA这样的设备,硬件支持较丰富的端点、DMA Buffer, 给软件提了支持复合功能的基础。
有两点值得注意,第一是 usb gaget 驱动框架不象 usb 主机端有 usb core 的概念,usb 主机可能支持成百类型的外设,把通用功能抽象出来很有意义。Usb device 端则通常没有这个需求,一些通用功能抽象在一些 Helper 函数里就可以了。第二是 usb 2.0 里提出了 OTG 的概念,可以在同一接口上支持 host 以及 device 功能。OTG 是一个比较复杂的规范,以后有时间再研究。
控制器驱动
常见的 usb device 有 U 盘, usb 鼠标、键盘,usb 蓝牙模块,usb 读卡器,等等。这些设备比较简单,通常不会运行Linux。运行Linux Gadget 的通常是一些集成 CPU 以及很多外设接口的 SOC (System-on-Chip), 其中 CPU通常为 32 bit 的 CPU, 并且 udc 也是该 SOC 的一部分( 顺带还有 DMA 通道,FIFO)。
Linux 标准内核里支持各主流 SOC 的 udc 驱动,make menuconfig 一下可以看到具体列表,其中值得一提的是 dummy_hcd, 它是一个软件模拟的 udc, 在开发新的 gadget 驱动时很有帮助。
控制器驱动处理很少的 USB 控制请求(主要由硬件负责的部分)。其它所有的控制请求,比如返回描述符,设置当前配置,由 Gadget Driver 完成。控制器驱动一个主要责任就是负责管理各个端点的 I/O 队列,在 Gadget Driver 的 buffer 和硬件buffer 之间传输数据(通常是通过 DMA)。
我们前面提过,上层 Gadget 驱动能够实现什么功能要依赖底层提供的硬件条件。比如一个复合设备需要至少5 个端点,这些硬件特性通过一组 gadget_is_*()函数实现。
Gadget 驱动
基于底层提供的资源, Gadget 驱动可以运行在各种硬件平台上。重要的驱动有:
Ø Gadget Zero, 类似于 dummy hcd, 该驱动用于测试 udc 驱动。它会帮助您通过 USB-IF 测试。
Ø Ethernet over USB, 该驱动模拟以太网网口,它支持多种运行方式:
² CDC Ethernet: usb 规范规定的 Communications Device Class “Ethernet Model” protocol。
² CDC Subset: 对硬件要求最低的一种方式,主要是 Linux 主机支持该方式。
² RNDIS: 微软公司对 CDC Ethernet 的变种实现。
Ø File-backed Storage Gadget最常见的 U 盘功能实现。
Ø Serial Gadget 实现,包括:
² Generic Serial 实现(只需要Bulk-in/Bulk-out端点+ep0)
² CDC ACM 规范实现。
Ø Gadget Filesystem, 将 Gadget API 接口暴露给应用层,以便在应用层实现user mode driver。
Ø MIDI: 暴露ALSA接口,提供 recording 以及 playback 功能。
前面讲过,gadget api 提供了usb device controller 驱动和上层gadget驱动交互的接口。 UDC 驱动是服务提供者,而各种 gadget 驱动则是服务的使用者。其实还有一些通用代码,因为功能比较简单,我们称之为 helpe 函数。在阅读了 Gadget API 文档后,让我们开始阅读代码, udb 驱动代码比较复杂,我们先从 gadget 驱动看起。各种gadget 驱动中, 最简单的要数 g_zero 驱动。
g_zero 驱动简介
作为最简单的 gadget 驱动,g_zero 的功能基于两个 BULK 端点实现了简单的输入输出功能, 它可以用作写新的gadget 驱动的一个实例。 g_zero 驱动还有一个重要角色, 即配合 host 端的 usbtest (内核模块及用户层代码),用于测试底层 udc 驱动。当然,也可以是测试主机的控制器驱动。
两个 BULK 端点为一个 IN 端点, 一个 OUT端点。基于这两个(由底层提供的)端点,g_zero 驱动实现了两个configuration。 第一个 configuration 提供了 sink/source功能:两个端点一个负责输入,一个负责输出,其中输出的内容根据设置可以是全0,也可以是按照某种算法生成的数据。另一个 configuration 提供了 loopback 接口, IN端点负责把从 OUT 端点收到的数据反馈给 Host.
根据系统配置,g_zero 驱动提供了全速及高速功能,从而稍微增加了代码复杂度。另外,它还支持 otg 接口,从usb2.0 协议我们知道, otg 其实是usb device实现的一个补充功能。它增加了一套接口,使得同一设备可以在设备角色以及有限主机角色之切换。上层gadget驱动主要是在描述符方面提供配合支持。下面我们开始看代码。
模块初始化
1309 static int __init init (void)
1310 {
1311 /* a real value would likely come through some id prom
1312 * or module option. this one takes at least two packets.
1313 */
1314 strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
1316 return usb_gadget_register_driver (&zero_driver);
1317 }
1318 module_init (init);
1320 static void __exit cleanup (void)
1321 {
1322 (&zero_driver);
1323 }
1324 module_exit (cleanup); usb_gadget_unregister_driver
Serial 变量存储的是设备序列号,我们是一个非正式设备,随便填充一下。模块初始化函数调用 usb_gadget_register_driver 来向udc driver 注册一个 gadget 驱动, 我们这里是 zero_driver。而退出函数则会做相反的操作:调用 usb_gadget_unregister_driver取消原来的注册。像所有的模块初始化、退出函数一样,现在还看不出什么花头。我们再看一下 zero_driver 的定义:
1283 static struct usb_gadget_driver zero_driver = {
1284 #ifdef CONFIG_USB_GADGET_DUALSPEED
1286 #else
1288 #endif
1289 .function = (char *) longname,
1291 .unbind = __exit_p(zero_unbind),
1293 .setup = zero_setup,
1294 .disconnect = zero_disconnect,
1296 .suspend = zero_suspend,
1297 .resume = zero_resume,
1300 .name = (char *) shortname,
1301 .owner = THIS_MODULE,
1302 },
1303 };
根据 CONFIG_USB_GADGET_DUALSPEED,代码选择是支持高速还是全速,我们使用的 PXA 平台支持高速传输,所以我们假定该配置变量为真。根据 Gadget API 文档(以及下面的代码调用图),在初始化阶段 usb_gadget_register_driver 函数会调用 bind 函数,而 setup 函数是用于处理 udc 驱动没有处理的控制传输部分。这两个函数是整个 zero gadget 驱动的精华部分。其它函数则只是为了完整性而提供,有兴趣者可以对照 Gadget API 文档及代码,自行研究。至于 .driver 成员变量,那主要是为LDM(linux device module)服务的。现在关于 LDM 的文档满天飞,这里就不多说了。
简单起见,我们目前不去深究 udc 驱动代码(那比我们的 g_zero 驱动要复杂很多, 而且很多代码硬件相关,需要阅读硬件 spec 才能理解),而是使用 kft及graphviz(见参考,colorant 大侠提供的文档)工具得到函数调用关系图:(我们这里使用 pxa udc驱动,如果使用 dummy_hcd 会得到类似但更简单的关系图)
从上图中,我们可以看到在初始化阶段, udc 驱动会调用 zero 驱动的 bind 函数,也会调用 zero 驱动的 setup 函数 (主要是得到一些描述符), setup 函数主要是在后面我们的 device 和主机连接后用于处理控制传输的响应(大部分)。在初始阶段只是顺便帮忙提供点信息,进行的是假传输,真提供信息给 udc 驱动。下面我们重点分析 bind 函数。
函数 zero_bind
1141 zero_bind (struct usb_gadget *gadget)
1142 {
1145 int gcnum;
首先映入眼帘的是zero_bind 函数的参数,根据 Gadget API,一个 gadget 代表一个 usb slave设备。这个数据结构是在底层控制器驱动中静态分配的。Udc 驱动在调用 gadget 驱动各接口函数时都会提供这个数据结构。
1147 /* FIXME this can't yet work right with SH ... it has only
1148 * one configuration, numbered one.
1149 */
1150 if (gadget_is_sh(gadget))
注意我们以前说过 gadget_is_* 系列函数提供了查询硬件能力的接口,这里用于判断是否是 SH 平台的 udc, 如果是, 直接出错返回:g_zero 驱动目前还不支持该平台。
1153 /* Bulk-only drivers like this one SHOULD be able to
1154 * autoconfigure on any sane usb controller driver,
1155 * but there may also be important quirks to address.
1156 */
1157 usb_ep_autoconfig_reset (gadget);
注意函数 usb_ep_autoconfig_reset 不是由底层 udc 驱动实现,而是我们以前提过的 helper 函数的一部分。该函数功能很简单:用于清空 gadget 的 端点列表。
1158 ep = usb_ep_autoconfig (gadget, &fs_source_desc);
1159 if (!ep) {
1160 autoconf_fail:
1161 printk (KERN_ERR "%s: can't autoconfigure on %s/n",
1162 shortname, gadget->name);
1164 }
1165 EP_IN_NAME = ep->name;
1166 ep->driver_data = ep; /* claim */
1168 ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
1169 if (!ep)
1170 goto autoconf_fail;
1171 EP_OUT_NAME = ep->name;
1172 ep->driver_data = ep; /* claim */
函数 usb_ep_autoconfig 根据第二个参数所描述的限制条件,自动寻找适合条件的端点,并插入 gadget的端点列表。这里 ep 是普通的数据端点,它的 driver_data 不需要存放特殊数据,那就保存一下自己的地址吧。(后面我们将看到 ep0 的 driver_data 放的是zero_driver 的特殊数据)。我们看一下 fs_source_desc:
296 static struct usb_endpoint_descriptor
297 fs_source_desc = {
298 .bLength = USB_DT_ENDPOINT_SIZE,
299 .bDescriptorType = USB_DT_ENDPOINT,
301 .bEndpointAddress = USB_DIR_IN,
302 .bmAttributes = USB_ENDPOINT_XFER_BULK,
303 };
可见该描述符描述的是一个类型为 BULK,方向为 IN 的端点。 fs_sink_desc 的定义类似,描述一个类型为 BULK, 方向为 OUT 的端点。下面继续看 zero_bind 的代码。
1174 gcnum = usb_gadget_controller_number (gadget);
1175 if (gcnum >= 0)
1176 device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
1177 else {
1178 /* gadget zero is so simple (for now, no altsettings) that
1179 * it SHOULD NOT have problems with bulk-capable hardware.
1180 * so warn about unrcognized controllers, don't panic.
1181 *
1182 * things like configuration and altsetting numbering
1183 * can need hardware-specific attention though.
1184 */
1185 printk (KERN_WARNING "%s: controller '%s' not recognized/n",
1186 shortname, gadget->name);
1187 device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
1188 }
每一个 udc 驱动被分配了一个编号,用作该设备描述符里的 bcd 码。 如果没有分配,没办法,就将就着用 0x9999 吧。
1191 /* ok, we made sense of the hardware ... */
1192 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1195 spin_lock_init (&dev->lock);
1197 set_gadget_data (gadget, dev);
stuct gadget 维护所有 gadget 驱动共性的内容,个性的数据则由各 gadget 驱动各自定义,对于 zero, 它定义了 zero_dev. 分配后存放在 gadget 结构的某个角落里: gadget.dev.driver_data。 zero_dev 定义如下:
121 struct usb_gadget *gadget;
122 struct usb_request *req; /* for control responses */
124 /* when configured, we have one of two configs:
125 * - source data (in to host) and sink it (out from host)
126 * - or loop it back (out from host back in to host)
127 */
129 struct usb_ep *in_ep, *out_ep;
131 /* autoresume timer */
132 struct timer_list resume;
133 };
这里 resume是用于唤醒 host 的 timer 的列表, config 表示我们当前使用第几个 configuration. 其它含义自明。下面继续看 zero bind 代码。
1199 /* preallocate control response and buffer */
1200 dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
1202 goto enomem;
1203 dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
1204 &dev->req->dma, GFP_KERNEL);
1206 goto enomem;
1208 dev->req->complete = zero_setup_complete;
这几行代码分配用于控制传输的请求/数据缓冲以及结束函数。控制传输是每个 gadget 驱动要使用的传输方式,这里及早分配。结束函数 zero_setup_complete 只是打印一下状态,我们就不贴出了。
1210 device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
这里根据底层的数据初始化设备描述符里端点 0 (控制端点)的最大包大小。
1212 #ifdef CONFIG_USB_GADGET_DUALSPEED
1213 /* assume ep0 uses the same value for both speeds ... */
1214 dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
1216 /* and that all endpoints are dual-speed */
1217 hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
1218 hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
1219 #endif
高速设备需要的额外的描述符,我们对某些字段进行初始化。
1221 if (gadget->is_otg) {
1222 otg_descriptor.bmAttributes |= USB_OTG_HNP,
1223 source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1224 loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1225 }
如果是 otg 设备,则需要在描述符里设置相关特性。
1227 usb_gadget_set_selfpowered (gadget);
能运行 Linux Gadget 驱动的设备一般电池供电,也就是 selfpowered。
1229 init_timer (&dev->resume);
1230 dev->resume.function = zero_autoresume;
1231 dev->resume.data = (unsigned long) dev;
1232 if (autoresume) {
1233 source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1234 loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
1235 }
这段代码跟自动唤醒 host 有关, 不深究。
1237 gadget->ep0->driver_data = dev;
多记一份 zero_dev 的地址, 方便使用。
1239 INFO (dev, "%s, version: " DRIVER_VERSION "/n", longname);
1240 INFO (dev, "using %s, OUT %s IN %s/n", gadget->name,
1241 EP_OUT_NAME, EP_IN_NAME);
1243 snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
1244 init_utsname()->sysname, init_utsname()->release,
1247 return 0;
1249 enomem:
1250 zero_unbind (gadget);
1252 }
自此 zero_bind 分析完毕。它主要是为 gadget 驱动找到了合适的端点,并且初始化了设备相关结构: zero_dev.从而把 gadget 驱动和 udc 驱动仅仅地绑定在一起。 看到现在,我们还没有感受到 gadget 驱动的真正意义, 前面的函数就像一座座桥梁,走过这些桥梁,我们终于来到美丽的湖心小岛:zero_setup。
函数 zero_setup
zero_setup 完成控制传输的大部分功能。比如获取各种描述符、设置配置等。Host 首先通过控制传输和设备进行通信,告诉设备它底下要干什么。 Zero gadget驱动比较简单,在主机进行set configuration后,就会在 IN/OUT 端点上准备好数据,供主机去用。并且通过call函数,在主机使用完前面准备好的数据后,继续插入请求,这样,主机就可以源源不断的对我们这个设备进行读写操作。以下开始看代码。
917 static int
918 zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
919 {
照例,我们得到 usb_gadget 结构,同时,我们的第二个参数是 usb_ctrlrequest 结构:
140 struct usb_ctrlrequest {
141 __u8 bRequestType;
142 __u8 bRequest;
143 __le16 wValue;
144 __le16 wIndex;
145 __le16 wLength;
146 } __attribute__ ((packed));
具体含义请参考 Usb spec Ch9。 这里结构名字有点误导, usb_ctrlrequest 代表的是主机传过来的控制请求。和后面的usb_request 有较大区别。 usb_request 代表放到端点的队列里等待主机过来读写的一个个数据包。下面我们继续看 zero_setup 函数代码。
920 struct zero_dev *dev = get_gadget_data (gadget);
921 struct usb_request *req = dev->req;
922 int value = -EOPNOTSUPP;
923 u16 w_index = le16_to_cpu(ctrl->wIndex);
924 u16 w_value = le16_to_cpu(ctrl->wValue);
925 u16 w_length = le16_to_cpu(ctrl->wLength);
获得我们在 bind 函数分配的 zero_dev, usb_request, 以及由主机传过来的“请求”的各字段。
927 /* usually this stores reply data in the pre-allocated ep0 buffer,
928 * but config change events will reconfigure hardware.*/
933 case USB_REQ_GET_DESCRIPTOR:
934 if (ctrl->bRequestType != USB_DIR_IN)
请求各种描述符,当然需要是 IN 类型的请求。
936 switch (w_value >> 8) {
938 case USB_DT_DEVICE:
939 value = min (w_length, (u16) sizeof device_desc);
940 memcpy (req->buf, &device_desc, value);
941 break;
942 #ifdef CONFIG_USB_GADGET_DUALSPEED
943 case USB_DT_DEVICE_QUALIFIER:
944 if (!gadget->is_dualspeed)
945 break;
946 value = min (w_length, (u16) sizeof dev_qualifier);
947 memcpy (req->buf, &dev_qualifier, value);
948 break;
对应 USB 2.0 Spec CH9, 以上代码很容易理解。 每一个描述符使用 struct usb_device_descriptor 描述,比如, 设备描述符:
222 static struct usb_device_descriptor
223 device_desc = {
224 .bLength = sizeof device_desc,
225 .bDescriptorType = USB_DT_DEVICE,
227 .bcdUSB = __constant_cpu_to_le16 (0x0200),
228 .bDeviceClass = USB_CLASS_VENDOR_SPEC, 0xff
230 .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
231 .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
232 .iManufacturer = STRING_MANUFACTURER, 25, 厂商描述符
233 .iProduct = STRING_PRODUCT, 42,厂品描述符
234 .iSerialNumber = STRING_SERIAL, 101, 序列号
235 .bNumConfigurations = 2,
236 };
950 case USB_DT_OTHER_SPEED_CONFIG:
951 if (!gadget->is_dualspeed)
952 break;
953 // FALLTHROUGH
954 #endif /* CONFIG_USB_GADGET_DUALSPEED */
955 case USB_DT_CONFIG:
956 value = config_buf (gadget, req->buf,
957 w_value >> 8,
958 w_value & 0xff);
960 value = min (w_length, (u16) value);
961 break;
配置描述符比较复杂,会返回该配置里的接口,端点等信息。配置描述符由:struct usb_descriptor_header[] 表达, 而且高速/全速设备的配置描述符是不一样。比如,高速 loopback 配置的配置描述符为:
378 static const struct usb_descriptor_header *hs_loopback_function [] = {
379 (struct usb_descriptor_header *) &otg_descriptor,
380 (struct usb_descriptor_header *) &loopback_intf,
381 (struct usb_descriptor_header *) &hs_source_desc,
382 (struct usb_descriptor_header *) &hs_sink_desc,
384 };
可见,本质上,配置描述符是返回一组描述符。下面看一下配置描述符是如何生成的。
432 static int
433 config_buf (struct usb_gadget *gadget,
434 u8 *buf, u8 type, unsigned index)
435 {
436 int is_source_sink;
438 const struct usb_descriptor_header **function;
439 #ifdef CONFIG_USB_GADGET_DUALSPEED
440 int hs = (gadget->speed == USB_SPEED_HIGH);
441 #endif
443 /* two configurations will always be index 0 and index 1 */
446 is_source_sink = loopdefault ? (index == 1) : (index == 0);
448 #ifdef CONFIG_USB_GADGET_DUALSPEED
449 if (type == USB_DT_OTHER_SPEED_CONFIG)
450 hs = !hs;
451 if (hs)
452 function = is_source_sink
455 else
456 #endif
457 function = is_source_sink
461 /* for now, don't advertise srp-only devices */
462 if (!gadget->is_otg)
463 function++;
465 len = usb_gadget_config_buf (is_source_sink
467 : &loopback_config,
468 buf, USB_BUFSIZ, function);
471 ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
473 }
代码很简单, config_buf 函数根据当前是否是高速设备,以及是否是 otg 设备,选择合适的 configuration( souce sink config or loopback config), 调用 usb_gadget_config_buf 生成最终的配置描述符。可以想象 usb_gadget_config_buf 的实现非常简单: 根据传过来的 描述符列表( 以 NULL 指针结束),使用 memcpy 之类见每个描述符的内容拷贝到 buf 里。 下面我们继续看 zero_setup函数。
963 case USB_DT_STRING:
964 /* wIndex == language code.
965 * this driver only handles one language, you can
966 * add string tables for other languages, using
967 * any UTF-8 characters
968 */
969 value = usb_gadget_get_string (&stringtab,
970 w_value & 0xff, req->buf);
972 value = min (w_length, (u16) value);
973 break;
974 }
975 break;
根据 host 传递过来的索引,响应相应的字符串。Zero驱动的字符串描述符则只支持一种语言(0409, en-us):
409 static struct usb_gadget_strings stringtab = {
410 .language = 0x0409, /* en-us */
412 };
399 /* static strings, in UTF-8 */
400 static struct usb_string strings [] = {
401 { STRING_MANUFACTURER, manufacturer, },
402 { STRING_PRODUCT, longname, },
403 { STRING_SERIAL, serial, },
404 { STRING_LOOPBACK, loopback, },
405 { STRING_SOURCE_SINK, source_sink, },
406 { } /* end of list */
407 };
有点像应用层(比如 vc)为了支持多语言而独立出来的字符串资源。事实上就是这样!我们可以很容易再增加一种语言。下面我们继续看 zero_setup 函数。
977 /* currently two configs, two speeds */
978 case USB_REQ_SET_CONFIGURATION:
979 if (ctrl->bRequestType != 0)
981 if (gadget->a_hnp_support)
982 DBG (dev, "HNP available/n");
983 else if (gadget->a_alt_hnp_support)
984 DBG (dev, "HNP needs a different root port/n");
985 else
986 VDBG (dev, "HNP inactive/n");
988 value = zero_set_config (dev, w_value, GFP_ATOMIC);
989 spin_unlock (&dev->lock);
990 break;
设置设备的当前配置,到这里,才凌空一脚,将设备带入数据传输状态,我们先把zero_setup 看完,再仔细看函数zero_set_config。
991 case USB_REQ_GET_CONFIGURATION:
992 if (ctrl->bRequestType != USB_DIR_IN)
994 *(u8 *)req->buf = dev->config;
995 value = min (w_length, (u16) 1);
996 break;
获取设备的当前配置
998 /* until we add altsetting support, or other interfaces,
999 * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
1000 * and already killed pending endpoint I/O.
1001 */
1002 case USB_REQ_SET_INTERFACE:
1003 if (ctrl->bRequestType != USB_RECIP_INTERFACE)
1006 if (dev->config && w_index == 0 && w_value == 0) {
1009 /* resets interface configuration, forgets about
1010 * previous transaction state (queued bufs, etc)
1011 * and re-inits endpoint state (toggle etc)
1012 * no response queued, just zero status == success.
1013 * if we had more than one interface we couldn't
1014 * use this "reset the config" shortcut.
1015 */
1017 zero_set_config (dev, config, GFP_ATOMIC);
1019 }
1020 spin_unlock (&dev->lock);
1021 break;
设置接口,由于我们每个configuration只有一个接口,所以这里的效果跟前面设置配置类似。
由于 zero_set_config 函数会调用 zero_reset_config, 所以这里应该可以不调用 zero_reset_config.
1022 case USB_REQ_GET_INTERFACE:
1023 if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
1026 break;
1027 if (w_index != 0) {
1029 break;
1030 }
1032 value = min (w_length, (u16) 1);
1033 break;
获取设备的当前配置的当前接口。
1035 /*
1036 * These are the same vendor-specific requests supported by
1037 * Intel's USB 2.0 compliance test devices. We exceed that
1038 * device spec by allowing multiple-packet requests.
1039 */
1040 case 0x5b: /* control WRITE test -- fill the buffer */
1041 if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
1043 if (w_value || w_index)
1044 break;
1045 /* just read that many bytes into the buffer */
1046 if (w_length > USB_BUFSIZ)
1047 break;
1049 break;
1050 case 0x5c: /* control READ test -- return the buffer */
1051 if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
1053 if (w_value || w_index)
1054 break;
1055 /* expect those bytes are still in the buffer; send back */
1056 if (w_length > USB_BUFSIZ
1057 || w_length != req->length)
1058 break;
1060 break;
根据协议,我们可以定制私有的类型,这里是 Intel 定义的测试类型,用于测试端点0的数据收发。端点0通常用于控制传输, 用它进行数据传输完全是为了测试目的。
1062 default:
1065 "unknown control req%02x.%02x v%04x i%04x l%d/n",
1066 ctrl->bRequestType, ctrl->bRequest,
1067 w_value, w_index, w_length);
1068 }
1070 /* respond with data transfer before status phase? */
1073 req->zero = value < w_length;
1074 value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
1076 DBG (dev, "ep_queue --> %d/n", value);
1078 zero_setup_complete (gadget->ep0, req);
1079 }
1080 }
如果有数据需要传给 Host, 则将其放到端点0的传送队列。底层 udc 驱动会负责将其发给 host.
1082 /* device either stalls (value < 0) or reports success */
1084 }
函数zero_setup 完成了usb spec ch9 定义的很多功能。而我们前面介绍的 bulk-in/bulk-out 数据端点开始工作则是在 set configuration (或者 set interface)后,由zero_set_config函数触发。下面开始分析该函数。
函数zero_set_config
848 static int
849 zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
850 {
852 struct usb_gadget *gadget = dev->gadget;
854 if (number == dev->config)
855 return 0;
函数 zero_reset_config 把所有的 端点置于 disable 状态。
865 case CONFIG_SOURCE_SINK:
866 result = set_source_sink_config (dev, gfp_flags);
867 break;
868 case CONFIG_LOOPBACK:
869 result = set_loopback_config (dev, gfp_flags);
870 break;
871 default:
873 /* FALL THROUGH */
874 case 0:
876 }
根据当前的配置,设置两种不同的传送方式。我们假定 host 设置的是 loopback 方式。另一种方式是类似的(数据内容不同)。
878 if (!result && (!dev->in_ep || !dev->out_ep))
882 else {
886 case USB_SPEED_LOW: speed = "low"; break;
887 case USB_SPEED_FULL: speed = "full"; break;
888 case USB_SPEED_HIGH: speed = "high"; break;
889 default: speed = "?"; break;
890 }
893 INFO (dev, "%s speed config #%d: %s/n", speed, number,
894 (number == CONFIG_SOURCE_SINK)
895 ? source_sink : loopback);
896 }
898 }
一些善后处理。 下面我们看函数 set_loopback_config
函数 set_loopback_config
747 static int
748 set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
749 {
752 struct usb_gadget *gadget = dev->gadget;
754 gadget_for_each_ep (ep, gadget) {
针对 gadget 端点列表的每一个端点进行操作。
755 const struct usb_endpoint_descriptor *d;
757 /* one endpoint writes data back IN to the host */
758 if (strcmp (ep->name, EP_IN_NAME) == 0) {
759 d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
760 result = usb_ep_enable (ep, d);
762 ep->driver_data = dev;
764 continue;
765 }
767 /* one endpoint just reads OUT packets */
768 } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
769 d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
770 result = usb_ep_enable (ep, d);
772 ep->driver_data = dev;
774 continue;
775 }
777 /* ignore any other endpoints */
778 } else
779 continue;
781 /* stop on error */
782 ERROR (dev, "can't enable %s, result %d/n", ep->name, result);
783 break;
784 }
激活端点。并设置速度(高速或者全速)。
786 /* allocate a bunch of read buffers and queue them all at once.
787 * we buffer at most 'qlen' transfers; fewer if any need more
788 * than 'buflen' bytes each.
789 */
791 struct usb_request *req;
795 for (i = 0; i < qlen && result == 0; i++) {
796 req = alloc_ep_req (ep, buflen);
797 if (req) {
798 req->complete = loopback_complete;
799 result = usb_ep_queue (ep, req, GFP_ATOMIC);
801 DBG (dev, "%s queue req --> %d/n",
803 } else
805 }
806 }
首先在 OUT 端点上挂一堆请求(usb_request), 等待主机向我们发送数据。等主机真正对我们进行OUT数据传输并且数据传完后,会调用 loopback_complete 回调函数。
808 DBG (dev, "qlen %d, buflen %d/n", qlen, buflen);
810 /* caller is responsible for cleanup on error */
812 }
下面看 函数 loopback_complete
函数 loopback_complete
698 static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
699 {
700 struct zero_dev *dev = ep->driver_data;
705 case 0: /* normal completion? */
707 /* loop this OUT packet back IN to the host */
708 req->zero = (req->actual < req->length);
709 req->length = req->actual;
710 status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
712 return;
714 /* "should never get here" */
715 ERROR (dev, "can't loop %s to %s: %d/n",
716 ep->name, dev->in_ep->name,
718 }
720 /* queue the buffer for some later OUT packet */
722 status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
724 return;
726 /* "should never get here" */
727 /* FALLTHROUGH */
729 default:
730 ERROR (dev, "%s loop complete --> %d, %d/%d/n", ep->name,
731 status, req->actual, req->length);
732 /* FALLTHROUGH */
734 /* NOTE: since this driver doesn't maintain an explicit record
735 * of requests it submitted (just maintains qlen count), we
736 * rely on the hardware driver to clean up on disconnect or
737 * endpoint disable.
738 */
739 case -ECONNABORTED: /* hardware forced ep reset */
740 case -ECONNRESET: /* request dequeued */
741 case -ESHUTDOWN: /* disconnect from host */
742 free_ep_req (ep, req);
743 return;
744 }
745 }
如果 OUT 传输正常结束,则会将其放到IN 端点的传输队列。
如果 IN 传输正常结束,则会将其放到 OUT 端点的传输队列。
这样,通过回调函数不断在两个队列(IN/OUT)之间切换这些请求(usb_request),就实现了在主机看来的 loopback 设备。
总结
Gadget 驱动的特殊性在于它是 host 端对等驱动的 slave, 而不是上层某个应用的 slave. 响应的,它是实现是很有意思的。我们没有看到 read/write 函数,也没有看到我们最常实现的 ioctl 函数, 而是把重点放在回调函数zero_setup 上。 g_zero gadget 驱动实现了一个最简单的 bulk-in/bulk-out 功能,向我们展示了 gadget 驱动如果利用 gadget API来完成数据传输功能。对于复杂的 gadget 驱动, setup 回调函数只是一个起点。