本文簡單介紹一下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;