- Linux那些事儿之我是USB
- 肖林甫 肖季东 任桥伟
- 5348字
- 2020-08-27 00:52:23
30.设备的生命线(十一)
现在已经使用GET_DESCRIPTOR请求获取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw,即原始的,所有数据不管是配置描述符、接口描述符还是端点描述符都挤在一起,所以得想办法将它们给分开,于是用到了usb_parse_configuration()函数。
264 static int usb_parse_configuration(struct device *ddev, int cfgidx, 265 struct usb_host_config *config, unsigned char *buffer, int size) 266 { 267 unsigned char *buffer0 = buffer; 268 int cfgno; 269 int nintf, nintf_orig; 270 int i, j, n; 271 struct usb_interface_cache *intfc; 272 unsigned char *buffer2; 273 int size2; 274 struct usb_descriptor_header *header; 275 int len, retval; 276 u8 inu ms[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; 277 278 memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); 279 if (config->desc.bDescriptorType != USB_DT_CONFIG || 280 config->desc.bLength < USB_DT_CONFIG_SIZE) { 281 dev_err(ddev, "invalid descriptor for config index %d: " 282 "type = 0x%X, length = %d\n", cfgidx, 283 config->desc.bDescriptorType, config->desc.bLength); 284 return -EINVAL; 285 } 286 cfgno = config->desc.bConfigurationValue; 287 288 buffer += config->desc.bLength; 289 size -= config->desc.bLength; 290 291 nintf = nintf_orig = config->desc.bNumInterfaces; 292 if (nintf > USB_MAXINTERFACES) { 293 dev_warn(ddev, "config %d has too many interfaces: %d, " 294 "using maximum allowed: %d\n", 295 cfgno, nintf, USB_MAXINTERFACES); 296 nintf = USB_MAXINTERFACES; 297 } 298 299 /* Go through the descriptors, checking their length and counting the 300 * number of altsettings for each interface */ 301 n = 0; 302 for ((buffer2 = buffer, size2 = size); 303 size2 > 0; 304 (buffer2 += header->bLength, size2 -= header->bLength)) { 305 306 if (size2 < sizeof(struct usb_descriptor_header)) { 307 dev_warn(ddev, "config %d descriptor has %d excess " 308 "Byte%s, ignoring\n", 309 cfgno, size2, plural(size2)); 310 break; 311 } 312 313 header = (struct usb_descriptor_header *) buffer2; 314 if ((header->bLength > size2) || (header->bLength < 2)) { 315 dev_warn(ddev, "config %d has an invalid descriptor " 316 "of length %d, skipping remainder of the config\n", 317 cfgno, header->bLength); 318 break; 319 } 320 321 if (header->bDescriptorType == USB_DT_INTERFACE) { 322 struct usb_interface_descriptor *d; 323 int inum; 324 325 d = (struct usb_interface_descriptor *) header; 326 if (d->bLength < USB_DT_INTERFACE_SIZE) { 327 dev_warn(ddev, "config %d has an invalid " 328 "interface descriptor of length %d, " 329 "skipping\n", cfgno, d->bLength); 330 continue; 331 } 332 333 inum = d->bInterfaceNumber; 334 if (inum >= nintf_orig) 335 dev_warn(ddev, "config %d has an invalid " 336 "interface number: %d but max is %d\n", 337 cfgno, inum, nintf_orig - 1); 338 339 /* Have we already encountered this interface? 340 * Count its altsettings */ 341 for (i = 0; i < n; ++i) { 342 if (inu ms[i] == inum) 343 break; 344 } 345 if (i < n) { 346 if (nalts[i] < 255) 347 ++nalts[i]; 348 } else if (n < USB_MAXINTERFACES) { 349 inu ms[n] = inum; 350 nalts[n] = 1; 351 ++n; 352 } 353 354 } else if (header->bDescriptorType == USB_DT_DEVICE || 355 header->bDescriptorType == USB_DT_CONFIG) 356 dev_warn(ddev, "config %d contains an unexpected " 357 "descriptor of type 0x%X, skipping\n", 358 cfgno, header->bDescriptorType); 359 360 } /* for ((buffer2 = buffer, size2 = size); ...) */ 361 size = buffer2 - buffer; 362 config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); 363 364 if (n != nintf) 365 dev_warn(ddev, "config %d has %d interface%s, different from " 366 "the descriptor's value: %d\n", 367 cfgno, n, plural(n), nintf_orig); 368 else if (n == 0) 369 dev_warn(ddev, "config %d has no interfaces?\n", cfgno); 370 config->desc.bNumInterfaces = nintf = n; 371 372 /* Check for missing interface numbers */ 373 for (i = 0; i < nintf; ++i) { 374 for (j = 0; j < nintf; ++j) { 375 if (inu ms[j] == i) 376 break; 377 } 378 if (j >= nintf) 379 dev_warn(ddev, "config %d has no interface number " 380 "%d\n", cfgno, i); 381 } 382 383 /* Allocate the usb_interface_caches and altsetting arrays */ 384 for (i = 0; i < nintf; ++i) { 385 j = nalts[i]; 386 if (j > USB_MAXALTSETTING) { 387 dev_warn(ddev, "too many alternate settings for " 388 "config %d interface %d: %d, " 389 "using maximum allowed: %d\n", 390 cfgno, inu ms[i], j, USB_MAXALTSETTING); 391 nalts[i] = j = USB_MAXALTSETTING; 392 } 393 394 len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; 395 config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); 396 if (!intfc) 397 return -ENOMEM; 398 kref_init(&intfc->ref); 399 } 400 401 /* Skip over any Class Specific or Vendor Specific descriptors; 402 * find the first interface descriptor */ 403 config->extra = buffer; 404 i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, 405 USB_DT_INTERFACE, &n); 406 config->extralen = i; 407 if (n > 0) 408 dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 409 n, plural(n), "configuration"); 410 buffer += i; 411 size -= i; 412 413 /* Parse all the interface/altsetting descriptors */ 414 while (size > 0) { 415 retval = usb_parse_interface(ddev, cfgno, config, 416 buffer, size, inu ms, nalts); 417 if (retval < 0) 418 return retval; 419 420 buffer += retval; 421 size -= retval; 422 } 423 424 /* Check for missing altsettings */ 425 for (i = 0; i < nintf; ++i) { 426 intfc = config->intf_cache[i]; 427 for (j = 0; j < intfc->num_altsetting; ++j) { 428 for (n = 0; n < intfc->num_altsetting; ++n) { 429 if (intfc->altsetting[n].desc. 430 bAlternateSetting == j) 431 break; 432 } 433 if (n >= intfc->num_altsetting) 434 dev_warn(ddev, "config %d interface %d has no " 435 "altsetting %d\n", cfgno, inu ms[i], j); 436 } 437 } 438 439 return 0; 440 }
其实前面也说到过的,使用GET_DESCRIPTOR请求时,得到的数据并不是杂乱无序的,而是有规可循的。一般来说,配置描述符后面跟的是第一个接口的接口描述符,接着是这个接口里第一个端点的端点描述符,如果有class-和vendor-specific描述符的话,会紧跟在对应的标准描述符后面,不管接口有多少端点都是按照这个规律顺序排列。
当然有些设备生产厂商会特立独行一些,非要先返回第二个接口然后再返回第一个接口,但配置描述符后面总归先是接口描述符然后是端点描述符。
267行,buffer里保存的就是GET_DESCRIPTOR请求获得的数据,要解析这些数据,不可避免地要对buffer指针进行操作,这里先将它备份。
278行,config是参数中传递过来的,是设备struct usb_device结构体中的struct usb_host_config结构体数组config中的一员。不出意外的话,buffer的前USB_DT_CONFIG_SIZE个字节对应的就是配置描述符,那么这里的意思就很明显了。
然后检验,查看这USB_DT_CONFIG_SIZE字节的内容究竟是不是正如我们所期待的那样是一个配置描述符,如果不是,那buffer里的数据问题可就大了,没什么利用价值了,还是返回吧,不必要再接着解析了。
288行,buffer的前USB_DT_CONFIG_SIZE个字节已经理清了,接下来该解析剩下的数据了,buffer需要紧跟形势的发展,位置和长度都要做相应的修正。
291行,获得这个配置所拥有的接口数目,不能简单赋值就行了,得知道系统里对这个数目是有USB_MAXINTERFACES这样的限制。如果数目比这个限制还大,就改为USB_MAXINTERFACES。
302行到360行,这函数就是统计记录这个配置里每个接口所拥有的设置数目。所以这里会提醒你,千万别被迷惑了,这个循环里使用的是buffer2和size2,buffer和size的两个替身。
306行,这里遇到一个新的结构struct usb_descriptor_header,在include/linux/usb/ch9.h中定义。
195 struct usb_descriptor_header { 196 __u8 bLength; 197 __u8 bDescriptorType; 198 } __attribute__ ((packed));
这个结构就包括了两个成员,它们的前两个字节都是一样的,一个表示描述符的长度,一个表示描述符的类型。
那么为什么要专门放这么一个结构?试想有一块数据缓冲区,让你判断里面保存的是哪个描述符,或者是其他什么东西,你怎么做?当然可以直接将它的前两个字节内容读出来,判断bDescriptorType,再判断bLength。不过这样的代码就好像你自己画的一副抽象画,太艺术化了,过了若干年连自己都不知道什么意思,更别说别人了。313行,把buffer2指针转化为struct usb_descriptor_header的结构体指针,然后就可以使用‘->’来取出bLength和bDescriptorType。
那么306行就表示如果GET_DESCRIPTOR请求返回的数据里除了包括一个配置描述符外,连两个字节都没有,能看不能用。
321行,如果这是个接口描述符就说明这个配置的某个接口拥有一个设置是没有什么所谓的设置描述符的,一个接口描述符就代表了存在一个设置,接口描述里的bInterfaceNumber会指出这个设置隶属于哪个接口。那么这里除了是接口描述符还有可能是class-和vendor-specific描述符。
325行,既然觉得这是一个接口描述符,就把这个指针转化为struct usb_interface_descriptor结构体指针,你可别被C语言里的这种指针游戏给转晕了,一个地址如果代码不给它赋予什么意义,它除了表示一个地址外就什么都不是。同样一个地址,上面转化为struct usb_descriptor_header结构体指针和这里转化为struct usb_interface_descriptor结构体指针,它就不再仅仅是一个地址,而是代表了不同的含义。
326行,bDescriptorType等于USB_DT_INTERFACE并不说明它就一定是接口描述符了,它的bLength还必须要等于USB_DT_INTERFACE_SIZE。bLength和bDescriptorType一起才能决定一个描述符。
341行到352行,这几行首先要明白n、inu ms和nalts表示什么,n记录的是接口的数目,数组inu ms里的每一项都表示一个接口号,数组nalts里的每一项记录的是每个接口拥有的设置数目,inu ms和nalts两个数组里的元素是一一对应的,inu ms[0]就对应nalts[0],inu ms[1]就对应nalts[1]。其次还要记住,发送GET_DESCRIPTOR请求时,设备并不一定会按照接口1,接口2这样的顺序循规蹈矩地返回数据。
361行,buffer的最后面可能会有一些垃圾数据,为了去除这些垃圾数据,这里需要将size和配置描述符里的wTotalLength修正。
364行,经过上面的循环之后,如果统计得到的接口数目和配置描述符里的bNumInterfaces不符,或者干脆就没有发现配置里有什么接口,就警告。
373行,一个for循环,目的是看一看是不是遗漏了哪个接口号,比如说配置6个接口,每个接口号都应该对应数组inu ms里的一项,如果在inu ms里面没有发现这个接口号,比如2吧,那2这个接口号就神秘失踪了,你找不到接口2。这个当然也属于不规范的,需要警告。
384行,又是一个for循环,USB_MAXALTSETTING的定义在config.c里。
11 #define USB_MAXALTSETTING 128 /* Hard limit */
一个接口最多可以有128个设置。394行根据每个接口拥有的设置数目为对应的intf_cache数组项申请内存。
403行,配置描述符后面紧跟的不一定就是接口描述符,还可能是class-和vendor-specific描述符。不管有没有,先把buffer的地址赋给extra,如果没有扩展的描述符,则404行返回的i就等于0,extralen也就为0。
404行,调用find_next_descriptor()在buffer里寻找配置描述符后面跟着的第一个接口描述符。它也在config.c中定义,进去看一看。
22 static int find_next_descriptor(unsigned char *buffer, int size, 23 int dt1, int dt2, int *num_skipped) 24 { 25 struct usb_descriptor_header *h; 26 int n = 0; 27 unsigned char *buffer0 = buffer; 28 29 /* Find the next descriptor of type dt1 or dt2 */ 30 while (size > 0) { 31 h = (struct usb_descriptor_header *) buffer; 32 if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) 33 break; 34 buffer += h->bLength; 35 size -= h->bLength; 36 ++n; 37 } 38 39 /* Store the number of descriptors skipped and return the 40 * number of Bytes skipped */ 41 if (num_skipped) 42 *num_skipped = n; 43 return buffer - buffer0; 44 }
这个函数需要传递两个描述符类型的参数,32行已经清清楚楚地表明它不是专一地去寻找一种描述符,而是去寻找两种描述符,比如你指定dt1为USB_DT_INTERFACE,dt2为USB_DT_ENDPOINT时,只要能够找到接口描述符或端点描述符中的一个,这个函数就返回。usb_parse_configuration函数在404行只需要寻找下一个接口描述符,所以dt1和dt2都设置为USB_DT_INTERFACE。
这个函数结束后,num_skipped里记录的是搜索过程中忽略的dt1和dt2之外其他描述符的数目,返回值表示搜索结束时,buffer的位置比搜索开始时前进的字节数。其他没什么好讲的,还是回到usb_parse_configuration函数。
410行,根据find_next_descriptor的结果修正buffer和size。你可能对C语言里的按引用传递和按值传递已经烂熟于心,看到find_next_descriptor()那里传递的是buffer,一个指针,条件反射地觉得它里面对buffer的修改必定影响了外面的buffer,所以认为buffer已经指向了寻找到的接口描述符。但是find_next_descriptor里修改的只是参数中buffer的值,并没有修改它指向的内容,对于地址本身来说仍然只能算是按值传递,怎么修改都影响不到函数外边,所以这里的410行仍然要对buffer的位置进行修正。
414行,事不过三,三个for循环之后轮到了一个while循环。如果size大于0,就说明配置描述符后面找到了一个接口描述符,根据这个接口描述符的长度,已经可以解析出一个完整的接口描述符了,但是仍然没到乐观时,这个接口描述符后面还会跟着一群端点描述符,再然后还会有其他接口描述符。
所以我们又迎来了另一个函数——usb_parse_interface,先不管它长什么样子,毕竟usb_parse_configuration()就快到头了,暂时只需要知道它返回时,buffer的位置已经在下一个接口描述符那里了,同理,对buffer地址本身来说是按值传递的,所以420行要对这个位置和长度进行调整以适应新形势。那么这个while循环的意思就很明显了,对buffer一段一段地解析,直到再也找不到接口描述符了。
425行,最后这个for循环没什么实质性的内容,就是找每个接口是不是有哪个设置编号给漏过去了,只要有耐心,你就能看得懂。接下来还是看config.c里的usb_parse_interface()函数。
158 static int usb_parse_interface(struct device *ddev, int cfgno, 159 struct usb_host_config *config, unsigned char *buffer, int size, 160 u8 inu ms[], u8 nalts[]) 161 { 162 unsigned char *buffer0 = buffer; 163 struct usb_interface_descriptor *d; 164 int inum, asnum; 165 struct usb_interface_cache *intfc; 166 struct usb_host_interface *alt; 167 int i, n; 168 int len, retval; 169 int num_ep, num_ep_orig; 170 171 d = (struct usb_interface_descriptor *) buffer; 172 buffer += d->bLength; 173 size -= d->bLength; 174 175 if (d->bLength < USB_DT_INTERFACE_SIZE) 176 goto skip_to_next_interface_descriptor; 177 178 /* Which interface entry is this? */ 179 intfc = NULL; 180 inum = d->bInterfaceNumber; 181 for (i = 0; i < config->desc.bNumInterfaces; ++i) { 182 if (inu ms[i] == inum) { 183 intfc = config->intf_cache[i]; 184 break; 185 } 186 } 187 if (!intfc || intfc->num_altsetting >= nalts[i]) 188 goto skip_to_next_interface_descriptor; 189 190 /* Check for duplicate altsetting entries */ 191 asnum = d->bAlternateSetting; 192 for ((i = 0, alt = &intfc->altsetting[0]); 193 i < intfc->num_altsetting; 194 (++i, ++alt)) { 195 if (alt->desc.bAlternateSetting == asnum) { 196 dev_warn(ddev, "Duplicate descriptor for config %d " 197 "interface %d altsetting %d, skipping\n", 198 cfgno, inum, asnum); 199 goto skip_to_next_interface_descriptor; 200 } 201 } 202 203 ++intfc->num_altsetting; 204 memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE); 205 206 /* Skip over any Class Specific or Vendor Specific descriptors; 207 * find the first endpoint or interface descriptor */ 208 alt->extra = buffer; 209 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 210 USB_DT_INTERFACE, &n); 211 alt->extralen = i; 212 if (n > 0) 213 dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 214 n, plural(n), "interface"); 215 buffer += i; 216 size -= i; 217 218 /* Allocate space for the right(?) number of endpoints */ 219 num_ep = num_ep_orig = alt->desc.bNumEndpoints; 220 alt->desc.bNumEndpoints = 0; // Use as a counter 221 if (num_ep > USB_MAXENDPOINTS) { 222 dev_warn(ddev, "too many endpoints for config %d interface %d " 223 "altsetting %d: %d, using maximum allowed: %d\n", 224 cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS); 225 num_ep = USB_MAXENDPOINTS; 226 } 227 228 if (num_ep > 0) { /* Can't allocate 0 Bytes */ 229 len = sizeof(struct usb_host_endpoint) * num_ep; 230 alt->endpoint = kzalloc(len, GFP_KERNEL); 231 if (!alt->endpoint) 232 return -ENOMEM; 233 } 234 235 /* Parse all the endpoint descriptors */ 236 n = 0; 237 while (size > 0) { 238 if (((struct usb_descriptor_header *) buffer)->bDescriptorType 239 == USB_DT_INTERFACE) 240 break; 241 retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, 242 num_ep, buffer, size); 243 if (retval < 0) 244 return retval; 245 ++n; 246 247 buffer += retval; 248 size -= retval; 249 } 250 251 if (n != num_ep_orig) 252 dev_warn(ddev, "config %d interface %d altsetting %d has %d " 253 "endpoint descriptor%s, different from the interface " 254 "descriptor's value: %d\n", 255 cfgno, inum, asnum, n, plural(n), num_ep_orig); 256 return buffer - buffer0; 257 258 skip_to_next_interface_descriptor: 259 i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, 260 USB_DT_INTERFACE, NULL); 261 return buffer - buffer0 + i; 262 }
171行,传递过来的buffer里开头儿那部分只能是一个接口描述符,所以这里将地址转化为struct usb_interface_descriptor结构体指针,然后调整buffer的位置和size。
175行,“只能是”并不说明“它就是”,只有bLength等于USB_DT_INTERFACE_SIZE才说明USB_DT_INTERFACE_SIZE字节确实是一个接口描述符。否则就没必要再对这些数据进行什么处理了,直接跳到最后吧。先看一看这个函数最后都发生了什么,从新的位置开始再次调用find_next_descriptor()在buffer里寻找下一个接口描述符。
179行,因为数组inu ms并不一定是按照接口的顺序来保存接口号的,inu ms[1]对应的可能是接口1也可能是接口0。所以这里要用for循环来寻找这个接口对应着inu ms里的哪一项,从而根据在数组里的位置获得接口对应的struct usb_interface_cache结构体。usb_parse_ configuration()已经告诉了我们,同一个接口在inu ms和intf_cache这两个数组里的位置是一样的。
191行,获得这个接口描述符对应的设置编号,然后根据这个编号从接口的cache里搜索看这个设置是不是已经遇到过了。如果设置已经遇到过,就没必要再对这个接口描述符进行处理,直接跳到最后。否则就意味着发现了一个新的设置,要将它添加到cache里,并将cache里的设置数目num_altsetting加1。要记住,设置是用struct usb_host_interface结构来表示的,一个接口描述符就对应一个设置。
208行,这段代码很熟悉。现在buffer开头儿的接口描述符已经理清了,现在要解析它后面的那些数据了。先把位置赋给这个刚解析出来的接口描述符的extra,然后再从这个位置开始去寻找下一个距离最近的一个接口描述符或端点描述符。如果这个接口描述符后面还跟有class-或vendor-specific描述符,则find_next_descriptor的返回值会大于0,buffer的位置和size也要进行相应调整,来指向新找到的接口描述符或端点描述符。
这里find_next_descriptor的dt1参数和dt2参数就不再是一样的了,因为如果一个接口只用到端点0,它的接口描述符后面是不会跟有端点描述符的。
219行,获得这个设置使用的端点数目,然后将相应接口描述符里的bNumEndpoints置0,为什么?往下看,USB_MAXENDPOINTS是在config.c中定义的。
12 #define USB_MAXENDPOINTS 30 /* Hard limit */
为什么这个最大上限为30?前面提到过,请参考前面章节的讲解。然后根据端点数为接口描述符里的endpoint数组申请内存。
237行,走到这里,buffer开头儿的那个接口描述符已经理清了,而且也找到了下一个接口描述符或端点描述符的位置,该从这个新的位置开始解析了,于是又遇到了一个似曾相识的while循环。
238行,先判断前面找到的是接口描述符还是端点描述符,如果是接口描述符就中断这个while循环,返回与下一个接口描述符的距离。否则说明在buffer当前的位置上是一个端点描述符,因此就要迎来另一个函数usb_parse_endpoint对紧接着的数据进行解析。usb_parse_endpoint()返回时,buffer的位置已经在下一个端点描述符里了。247行,调整buffer的位置长度,这个while循环也很明显了,对buffer一段一段地解析,直到遇到下一个接口描述符或者已经走到buffer结尾。现在看一看config.c中定义的usb_parse_endpoint函数。
46 static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, 47 int asnum, struct usb_host_interface *ifp, int num_ep, 48 unsigned char *buffer, int size) 49 { 50 unsigned char *buffer0 = buffer; 51 struct usb_endpoint_descriptor *d; 52 struct usb_host_endpoint *endpoint; 53 int n, i, j; 54 55 d = (struct usb_endpoint_descriptor *) buffer; 56 buffer += d->bLength; 57 size -= d->bLength; 58 59 if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE) 60 n = USB_DT_ENDPOINT_AUDIO_SIZE; 61 else if (d->bLength >= USB_DT_ENDPOINT_SIZE) 62 n = USB_DT_ENDPOINT_SIZE; 63 else { 64 dev_warn(ddev, "config %d interface %d altsetting %d has an " 65 "invalid endpoint descriptor of length %d, skipping\n", 66 cfgno, inum, asnum, d->bLength); 67 goto skip_to_next_endpoint_or_interface_descriptor; 68 } 69 70 i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; 71 if (i >= 16 || i == 0) { 72 dev_warn(ddev, "config %d interface %d altsetting %d has an " 73 "invalid endpoint with address 0x%X, skipping\n", 74 cfgno, inum, asnum, d->bEndpointAddress); 75 goto skip_to_next_endpoint_or_interface_descriptor; 76 } 77 78 /* Only store as many endpoints as we have room for */ 79 if (ifp->desc.bNumEndpoints >= num_ep) 80 goto skip_to_next_endpoint_or_interface_descriptor; 81 82 endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; 83 ++ifp->desc.bNumEndpoints; 84 85 memcpy(&endpoint->desc, d, n); 86 INIT_LIST_HEAD(&endpoint->urb_list); 87 88 /* If the bInterval value is outside the legal range, 89 * set it to a default value: 32 ms */ 90 i = 0; /* i = min, j = max, n = default */ 91 j = 255; 92 if (usb_endpoint_xfer_int(d)) { 93 i = 1; 94 switch (to_usb_device(ddev)->speed) { 95 case USB_SPEED_HIGH: 96 n = 9; /* 32 ms = 2^(9-1) uframes */ 97 j = 16; 98 break; 99 default: /* USB_SPEED_FULL or _LOW */ 100 /* For low-speed, 10 ms is the official minimum. 101 * But some "overclocked" devices might want faster 102 * polling so we'll allow it. */ 103 n = 32; 104 break; 105 } 106 } else if (usb_endpoint_xfer_isoc(d)) { 107 i = 1; 108 j = 16; 109 switch (to_usb_device(ddev)->speed) { 110 case USB_SPEED_HIGH: 111 n = 9; /* 32 ms = 2^(9-1) uframes */ 112 break; 113 default: /* USB_SPEED_FULL */ 114 n = 6; /* 32 ms = 2^(6-1) frames */ 115 break; 116 } 117 } 118 if (d->bInterval < i || d->bInterval > j) { 119 dev_warn(ddev, "config %d interface %d altsetting %d " 120 "endpoint 0x%X has an invalid bInterval %d, " 121 "changing to %d\n", 122 cfgno, inum, asnum, 123 d->bEndpointAddress, d->bInterval, n); 124 endpoint->desc.bInterval = n; 125 } 126 127 /* Skip over any Class Specific or Vendor Specific descriptors; 128 * find the next endpoint or interface descriptor */ 129 endpoint->extra = buffer; 130 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 131 USB_DT_INTERFACE, &n); 132 endpoint->extralen = i; 133 if (n > 0) 134 dev_dbg(ddev, "skipped %d descriptor%s after %s\n", 135 n, plural(n), "endpoint"); 136 return buffer - buffer0 + i; 137 138 skip_to_next_endpoint_or_interface_descriptor: 139 i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, 140 USB_DT_INTERFACE, NULL); 141 return buffer - buffer0 + i; 142 }
55行,buffer开头儿只能是一个端点描述符,所以这里将地址转化为struct usb_endpoint_ descriptor结构体指针,然后调整buffer的位置和size。
59行,这里要明白的是端点描述符与配置描述符、接口描述符不一样,它是可能有两种大小的。
70行,得到端点号。这里的端点号不能为0,因为端点0是没有描述符的,也不能大于16。
79行,这个bNumEndpoints在usb_parse_interface()的220行是被赋为0值了的。
82行,这个endpoint数组在usb_parse_interface()的230行也是已经申请好内存了的。从这里你应该明白bNumEndpoints是被当成了一个计数器,发现一个端点描述符,它就加1,并把找到的端点描述符复制到设置的endpoint数组里。
86行,初始化端点的urb队列urb_list。
88行到125行,这堆代码的目的是处理端点的bInterval,先得明白几个问题。第一个问题就是i,j,n分别表示什么。90行到117行这么多行的代码就为了给它们选择一个合适的值,i和j限定了bInterval的一个范围,bInterval如果在这里面,像124行做的那样将n赋给它,那么n表示的就是bInterval的一个默认值。i和j的默认值分别为0和255,也就是说合法的范围默认是0~255。对于批量端点和控制端点,bInterval对我们来说并没有太大的用处,不过协议中还是规定了,这个范围只能为0~255。对于中断端点和等时端点,bInterval表演的舞台就很大了,对这个范围也要做一些调整。
第二个问题就是如何判断端点是中断的还是等时的。这涉及两个函数usb_endpoint_xfer_int和usb_endpoint_xfer_isoc,它们都在include/linux/usb.h中定义。
596 static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) 597 { 598 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 599 USB_ENDPOINT_XFER_INT); 600 } 601 609 static inline int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) 610 { 611 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 612 USB_ENDPOINT_XFER_ISOC); 613 }
这两个函数的意思简单明了,另外两个函数就是usb_endpoint_xfer_bulk和usb_endpoint_ xfer_control,用来判断批量端点和控制端点的。
第三个问题是to_usb_device。usb_parse_endpoint()的参数是struct device结构体,要获得设备的速度就需要使用to_usb_device将它转化为struct usb_device结构体,这是一个include/ linux/usb.h中定义的宏:
410 #define to_usb_device(d) container_of(d, struct usb_device, dev)
接着看usb_parse_endpoint的129行,现在你对这几行的意思明白了。这里接着在buffer里寻找下一个端点描述符或者接口描述符。
经过usb_parse_configuration、usb_parse_interface和usb_parse_endpoint这三个函数的层层推进,通过GET_DESCRIPTOR请求所获得那堆数据现在已经解析地清清白白。现在,设备的各个配置信息已经了然于胸,那接下来设备的那条生命线该怎么去走?它已经可以进入Configured状态了吗?事情没这么简单,光是获得设备各个配置信息没用,要进入Configured状态,你还得有选择、有目的、有步骤、有计划地去配置设备,那怎么才做到?这好像就不是Core能够答复的问题了,毕竟它并不知道你希望设备采用哪种配置,只有设备的驱动才知道,所以接下来设备要做的是去在设备模型中寻找属于自己的驱动。
不要忘记设备的struct usb_device结构体在出生时就带有usb_bus_type和usb_device_type这样的“胎记”,Linux设备模型根据总线类型usb_bus_type将设备添加到USB总线的那条有名的设备链表里,然后去轮询USB总线的另外一条有名的驱动链表,针对每个找到的驱动去调用USB总线的match函数,也就是usb_device_match()函数,去为设备寻找另一个匹配的驱动。match函数会根据设备的自身条件和类型usb_device_type安排设备走设备链表,从而匹配到那个对所有usb_device_type类型的设备都来者不拒的“花心大萝卜”——USB世界里唯一的一个USB设备驱动(不是USB接口驱动)struct device_driver结构体对象usb_generic_driver。