welfear 2009年08月31日 星期一 23:50 | 2395次浏览 | 2条评论
总结关于USB设备工作经验。
welfear 2009.6.28
背景
公司客户反馈我们的产品无法识别联想USB键盘。在拿到联想USB键盘后,我使用
UsbView.exe对其进行观察,发现这个键盘没把自己当成键盘。解决问题也很简单,
为特殊客户添加特殊照顾,如果发现是设备的产品描述是联想的,那就放过,不控制。
本来很容易、很普通的工作直到最后完成时才知道事情其实没有那么简单。
知识
USB设备是由系统总线通过主控制器以及根Hub来控制的。根Hub可以连接Hub或者是
具体的USB设备。在每个USB设备中有一个或多个配置来描述其属性。每个配置里
包含一个或多个接口,每个接口里包含一个或多个端点。当然最关键的概念是描述符,
其中一项指明该USB设备属于哪一类
#define USB_DEVICE_CLASS_RESERVED 0x00
#define USB_DEVICE_CLASS_AUDIO 0x01
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
#define USB_DEVICE_CLASS_MONITOR 0x04
#define USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05
#define USB_DEVICE_CLASS_POWER 0x06
#define USB_DEVICE_CLASS_PRINTER 0x07
#define USB_DEVICE_CLASS_STORAGE 0x08
#define USB_DEVICE_CLASS_HUB 0x09
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
如果发现该设备是人机接口设备,比如键盘,那么就应该无条件使其可以正常使用。
如果是别的设备,那么就要根据系统设置的策略加以控制。此结构中还有一项指明了
该设备的产品描述字符的索引,根据索引就可以找到产品描述字符,这也可以作为
判定设备的辅助办法。
问题
联想的USB键盘是用做指纹识别登陆用的高级设备,所以查询出来的类型不是0x3。
但它的产品描述还是很有特点的。我本以为这样就可以完成任务了,但经过测试后,
测试人员告诉我,Vista操作系统需要将近一分钟的时间才能识别该设备并载入驱动。
这里撇开具体的技术细节不谈,当时听到这个描述时我不大相信是软件问题。谁知道
那个机器有什么毛病呢?再亲自体验过后,我开始正视这个问题。问题100%可以重复,
有两个情况可以消除这个现象:
1、解除USB控制的策略。
2、直接杀死产品进程。
分析
上面的两个条件有联系但又没有直接联系。直接杀死进程不会解除策略,因为USB
设备是由驱动控制的。解除策略可以消除现象说明有可能是驱动的问题。开始想法
很乱,也觉得这个问题真的不好找。不管怎么说先从驱动找起,毕竟我修改过它,
而且这个应该新问题。找驱动的问题有两个办法:
1、直接注释掉策略相关的代码。
2、在每个KeWaitForXxx处打印等待消息。
问题和时间有关系所以有可能是在等待,同时问题又很策略有关系,所以去掉相关
代码测试。可即便这样,问题依旧。看来要排除驱动问题只好使用杀手锏了,直接
去掉所有注册表中的UpperFilters和LowerFilters的项,这样驱动的AddDevice就不会
被调用了,也就没有PnP Irp之类的事了。最后,问题还有。
到这里应该排除是驱动引发的问题了,如果我的思路正确,等等,系统中的驱动程序
不只有USB设备管理的,还有系统保护。这些保护包括注册表、文件,有可能是因为
这个键盘特殊,它的登陆程序可能访问了被我们禁止的区域。这样我就又编译了Debug
版本的保护驱动程序,它会把所有被它拒绝的操作都记录下来,结果很令人失望,没
发现什么有规律的或是特殊的操作。
这时,思路应该放宽了。但如果不是驱动程序的问题,一般应用程序怎么改变系统识别
设备的速度呢?如果没有好的想法或思路,那么最直接的做法还是一个个的排除。
回到最出我们得到的两个结论,它们之间表面上没有联系,那么背后的联系有可能就是
问题的原因所在。这样我们就想到了一个思路,一定是有个操作是在解除策略时会取消,
而在直接杀死进程时也会被取消。这个操作就应该是申请系统资源之类的。而申请资源
相关操作一定会在程序初始化时依次完成。那么现在要做的就是二分法排除。每次排除
一半的代码,然后观察现象是否存在。
终于在来到USB设备功能初始化的时候,现象消失了。原来USB功能之前的实现是在
应用层做的。通过注册设备通知消息来控制设备的使用。但之后该用驱动实现后,这段
代码并没有完全去掉。在处理系统发送的设备通知消息时,它采用轮询的策略,轮询
10次,第一次Sleep一秒,第二次两秒......。这样就产生了将近一分钟的等待。
结论
查找错误需要拓宽思路。由于当初一直以为是驱动的问题,所以浪费了很长时间。如果
问题的现象实在令人迷惑,那就多试验几种情形,缩小问题的范围。在排除范围时,刚
开始可以大范围的排除,并且不要遗漏相关程序。最后,当然出错人员需要定力,坚信
自己可以找到问题,排除测试人员和其他开发人员主观干扰。
Zeuux © 2024
京ICP备05028076号
回复 王单单 2009年09月01日 星期二 17:56
回复 welfear 2009年09月01日 星期二 22:08
仔细想想
无论现象