(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
前两篇中,我们了解了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所示。
【示例1】GopRotate的私有结构体
typedef struct
{
UINTN Signature; //私有数据结构体签名
EFI_HANDLE Handle; //管理设备的句柄
EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT Blt; //原始的Blt()接口函数
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop; //Gop实例
GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL GopRotate;//用户使用的Protocol
ROTATE_SCREEN Rotation; //控制屏幕旋转角度
} GRAPHICS_OUTPUT_ROTATE_PRIVATE;
typedef enum
{
Rotate0 = 0, //不旋转
Rotate90 = 1, //旋转90度
Rotate180 = 2, //旋转180度
Rotate270 = 3, //旋转270度
RotateMax = 4
} ROTATE_SCREEN;
GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL用来设置和获取屏幕旋转的角度,它提供了两个接口函数,如示例2所示。
【示例2】GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL函数接口
typedef struct _GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL \
GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL;
struct _GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL
{
GRAPHICS_OUTPUT_PROTOCOL_ROTATE_GET_ROTATION GetRotation; //获取旋转角度
GRAPHICS_OUTPUT_PROTOCOL_ROTATE_SET_ROTATION SetRotation; //设置旋转角度
};
typedef EFI_STATUS (EFIAPI *GRAPHICS_OUTPUT_PROTOCOL_ROTATE_GET_ROTATION)(
IN GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL *This, //Protocol实例
IN ROTATE_SCREEN *Rotation //旋转的角度
);
typedef EFI_STATUS (EFIAPI *GRAPHICS_OUTPUT_PROTOCOL_ROTATE_SET_ROTATION)(
IN GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL *This, //Protocol实例
IN ROTATE_SCREEN Rotation //旋转的角度
);
为了实现旋转UEFI Shell界面的功能,示例工程GopRotate中实现了大量的代码,这些代码主要是围绕私有结构体GRAPHICS_OUTPUT_ROTATE_PRIVATE来构建逻辑的。核心逻辑有两处:一是替换原有Blt()函数,使得其他UEFI应用或驱动在调用Blt()接口时,实际上是调用了我们准备的函数BltRotate();二是根据用户指定的旋转角度,实现UEFI Shell界面的转换显示,此功能主要由BltRotate()函数实现。
替换接口函数Blt()的操作,在驱动的Start()函数中实现,代码就不贴出来了。
经过Start()函数的操作后,当用户调用Blt()接口函数时,实际上调用的是BltRotate()函数。在BltRotate()函数中,调用了PerformTranslations()函数,它针对不同的旋转角度,对显示进行了处理。
在GopRotate的代码中,能够清楚地看出处理逻辑,函数根据用户设定的旋转角度,对显示进行了变换处理。完成了上述两个核心逻辑后,实现设置旋转角度和获取旋转角度两个接口函数,以及其他管理驱动的代码就可以了。这些编写过程,与框架驱动BlankDrv的编写过程很类似,并不难理解,直接查看代码很容易明白。
2 UEFI应用TestGopRotate
GopRotate提供了GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL,以及此Protocol的两个接口函数,供用户设定UEFI Shell界面旋转的角度,以及获取旋转的角度。为了测试GopRotate,我编写了应用程序TestGopRotate,可通过命令行指定旋转的角度,源代码地址在文末提供。
TestGopRotate可以读取当前设定的旋转角度,设定旋转角度是通过不同的命令行参数来实现的,其用法如示例3所示。
【示例3】TestGopRotate的用法
FS0:\> TestGopRotate //不带参数,获取当前旋转角度
Rotate90 //旋转90度
FS0:\> TestGopRotate 3//可选择参数0,1,2,3,分别表示旋转0度,90度,180度和270度
代码的编写方法,与67篇示例工程TestServiceDrv的编写方法类似。将需要访问的Protocol的头文件GopRotate.h拷贝到TestGopRotate的文件夹下,编写访问Protocol及接口函数的代码就可以了。代码的核心部分如示例4所示。
【示例4】设置旋转的角度
EFI_STATUS Status;
GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL *GopRotate = NULL;
…… //代码略
Status=gBS->LocateProtocol(&gGraphicsOutputProtocolRotateProtocolGuid,
NULL, (VOID **)&GopRotate);//获取Protocol实例
…… //代码略
if(Argc == 2)
{
switch(Argv[1][0])
{
case ‘0’:
GopRotate->SetRotation(GopRotate, Rotate0); //不旋转
break;
case ‘1’:
GopRotate->SetRotation(GopRotate, Rotate90); //旋转90度
break;
case ‘2’:
GopRotate->SetRotation(GopRotate, Rotate180); //旋转180度
break;
case ‘3’:
GopRotate->SetRotation(GopRotate, Rotate270); //旋转270度
break;
default:
break;
}
}
return EFI_SUCCESS;
3 测试
编译这两个示例的方法,和前几篇中的方法是一样的。
编译驱动:
C:\UEFIWorkspace>build -t VS2015x86 -p RobinPkg\RobinPkg.dsc \
-m RobinPkg\Drivers\GopRotate\GopRotate.inf -a IA32
编译UEFI应用:
C:\UEFIWorkspace>build -t VS2015x86 -p RobinPkg\RobinPkg.dsc \
-m RobinPkg\Applications\TestGopRotate\TestGopRotate.inf -a IA32
运行效果:
图1 测试GopRotate
Gitee地址:https://gitee.com/luobing4365/uefi-exolorer
项目代码位于:/FF RobinPkg/ RobinPkg /Applications/TestGopRotate
/FF RobinPkg/ RobinPkg /Drivers/GopRotate