版本1: 发现错误描述符报错返回
版本2: 版本1产生的内核OOPS问题解决
--------------------------------------------------------------------------------------
版本1:
这次USB主要改变了linux-2.6.29-0xlab\drivers\usb\core\config.c文件
1.修改usb_parse_configuration函数在发现描述符长度不合法时的处理,
旧的是breakt跳出循环,新的是返回EAGAIN(再处理一次)
修改前:
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
break;
}
修改后:
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
return EAGAIN;
}
2.修改usb_get_configuration函数中调用usb_parse_configuration函数返回结果的处理
旧的只有当结果为负值时,做错误处理;新的增加了一个返回EAGAIN时重复操作处理
(设置为最多3次,经过测试,基本2次以内可以得到合法的操作符)
修改前:
if (result < 0) {
++cfgno;
goto err;
}
修改后:(增加对返回EAGAIN的处理)
if (result < 0) {
++cfgno;
goto err;
}
if (EAGAIN == result){
times++;
if(2 == times){
times = 0;
cfgno++;
}
cfgno--;
} /*通过减少cfgno配置的下标达到重复的目的,当重复两次后,cfgno的值不变
达到跳到下一个配置的处理*/
------------------------------------------------------------------------------------------
版本2:
1.USB遗留问题:
上次解决重新获取描述符的方法是采用在发现错误的时候报错返回,再限制对报错处理的次数来解决问题.
但是这样遗留下了一个很重要的问题,就是当出错次数超过报错次数的时候(即没有对错误做处理),这时候
会产生内核OOPS,报错情况如下:
Console: switching to colour frame buffer device 100x30
usb 1-1: config 1 has an invalid descriptor of length 0, skipping remainder of the config
usbcore: bogus descriptor, type 0 length 0
usb 1-1: New USB device found, idVendor=1a40, idProduct=0101
usb 1-1: New USB device strings: Mfr=0, Product=1, SerialNumber=0
usb 1-1: Product: USB 2.0 Hub [MTT]
Unable to handle kernel NULL pointer dereference at virtual address 0000000d
pgd = c0004000
[0000000d] *pgd=00000000
Internal error: Oops: 5 [#1]
Modules linked in:
CPU: 0 Not tainted (2.6.29-omap1 #41)
PC is at usb_choose_configuration+0x6c/0x1c8
LR is at 0x32
pc : [<c0230d78>] lr : [<00000032>] psr: 20000013
sp : cf96bdc0 ip : 000001f8 fp : cf96bde4
r10: c0473670 r9 : 00000002 r8 : 00000000
r7 : 00000001 r6 : 00000000 r5 : cf9a3c00 r4 : 00000000
r3 : 00000008 r2 : cf931200 r1 : 00000000 r0 : 00000001
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c5387d Table: 80004019 DAC: 00000017
2.遗留问题解决办法:
通过采用限制发现报错返回次数,并对报错做处理(次数不限),来达到重新获取描述符的目的.
即把限制重新获取描述符的限制条件转移到发现错误的地方.
a) 旧的解决方法:
usb_parse_configuration函数中发现错误并返回:
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
return EAGAIN;
} /* 发现错误并报错*/
usb_get_configuration函数获取usb_parse_configuration的错误返回,并错误处理,次数限制为2次:
if (result < 0) {
++cfgno;
goto err;
}
if (EAGAIN == result){
times++;
if(2 == times){
times = 0;
cfgno++;
}
cfgno--;
} /*通过减少cfgno配置的下标达到重复的目的,当重复两次后,cfgno的值不变
达到跳到下一个配置的处理*/
b) 新的解决办法:
usb_parse_configuration函数中发现错误并限制错误返回次数(超过次数则继续按原来USB的流程走),
次数增加到3次:
header = (struct usb_descriptor_header *) buffer2;
if ((header->bLength > size2) || (header->bLength < 2)) {
dev_warn(ddev, "config %d has an invalid descriptor "
"of length %d, skipping remainder of the config\n",
cfgno, header->bLength);
if(3 == times){
times = 0;
break;
} /* 限制出错返回次数为3次*/
times++;
return EAGAIN; /* 发现错误前三次报错返回 */
}
usb_get_configuration函数获取usb_parse_configuration的错误返回,并错误处理:
result = usb_parse_configuration(&dev->dev, cfgno,
&dev->config[cfgno], bigbuffer, length);
if (result < 0) {
++cfgno;
goto err;
}
if (EAGAIN == result){
cfgno--;
} /* 对发现错误描述符时做错误处理 */