一种图形显示驱动的设计和实现

时间:2011-07-19

 

  在嵌入式系统这个IT产业的新领域,Linux 以其所具备的稳定、高效、易定制、易裁减、硬件支持广泛的特点,结合其、源码开放的特征。使得Linux在嵌入式操作系统中的地位越来越重要。越来越多的嵌入式系统,包括 PDA、机顶盒、WAP 手机等等系统均要求提供全功能的 Web 浏览器。这包括 HTML 的支持、JavaScript 的支持,甚至包括 Java 虚拟机的支持。而这一切都要求有一个高性能、高可靠的 GUI 的支持。这些系统一般不希望建立在庞大累赘的、非常消耗系统资源的操作系统和 GUI 之上,比如 Windows 或 X Window.但是,在出现 Linux 系统之后 GUI 仍然是一个问题。关键是 X Window 太过庞大和臃肿。uClinux是专为无存储器管理单元的处理器定制的嵌入式Linux操作系统。其内嵌的Microwindow为嵌入式系统图形界面提供了良好的支持。

    本文详细阐述了基于μClinux 操作系统的图形应用的软件结构,并在此基础上介绍了图形显示的底层硬件驱动技术,系统地给出了实现驱动的数据结构和算法。

  1  μClinux简介

  μClinux是一个完全符合GNU/GPL公约的操作系统,完全开放源代码,现在由Line公司支持维护。μClinux的发音是you-see-linux,它的名字来自于希腊字母μ和英文大写字母C结合。μ代表"微小"之意,字母C代表"控制器",所以从字面上就可以看出它的含义,即"微控制领域中的Linux系统".

  μClinux由Linux2.0内核发展而来,它继承了Linux的主要特点,并针对微控制领域中不具有MMU(存储管理单元)的处理器做了修改。μClinux重写了内核中大部分的二进制代码和源代码,因此内核比Linux2.0小很多,但它同时却保留了Linux操作系统的稳定性以及出色地支持多种文件系统的特性。?滋Clinux已被广泛应用于嵌入式系统中,本文将基于该操作系统研究图形硬件驱动。

  2  图形系统的体系结构

  嵌入式系统的显示输出分为图形输出和纯文本输出二部分。μClinux操作系统中控制台(Console)处理纯文本的输出,而帧缓冲(Frame Buffer)负责图形信息的输出。

  μClinux操作系统的图形系统从软件结构角度可以分为如图1所示的三层。

 

 

  层是图形硬件驱动程序,用来操作图形硬件设备。μClinux系统中对图形硬件设备的操作通过标准化的调用接口映射到该层实施。

  中间层是GUI图形引擎,该层把层提供的基本图形输出操作结合起来完成较为复杂的图形输出。为该层设计的GUI图形引擎已经有成熟的产品,如国内的MiniGUI、国外的MicroWindows以及Embedded QT等。

  层是图形应用程序层,各种图形应用程序都在该层实现。应用程序调用中间层的图形引擎完成各种复杂图形效果的输出。

  本文研究的对象是图形系统层的硬件驱动。

  3  图形硬件驱动

  3.1 μClinux设备驱动简介

  μClinux将设备分为字符设备、块设备和网络设备三大类。图形显示硬件设备属于字符设备。

  μClinux驱动程序的基本结构和Linux驱动程序的结构类似。不同的是:Linux使用模块化(module)的方式处理设备驱动,可以根据需求将所需驱动加载到系统内核中。μClinux虽然也支持模块化的处理方式,但是,由于存储空间的限制以及嵌入式系统具有针对性的功能要求,所以,通常在编译内核时便放弃了对模块化的支持而采用将驱动直接编译进内核的方式安装驱动。

  μClinux的设备驱动程序和文件系统紧密地结合在一起,各种设备以文件的形式存放在/dev目录下,称为设备文件。用户程序使用open( )、close( )、read( )、write( )等标准调用函数操作硬件设备。内核通过file_operations结构调用驱动程序中的函数。这是一个通用的文件操作函数指针的集合,包含了?滋Clinux提供的全部文件系统操作函数。在硬件驱动程序中只需实现该硬件所需的部分函数,而将其他的函数指针置空。

  3.2 图形硬件驱动的研究与实现

  3.2.1 图形硬件驱动

  图形硬件的驱动在滋Clinux中是比较复杂的驱动,同它相关的函数及文件分为二类。

  (1)Frame Buffer驱动程序。驱动程序的代码存放在fbmem.c文件中。Frame Buffer为显示设备提供一个通用接口,它是将显存抽象后的设备。它通过地址映射允许上层用户在图形模式下对显示缓冲区进行读写。Frame Buffer的存在使用户不必关心物理显存的位置、换页机制等细节问题,同时简化了用户程序代码在不同硬件平台间的移植。

  (2)Frmae Buffer的辅助函数。这些函数声明在fb.h中。不同的嵌入式系统中,图形显示硬件不完全相同,硬件独有的状态数据由这些辅助函数记录并修改。Frame Buffer调用辅助函数控制显示硬件设备。

  下面从这二方面探讨图形硬件驱动的实现。

  3.2.2 Frame Buffer驱动

  Frame Buffer的驱动代码存放在fbmem.c中,该文件早出现在Linux-1.3.94内核版本中。其中的数据结构是包含操作Frame Buffer函数的指针集合struct file_operations fb_fops.

  static struct file_operations fb_fops={

  NULL,  //lseek

  fb_read, //read

  fb_write, //write

  NULL,  //readdir

  NULL,  //select

  fb_ioctl, //ioctl

  fb_mmap, //mmap

  fb_open, //open

  fb_release, //release

  NULL  //fsync

  };

  Frame Buffer设备文件的特征决定了其只需要实现文件操作函数中的部分调用,如:fb_read、fb_write、fb_mmap等。

  由于处理器不支持MMU,μClinux操作系统对内存的管理不同于标准的Linux.在没有MMU的嵌入式系统中,显存的空间是独立且固定的,μClinux操作系统可以线性地访问显存空间。基于此,?滋Clinux中的fb_mmap可以修改成如下代码:

  static int fb_mmap(struct inode*inode,struct file*file,

  struct vm_area_struct*vma) {

  struct fb_ops*fb=registered_fb[ GET_FB_IDX(inode->i_rdev)];

  struct fb_fix_screeninfo fix;

  if(!fb)

  return -ENODEV;

  fb->fb_get_fix(&fix,PROC_CONSOLE( ));

  vma->vm_start=fix.smem_start+vma->vm_offset;

  return 0;

  }

  由于μClinux直接通过地址总线访问显存空间,所以地址映射被处理成直接访问内存地址的方式。

  fb_open、fb_write、fb_read等函数完成驱动Frame Buffer所必须的另外几个操作,函数fb_ioctl则用来调用辅助函数记录和修改硬件状态数据。这些函数只需做微小的修改便可以满足嵌入式系统图形显示的需要。限于篇幅,在此不作详细说明。

  3.2.3 Frame Buffer的辅助函数

  Frame Buffer调用显示驱动的辅助函数记录与修改显示硬件状态数据。由于不同显示硬件设备的工作方式不同,所以需要为它们定制特别的辅助函数。Frame Buffer的实现离不开辅助函数,因此include/linux/fb.h初和fbmem.c一起出现在Linux-1.3.94内核版本中。fb.h中声明了辅助函数的接口,函数实现代码则需要根据具体的硬件结构编写并保存在文件xxxfb.c中。

  fb.h文件中定义了记录图形硬件固有状态参数的struct fb_fix_screeninfo和记录图形硬件可变参数的struct fb_var_screeninfo,同时声明了操作这二组数据的函数指针集合struct fb_ops:

  struct fb_ops {

  //读取固有参数

  int (*fb_get_fix) (struct fb_fix_screeninfo*,int);

  //读取可变参数

  int (*fb_get_var) (struct fb_var_screeninfo*,int);

  //设置可变参数

  int (*fb_set_var) (struct fb_var_screeninfo*,int);

  //读取color map

  int (*fb_get_cmap) (struct fb_cmap*,int,int);

  //设置color map

  int (*fb_set_cmap) (struct fb_cmap*,int,int);

  //平面显示函数

  int (*fb_pan_display) (struct fb_var_screeninfo*,int);

  int (*fb_ioctl)(struct inode*,struct file*,unsigned int,

  unsigned long,int);

  };

  在xxxfb.c文件中必须声明这样两个变量:

  static struct fb_fix_screeninfo   xxx_fb_fix;/*硬件固有参数*/

  static struct fb_var_screeninfo   xxx_fb_var;/*硬件可变参数*/

  fb_ops中的函数指针在xxxfb.c文件中完成函数代码:

  static struct fb_ops xxxfb_ops={

  xxxfb_get_fix,

  xxxfb_get_var,

  xxxfb_set_var,

  xxxfb_get_cmap,

  xxxfb_set_cmap,

  xxxfb_pan_display,

  xxxfb_ioctl

  };

  结合显示硬件结构特征实现这几个函数,其中关键的函数有xxxfb_get_fix、xxxfb_set_var和xxxfb_get_var.这三个函数分别对xxx_fb_fix和xxx_fb_var中的参数进行读取和设置。

  以xxxfb_get_fix为例,该函数从xxx_fb_fix中读取硬件的固有状态参数。有二种实现方法:(1)从xxx_fb_fix中逐个读取需要的参数。对具体的硬件,fb_fix_screeninfo中只有部分数据是需要被处理的,因此只需要读取有效数据。(2)调用系统的memcpy( )函数将xxx_fb_fix完全拷贝出来。这种方法方便,但对嵌入式系统来说是以加大存储空间的开销为代价的。

  另外二个函数xxxfb_get_var和xxxfb_set_var也可以做类似的处理。

  在xxxfb.c文件中,启动显示硬件的函数是xxxfb_init( )。该函数将当前的显示硬件注册到系统中供Frame buffer调用,同时还完成对xxx_fb_fix的赋值。具体代码如下:

  void xxxfb_init(void)

  {

  ……

  /*硬件的固有数据是固定的,因此在这里对xxx_fb_fix进行赋值*/

  ……

  //将显示硬件注册到系统中

  err=register_framebuffer(&fb_info.gen.info);

  if (err<0)

  return err;

  ……

  return mem_start;//返回显存起始地址

  }

  xxxfb_init( )函数被fbmem.c文件的fb_open( )函数调用。由于图形硬件的多样性,fb_open( )函数根据具体硬件信息选择xxxfb_init( )启动辅助函数。

  μClinux中线性的显存访问是实现图形显示驱动首先要注意的问题,处理好上面提到的函数和数据就可以为特定嵌入式系统的显示设备开发出合适的辅助函数。

  3.2.4 安装驱动

  下面介绍将显示驱动安装进内核的步骤。

  (1)图形显示硬件属字符设备,因此将fbme.c文件保存到目录/linux-2.0/driver/char/中。

  (2)将图形设备加入到的Makefile文件中。

  (3)在/linux/init/main.c文件中添加驱动的启动函数fbmem_init( )。

  (4)修改编译选项文件,在/linux/arm/armnommu/config.in文件中加入:

  bool′ framebuffer support′ CONFIG_FB_XXX

  (5)为文件系统的open( )调用提供设备文件名。在/vendors/<VENDOR>/<BOARD>/Makefile的'DEVICES='中,加入'xxxfb,c,29,0'作为显示设备驱动的入口。其中29是主设备号,从设备号可以根据需要改变,这里将它设为0.

  (6)使用make工具重新编译内核,就可将图形显示的驱动编译进μClinux内核。

  以上六步将显示硬件驱动安装到μClinux的内核中,在此基础上选用合适的图形包就可以在嵌入式系统中方便地开发图形应用程序。

  4  结束语

 目前越来越多嵌入式系统要求图形显示界面,特别是在一些工业控制领域。本系统已经成功运用于色谱仪工作站上。其友好的人机界面大大降低了仪表操作难度,简化了操作流程,提高了生产效率。  

 


  
上一篇:简述车载姿态测量系统的开发
下一篇:浅谈家庭网络视频监控技术及前景应用

免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

相关技术资料