注:完整代码及其配置文件信息见最后
一、确定读取方式
正常情况下有两种读取方式,一种是通过IO端口直接读取配置空间,另一种是通过内存映射MMIO来读取设备信息。
也可以直接通过UEFI Spec提供的Protocol来直接定位拿到键盘设备,这个方法比较简单,后面有时间再介绍。
二、遍历设备类型,找出键盘设备
我们需要判定一个设备是不是键盘,可以根据上图中的08H中的Class Code来判断设备类型,其中Class Code分为三部分:
(1)Base Class:位于Class Code的高8位
(2)Sub-Class:位于Class Code的中8位
(3)Prog. I/F:位于Class Code的低8位
下表中表示出了Class Code具体的设备类型码:
从上述我们得知,键盘属于输入设备,因此ClassCode中的Base Class应该属于0x09
根据Base Class,接着读取Sub-Class,可以得知键盘设备的Sub-Class位0x00
因此可以通过0x09 0x00拿到键盘控制器Keyboard controller
三、读取键盘设备信息
【尚未完成】拿到键盘控制器之后,可以扫描该键盘控制器下的设备,查看是否存在键盘设备,拿到键盘设备的Handle。
下图中显示了PCI的配置空间,通过配置空间可以读取键盘信息:
四、代码
Get-USB-Keyboard-Info.h
#ifndef GET_USB_KEYBOARD_INFO_H
#define GET_USB_KEYBOARD_INFO_H
#include<Uefi.h>
#include<Library/IoLib.h>
#include<Library/UefiLib.h>
#define PCI_CONFIGURATION_ADDRESS_PORT 0xCF8
#define PCI_CONFIGURATION_DATA_PORT 0xCFC
#define PCIADDR_IO(B,D,F,OFF) ( 0x80000000 + ((B)<<16) +((D)<<11) + ((F)<<8) +((OFF)&0xFC) )
#define PCIADDR_MMIO(B,D,F,OFF) ( 0x80000000+ ((B)<<20) + ((D)<<15)+ ((F)<<12) + OFF )
UINT8 PCIRead8( UINT32 Bus, UINT32 Device, UINT32 Func, UINT8 OFF );
UINT8 PCIRead16( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF );
#endif
Get-USB-Keyboard-Info.c
#include "Get-USB-Keyboard-Info.h"
UINT8 PCIRead8_Byte0 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead8 ( PCI_CONFIGURATION_DATA_PORT );
}
UINT8 PCIRead8_Byte1 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead8 ( PCI_CONFIGURATION_DATA_PORT + 1 );
}
UINT8 PCIRead8_Byte2 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead8 ( PCI_CONFIGURATION_DATA_PORT + 2 );
}
UINT8 PCIRead8_Byte3 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead8 ( PCI_CONFIGURATION_DATA_PORT + 3 );
}
UINT16 PCIRead16_Word0 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead16 (PCI_CONFIGURATION_DATA_PORT);
}
UINT16 PCIRead16_Word1 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead16 (PCI_CONFIGURATION_DATA_PORT +1 );
}
UINT32 PCIRead32 ( UINT32 B, UINT32 D, UINT32 F, UINT8 OFF ) {
IoWrite32 ( PCI_CONFIGURATION_ADDRESS_PORT, PCIADDR_IO(B,D,F,OFF) );
return IoRead32 ( PCI_CONFIGURATION_DATA_PORT );
}
VOID
PrintDeviceInfo ( UINT32 B, UINT32 D, UINT32 F ) {
//define
UINT16 DeviceID = PCIRead16_Word1( B, D, F, 0 );
Print(L"DeviceID:%04x\n",DeviceID);
UINT16 VendorID = PCIRead16_Word0( B, D, F, 0 );
Print(L"VendorID:%04x\n",VendorID);
UINT16 Status = PCIRead16_Word1( B, D, F, 0x04 );
Print(L"Status:%04x\n",Status);
UINT16 Command = PCIRead16_Word0( B, D, F, 0x04 );
Print(L"Command:%04x\n",Command);
UINT32 ClassCode = ( ( PCIRead32( B, D, F, 0x08 ) ) >>8 );
Print(L"ClassCode:%06x\n",ClassCode);
UINT8 RevisionID = PCIRead8_Byte0( B, D, F, 0x08 );
Print(L"RevisionID:%02x\n",RevisionID);
UINT8 BIST = PCIRead8_Byte3( B, D, F, 0x0C );
Print(L"BIST:%02x\n",BIST);
UINT8 HeaderType = PCIRead8_Byte2( B, D, F, 0x0C );
Print(L"HeaderType:%02x\n",HeaderType);
UINT8 LatencyTimer = PCIRead8_Byte1( B, D, F, 0x0C );
Print(L"LatencyTimer:%02x\n",LatencyTimer);
UINT8 CachelineSize = PCIRead8_Byte0( B, D, F, 0x0C );
Print(L"CachelineSize:%02x\n",CachelineSize);
UINT8 BaseAddressRegisters;
Print(L"BaseAddressRegisters:\n");
for(UINT8 i = 0x10; i < 0x28; i+=4 )
{
BaseAddressRegisters = PCIRead8_Byte0( B, D, F, i );
Print(L"%02x ",BaseAddressRegisters);
BaseAddressRegisters = PCIRead8_Byte1( B, D, F, i );
Print(L"%02x ",BaseAddressRegisters);
BaseAddressRegisters = PCIRead8_Byte2( B, D, F, i );
Print(L"%02x ",BaseAddressRegisters);
BaseAddressRegisters = PCIRead8_Byte3( B, D, F, i );
Print(L"%02x",BaseAddressRegisters);
Print(L"\n");
}
UINT32 CardbusCISPointer = PCIRead32( B, D, F, 0x28 );
Print(L"CardbusCISPointer:%08x\n",CardbusCISPointer);
UINT16 SubsystemID = PCIRead16_Word1( B, D, F, 0x2C );
Print(L"SubsystemID:%04x\n",SubsystemID);
UINT16 SubsystemVendorID = PCIRead16_Word0( B, D, F, 0x2C );
Print(L"SubsystemVendorID:%04x\n",SubsystemVendorID );
UINT32 ExpansionROMBaseAddress = PCIRead32( B, D, F, 0x30 );
Print(L"ExpansionROMBaseAddress:%08x\n",ExpansionROMBaseAddress);
UINT8 CapabilitiesPointer = PCIRead8_Byte0( B, D, F, 0x34 );
Print(L"CapabilitiesPointer:%02x\n",CapabilitiesPointer);
UINT8 Max_Lat = PCIRead8_Byte3( B, D, F, 0x3C );
Print(L"Max_Lat:%02x\n",Max_Lat);
UINT8 Min_Gnt = PCIRead8_Byte2( B, D, F, 0x3C );
Print(L"Min_Gnt:%02x\n",Min_Gnt);
UINT8 InterruptPin = PCIRead8_Byte1( B, D, F, 0x3C );
Print(L"InterruptPin:%02x\n",InterruptPin);
UINT8 InterruptLine = PCIRead8_Byte0( B, D, F, 0x3C );
Print(L"InterruptLine:%02x\n",InterruptLine);
}
EFI_STATUS IsUSBKeyBoardDevice(UINT32 B, UINT32 D, UINT32 F) {
UINT8 Class = PCIRead8_Byte3( B, D, F, 0x08 );
UINT8 SubClass = PCIRead8_Byte2( B, D, F, 0x08 );
if ( (Class == 0x09) && (SubClass == 0x00) )
{
Print(L"Check USB Device success \n");
return EFI_SUCCESS;
}
return EFI_LOAD_ERROR;
}
EFI_STATUS EFIAPI
EntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//Bus
for (UINT32 B = 0; B <= 255; B++)
{
//Device
for ( UINT32 D = 0; D <= 31; D++ )
{
//Function
for ( UINT32 F = 0; F <= 7; F++ )
{
// F == 0
if ( F == 0 )
{
//No device
if ( PCIRead32(B, D, F, 0x00) == 0xFFFFFFFF )
{
break;
}// end if
if ( ( PCIRead8_Byte2 (B, D, F, 0x0C) & 0x80 ) == 0)
{//0 signal-function 1 multi-function
Status = IsUSBKeyBoardDevice( B, D, F );
if ( !EFI_ERROR (Status) )
{
PrintDeviceInfo(B, D, F);
}
break;
}
}
if ( PCIRead32 (B, D, F, 0x00) != 0xFFFFFFFF )
{
//Judge device type
Status = IsUSBKeyBoardDevice( B, D, F );
if ( !EFI_ERROR (Status) )
{
PrintDeviceInfo(B, D, F);
}
}
}//Function
}//Device
}//Bus
return Status;
}
Get-USB-Keyboard-Info.inf
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = Get-USB-Keyboard-Info
FILE_GUID = dbe25720-dfb7-45c2-8574-2d3f340483f2
VERSION_STRING = 1.0
MODULE_TYPE = UEFI_APPLICATION
ENTRY_POINT = EntryPoint
[Sources]
Get-USB-Keyboard-Info.c
[Packages]
MdePkg/MdePkg.dec
Pkg/Pkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
IoLib
UefiLib