UEFI开发探索82- YIE002USB开发板(05 制作HID设备)

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

从软件的角度,制作USB HID设备,需要理解的知识包括几大块:
1) USB协议的基本架构和软件架构;
2) USB描述符,包括标准描述符和类描述符;
3) USB命令,包括标准命令和类命令。

当然,如果能从字节序上(比如USB包的构成)了解USB通信的过程,对理解整个USB协议的构成也很有好处。但在编程中,不需要理解到这个地步。大部分介绍USB协议的书籍,以及USB规范中,都很详细地描述了这些过程,非常建议读一读。

在前一篇中,已经简要地概述了USB协议的基本架构和软件架构。本篇主要介绍USB描述符中的标准描述符,这是所有USB设备都要支持的描述符。

1 USB描述符概述

为了方便USB主机对USB设备进行管理,USB-IF对USB设备的功能采用了分层结构,包括设备层、配置层、接口层和端点层。图1给出了一个复合设备的例子,展示了USB设备的分层结构。

图1 USB设备的功能分层结构

这四层的作用分别为:

  1. 设备层。说明USB设备的主要类型特征(如设备类别、接口、端点等属性),保障设备枚举过程的正常进行。
  2. 配置层。选择不同的失败配置满足USB主机对设备功能的选择,可选择复式的设备接口功能,如图1展示的选择鼠标、键盘和游戏杆的复合功能。
  3. 接口层。将具体功能分类,不同的功能对用不同的操作方式。
  4. 端点层。针对特定的设备功能,选择不同的端点,提供不同的数据管道,与USB主机进行数据通讯。
继续阅读“UEFI开发探索82- YIE002USB开发板(05 制作HID设备)”

1,304 total views, no views today

UEFI开发探索81- YIE002USB开发板(04 制作HID设备)

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

YIE002开发板上的开发,停滞了有一段时间了,这几天重新开始编写。

在最早编写的《UEFI编程实践》的书稿中,我是使用正点原子的探索者F4来制作HID设备的。感觉在自己的书中,使用其他家的开发板和代码,总是觉得有点不对。另外,在其代码上进行改造开发,存在版权的问题。

当然,最主要的,我也希望能有一个容易携带的开发板,方便我回家、或者出差的时候使用。于是才构建了这么一个机会,取名为YIE002。YIE中文含义为“易也”,来自于好友张佩的博客网站YIIEE,同音于中文“耶”和英文“yeah”。该是来自于程序员解决BUG、完成任务时,不由自主发出的欢呼声。

YIE002开发板的开篇中,描述了USB HID通信架构,包含USB HID的设备和上位机程序编写。上位机包括Windows系统、Linux系统和UEFI系统。之前用来两篇,介绍了如何在Windows系统下进行上位机编写,并开发了一个方便使用的调试工具。从本篇开始,介绍如何使用开发板制作USB HID设备,并使之支持三种通信方式。

从我的博客编写规划来说,YIE002的开发,到现在为止,都还没有进入实质的UEFI开发。主要原因在于,USB协议比较复杂。目前的开发,主要关注的是HID类协议,所需要了解的背景知识也非常庞杂。

在没有掌握USB协议相关的知识前,去读UEFI中关于USB的Protocol,会满头雾水,无法理解的。

因此,我觉得还是有必要通过学习制作USB HID设备,用几篇博客的篇幅,大致了解了USB协议的框架和编程方法,才能深入理解UEFI下USB设备的访问方法。

1 USB规范简介

通用串行总线(Universal Serial Bus,简称USB)由Intel、IBM、微软等计算机和通信公司,于1995年联合制定,解决旧有接口的问题,以适应当时计算机的飞速发展。作为一种高速串行总线,其极高的传输速度可以满足高速数据传输的应用环境要求。并且由于它供电简单、支持热插拔、扩展端口简单以及传输方式多样化等特点,目前广泛应用于各种计算机、手机等电子设备中。

相比于RS-232、PS/2等传统接口,USB最突出的特点是,其扩展性极强。RS-232等传统接口,一个预留接口只能用来连接一个相关设备,当需要扩展时,必须占用大量的计算机内部资源(如系统I/O口、中断向量和总线地址等)。而一个USB口,可以通过USB集线器,连接127个USB设备。USB简便的外设连接方式,以及优良的数据传输功能,为计算机外设接口带来了革命性的变化。

