本文简单介绍一下USB设备的驱动程序是如何匹配设备以及被加载的:
上文(UDK中USB总线驱动的实现框架)提到USB总线枚举设备的最后一步是调用gBS->ConnectController()去查找device的驱动并加载。
1.查找驱动:
首先UEFI中所有符合UEFI Driver Model的驱动在模块的入口点,都会去安装EFI_DRIVER_BINDING_PROTOCOL;gBS->ConnectController()会去遍历系统中所有的EFI_DRIVER_BINDING_PROTOCOL,并调用其中的Support函数,来做判断,如果匹配成功,就接着调用Start函数来初始化硬件。
2.举例说明support()是如何匹配driver和device的:
Support()会通过USBDI获取设备的接口描述符InterfaceDescriptor,通过判断接口描述符来判断device的类型,如下:
(1)USB键盘驱动程序:USBKeyboardDriverBindingSupported()
if (InterfaceDescriptor.InterfaceClass == CLASS_HID && //CLASS_HID 3
InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT && //SUBCLASS_BOOT 1
InterfaceDescriptor.InterfaceProtocol == PROTOCOL_KEYBOARD //PROTOCOL_KEYBOARD 1
) {
return TRUE;
}
(2)USB鼠标驱动:
if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) && // CLASS_HID 3
(InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) && // SUBCLASS_BOOT 1
(InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE) // PROTOCOL_MOUSE 2
) {
return TRUE;
}
(3)USB Mass Storage驱动程序:
if (Interface.InterfaceClass != USB_MASS_STORE_CLASS) { // USB_MASS_STORE_CLASS 0x08
goto ON_EXIT;
}
下图是USB Class Codes的分类:
至此,差不多了解了UEFI中USB整个驱动的框架,下面来做个总结,顺便总结一下UEFI的 UEFI Driver Model:
1.符合UEFI Driver Model的模块都会在模块入口点安装EFI_DRIVER_BINDING_PROTOCOL(类似于Linux中的USB设备驱动都会注册usb_driver);
2.只有当内核去调用gBS->ConnectController()的时候,才会去访问EFI_DRIVER_BINDING_PROTOCOL->support(),来为device加载合适的驱动;(这一点与Linux中不同,Linux中每当注册一个usb_driver就会紧接着执行probe函数去查找系统中有没有合适的device);
3.UEFI中的整个USB驱动框架的层次很清晰,必须先加载HCD,然后加载USBD,最后加载USB DEVICE Driver;