UEFI开发探索87

您所在的位置:网站首页 华秋pcb官网入口 UEFI开发探索87

UEFI开发探索87

2024-06-05 15:00| 来源: 网络整理| 查看: 265

(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)

YIE002USB开发板之UEFI对USB的支持2 3 EFI_USB_IO_PROTOCOL4 使用USB Protocol

3 EFI_USB_IO_PROTOCOL

EFI_USB_IO_PROTOCOL由USB总线驱动产生,可由UEFI应用和驱动使用,用来访问各种USB设备,比如USB键盘、鼠标和大容量存储设备等。EFI_USB_IO_PROTOCOL所提供的接口,可提供四种类型的传输方式与USB设备通信,即之前介绍过的控制传输、中断传输、批量传输和实时传输。

EFI_USB_IO_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; //重启USB控制器 } EFI_USB_IO_PROTOCOL;

对照之前介绍过的USB协议的知识,很容易理解EFI_USB_IO_PROTOCOL所提供的各类接口函数。下面主要介绍下常用的两个接口函数,UsbGetDeviceDescriptor()和UsbControlTransfer(),其他接口函数的说明,请查询UEFI Spec。

**接口函数UsbGetDeviceDescriptor()**用来获取USB设备的设备描述符,其原型如下所示。

typedef EFI_STATUS (EFIAPI *EFI_USB_IO_GET_DEVICE_DESCRIPTOR) ( IN EFI_USB_IO_PROTOCOL *This, //Protocol实例 OUT EFI_USB_DEVICE_DESCRIPTOR *DeviceDescriptor //设备描述符指针变量 ); typedef struct { UINT8 Length; //描述符长度(0x12) UINT8 DescriptorType; //描述符类型(0x01) UINT16 BcdUSB; //USB设备支持的协议版本号 UINT8 DeviceClass; //类代码 UINT8 DeviceSubClass; //子类代码 UINT8 DeviceProtocol; //协议码 UINT8 MaxPacketSize0; //端点0最大包长度 UINT16 IdVendor; //厂商ID UINT16 IdProduct; //产品ID UINT16 BcdDevice; //设备发行号 UINT8 StrManufacturer; //厂商信息 UINT8 StrProduct; //产品信息 UINT8 StrSerialNumber; //设备序列号 UINT8 NumConfigurations;//配置描述符数目 } EFI_USB_DEVICE_DESCRIPTOR;

UsbGetDeviceDescriptor()所获取的设备描述符,各成员变量与第82篇中介绍的描述符是完全一致的,对照着看,很容易理解。

而接口函数UsbControlTransfer()用来进行控制传输,包括USB标准命令、类命令,都是通过控制传输来进行的。其函数接口原型为:

typedef EFI_STATUS (EFIAPI *EFI_USB_IO_CONTROL_TRANSFER) ( IN EFI_USB_IO_PROTOCOL *This, //Protocol实例 IN EFI_USB_DEVICE_REQUEST *Request, //USB命令(标准命令、类命令、厂商命令) IN EFI_USB_DATA_DIRECTION Direction,//方向 IN UINT32 Timeout, //超时时间,单位为毫秒 IN OUT VOID *Data OPTIONAL, //发往或接收自USB设备的数据缓冲区 IN UINTN DataLength OPTIONAL, //数据缓冲区的长度 OUT UINT32 *Status //USB传输的结果 ); typedef enum { EfiUsbDataIn, //接收自USB设备,即从USB设备往USB主机发送 EfiUsbDataOut, //发往USB设备,即从USB主机发往USB设备 EfiUsbNoData } EFI_USB_DATA_DIRECTION; typedef struct { UINT8 RequestType; //命令类型 UINT8 Request; //命令序号 UINT16 Value; //不同的命令,含义不同 UINT16 Index; //不同的命令,含义不同 UINT16 Length; //如果有数据阶段,此字段为数据的字节数 } EFI_USB_DEVICE_REQUEST; //USB命令结构体

UsbControlTransfer()搭建了USB设备驱动与USB设备间的传输通道。从函数原型可以看出,它主要的功能就是用来执行各类USB命令,包括USB标准命令、类命令和厂商命令。其参数Request的数据结构,与UEFI探索系列博客的第84篇给出的USB命令的结构是完全一样的,含义也完全相同。

参数Status给出的是USB传输的结果,与函数执行返回值是不一样的。函数返回值用来反映函数执行情况,比如参数是否错误、执行是否超时等。而参数Status给出的传输中错误的类型,比如CRC校验错误等,Status可能的值如下所示:

#define EFI_USB_NOERROR 0x0000 #define EFI_USB_ERR_NOTEXECUTE 0x0001 #define EFI_USB_ERR_STALL 0x0002 #define EFI_USB_ERR_BUFFER 0x0004 #define EFI_USB_ERR_BABBLE 0x0008 #define EFI_USB_ERR_NAK 0x0010 #define EFI_USB_ERR_CRC 0x0020 #define EFI_USB_ERR_TIMEOUT 0x0040 #define EFI_USB_ERR_BITSTUFF 0x0080 #define EFI_USB_ERR_SYSTEM 0x0100 4 使用USB Protocol

EFI_USB2_HC_PROTOCOL和EFI_USB_IO_PROTOCOL的用法,实际上与之前博客介绍的PCI Protocol、SMBUS Protocol等差不多。基本的使用过程包括:

添加支持USB访问的头文件,包括UsbHostController.h和UsbIo.h;在INF文件的[Protocols] Section部分添加支持USB访问Protocol的GUID,包括 gEfiUsbIoProtocolGuid和gEfiUsb2HcProtocolGuid;编写获取Protocol实例的函数。

下面给出了一个例子,数组gUsb2HC[]和gUsbIO[]中包括了EFI_USB2_HC_PROTOCOL和EFI_USB_IO_PROTOCOL的实例,可以直接使用它们来获取USB主控制器信息和USB设备信息。

示例1 获取USB主控制器信息

VOID lsUsb2HC(void) { EFI_STATUS Status; UINTN i; UINT8 maxSpeed,portNumber,is64BC; EFI_USB_HC_STATE state; CHAR16 *speed[]={L"FULL ",L"LOW ",L"HIGH ",L"SUPER"}; CHAR16 *hcState[]={L"Halt",L"Operational",L"Suspend"}; if(gUsb2HCCount == 0) //没有Protocol实例,直接退出 return; Print(L"Usb HC: %d \n",gUsb2HCCount); Print(L"No. MaxSpeed PortNumber Is64BitCapable State\n"); for(i=0;iGetCapability(gUsb2HC[i],&maxSpeed, \ &portNumber,&is64BC); //获取属性 if(EFI_ERROR(Status)) Print(L"???"); else Print(L"%*S %*d %*d ",8,speed[maxSpeed],10,portNumber,14,is64BC); Status = gUsb2HC[i]->GetState(gUsb2HC[i],&state); //获取状态 if(EFI_ERROR(Status)) Print(L" ???\n"); else Print(L"%S \n",hcState[state]); } }

函数的逻辑比较简单,主要是调用EFI_USB2_HC_PROTOCOL的接口函数GetCapability()和GetState(),得到USB主控制器的属性和状态。

获取USB设备信息的方式类似,使用EFI_USB_IO_PROTOCOL的接口函数UsbGetDeviceDescriptor(),得到USB设备的设备描述符。将设备描述符中的类、子类、厂商ID和产品ID打印出来接口。其实现代码如示例2所示。

示例2 获取USB设备信息

VOID lsUsbIO(void) { EFI_STATUS Status; UINTN i; EFI_USB_DEVICE_DESCRIPTOR UsbDevDesc; if(gUsbIOCount == 0) //没有Protocol实例,直接退出 return; Print(L"Usb device: %d \n",gUsbIOCount); Print(L"No. DevClass SubClass IdVendor IdProduct \n"); for(i=0;iUsbGetDeviceDescriptor(gUsbIO[i], &UsbDevDesc); if(EFI_ERROR(Status)) Print(L"Get Device Descriptor Error!\n"); else { Print(L" %03d %03d ", \ UsbDevDesc.DeviceClass,UsbDevDesc.DeviceSubClass); Print(L" 0x%04x 0x%04x\n", \ UsbDevDesc.IdVendor,UsbDevDesc.IdProduct); } } }

至此,关于UEFI系统中对USB的支持,就介绍完成了。

下一篇,将使用这些知识,构建访问USB HID设备的例程。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3