一个问题:如何获得 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中也可以找到上面的定义








































