作者: zjujoe 转载请注明出处
Email:[email protected]
BLOG:http://blog.csdn.net/zjujoe
前面讲过,gadget api 提供了usb device controller 驱动和上层gadget驱动交互的接口。 UDC 驱动是服务提供者,而各种 gadget 驱动则是服务的使用者。其实还有一些通用代码,因为功能比较简单,我们称之为 helpe 函数。在阅读了 Gadget API 文档后,让我们开始阅读代码, udb 驱动代码比较复杂,我们先从 gadget 驱动看起。各种 gadget 驱动中, 最简单的要数 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);
1315
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
1285 .speed = USB_SPEED_HIGH,
1286 #else
1287 .speed = USB_SPEED_FULL,
1288 #endif
1289 .function = (char *) longname,
1290 .bind = zero_bind,
1291 .unbind = __exit_p(zero_unbind),
1293 .setup = zero_setup,
1294 .disconnect = zero_disconnect,
1296 .suspend = zero_suspend,
1297 .resume = zero_resume,
1299 .driver = {
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 函数。
1140 static int __init
1141 zero_bind (struct usb_gadget *gadget)
1142 {
1143 struct zero_dev *dev;
1144 struct usb_ep *ep;
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))
1151 return -ENODEV;
注意我们以前说过 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);
1163 return -ENODEV;
1164 }
1165 EP_IN_NAME = ep->name;
1166 ep->driver_data = ep; /* claim */
1167
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,
300
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);
1193 if (!dev)
1194 return -ENOMEM;
1195 spin_lock_init (&dev->lock);
1196 dev->gadget = gadget;
1197 set_gadget_data (gadget, dev);
1198
stuct gadget 维护所有 gadget 驱动共性的内容,个性的数据则由各 gadget 驱动各自定义,对于 zero, 它定义了 zero_dev. 分配后存放在 gadget 结构的某个角落里: gadget.dev.driver_data。 zero_dev 定义如下:
119 struct zero_dev {
120 spinlock_t lock;
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 */
128 u8 config;
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);
1201 if (!dev->req)
1202 goto enomem;
1203 dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
1204 &dev->req->dma, GFP_KERNEL);
1205 if (!dev->req->buf)
1206 goto enomem;
1207
1208 dev->req->complete = zero_setup_complete;
1209
这几行代码分配用于控制传输的请求/数据缓冲以及结束函数。控制传输是每个 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;
1215
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);
1242
1243 snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
1244 init_utsname()->sysname, init_utsname()->release,
1245 gadget->name);
1246
1247 return 0;
1248
1249 enomem:
1250 zero_unbind (gadget);
1251 return -ENOMEM;
1252 }
自此 zero_bind 分析完毕。它主要是为 gadget 驱动找到了合适的端点,并且初始化了设备相关结构: zero_dev. 从而把 gadget 驱动和 udc 驱动仅仅地绑定在一起。 看到现在,我们还没有感受到 gadget 驱动的真正意义, 前面的函数就像一座座桥梁,走过这些桥梁,我们终于来到美丽的湖心小岛: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.*/
930 req->zero = 0;
931 switch (ctrl->bRequest) {
932
933 case USB_REQ_GET_DESCRIPTOR:
934 if (ctrl->bRequestType != USB_DIR_IN)
935 goto unknown;
请求各种描述符,当然需要是 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,
226
227 .bcdUSB = __constant_cpu_to_le16 (0x0200),
228 .bDeviceClass = USB_CLASS_VENDOR_SPEC, 0xff
229
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);
959 if (value >= 0)
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,
383 NULL,
384 };
可见,本质上,配置描述符是返回一组描述符。下面看一下配置描述符是如何生成的。
432 static int
433 config_buf (struct usb_gadget *gadget,
434 u8 *buf, u8 type, unsigned index)
435 {
436 int is_source_sink;
437 int len;
438 const struct usb_descriptor_header **function;
439 #ifdef CONFIG_USB_GADGET_DUALSPEED
440 int hs = (gadget->speed == USB_SPEED_HIGH);
441 #endif
442
443 /* two configurations will always be index 0 and index 1 */
444 if (index > 1)
445 return -EINVAL;
446 is_source_sink = loopdefault ? (index == 1) : (index == 0);
447
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
453 ? hs_source_sink_function
454 : hs_loopback_function;
455 else
456 #endif
457 function = is_source_sink
458 ? fs_source_sink_function
459 : fs_loopback_function;
460
461 /* for now, don't advertise srp-only devices */
462 if (!gadget->is_otg)
463 function++;
464
465 len = usb_gadget_config_buf (is_source_sink
466 ? &source_sink_config
467 : &loopback_config,
468 buf, USB_BUFSIZ, function);
469 if (len < 0)
470 return len;
471 ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
472 return len;
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);
971 if (value >= 0)
972 value = min (w_length, (u16) value);
973 break;
974 }
975 break;
976
根据 host 传递过来的索引,响应相应的字符串。Zero驱动的字符串描述符则只支持一种语言(0409, en-us):
409 static struct usb_gadget_strings stringtab = {
410 .language = 0x0409, /* en-us */
411 .strings = strings,
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)
980 goto unknown;
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");
987 spin_lock (&dev->lock);
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)
993 goto unknown;
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)
1004 goto unknown;
1005 spin_lock (&dev->lock);
1006 if (dev->config && w_index == 0 && w_value == 0) {
1007 u8 config = dev->config;
1008
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 */
1016 zero_reset_config (dev);
1017 zero_set_config (dev, config, GFP_ATOMIC);
1018 value = 0;
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))
1024 goto unknown;
1025 if (!dev->config)
1026 break;
1027 if (w_index != 0) {
1028 value = -EDOM;
1029 break;
1030 }
1031 *(u8 *)req->buf = 0;
1032 value = min (w_length, (u16) 1);
1033 break;
1034
获取设备的当前配置的当前接口。
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))
1042 goto unknown;
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;
1048 value = w_length;
1049 break;
1050 case 0x 5c : /* control READ test -- return the buffer */
1051 if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
1052 goto unknown;
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;
1059 value = w_length;
1060 break;
1061
根据协议,我们可以定制私有的类型,这里是 Intel 定义的测试类型,用于测试端点0的数据收发。端点0通常用于控制传输, 用它进行数据传输完全是为了测试目的。
1062 default:
1063 unknown:
1064 VDBG (dev,
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 }
1069
1070 /* respond with data transfer before status phase? */
1071 if (value >= 0) {
1072 req->length = value;
1073 req->zero = value < w_length;
1074 value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
1075 if (value < 0) {
1076 DBG (dev, "ep_queue --> %d/n", value);
1077 req->status = 0;
1078 zero_setup_complete (gadget->ep0, req);
1079 }
1080 }
如果有数据需要传给 Host, 则将其放到端点0的传送队列。底层 udc 驱动会负责将其发给 host.
1082 /* device either stalls (value < 0) or reports success */
1083 return value;
1084 }
函数zero_setup 完成了usb spec ch9 定义的很多功能。而我们前面介绍的 bulk-in/bulk-out 数据端点开始工作则是在 set configuration (或者 set interface)后,由zero_set_config函数触发。下面开始分析该函数。
848 static int
849 zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
850 {
851 int result = 0;
852 struct usb_gadget *gadget = dev->gadget;
853
854 if (number == dev->config)
855 return 0;
862 zero_reset_config (dev);
863
函数 zero_reset_config 把所有的 端点置于 disable 状态。
864 switch (number) {
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:
872 result = -EINVAL;
873 /* FALL THROUGH */
874 case 0:
875 return result;
876 }
根据当前的配置,设置两种不同的传送方式。我们假定 host 设置的是 loopback 方式。另一种方式是类似的(数据内容不同)。
878 if (!result && (!dev->in_ep || !dev->out_ep))
879 result = -ENODEV;
880 if (result)
881 zero_reset_config (dev);
882 else {
883 char *speed;
884
885 switch (gadget->speed) {
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 }
891
892 dev->config = number;
893 INFO (dev, "%s speed config #%d: %s/n", speed, number,
894 (number == CONFIG_SOURCE_SINK)
895 ? source_sink : loopback);
896 }
897 return result;
898 }
一些善后处理。 下面我们看函数 set_loopback_config
747 static int
748 set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
749 {
750 int result = 0;
751 struct usb_ep *ep;
752 struct usb_gadget *gadget = dev->gadget;
753
754 gadget_for_each_ep (ep, gadget) {
针对 gadget 端点列表的每一个端点进行操作。
755 const struct usb_endpoint_descriptor *d;
756
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);
761 if (result == 0) {
762 ep->driver_data = dev;
763 dev->in_ep = ep;
764 continue;
765 }
766
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);
771 if (result == 0) {
772 ep->driver_data = dev;
773 dev->out_ep = ep;
774 continue;
775 }
776
777 /* ignore any other endpoints */
778 } else
779 continue;
780
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 */
790 if (result == 0) {
791 struct usb_request *req;
792 unsigned i;
793
794 ep = dev->out_ep;
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);
800 if (result)
801 DBG (dev, "%s queue req --> %d/n",
802 ep->name, result);
803 } else
804 result = -ENOMEM;
805 }
806 }
首先在 OUT 端点上挂一堆请求(usb_request), 等待主机向我们发送数据。等主机真正对我们进行OUT数据传输并且数据传完后,会调用 loopback_complete 回调函数。
807 if (result == 0)
808 DBG (dev, "qlen %d, buflen %d/n", qlen, buflen);
809
810 /* caller is responsible for cleanup on error */
811 return result;
812 }
下面看 函数 loopback_complete
698 static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
699 {
700 struct zero_dev *dev = ep->driver_data;
701 int status = req->status;
702
703 switch (status) {
704
705 case 0: /* normal completion? */
706 if (ep == dev->out_ep) {
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);
711 if (status == 0)
712 return;
713
714 /* "should never get here" */
715 ERROR (dev, "can't loop %s to %s: %d/n",
716 ep->name, dev->in_ep->name,
717 status);
718 }
719
720 /* queue the buffer for some later OUT packet */
721 req->length = buflen;
722 status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
723 if (status == 0)
724 return;
725
726 /* "should never get here" */
727 /* FALLTHROUGH */
728
729 default:
730 ERROR (dev, "%s loop complete --> %d, %d/%d/n", ep->name,
731 status, req->actual, req->length);
732 /* FALLTHROUGH */
733
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 回调函数只是一个起点。
USB 2.0 Spec
http://www.usb.org/developers/docs/
用KFI和Graphviz跟踪/优化内核代码
http://blog.csdn.net/colorant/archive/2008/07/09/2627493.aspx