看图说话:
首先,明确一点,USB设备的驱动都是保存在主机上的,如果主机上没有驱动,那么设备是无法正常工作的。
实际上对于Windows来说,所有设备要想使用,必须在主机上实现装好驱动才行,如果没有,会尝试到网上搜索安装,如果找不到的话,会被作为“不可识别的设备”存在。
对于USB设备来说,它本身首先是一个USB设备,设备插入时USB总线驱动会获得设备的基本描述符信息,并以这些信息查找对应的驱动。
USB设备驱动分为两大类,一类是通用的设备类驱动(class specific),另一类厂商自定义的设备驱动(vendor specific),Windows基本上集成了大部分通用驱动,而很多厂商自定义的设备驱动则需要通过网络或者光盘等事先安装好才行。
我上面截图中,是一个USB鼠标的描述符信息,包括设备描述符和接口描述符(此接口是逻辑层面上的),USB鼠标是通用设备类的设备,蓝色框里的bInterfaceClass是03,表示是HID类的设备,SubClass和Protocol标识了它是一个鼠标,通过这些信息,Windows能识别出这个设备是USB鼠标,在本机查找USB鼠标通用驱动并安装,安装完成后该设备就可以使用了。
如果这个设备碰巧不是一个通用设备类的设备,那么Windows会尝试用设备的VID(idVendor)和PID(idProduct)来匹配驱动,我绿色框里的部分就是这些信息。如果找到了,就安装,如果找不到,就显示设备不可用。
USB无线鼠标跟有线没有本质区别,无线部分是厂商自己实现的,有线部分仍然走的通用的USB协议,如果是蓝牙则是另外的事情(评论里说其实是跟USB HID一样的)。
鼠标的信息本质上是周期性的汇报运动状态,实际上就是按键状态+坐标,主机(Windows)周期性轮询USB鼠标的状态,并在驱动层把这些状态转换成I/O信息,剩下的就是Windows消息栈的事情了,具体就不展开说了,Windows键盘的消息栈大概是这样的(XP时代,Win7以后未分析):
1)硬件中断/硬件端口数据
//WinIO能模拟,或者修改IDT是在这一层
2)键盘Port驱动(USB or PS/2)
//Filter驱动在此
//KeyboardClassServiceCallback也在这一层被调用
3)kbdclass驱动
//处理键盘布局和键盘语言,部分高端的病毒也工作在这里
4)Windows内核边界(zwCreate/zwReadFile)
----------------------(系统调用)----------------------
5)Windows内核边界(zwCreate/zwReadFile)
6)csrss.exe的win32k!RawInputThread读取,完成scancode和vk的转换
//SetWindowHook工作在这里(全局)
//kbd_event工作在这里
7)csrss.exe调用DispatchMessage等函数分发消息
//SetWindowHook工作在这里(进程)
//PostMessage和SendMessage在这里
8)各个进程处理消息