标题:
Linux那些事儿 之 戏说USB(32)设备的生命线(十一)
[打印本页]
作者:
bingchentiao
时间:
2013-5-23 10:19
标题:
Linux那些事儿 之 戏说USB(32)设备的生命线(十一)
现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符、接口描述符还是端点描述符都不分男女不分彼此的挤在一起,这放在今天当然是有伤风化的,再说群租也是要禁止的,所以得想办法将它们给分开,丁是丁卯是卯的,于是usb_parse_configuration()和上海的那个群租管理条例一起登上了历史舞台,显然它们两个不管是谁想简短几句就搞定是不可能的,不过也没什么可怕的,咱写不会,看还不会么?和mm打交道,要记住一点:做不到健谈,就装酷,说话不会,闭嘴还不会么?
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
inums[
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 (inums[
i
] == inum)
343
break;
344
}
345
if (
i
< n) {
346
if (nalts[
i
] < 255)
347
++nalts[
i
];
348
} else if (n <
USB_MAXINTERFACES
) {
349
inums[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 (inums[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, inums[
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
, inums, 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, inums[
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这样的限制的。世青赛限制了年龄必须在20岁以下,大牌们想参加怎么办,改年龄啊,把年龄改成20不就符合标准了,这里也是,如果数目比这个限制还大,就改为USB_MAXINTERFACES。
302~360行,这函数真是酷到家了,连里面一个循环都这么长这么酷,不过别看它cool,完成的事情却很单一,就是统计记录一下这个配置里每个接口所拥有的设置数目。俺
喝水只喝纯净水,牛奶只喝纯牛奶,所以俺很单纯,也很善良,所以这里会提醒你一下,
千万别被写代码的哥们儿给迷惑了,这个循环里使用的是buffer2和size2, buffer和size的两个替身,专门拍飚车跳崖什么刺激镜头的角色,拍完了就得收拾行李走人连演员列表都进不去淹死了也没人给你道歉的那种,buffer和size就停在302行享受阳光海滩,等着拍下面的吻戏床戏,同样很刺激的那种镜头。
306行,这里遇到一个新的结构struct usb_descriptor_header,在include/linux/usb/ch9.h里定义
194
/* All standard descriptors have these 2 fields at the beginning */
195
struct
usb_descriptor_header
{
196
__u8
bLength;
197
__u8
bDescriptorType;
198
}
__attribute__
((packed));
这个结构比俺还单纯,就包括了两个成员,你研究一下所有的那些标准描述符,会兴奋的发现它们的前两个字节都是一样的,一个表示描述符的长度,一个表示描述符的类型,就好像你顺着族谱向前研究那么几十代几百代,兴奋的发现自己原来和贝克汉姆巴菲特是同一个祖先一样,但是如果认为自己可以像贝克汉姆那样踢球像巴菲特那样炒股那就错了。那么为什么要专门搞这么一个结构?试想一下,有块数据缓冲区,让你判断一下里面保存的是哪个描述符,或者是其它什么东西,你怎么做?你当然可以直接将它的前两个字节内容读出来,判断判断bDescriptorType,再判断判断bLength,不过这样的代码就好像你自己画的一副抽象画,太艺术化了,过个若干年自己都不知道啥意思,更别说别人了,你纵使不能像linus那样写程序,可也别不拿豆包当干粮不拿看你代码的人当回事儿。写C不是写机器码,尽折腾那些原始的二进制数据。313行做了个很好的示范,把buffer2指针转化为struct usb_descriptor_header的结构体指针,然后就可以使用‘->’来取出bLength和bDescriptorType,这样写的人顺心看的人舒心,你好我好大家好。
那么306行就表示如果GET_DESCRIPTOR请求返回的数据里除了包括一个配置描述符外,连两个字节都没有,那就说明这个配置在进行裸体行为艺术,能看不能用。
321行,如果这是个接口描述符就说明这个配置的某个接口拥有一个设置,是没有什么所谓的设置描述符的,一个接口描述符就代表了存在一个设置,接口描述里的bInterfaceNumber会指出这个设置隶属于哪个接口。那么这里除了是接口描述符还有可能是什么?还有可能是class-和vendor-specific描述符。
325行,既然觉得这是个接口描述符,就把这个指针转化为struct usb_interface_descriptor结构体指针,你可别被C里的这种指针游戏给转晕了,一个地址如果代码不给它赋予什么意义,它除了表示一个地址外就什么都不是,就好像单单说外滩3号外滩9号什么的,你除了知道它是外滩那边的一个地址外一点概念都没有,但是如果你取google一下或者无聊的去看一下里边儿都有些什么东西,它在你的头脑里就不再仅仅是一个地址。同样一个地址,上面转化为struct usb_descriptor_header结构体指针和这里转化为struct usb_interface_descriptor结构体指针,它就不再仅仅是一个地址,而是代表了不同的含义,外滩3号里可以卖阿玛尼开Jean Georges也可以堆10顿洋垃圾,就看它被赋予了什么。
326行,仍然不忘保持革命斗争警惕性,年轻单纯期待富婆生活的少女们要记住并不是谁说他是富商他就是富商的,他还有可能是骗子。这里我们也要记住,骑白马的不一定是王子,他还可能是唐僧;带翅膀的也不一定是天使,妈妈说,那是鸟人;bDescriptorType等于USB_DT_INTERFACE并不说明它就一定是接口描述符了,它的bLength还必须要等于USB_DT_INTERFACE_SIZE。bLength和bDescriptorType一起才能决定一个描述符。
341~352这几行是用来考验咱们的耐心和勇气的,作为一个男人当然会去努力弄懂它,时代在变,时代女性对男人的要求也在变:
做男人得做金刚那样的男人
——
在世界最高的大楼上为心爱的女人打飞机
。要做这样一个顺应潮流的男人首先要明白n、inums和nalts这几个枯燥的东东是表示什么的,n记录的是接口的数目,数组inums里的每一项都表示一个接口号,数组nalts里的每一项记录的是每个接口拥有的设置数目,inums和nalts两个数组里的元素是一一对应的,inums[0]就对应nalts[0],inums[1]就对应nalts[1]。其次还要谨记一个残酷的事实,发送GET_DESCRIPTOR请求时,设备并不一定会按照接口1,接口2这样的顺序循规蹈矩的返回数据,虽说协议里是这么要求的,但都在江湖行走谁能没点个性。
361行,buffer的最后边儿可能会有些垃圾数据,为了去除这些洋垃圾,这里需要将size和配置描述符里的那个wTotalLength修正一下。借此地呼吁一下:抵制洋垃圾,从现在人人做起。
364行,经过上面那个超酷的循环之后,如果统计得到的接口数目和配置描述符里的bNumInterfaces不符,或者干脆就没有发现配置里有什么接口,就警告一下。
373行,又一个for循环,目的是看看是不是遗漏了哪个接口号,比如说配置6个接口,为什么是6那,因为俺的幸运数字是6,呵呵,每个接口号都应该对应数组inums里的一项,如果在inums里面没有发现这个接口号,比如2吧,那2这个接口号就神秘失踪了,你找不到接口2。这个当然也属于违章驾驶,需要警告一下,开票罚600,不开票罚200,你自己选。
384行,再一个for循环,struct usb_interface_caches做嘛用的早就说过了,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
inums[],
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 (inums[
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行,因为数组inums并不一定是按照接口的顺序来保存接口号的,inums[1]对应的可能是接口1也可能是接口0,所以这里要用for循环来寻找这个接口对应着inums里的哪一项,从而根据在数组里的位置获得接口对应的struct usb_interface_cache结构体。usb_parse_configuration()已经告诉了我们,同一个接口在inums和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
}
一个一个变态的函数看过来,到现在都已经麻木了,古语云,生活就像被强奸,如果无力反抗就闭上眼睛享受吧。遇到现在这种鬼天气,你可以骂老天“
你让夏天和冬天同房了吧?生出这鬼天气。”但是遇到这种函数,你谁都不能骂,对
linus
,对
Greg
,对
Alan
,你有的只能是崇敬。
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,并把找到的端点描述符copy到设置的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里定义
589
/**
590
* usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
591
* @epd: endpoint to be checked
592
*
593
* Returns true if the endpoint is of type interrupt, otherwise it returns
594
* false.
595
*/
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
602
/**
603
* usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
604
* @epd: endpoint to be checked
605
*
606
* Returns true if the endpoint is of type isochronous, otherwise it returns
607
* false.
608
*/
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
}
这俩函数so直白,一点都不含蓄,你根本不用去猜它们的心思就能明明白白了。一桌麻将还差两个,另外两个就是
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
)
OK,接着继续看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
。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0