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

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

作者: zjujoe 转载请注明出处

Emailzjujoe@yahoo.com

BLOGhttp://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 才能理解),而是使用 kftgraphviz(见参考,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 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函数触发。下面开始分析该函数。

 

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

 

KFIGraphviz跟踪/优化内核代码

http://blog.csdn.net/colorant/archive/2008/07/09/2627493.aspx

 

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值