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所示。

【示例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所示。

【示例2GRAPHICS_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-explorer
项目代码位于:/FF RobinPkg/ RobinPkg /Applications/TestGopRotate
              /FF RobinPkg/ RobinPkg /Drivers/GopRotate

1,357 total views, 2 views today

发表评论

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