welfear

welfear的博客

他的个人主页  他的博客

USB除错经历

welfear  2009年08月31日 星期一 23:50 | 2270次浏览 | 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哲思注册吗?现在 注册 !
王单单

回复 王单单  2009年09月01日 星期二 17:56

我靠,辛苦了,哈哈

1条回复

  • welfear

    回复 welfear  2009年09月01日 星期二 22:08

    工作中遇到的奇怪事不少,但很有机会总结。
    仔细想想这些问题都挺有意思。
    无论现象多么不合理,总是会有合理的解释

    0条回复

暂时没有评论

Zeuux © 2024

京ICP备05028076号