USB标准规范包括USB1.0、USB1.1、USB2.0、USB3.0,以及2019年9月发布的USB4TM规范。如表1所示,从推出时间、传输速率等方面,对USB规范的各版本进行了描述。

表1 USB规范各版本信息

USB版本最大传输速率名称推出时间
USB1.01.5Mbps低速(Low-Speed)1996年1月
USB2.0480Mbps高速(High-Speed)2000年4月
USB3.0(USB3.2 Gen 1)5Gbps超高速(Super-Speed)2008年11月
USB3.1(USB3.2 Gen 2)10Gbps超高速(Super-Speed 10Gbps)2013年12月
USB3.2(USB3.2 Gen 2×2)20Gbps超高速(Super-Speed 20Gbps)2017年9月
USB4TM (USB4 Gen 2×2)20GbpsUSB4TM 20Gbps2019年9月
USB4TM(USB4 Gen 3×2)40GbpsUSB4TM 40Gbps2019年9月
继续阅读“UEFI开发探索81- YIE002USB开发板(04 制作HID设备)”

1,074 total views, 1 views today

YIE002开发探索00-起篇

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

YIE002开发板,是我在撰写UEFI开发探索系列博客,以及编写《UEFI编程实践》的时候,做的一款开发板。

在UEFI下访问USB HID设备,需要一个自制的USB HID设备。最初的时候,我是使用了正点原子的探索者F4的板子,做了一个需要的设备。那个板子很大,在频繁带着它往返家和公司的过程中,终于厌倦了。想着是不是能做个方便携带、可以直接通过USB取电的小开发板,这就是YIE002开发板的来源。

我的需求,本来是只想做个USB HID设备,然后开发个Windows/Linux的上位机程序,以及UEFI下的上位机程序。在定义YIE002的时候,只提出了USB接口和LED灯的要求。将这个想法告诉了做硬件的朋友,他把按键、RS232串口、485串口和TTL串口都加上了,做成了一个不错的小型开发板。

这个过程,我在UEFI开发探索的博客中也曾经说过。既然拿到了这个资源相对丰富的小开发板,我就萌发了再开一个“嵌入式开发”的专栏,按照自己的设想,把一直以来这方面的开发,做个整理。

1 开发板构思

如图1所示,是目前所构思的YIE002的结构图。

图1 YIE002结构图

主要包含以下硬件资源:

4个LED灯和1个电源显示灯;
3个按键;
三类 串口,包括RS232、485和TTL;
USB 全速设备。

当前我在使用的YIE002开发板,其主芯片是STM32F103C8T6。以前曾使用过这个芯片,开发过一些公司的项目,相对比较熟悉。

继续阅读“YIE002开发探索00-起篇”

1,161 total views, no views today

UEFI开发探索80- YIE001PCIe开发板(终篇 移植杂谈)

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

粗略地数了数,在博客中起码开发了近50个各类UEFI的演示程序。从理论上来说,大部分的代码,实际上都可以移植到YIE001开发板的Option ROM中。

只不过,YIE001所用的Ch366芯片,只支持窗口容量为32K的程序文件(当然,可以通过CH366的I2C两线串口进行扩展)。在这种情况下,对代码的编写设置了一定的限制。

本篇将以《UEFI编程实践》第6章的示例MyGuiFrame为蓝本,将其移植到YIE001的Option ROM框架代码中。此示例在仓库https://gitee.com/luobing4365/uefi-practical-programming.git的/ RobinPkg\Applications\MyGuiFrame下。(目前仍旧在整理中,还没有上传到仓库中,by robin,20210215)

1 Option ROM开发注意点

开发板YIE001主要用来进行Option ROM的开发,由于其本身所用的PCIE芯片CH366的限制,以及UEFI下Option ROM的本身限制,编写代码中还是有不少需要注意的地方。从我的角度出发,有以下点需要注意。

1) 减少生成文件的尺寸

毕竟YIE001的窗口容量只有32K,能够容纳的代码量有限。而且由于代码是用C语言编写的,很难精确地计算生成后文件的大小,必须要注意代码的大小。

因此,第一个规则是尽量使用EDK2提供的库函数。不要使用外部库,比如StdLib库等所提供的函数。使用封装过的库函数,会导致生成文件增大。在EDK2本身提供的库函数中,对内存处理、字符串处理等常用的函数,都有提供,尽量使用这些函数就行。

