10

UEFI开发探索73- YIE002USB开发板(02 Windows编程)

 3 years ago
source link: http://yiiyee.cn/blog/2021/01/24/uefi%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a273-yie002usb%e5%bc%80%e5%8f%91%e6%9d%bf%ef%bc%8802-windows%e7%bc%96%e7%a8%8b%ef%bc%89/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

UEFI开发探索73- YIE002USB开发板(02 Windows编程)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

1 HID(人机接口设备)介绍

HID设备是USB规范中最早提出并支持的一种类设备,日常使用的键盘、鼠标等,都属于HID设备,是一种使用非常广泛的USB设备。

HID一开始为USB,但设计为与总线无关。它是为低延迟、低宽带的设备而设计的,在Windows 7以上,也支持蓝牙、I2C、GPIO等HID设备。

当然,我们主要还是研究跨平台的USB HID。

HID包含两个基本概念:报告描述符和报告。报告描述符描述设备支持的数据格式和含义,报告是在设备和软件客户端之间交换的实际数据。

上位机程序和HID设备通过报告来交换数据,上一篇中了解到,有三种报告类型:

输入报告(Input Report): 从HID设备发送到上位机程序的数据,通常在状态发生更改时发送;

输出报告(Output Report):从上位机程序发送到HID设备(比如键盘上的LED状态)数据;

功能报告(Feature Report):通常与配置信息相关。

在报告描述符中,可以定义每种类型的0个或多个报告,通常Input Report至少有一个。

不同的操作系统,对USB HID的支持方式不一样。Windows下有驱动Hidusb.sys支持HID传输,并提供了HID应用程序接口;UEFI的下使用EFI_USB_IO_PROTOCOL构建通信函数;而Linux下则可以使用libusb与HID设备通信。

2 Windows上位机程序UsbHID

为YIE002开发的Windows上位机,我命名为UsbHID。其界面图如图1所示。

图1 UsbHID界面

UsbHID工具运行于Windows系统下, 主要用来在与YIE002进行通信。它将系统中所有能够找到的HID设备以列表的形式显示,用户选择需要通信的设备,再选择三种通信方式中的一种,即可发送数据。

USB通信中,所有的命令都是由主机发出的。USB设备根据主机发出的命令,进行相应的处理。YIE002设计的固件中,对主机发出来的数据,进行了一定的处理并进行回传,以演示双方的通信过程。

YIE002的开发板上,提供了LED灯控制以及随机数生成的功能。上位机可以通过此数据通道,控制LED灯,并获取生成的随机数。

3 Windows系统的HID API

Windows系统上提供的HID应用程序编程接口(API),大致可以分为两类:

I 获取设备属性的函数

HidD _ GetAttributes()
HidD _ GetHidGuid()
HidD _ GetIndexedString()
HidD _ GetManufacturerString()
HidD _ GetPhysicalDescriptor()
HidD _ GetPreparsedData()
HidD _ GetProductString()
HidD _ GetSerialNumberString()
HidD _ GetNumInputBuffers()
HidD _ SetNumInputBuffers()

II 数据通信的函数

ReadFile()
WriteFile()
HidD _ GetInputReport()
HidD _ SetOutputReport()
HidD _ SetFeature()
HidD _ GetFeature()

获取设备属性函数的使用方法相对简单,直接查看MSDN上的函数描述就可以了。这里主要介绍下HID设备数据通讯函数的用法。

3.1 CreateFile()、ReadFile()和WriteFile()

这三个函数的函数原型为:

HANDLE CreateFile(
  LPCWSTR lpFileName,        //指向路径的指针
  DWORD dwDesiredAccess,     //访问模式(读/写)
  DWORD dwShareMode,         //共享模式
  LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
  DWORD dwCreationDisposition,   //如何创建
  DWORD dwFlagsAndAttributes,    //文件属性(同步或异步)
  HANDLE hTemplateFile           //用于复制文件句柄
);
BOOL ReadFile(
  HANDLE hFile,        //设备句柄,可通过CreateFile得到
  LPVOID lpBuffer,     //存储数据的缓冲区
  DWORD nNumberOfBytesToRead,   //要读取的数据长度
  LPDWORD lpNumberOfBytesRead,  //实际收到的数据长度
  LPOVERLAPPED lpOverlapped      //OVERLAPPED结构体指针
);
BOOL WriteFile(
  HANDLE hFile,             //设备句柄,可通过CreateFile得到
  LPCVOID lpBuffer,         //要发送的buffer(指针)
  DWORD nNumberOfBytesToWrite,   //要发送数据的长度
  LPDWORD lpNumberOfBytesWritten,   //实际发送数据的长度
  LPOVERLAPPED lpOverlapped  //OVERLAPPED结构体指针,如果设备是以
//FILE_FLAG_OVERLAPPED方式打开的话,那么这个指针就不能为NULL
);

CreateFile()用于打开HID设备,设备路径可通过函数SetupDi系列函数获取。此函数有以下需要注意的地方:

● 访问模式。 系统独占设备,比如鼠标、键盘等,应将此参数设置为0,否则后续函数的操作将失败。也就是说,对独占设备只能进行查询操作,所以可使用的函数有限。

● 文件属性。此参数用来设置同步或异步模式,它主要是对后续的WriteFile()和ReadFile()有影响。此参数为0时,代表同步模式,也即数据处理完成之后才返回,否则阻塞在函数内部。

ReadFile()用于读取设备通过中断IN传输发来的输入报告,读取的数据从中断输入管道传入。其读取的数据是从HID设备驱动的缓冲区中得到的,缓冲区的大小,可通过HidD _ SetNumInputBuffers()来改变。

ReadFile()的入口参数nNumberOfBytesToRead代表要读取数据的长度(数据正文+1字节报告ID)。当然,在实际设计中,HID设备是由我们自己设计的,我们是知道设备固件的信息的。

上位机也可通过HidD _ GetPreparsedData()来取得报告的长度。此参数设置过大,不会有错误产生,上位机将受到实际读到的长度;此参数设置过小,也即小于数据长度,会返回错误。

WriteFile()通过中断OUT得到来自设备的数据,其入口参数lpBuffer的第一个元素为待发送的报告ID,而且此报告ID必须是Output Report,否则会返回错误。

3.2 HidD _ GetInputReport()和HidD _ SetOutputReport()

BOOLEAN HidD_GetInputReport(
  HANDLE HidDeviceObject,     //设备句柄
  PVOID  ReportBuffer,        //存储数据的缓冲区
  ULONG  ReportBufferLength  //缓冲区长度
);
BOOLEAN HidD_SetOutputReport(
  HANDLE HidDeviceObject,    //设备句柄
  PVOID  ReportBuffer,       //存有待发送数据的缓冲区
  ULONG  ReportBufferLength //缓冲区长度
);

这两个函数通过Input Report和Output Report进行数据传输。主要在其它们的入口参数中,缓冲区的数据,第一个元素为Report ID,后面跟着的才是数据正文。

在固件程序中,这两个函数对应的类命令为Get Report和Set Report。

3.3 HidD _ SetFeature()和HidD _ GetFeature()

BOOLEAN HidD_GetFeature(
  HANDLE HidDeviceObject,     //设备句柄
  PVOID  ReportBuffer,        //存储数据的缓冲区
  ULONG  ReportBufferLength  //缓冲区长度
);
BOOLEAN HidD_SetFeature(
  HANDLE HidDeviceObject,    //设备句柄
  PVOID  ReportBuffer,       //存有待发送数据的缓冲区
  ULONG  ReportBufferLength //缓冲区长度
);

与3.2介绍的两个函数类似,不过这两个函数是通过Feature Report进行数据传输的。在固件程序中,对应的类命令也是Get Report和Set Report。

了解了上述函数的基本用法后,就可以着手编写UsbHID工具了。具体的代码编写过程,在下一篇中进行介绍。

110 total views, 1 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK