一个问题:如何获得 Shell 下面所有 USB 设备的 PID 和 VID ?
首先在网上搜索一下,找到【参考1】,上面使用了 USBIO Protocol。
typedef struct _EFI_USB_IO_PROTOCOL { EFI_USB_IO_CONTROL_TRANSFER UsbControlTransfer; EFI_USB_IO_BULK_TRANSFER UsbBulkTransfer; EFI_USB_IO_ASYNC_INTERRUPT_TRANSFER UsbAsyncInterruptTransfer; EFI_USB_IO_SYNC_INTERRPUT_TRANSFER UsbSyncInterruptTransfer; EFI_USB_IO_ISOCHRONOUS_TRANSFER UsbIsochronousTransfer; EFI_USB_IO_ASYNC_ISOCHRONOUS_TRANSFER UsbAsyncIsochronousTransfer; EFI_USB_IO_GET_DEVICE_DESCRIPTOR UsbGetDeviceDescriptor; EFI_USB_IO_GET_CONFIG_DESCRIPTOR UsbGetConfigDescriptor; EFI_USB_IO_GET_INTERFACE_DESCRIPTOR UsbGetInterfaceDescriptor; EFI_USB_IO_GET_ENDPOINT_DESCRIPTOR UsbGetEndpointDescriptor; EFI_USB_IO_GET_STRING_DESCRIPTOR UsbGetStringDescriptor; EFI_USB_IO_GET_SUPPORTED_LANGUAGES UsbGetSupportedLanguages; EFI_USB_IO_PORT_RESET UsbPortReset; } EFI_USB_IO_PROTOCOL;
来自【参考2】。
我们在实体机上用 dh –p USBIO 命令看一下(注意:EDK自带的模拟环境没有设备挂USBIO 这个 Protocol,所以只能用实体机查看)。可以看到 USB设备上都有这个 Protocol,于是,一切都简单了。
我们再把实体机启动到 Windows中,也是同样的顺序,分别是 USB Hub (这是我外接的一个 USB HUB),USB鼠标,USB键盘(这个键盘是一个复合设备,所以会显示为2个),最后是我的 U盘。多说两句对照上面的截图,我们可以看到USB鼠标上附加了一个 SimplePointer Protocol,键盘上有 TxtinEx/Txtin/ConIn Protocol ,U盘上附加了 DiskIo/BlkIo Protocol,后面我们会分别研究一下这些 Protocol 的使用。
每一个USB设备上都有这个 Protocol 所以我们要用 LocateHandleBuffer 和HandleProtocol 这样的组合把所有有这个 Protocol 的设备都取下来,然后调用 UsbIO 中的UsbGetDeviceDescriptor 即可。
弄清楚原理整个程序还是比较简单的,如下:
#include <Uefi.h> #include <Library/UefiLib.h> #include <Library/ShellCEntryLib.h> #include <Protocol/UsbIo.h> extern EFI_BOOT_SERVICES *gBS; EFI_GUID gEfiUsbIoProtocolGuid = { 0x2B2F68D6, 0x0CD2, 0x44CF, { 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 }}; UINTN GetUSB( ) { EFI_STATUS Status; UINTN HandleIndex, HandleCount; EFI_HANDLE *DevicePathHandleBuffer = NULL; EFI_USB_IO_PROTOCOL *USBIO; EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; Status = gBS->LocateHandleBuffer( ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &HandleCount, &DevicePathHandleBuffer); if (EFI_ERROR(Status)) { Print(L"ERROR : Get USBIO count fail.\n"); return 0; } for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { Status = gBS->HandleProtocol( DevicePathHandleBuffer[HandleIndex], &gEfiUsbIoProtocolGuid, (VOID**)&USBIO); if (EFI_ERROR(Status)) { Print(L"ERROR : Open USBIO fail.\n"); gBS->FreePool(DevicePathHandleBuffer); return 0; } Status = USBIO->UsbGetDeviceDescriptor(USBIO, &DeviceDescriptor); if (EFI_ERROR(Status)) { Print(L"ERROR : Usb Get Device Descriptor fail.\n"); gBS->FreePool(DevicePathHandleBuffer); return 0; } Print(L"VendorID = %04X, ProductID = %04X\n", DeviceDescriptor.IdVendor, DeviceDescriptor.IdProduct); } gBS->FreePool(DevicePathHandleBuffer); return HandleCount; } int EFIAPI main ( IN int Argc, IN CHAR16 **Argv ) { GetUSB( ); return EFI_SUCCESS; }
最终运行结果如下:
完整的代码和程序下载:
GetPIDVID
参考:
1. http://biosren.com/viewthread.php?tid=5925&highlight=usbio 請問如何透過DevicePath獲取對應的device全名?
2. http://wiki.phoenix.com/wiki/index.php/EFI_USB_IO_PROTOCOL EFI USB IO PROTOCOL 同样的,在 UEFI spec中也可以找到上面的定义
請問前輩,有試過使用EDK2的USB IO PROTOCOL,存取USB HID(MCU)裝置嗎?
譬如用usb interrupt transfer,寫值到MCU,MCU再parse資料後做相對應動作。
呃 之前想搞来着,后来发现手上没有合适的开发板。用那个 51的速度太慢,对现在的 chipset 兼容性不好,后来就没有继续。
看前輩有用Arduino,不知道它有沒有USB接口(Arduino),或許可以試試看...
我手邊有Microchip的實驗板,參考前輩的sample code可以讀取USB裝置資訊,
但怎麼用interrupt transfer就不太了解了,,
手邊的AMI BIOS code也找不到相關範例可以參考...
哦 。回头我看一下,主要是EFI Driver 设计我还不懂。前一段看了一个 FT232 UEFI Driver 的项目,还没有实验。
你好,我想请教一个问题,我在使用HandleProtocol或LocateProtocol的时候,总是得到的EFI_STATUS总是错的:0x8000000e。小弟刚入门,还请大哥帮我出坑。感激涕零!
可以用 print %r 来输出 EFI_STATUS 的具体含义,之前的文章有介绍过这个功能,你可以试试。
谢谢您的回复。我有试过,打印的结果为Not Found , 原因应该是和楼下darren所遇到的问题一致。另外,我在尝试 EFI_PCI_IO_PROTOCOL 和 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL 这两个pci protocol的时候也是如此情况,Not Found。但是有些Protocol是可以用的,如:BLOCKIO 和 SIMPLE FILE SYSTEM 等。综上我有一个理解上的问题:
在NT32环境中有些程序无出现Not Found,是NT32环境中没有对应Protocol,还是没有设备挂载这个Protocol?
请您帮我释疑,万分感激。
NT32 本质是模拟出来的虚拟机,很多硬件没有做到,就是说没有设备挂这个这个 Protocol 然后也就没有对应的 Protocol 了。
请问是不是在,EDKII 模拟环境下,这个USB demo程序也是没办法运行的 ? 是不是也是在拟环境没有设备挂USBIO Protocol 这个原因造成的?
是啊 NT32 中没有 USBIO 必须在实体机才行
你好, 我在模拟的板子, 最后会boot到shell envorinment
Edk2\ShellPkg\Application\Shell\Shell.c
目前问题是在Shell环境键盘没有回应
我参考你的方式在Shell.c UefiMain 尝试去LocateHandleBuffer
结果发现Get USBIO count fail
追到最后发现
CoreLocateHandleBuffer
CoreLocateHandle
//
// Look up the protocol entry and set the head pointer
//
Position.ProtEntry = CoreFindProtocolEntry (Protocol, FALSE);
if (Position.ProtEntry == NULL) {
Status = EFI_NOT_FOUND;
break;
}
这段回传 EFI_NOT_FOUND;
看起来是mProtocolDatabase 里面找不到gEfiUsbIoProtocolGuid
不太理解为什么会找不到, gEfiUsbIoProtocolGuid前面应该很多地方有去Locate
不知道大大有没有什么想法or方向
你说的模拟的板子是什么意思?是模拟器吗?模拟器不一定有 USBIO 这个Protocol
是的, 用的是Simics模擬器, 但不確定是模擬器本身沒有Usb controller 還是Bios Code 問題, 目前就開到shell, keyboard無法輸入, 所以用cmd drivers去檢查
目前想法是Shell.c 去list 所有的handle 以及 protocol
還是有其他的方式去驗證呢?
这种模拟器应该能支持其他形式的键盘吧,如果能输入命令可以试试检查有没有 usb controller
目前手邊沒有PS2鍵盤, 我使用
Status = gBS->LocateHandleBuffer (
AllHandles,
NULL,
NULL,
&HandleCount,
&HandleBuffer);
ProtocolsPerHandle(HandleBuffer, &ProtocolBuffer, &ProtocolCount);
列出所有handle下所掛的protocol GUID 以及Name
把這功能寫成Application 在Notebook 上跑可以找到UsbIo 和Controller Protocol, 寫在模擬器上Shell.c嘗試log 則都沒有Usb相關的Protocol
代表模擬器沒有USB Controller? 還是可能BIOS某些地方沒設定好呢?
謝謝
我找人问问哈,晚点答复你
我找人问了一下,说是 Simics 可以模拟 USB Controller ,但是怎么开需要看具体环境。建议你再找人问问。
謝謝! 我後來去掃PCI Device, 的確有USB Controller 沒錯, 目前懷疑是某個usb controller protocol 沒有正確初始化,持續Debug..
getpidvid.efi程序在 UEFI SHELL X64 跑不了, 提示:
Image type IA32 is not supported by this X64 shell
这个文章比较老了,当时在 IA32 下编译的。你重新在 X64 下编译应该可以运行(因为你的环境是 X64 )