开发中,最占用空间的是图像、汉字字模等这些资源。一般来说,应该尽可能使用图形函数自己绘制图像,尽量少使用标准的图像进行显示。第二条规则是图形界面尽量简单,汉字库应该采用小字库的技术,也即用哪些汉字,就提取这些汉字的字库。

在之前的博客中,针对汉字的显示,以及图形和图像的显示,已经花了比较多的篇幅进行描述,可以去查看相应的篇章。

当然,也可以用一些无损压缩算法,对资源进行压缩。不过,个人认为在32K的空间内去压缩,也很难容纳较大的文件,有兴趣的技术同好可以试一下。

继续阅读“UEFI开发探索80- YIE001PCIe开发板(终篇 移植杂谈)”

1,637 total views, no views today

UEFI开发探索79- YIE001PCIe开发板(12 贪吃蛇)

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

上一篇开发的贪吃蛇,除了使用了启动服务所提供的键盘服务函数和延时函数外,主要使用了GraphicsOutput Protocol。

这使得代码无需进行修改,能很容易地移植到Option ROM的框架代码中。

本篇比较短,主要是介绍如何将UEFI应用Snake移植到YIE001的OpROM框架中。

移植的步骤如下。

1 代码整理

上一篇的示例工程Snake,实际上是在以前的RngEvent的示例上进行修改的。所需要的函数,仍旧是RngEvent中使用过的。

在Option ROM的框架示例中,新建C文件GreedSnake.c,把Snake中与贪吃蛇相关的函数全部拷贝进去。函数的功能在上一篇中都介绍了,包括:

VOID CreateMap(VOID);
VOID SnakeElement(UINT32 x,UINT32 y,UINT8 ColorIndex);
VOID InitSnake(VOID);
UINT8 BiteSelf();
VOID RandomFood(VOID);
UINT8 NotCrossWall(VOID);
UINT8 SnakeMove(VOID);
VOID GameRun(VOID);
VOID EndGame(VOID);
继续阅读“UEFI开发探索79- YIE001PCIe开发板(12 贪吃蛇)”

1,215 total views, no views today

UEFI开发探索78- YIE001PCIe开发板(11 贪吃蛇)

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

是时候实现个有趣的项目了,我选择在UEFI下实现贪吃蛇的游戏。

在Option ROM上直接实现,会很难调试。因此,我首先实现了贪吃蛇的UEFI应用。调试成功后,再将其移植到YIE001上。

1 贪吃蛇框架设计

考虑到代码最终是要移植到YIE001上,我尽量减少所用到的Protocol。主要是在平常开发中发现,不同的主机,在运行Option ROM时能支持的Protocol不大一致。比如在我目前测试用的平台上,就不支持SimplePointer的Protocol(鼠标)。

为简化对程序的思考,我们设计的贪吃蛇由一个个的矩形块组成。主要需要解决的问题包括:
(1) 地图的设计;
(2) 贪吃蛇的数据结构设计;
(3) 如何判断蛇撞墙;
(4) 如何判断蛇咬自身了;
(5) 随机出现蛇吃的食物。

实际上,解决了问题1和2,基本上后续的几个问题都迎刃而解了。

我们把地图、蛇和食物设计成如图1所示:

图1 贪吃蛇概念图
继续阅读“UEFI开发探索78- YIE001PCIe开发板(11 贪吃蛇)”

1,147 total views, no views today

UEFI开发探索77- YIE001PCIe开发板(10 拨动开关及显示)

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

YIE001上有两个拨动开关,可通过对应的寄存器位得知它们的状态,以实现交互控制。这篇尝试将按键获取,以及图形显示的编码。

1 获取拨动开关状态

UEFI开发探索第75篇中,列出了YIE001开发板的硬件资源。板子上提供了两个拨动开关,分别对应CH366的GPI1和GPI2。

对照CH366的芯片手册,定义其相关的宏定义:

#define CH366GPIR 0x02

#define KEY1 1   //GPI1 -- GPIR(IO基地址+02h) bit 1
#define KEY2 2   //GPI2 -- GPIR(IO基地址+02h) bit 2

在开发板YIE001上,拨动开关拨下(也即靠近PCIE槽的方向),对应的寄存器位值为0;拨上后对应的寄存器值为1。实现代码如下:

