请保留-> 【原文: https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】
通过前面几篇博客,我们制作了具备通信能力的USB HID设备。使用之前写的Windows下的测试工具,设备工作得很好。
同样的,UEFI环境下,也可以编写上位机程序,访问USB HID设备。本篇主要介绍UEFI对USB的支持,包括UEFI的USB驱动架构和提供的USB Protocol。
1 UEFI下的USB驱动协议架构
在UEFI系统中,包含USB主控制器驱动、USB总线驱动和USB设备驱动,它们共同工作构建了UEFI平台的USB驱动协议栈。USB驱动协议栈的模型如图1所示,图中演示了USB驱动的关系和使用的Protocol。
平台硬件的PCI总线上,提供了一个单独的USB控制器。PCI总线驱动为USB主控制器句柄安装Protocol,包括EFI_DEVICE_PATH_PROTOCOL和EFI_PCI_IO_PROTOCOL。而USB主控制器则使用EFI_PCI_IO_PROTOCOL,在其句柄上安装EFI_USB2_HC_PROTOCOL。
USB总线驱动则使用EFI_USB2_HC_PROTOCOL提供的服务,与USB总线上的USB设备进行通信。图1中,USB总线驱动检测到了3个设备,USB键盘、USB鼠标和USB大容量存储设备。USB总线驱动会为这3个设备创建3个子句柄,并且为它们安装Protocol,也即EFI_DEVICE_PATH_PROTOCOL和EFI_USB_IO_PROTOCL。
这些设备会使用其句柄的EFI_USB_IO_PROTOCOL,并产生对应的Protocol。以USB鼠标驱动为例,它会使用EFI_USB_IO_PROTOCOL并且产生EFI_SIMPLE_POINTER_PROTOCOL。
其他的设备处理过程差不多,从图中可以看出它们各自产生的Protocol。
2 EFI_USB2_HC_PROTOCOL
USB主控制器驱动属于设备驱动,遵循UEFI驱动模型。在EDK2的MdeModulePkg中,准备了各类USB主控制器驱动,所支持的USB主控制器包括:
- Open Host Controller Interface (OHCI) (USB 1.0 and USB 1.1)
- Universal Host Controller Interface (UHCI) (USB 1.0 and USB 1.1)
- Enhanced Host Controller Interface (EHCI) (USB 2.0)
- Extended Host Controller Interface (XHCI) (USB 3.0)
USB主机控制器驱动使用EFI_PCI_IO_PROTOCOL提供的服务,并且在主机控制器句柄上安装EFI_USB2_HC_PROTOCOL。我们知道,USB2主控制器是与通用串行总线(USB)连接的硬件组件,它在USB上产生传输事件,并在系统内存和设备之间传输数据。因此,此Protocol一般由USB总线驱动使用,用来管理USB根Hub以及各类USB设备。
EFI_USB2_HC_PROTOCOL的函数接口如下所示。
typedef struct _EFI_USB2_HC_PROTOCOL {
EFI_USB2_HC_PROTOCOL_GET_CAPABILITY GetCapability; //获取USB主控制器的属性
EFI_USB2_HC_PROTOCOL_RESET Reset; //软重启USB主控制器
EFI_USB2_HC_PROTOCOL_GET_STATE GetState; //获取当前USB主控制的状态
EFI_USB2_HC_PROTOCOL_SET_STATE SetState; //设置USB主控制器状态
EFI_USB2_HC_PROTOCOL_CONTROL_TRANSFER ControlTransfer;
//向目标USB设备发送控制传输
EFI_USB2_HC_PROTOCOL_BULK_TRANSFER BulkTransfer;//向目标USB设备发送批量传输
EFI_USB2_HC_PROTOCOL_ASYNC_INTERRUPT_TRANSFER \
AsyncInterruptTransfer; //异步中断传输
EFI_USB2_HC_PROTOCOL_SYNC_INTERRUPT_TRANSFER \
SyncInterruptTransfer; //同步中断传输
EFI_USB2_HC_PROTOCOL_ISOCHRONOUS_TRANSFER \
IsochronousTransfer; //实时传输
EFI_USB2_HC_PROTOCOL_ASYNC_ISOCHRONOUS_TRANSFER
AsyncIsochronousTransfer; //异步实时传输
EFI_USB2_HC_PROTOCOL_GET_ROOTHUB_PORT_STATUS
GetRootHubPortStatus; //获得根USB Hub端口状态
EFI_USB2_HC_PROTOCOL_SET_ROOTHUB_PORT_FEATURE
SetRootHubPortFeature; //设置根USB Hub端口状态
EFI_USB2_HC_PROTOCOL_CLEAR_ROOTHUB_PORT_FEATURE
ClearRootHubPortFeature; //清除特征
UINT16 MajorRevision; //主版本号
UINT16 MinorRevision; //次版本号
} EFI_USB2_HC_PROTOCOL;
在EDK2的目录MdeModulePkg/Bus/Usb/UsbBusDxe下,可以查看USB总线驱动如何使用此Protocol。我们主要使用EFI_USB2_HC_PROTOCOL来枚举USB控制器,要用到的接口函数包括GetCapability()和GetState(),下面介绍这两个函数的用法。
接口函数GetCapability()用来获取主控制器的属性,其函数原型为:
typedef EFI_STATUS (EFIAPI *EFI_USB2_HC_PROTOCOL_GET_CAPABILITY) (
IN EFI_USB2_HC_PROTOCOL *This, //Protocol实例
OUT UINT8 *MaxSpeed, //最大传输速度
OUT UINT8 *PortNumber, //根hub端口号
OUT UINT8 *Is64BitCapable //是否支持64位内存地址
);
#define EFI_USB_SPEED_FULL 0x0000 //全速,12Mb/s
#define EFI_USB_SPEED_LOW 0x0001 //低速,1.5Mb/s
#define EFI_USB_SPEED_HIGH 0x0002 //高速,480Mb/s
#define EFI_USB_SPEED_SUPER 0x0003 //超高速,4.8GMb/s
此函数可通过EFI_USB2_HC_PROTOCOL实例,取得主控制器的属性。其中,MaxSpeed为控制器的最大传输速率,可以是低速、全速、高速和超高速四种之一。PortNumber为根Hub端口后,USB总线驱动在执行总线枚举时需要此参数。而Is64BitCapable用来显示控制器是否支持64位内存访问,主控制器软件可据此判断,是否使用4G以上的内存进行数据传输。
接口函数GetState()用来获得当前USB主控制器状态,其原型如下:
typedef EFI_STATUS (EFIAPI *EFI_USB2_HC_PROTOCOL_GET_STATE) (
IN EFI_USB2_HC_PROTOCOL *This, //Protocol实例
OUT EFI_USB_HC_STATE *State //指向EFI_USB_HC_STATE数据类型,USB主控制器状态
);
typedef enum {
EfiUsbHcStateHalt, //停止状态
EfiUsbHcStateOperational, //运行中的状态
EfiUsbHcStateSuspend, //挂起状态
EfiUsbHcStateMaximum
} EFI_USB_HC_STATE;
USB主控制器可以是三种状态之一:停止、运行和挂起。只有在运行状态,主控制器才可以执行总线通信。当没有发生总线通信3秒以上,主控制器将进入挂起状态,此状态也可以由软件设定。在主控制器硬件重启,或者发生致命错误,比如一致性校验错误,主控制器将进入停止状态。当然,停止状态也可以由软件设定进入。
EFI_USB2_HC_PROTOCOL可以用来获取系统中存在的USB设备,以及其相关的信息。UEFI Shell中,提供了“pci”命令,没有提供对USB设备的信息获取。可以仿照其思想,使用EFI_USB2_HC_PROTOCOL编写获取USB设备的信息。
对于制定USB设备的访问,则需要用到另一个Protocol-EFI_USB_IO_PROTOCOL了。限于篇幅,这部分的内容在下一篇博客中描述。
1,272 total views, 1 views today