UEFI开发探索86- YIE002USB开发板(09 UEFI对USB的支持1)

请保留-> 【原文:  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。

图1 UEFI中的USB驱动协议栈

平台硬件的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主控制器包括:

  1. Open Host Controller Interface (OHCI) (USB 1.0 and USB 1.1)
  2. Universal Host Controller Interface (UHCI) (USB 1.0 and USB 1.1)
  3. Enhanced Host Controller Interface (EHCI) (USB 2.0)
  4. 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了。限于篇幅,这部分的内容在下一篇博客中描述。

59 total views, 1 views today

发表评论

电子邮件地址不会被公开。