/**
  获取开发板YIE001上拨动开关的状态.
  
  @param  IoBaseAddress     YIE001上PCIE芯片的基地址
  @param  KeyNum            拨动开关的标识,Key1和Key2
  @retval 1           拨下(靠近PCIE插槽)
          0           拨上    
**/
UINT8 GetYIE001Key(UINT16 IoBaseAddress,UINT8 KeyNum)
{
  UINT8 regValue=0;

  regValue = IoRead8(MyIoBaseAddr+CH366GPIR);   //GPIR
  if(KeyNum == KEY1)
    regValue &=0x02;
  if(KeyNum == KEY2)
    regValue &=0x04;
  if(regValue)
    return 1;
  else
    return 0;
}
继续阅读“UEFI开发探索77- YIE001PCIe开发板(10 拨动开关及显示)”

1,375 total views, 1 views today

UEFI开发探索76- YIE001PCIe开发板(09 界面和键盘控制)

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

在开发板YIE001上进行开发,实际上和之前博客中开发UEFI应用,并没有本质的区别。所要注意的,是在Option ROM被BIOS加载之时,所用的UEFI机制以及Protocol是否能正常使用。

一般来说, GraphicsOutput Protocol和ConOut Protocol是可以正常使用的。但是,其他的Protocol,比如创建Event,就很难说了。笔者目前测试的机器上,在加载Option ROM时,创建的Event完全无法按照预期运作。而同样的代码,在同一机器的UEFI Shell下测试却是正常的。

本篇代码的编程过程如下。

1 图形支持和汉字支持

UEFI开发探索中的代码,特别是图形和汉字部分,是从我的开源项目Foxdisk中移植过来的。针对UEFI的机制,进行了改动。所以,在博客中的代码,同文件名的,其内容都差不多。

当然,随着各个课题的展开,代码也在不断地修改。甚至对我而言,也很难分清楚目前所用的文件是什么时候修改的。比如近期又在处理键盘的源文件中,添加了检查键盘按键的非阻塞处理函数CheckKey()。

我尽力维持一个松散而逻辑一致的结构,保证源文件可以直接使用。处理同一硬件的或者同一逻辑层的代码,基本上会在相同的源文件中。

以下列出了源文件的功能:

表1 源文件的功能

源文件引脚名称
Graphic.c, Graphic.h功能
Keyboard.c, Keyboard.h键盘处理
Window.c, Window.h界面相关的代码,比如背景设置等
Font.c, Font.h文字的显示,包括汉字、英文的显示
Common.c, Common.h提供各种Protocol实例,以及共用的一些函数
继续阅读“UEFI开发探索76- YIE001PCIe开发板(09 界面和键盘控制)”

1,354 total views, no views today

UEFI开发探索75- YIE001PCIe开发板(08 跑马灯实验)

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

在等待开发板YIE002焊接的日子里,回到YIE001上继续编程。

本篇准备完成跑马灯的实验,让YIE001上的4个LED灯跑起来。在开篇中,已经大致了解了YIE001上的硬件资源,为方便后续的编程,把这些资源先记录一下。

表1 开发板YIE001上硬件资源

开发板上名称引脚名称所属寄存器地址位址
LED1SW0控制寄存器CTLRIO基址+0x1bit 0
LED2SW1控制寄存器CTLRIO基址+0x1bit 1
LED3GPO辅助寄存器AUXRIO基址+0xf8bit 0
LED4RST0辅助寄存器AUXRIO基址+0xf8bit 7
KEY1GPI1输入寄存器GPIRIO基址+0x2bit 1
KEY2GPI2输入寄存器GPIRIO基址+0x2bit 2
I2CSDA输出寄存器GPORIO基址+0x0bit 0
I2CSCL输出寄存器GPORIO基址+0x0bit 1

需要注意的是,在CH366提供的芯片手册上,对于GPO和RST0所属的寄存器AUXR,给出的地址为IO基址+0x18。在实际使用中,此寄存器无法写入,经过测试发现应该是0xf8才对。

需要注意的是,在CH366提供的芯片手册上,对于GPO和RST0所属的寄存器AUXR,给出的地址为IO基址+0x18。在实际使用中,此寄存器无法写入,经过测试发现应该是0xf8才对。

下面介绍下跑马灯的编写以及测试过程。

继续阅读“UEFI开发探索75- YIE001PCIe开发板(08 跑马灯实验)”

1,172 total views, 1 views today

UEFI开发探索74- YIE002USB开发板(03 Windows编程)


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

在上篇学习了访问HID设备的Windows API之后,本篇开始着手进行Windows上位机的编程。所编写的程序名为UsbHID,其主要功能在上一篇中已经介绍过,下面介绍其编写过程。

1 添加库文件

我是使用MFC编写的上位机程序,开发工具为VS2015。建立基于Dialog的工程,并在对话框的CPP文件中,添加如下语句:

#include <hidsdi.h>
#include <setupapi.h>
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib")

所添加的头文件和库文件,包含UsbHID编程时需要用到的SetupDi系列函数,以及HID设备获取信息的函数和数据通信函数。早期的VS中,需要将库文件拷贝到工程的目录下,并手动添加库文件到工程中。

2 枚举HID设备

枚举HID设备包括获取HID类的GUID、查找所有HID设备、获取设备的信息等步骤。枚举过程中,用到了上篇博客所说的获取设备属性的若干函数。另外,也使用了几个SetupAPI函数,这几个函数的原型列举如下。

2.1 SetupAPI函数

返回一个设备信息集的句柄,包含本地计算机所请求的设备信息元素。

WINSETUPAPI HDEVINFO SetupDiGetClassDevsW(
  const GUID *ClassGuid,  //指向设备安装类或接口类的GUID指针,可以为空
  PCWSTR     Enumerator,  //指向空字符结尾的字符串
  HWND       hwndParent, //与设备实例相关的用户界面的顶级窗口句柄,可为空
  DWORD      Flags       //过滤设备用的标识
);

请求获得设备信息集内某个设备的信息

WINSETUPAPI BOOL SetupDiEnumDeviceInterfaces(
  HDEVINFO              DeviceInfoSet,   //指向设备信息集
  PSP_DEVINFO_DATA      DeviceInfoData,  //指向设备信息参数指针,可为空
  const GUID      *InterfaceClassGuid, //指向设备安装类或接口类的GUID指针
  DWORD           MemberIndex,   //位于设备信息集中的序号,以0起始
  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData //回传的设备接口数据
);

请求获得设备的路径

WINSETUPAPI BOOL SetupDiGetDeviceInterfaceDetailW(
  HDEVINFO                           DeviceInfoSet,    //指向设备信息集
  PSP_DEVICE_INTERFACE_DATA          DeviceInterfaceData, //设备接口数据
  PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
  DWORD                              DeviceInterfaceDetailDataSize,
  PDWORD                             RequiredSize,
  PSP_DEVINFO_DATA                   DeviceInfoData
);

2.2 枚举HID设备的流程图

枚举HID设备时,将调用上述的函数,其流程如下图所示:

图1 枚举HID设备流程图
继续阅读“UEFI开发探索74- YIE002USB开发板(03 Windows编程)”

1,287 total views, no views today

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界面
继续阅读“UEFI开发探索73- YIE002USB开发板(02 Windows编程)”

1,442 total views, no views today

UEFI开发探索72- YIE002USB开发板(01 开篇)

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

最近把USB的各个方面都研究了一遍,也在UEFI下实现了USB设备的访问。趁着这热乎劲,我计划把USB HID通信的知识,集合到一个新的开发板中进行介绍,也即我目前正在考虑设计的YIE002。

虽然YIE002的开发板还在规划中,我使用其他的开发板,已经打通了USB的通道了。只等着YIE002开发打样回来,把嵌固件代码移植过去就行了。

因为涉及到三个平台的开发(Windows、UEFI以及嵌入式平台),开发中需要记忆的知识点有点多。虽然现在对这些知识还比较清楚,时间长了后,有些细节容易忘记。因此,本篇开始进行YIE002的各类软件实验。

后续的篇章中,会交叉进行YIE001和YIE002的实验。两者的区别在于,YIE001主要是基于PCIE总线的,而YIE002则使用的是USB总线。

1 YIE002开发板计划

首先简单介绍下YIE002的开发板计划。 如图1所示,是我规划的YIE002开发板。

继续阅读“UEFI开发探索72- YIE002USB开发板(01 开篇)”

1,595 total views, no views today

UEFI开发探索71- YIE001PCIe开发板(07 OptionROM框架)


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

正在编辑新书《UEFI编程实践》(暂定名),现在介绍的内容,都整理到了第8章中了。

