Linux-USB Gadget : Part 4: 最简单的 gadget驱动:g_zero

Linux-USB Gadget : Part 4: 最简单的 gadget驱动:g_zero

作者: zjujoe 转载请注明出处

Email : zjujoe@yahoo.com

BLOG : http://blog.csdn.net/zjujoe

前言

前面讲过, 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 );

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 函数。

函数 zero_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

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 0x5c:       /* 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 函数触发。下面开始分析该函数。

 

函数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

函数 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

 

函数 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

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注