写书还是比较费神的,博客中可以随意行文,书稿则完全不能这么做。为了做到准确,有时为了确定一个数据,需要花费整个上午查找资料。期待今年上半年能够出版吧。

关于Option ROM,在第34、35和36篇中,已经描述过其历史和原理了。现在有了开发板,就可以在上面直接进行开发了。

1 开发Option ROM

代码是基于BlankDrv中的架构进行开发的,主要修改Supported()函数和Start()函数。Supported()函数中,判断是否为目标PCIE设备(也即是否为YIE001开发板);Start()函数中,添加界面代码以及访问硬件设备的代码。

示例1中给出了修改后的Supported()代码。

【示例1】Supported()函数

EFI_STATUS EFIAPI BlankDrvDriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL)
{
  EFI_STATUS Status;
  UINT16 MyVendorID, MyDeviceID;
EFI_PCI_IO_PROTOCOL  *PciIo;
  Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,
                  (VOID **) &PciIo,This->DriverBindingHandle,
                  Controller,EFI_OPEN_PROTOCOL_BY_DRIVER);
  if (EFI_ERROR (Status)) return Status;
  Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint16,0,1,&MyVendorID);
  if (EFI_ERROR (Status)) goto Done; //获取厂商ID
  Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint16,2,1,&MyDeviceID);
  if (EFI_ERROR (Status)) goto Done; //获取设备ID
  Status = EFI_SUCCESS;
  //通过厂商ID和设备ID,判断是否为目标设备
  if (MyVendorID != CH366_VENDOR_ID || MyDeviceID != CH366_DEVICE_ID)
    Status = EFI_UNSUPPORTED;
  Done:  //关闭所用的Protocol
  gBS->CloseProtocol(Controller,&gEfiPciIoProtocolGuid,
         This->DriverBindingHandle,Controller);
  return Status;
}

在Supported()函数中,首先使用OpenProtocol()打开PCI I/O Protocol,如果打开失败,则返回EFI_UNSUPPORTED。然后使用得到的PCI I/O Protocol实例,从PCI设备的配置空间,获得厂商ID和设备ID。如果所得到的厂商ID及设备ID,与目标设备的一致,则返回EFI_SUCCESS,否则返回EFI_UNSUPPORTED。

继续阅读“UEFI开发探索71- YIE001PCIe开发板(07 OptionROM框架)”

1,569 total views, no views today

UEFI开发探索70- YIE001PCIe开发板(06 UEFI驱动)

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

前两篇中,我们了解了UEFI驱动模型的基本架构。 在此基础上,本篇将以一个有趣的UEFI驱动GopRotate,配合自己编写的测试用UEFI应用TestGopRotate,演示UEFI驱动的运行和测试过程。

1 UEFI驱动GopRotate

此示例由apop2提供,源码仓库为https://github.com/apop2/GopRotate。工程GopRotate包含5个源文件:ComponentName.c、GopRotate.c、GopRotate.h、GopRotateBlt.c和GopRotate.inf。这几个文件的作用分别如下:

1) ComponentName.c。实现了EFI_COMPONENT_NAME_PROTOCOL的接口函数,提供UEFI驱动的名称;
2)GopRotate.c。实现EFI_DRIVER_BINDING_PROTOCOL及其接口函数,安装EFI_DRIVER_BINDING_PROTOCOL和EFI_COMPONENT_NAME_PROTOCOL,以及实现UEFI Shell界面旋转功能的Protocol;
3) GopRotate.h。定义了驱动所需数据结构以及Protocol接口函数原型;
4) GopRotateBlt.c。实现UEFI Shell界面旋转的函数,以及提供此功能的Protocol接口函数的实现;
5) GopRotate.inf,编译UEFI驱动的INF文件。

为实现UEFI Shell界面的旋转,示例工程GopRotate主要做了以下工作:

  • 找到安装了EFI_GRAPHICS_OUTPUT_PROTOCOL的控制器,并且不能是虚拟设备;
  • 对EFI_GRAPHICS_OUTPUT_PROTOCOL的Blt()接口函数进行替换,更换为GopRotate中实现旋转显示的函数BltRotate();
  • Shell界面旋转多少度,由内部私有结构体的成员变量Rotation决定。实现控制此变量的GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL,此Protocol提供了两个接口函数,用来获取Rotation值和设置Rotation的值。

示例工程GopRotate的私有结构体如示例1所示。

继续阅读“UEFI开发探索70- YIE001PCIe开发板(06 UEFI驱动)”

1,616 total views, no views today

UEFI开发探索69- YIE001PCIe开发板(05 UEFI驱动)

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

上一篇中,驱动BlankDrv完成了核心的EFI_DRIVER_BINDING_PROTOCOL,以及获取驱动名Protocol的处理后,整个UEFI驱动框架还有两项工作等待完成:

  • 安装UEFI驱动所提供的Protocol;
  • 驱动加载后是常驻内存的,应该提供UEFI驱动的卸载函数,以支持将驱动系统中移除的功能。

1 完成驱动框架

安装Protocol可以使用InstallMultipleProtocolInterfaces()函数,由于BlankDrv中有三种Protocol需要安装,所以使用了库函数EfiLibInstallDriverBindingComponentName2()来安装所有的Protocol。如示例1所示。

【示例1】安装BlankDrv所提供的Protocol

EFI_STATUS EFIAPI UefiMain(
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS          Status;
  …..
//安装需要提供的三种Protocol
  Status = EfiLibInstallDriverBindingComponentName2 (
             ImageHandle,
             SystemTable,
             &gBlankDrvDriverBinding, 
             ImageHandle,
             &gBlankDrvComponentName,
             &gBlankDrvComponentName2
             );
  return Status;
}

驱动的卸载函数,在使用UEFI Shell命令unload的时候会被调用。此函数的入口在UEFI工程的INF文件中添加,由[Defines] Section的UNLOAD_IMAGE字段给出。在示例工程BlankDrv的BlankDrv.inf中,按照如下方式进行了定义:

[Defines]
  ……
ENTRY_POINT                    = UefiMain         //驱动的入口函数
UNLOAD_IMAGE                   = DefaultUnload   //驱动的卸载函数

继续阅读“UEFI开发探索69- YIE001PCIe开发板(05 UEFI驱动)”

2,237 total views, 1 views today

UEFI开发探索68- YIE001PCIe开发板(04 UEFI驱动)

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

插个新告知:YIE001的开发板,思路已经比较清晰了-使用PCIE芯片,编写Option ROM,在此基础上控制硬件,做一些有趣的实验。由于主要是用业余时间,估计在这两个月内就能把要做的实验完成。

因此,有了新的想法-做一个USB的开发板YIE002,实现从UEFI访问、Windows/Linux访问的全通道USB HID设备。当然,可以用它来收集温度、产生随机数等。准备做成U盘大小,方便直接插在电脑上进行实验。我正在收集网友的想法,有啥想实现的,留言就行,资源允许,我就在板子上实现了。

回到UEFI驱动的介绍。

UEFI开发探索66和67,介绍了服务型驱动的构建和实现。下面几篇,用来介绍符合UEFI驱动模型的驱动程序。本篇主要介绍其框架结构和程序接口,内容有点枯燥,最好对照着源码进行阅读。

一个完整的符合UEFI驱动模型的驱动程序,大致可以分为两个部分:EFI Driver Binding Protocol和驱动本身提供的服务。前者用来管理驱动,后者才是用户需要使用的部分,一般包括一个或多个Protocol。

比如UEFI的USB主控制器驱动,它提供了两个Protocol供用户使用,包括EFI_USB_HC_PROOCOL和EFI_USB2_HC_PROTOCOL,用来访问USB设备。另外,为了方便用户使用,驱动程序一般还会包含EFI Component Name Protocol,用来显示驱动信息。

在网页https://sourceforge.net/projects/edk2/files/EDK%20II%20Releases/Demo%20apps/上,可以下载Intel早期提供的驱动框架示例BlankDrv,用来学习UEFI驱动模型。

1 EFI Driver Binding Protocol

示例工程BlankDrv包含四个文件:

  1. BlankDrv.c。实现EFI_DRIVER_BINDING_PROTOCOL及其接口函数,并安装EFI_DRIVER_BINDING_PROTOCOL和EFI_COMPONENT_NAME_PROTOCOL。
  2. BlankDrv.h。定义了驱动所需数据结构以及Protocol接口函数原型;
  3.  ComponentName.c。实现了EFI_COMPONENT_NAME_PROTOCOL的接口函数;
  4. BlankDrv.inf,编译UEFI驱动的INF文件。
继续阅读“UEFI开发探索68- YIE001PCIe开发板(04 UEFI驱动)”

1,450 total views, 1 views today