《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 嵌入式技術(shù) > 設(shè)計應(yīng)用 > 基于μClinux的圖形顯示驅(qū)動的研究與實現(xiàn)
基于μClinux的圖形顯示驅(qū)動的研究與實現(xiàn)
趙 鑫, 李 曦
中國科學(xué)技術(shù)大學(xué) 計算機系,安徽 合肥230027
摘要: 本文在分析嵌入式系統(tǒng)中圖形系統(tǒng)的軟件體系結(jié)構(gòu)后,系統(tǒng)介紹了實現(xiàn)圖形化輸出的底層驅(qū)動的相關(guān)數(shù)據(jù)結(jié)構(gòu)和算法實現(xiàn),并介紹了將圖形顯示驅(qū)動安裝到嵌入式操作系統(tǒng)?滋Clinux內(nèi)核的方法。
Abstract:
Key words :

摘  要: 本文在分析嵌入式系統(tǒng)中圖形系統(tǒng)的軟件體系結(jié)構(gòu)后,系統(tǒng)介紹了實現(xiàn)圖形化輸出的底層驅(qū)動的相關(guān)數(shù)據(jù)結(jié)構(gòu)和算法實現(xiàn),并介紹了將圖形顯示驅(qū)動安裝到嵌入式操作系統(tǒng)?滋Clinux內(nèi)核的方法。
關(guān)鍵詞: μClinux  驅(qū)動  FrameBuffer

  隨著計算機技術(shù)的迅速發(fā)展,嵌入式系統(tǒng)得到了廣泛的應(yīng)用。因為嵌入式系統(tǒng)本身固有的嵌入性和專用性,所以對嵌入式系統(tǒng)的開發(fā)有別于傳統(tǒng)意義上的計算機系統(tǒng)開發(fā)。嵌入式操作系統(tǒng)的普及使得基于嵌入式操作系統(tǒng)的開發(fā)成為嵌入式應(yīng)用系統(tǒng)開發(fā)的主導(dǎo)方式。
嵌入式系統(tǒng)對完整的圖形系統(tǒng)的要求越來越迫切,GUI(圖形化接口)已經(jīng)成為嵌入式系統(tǒng)信息輸出的一種重要方式。本文詳細(xì)闡述了基于?滋Clinux操作系統(tǒng)的圖形應(yīng)用的軟件結(jié)構(gòu),并在此基礎(chǔ)上介紹了圖形顯示的底層硬件驅(qū)動技術(shù),系統(tǒng)地給出了實現(xiàn)驅(qū)動的數(shù)據(jù)結(jié)構(gòu)和算法。
1  μClinux簡介
  μClinux由Linux2.0內(nèi)核發(fā)展而來,它繼承了Linux的主要特點,并針對微控制領(lǐng)域中不具有MMU(存儲管理單元)的處理器做了修改。μClinux重寫了內(nèi)核中大部分的二進(jìn)制代碼和源代碼,因此內(nèi)核比Linux2.0小很多,但它同時卻保留了Linux操作系統(tǒng)的穩(wěn)定性以及出色地支持多種文件系統(tǒng)的特性。?滋Clinux已被廣泛應(yīng)用于嵌入式系統(tǒng)中,本文將基于該操作系統(tǒng)研究圖形硬件驅(qū)動。
2  圖形系統(tǒng)的體系結(jié)構(gòu)
  嵌入式系統(tǒng)的顯示輸出分為圖形輸出和純文本輸出二部分。μClinux操作系統(tǒng)中控制臺(Console)處理純文本的輸出,而幀緩沖(Frame Buffer)負(fù)責(zé)圖形信息的輸出。
  μClinux操作系統(tǒng)的圖形系統(tǒng)從軟件結(jié)構(gòu)角度可以分為如圖1所示的三層。

  最底層是圖形硬件驅(qū)動程序,用來操作圖形硬件設(shè)備。μClinux系統(tǒng)中對圖形硬件設(shè)備的操作通過標(biāo)準(zhǔn)化的調(diào)用接口映射到該層實施。
  中間層是GUI圖形引擎,該層把最底層提供的基本圖形輸出操作結(jié)合起來完成較為復(fù)雜的圖形輸出。為該層設(shè)計的GUI圖形引擎已經(jīng)有成熟的產(chǎn)品,如國內(nèi)的MiniGUI、國外的MicroWindows以及Embedded QT等。
  最高層是圖形應(yīng)用程序?qū)?,各種圖形應(yīng)用程序都在該層實現(xiàn)。應(yīng)用程序調(diào)用中間層的圖形引擎完成各種復(fù)雜圖形效果的輸出。
  本文研究的對象是圖形系統(tǒng)最底層的硬件驅(qū)動。
3  圖形硬件驅(qū)動
3.1 μClinux設(shè)備驅(qū)動簡介
  μClinux將設(shè)備分為字符設(shè)備、塊設(shè)備和網(wǎng)絡(luò)設(shè)備三大類。圖形顯示硬件設(shè)備屬于字符設(shè)備。
μClinux驅(qū)動程序的基本結(jié)構(gòu)和Linux驅(qū)動程序的結(jié)構(gòu)類似。不同的是:Linux使用模塊化(module)的方式處理設(shè)備驅(qū)動,可以根據(jù)需求將所需驅(qū)動加載到系統(tǒng)內(nèi)核中。μClinux雖然也支持模塊化的處理方式,但是,由于存儲空間的限制以及嵌入式系統(tǒng)具有針對性的功能要求,所以,通常在編譯內(nèi)核時便放棄了對模塊化的支持而采用將驅(qū)動直接編譯進(jìn)內(nèi)核的方式安裝驅(qū)動。
  μClinux的設(shè)備驅(qū)動程序和文件系統(tǒng)緊密地結(jié)合在一起,各種設(shè)備以文件的形式存放在/dev目錄下,稱為設(shè)備文件。用戶程序使用open( )、close( )、read( )、write( )等標(biāo)準(zhǔn)調(diào)用函數(shù)操作硬件設(shè)備。內(nèi)核通過file_operations結(jié)構(gòu)調(diào)用驅(qū)動程序中的函數(shù)。這是一個通用的文件操作函數(shù)指針的集合,包含了?滋Clinux提供的全部文件系統(tǒng)操作函數(shù)。在硬件驅(qū)動程序中只需實現(xiàn)該硬件所需的部分函數(shù),而將其他的函數(shù)指針置空。
3.2 圖形硬件驅(qū)動的研究與實現(xiàn)
3.2.1 圖形硬件驅(qū)動
  圖形硬件的驅(qū)動在?滋Clinux中是比較復(fù)雜的驅(qū)動,同它相關(guān)的函數(shù)及文件分為二類。
  (1)Frame Buffer驅(qū)動程序。驅(qū)動程序的代碼存放在fbmem.c文件中。Frame Buffer為顯示設(shè)備提供一個通用接口,它是將顯存抽象后的設(shè)備。它通過地址映射允許上層用戶在圖形模式下對顯示緩沖區(qū)進(jìn)行讀寫。Frame Buffer的存在使用戶不必關(guān)心物理顯存的位置、換頁機制等細(xì)節(jié)問題,同時簡化了用戶程序代碼在不同硬件平臺間的移植。
  (2)Frmae Buffer的輔助函數(shù)。這些函數(shù)聲明在fb.h中。不同的嵌入式系統(tǒng)中,圖形顯示硬件不完全相同,硬件獨有的狀態(tài)數(shù)據(jù)由這些輔助函數(shù)記錄并修改。Frame Buffer調(diào)用輔助函數(shù)控制顯示硬件設(shè)備。
下面從這二方面探討圖形硬件驅(qū)動的實現(xiàn)。
3.2.2 Frame Buffer驅(qū)動
  Frame Buffer的驅(qū)動代碼存放在fbmem.c中,該文件最早出現(xiàn)在Linux-1.3.94內(nèi)核版本中。其中最核心的數(shù)據(jù)結(jié)構(gòu)是包含操作Frame Buffer函數(shù)的指針集合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設(shè)備文件的特征決定了其只需要實現(xiàn)文件操作函數(shù)中的部分調(diào)用,如:fb_read、fb_write、fb_mmap等。
  由于處理器不支持MMU,μClinux操作系統(tǒng)對內(nèi)存的管理不同于標(biāo)準(zhǔn)的Linux。在沒有MMU的嵌入式系統(tǒng)中,顯存的空間是獨立且固定的,μClinux操作系統(tǒng)可以線性地訪問顯存空間?;诖?,?滋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直接通過地址總線訪問顯存空間,所以地址映射被處理成直接訪問內(nèi)存地址的方式。
  fb_open、fb_write、fb_read等函數(shù)完成驅(qū)動Frame Buffer所必須的另外幾個操作,函數(shù)fb_ioctl則用來調(diào)用輔助函數(shù)記錄和修改硬件狀態(tài)數(shù)據(jù)。這些函數(shù)只需做微小的修改便可以滿足嵌入式系統(tǒng)圖形顯示的需要。限于篇幅,在此不作詳細(xì)說明。
3.2.3 Frame Buffer的輔助函數(shù)
  Frame Buffer調(diào)用顯示驅(qū)動的輔助函數(shù)記錄與修改顯示硬件狀態(tài)數(shù)據(jù)。由于不同顯示硬件設(shè)備的工作方式不同,所以需要為它們定制特別的輔助函數(shù)。Frame Buffer的實現(xiàn)離不開輔助函數(shù),因此include/linux/fb.h最初和fbmem.c一起出現(xiàn)在Linux-1.3.94內(nèi)核版本中。fb.h中聲明了輔助函數(shù)的接口,函數(shù)實現(xiàn)代碼則需要根據(jù)具體的硬件結(jié)構(gòu)編寫并保存在文件xxxfb.c中。
  fb.h文件中定義了記錄圖形硬件固有狀態(tài)參數(shù)的struct fb_fix_screeninfo和記錄圖形硬件可變參數(shù)的struct fb_var_screeninfo,同時聲明了操作這二組數(shù)據(jù)的函數(shù)指針集合struct fb_ops:
  struct fb_ops {
  //讀取固有參數(shù)
  int (*fb_get_fix) (struct fb_fix_screeninfo*,int);
  //讀取可變參數(shù)
  int (*fb_get_var) (struct fb_var_screeninfo*,int);
  //設(shè)置可變參數(shù)
  int (*fb_set_var) (struct fb_var_screeninfo*,int);
  //讀取color map
  int (*fb_get_cmap) (struct fb_cmap*,int,int);
  //設(shè)置color map
  int (*fb_set_cmap) (struct fb_cmap*,int,int);
  //平面顯示函數(shù)
  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;/*硬件固有參數(shù)*/
  static struct fb_var_screeninfo   xxx_fb_var;/*硬件可變參數(shù)*/
  fb_ops中的函數(shù)指針在xxxfb.c文件中完成函數(shù)代碼:
  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
  };
  結(jié)合顯示硬件結(jié)構(gòu)特征實現(xiàn)這幾個函數(shù),其中關(guān)鍵的函數(shù)有xxxfb_get_fix、xxxfb_set_var和xxxfb_get_var。這三個函數(shù)分別對xxx_fb_fix和xxx_fb_var中的參數(shù)進(jìn)行讀取和設(shè)置。
  以xxxfb_get_fix為例,該函數(shù)從xxx_fb_fix中讀取硬件的固有狀態(tài)參數(shù)。有二種實現(xiàn)方法:(1)從xxx_fb_fix中逐個讀取需要的參數(shù)。對具體的硬件,fb_fix_screeninfo中只有部分?jǐn)?shù)據(jù)是需要被處理的,因此只需要讀取有效數(shù)據(jù)。(2)調(diào)用系統(tǒng)的memcpy( )函數(shù)將xxx_fb_fix完全拷貝出來。這種方法方便,但對嵌入式系統(tǒng)來說是以加大存儲空間的開銷為代價的。
  另外二個函數(shù)xxxfb_get_var和xxxfb_set_var也可以做類似的處理。
  在xxxfb.c文件中,啟動顯示硬件的函數(shù)是xxxfb_init( )。該函數(shù)將當(dāng)前的顯示硬件注冊到系統(tǒng)中供Frame buffer調(diào)用,同時還完成對xxx_fb_fix的賦值。具體代碼如下:
  void xxxfb_init(void)
  {
      ……
      /*硬件的固有數(shù)據(jù)是固定的,因此在這里對xxx_fb_fix進(jìn)行賦值*/
      ……
      //將顯示硬件注冊到系統(tǒng)中
  err=register_framebuffer(&fb_info.gen.info);
  if (err<0)
     return err;
      ……
  return mem_start;//返回顯存起始地址
  }
  xxxfb_init( )函數(shù)被fbmem.c文件的fb_open( )函數(shù)調(diào)用。由于圖形硬件的多樣性,fb_open( )函數(shù)根據(jù)具體硬件信息選擇xxxfb_init( )啟動輔助函數(shù)。
  μClinux中線性的顯存訪問是實現(xiàn)圖形顯示驅(qū)動首先要注意的問題,處理好上面提到的函數(shù)和數(shù)據(jù)就可以為特定嵌入式系統(tǒng)的顯示設(shè)備開發(fā)出合適的輔助函數(shù)。
3.2.4 安裝驅(qū)動
  下面介紹將顯示驅(qū)動安裝進(jìn)內(nèi)核的步驟。
  (1)圖形顯示硬件屬字符設(shè)備,因此將fbme.c文件保存到目錄/linux-2.0/driver/char/中。
  (2)將圖形設(shè)備加入到的Makefile文件中。
  (3)在/linux/init/main.c文件中添加驅(qū)動的啟動函數(shù)fbmem_init( )。
  (4)修改編譯選項文件,在/linux/arm/armnommu/config.in文件中加入:
  bool′ framebuffer support′ CONFIG_FB_XXX
  (5)為文件系統(tǒng)的open( )調(diào)用提供設(shè)備文件名。在/vendors/<VENDOR>/<BOARD>/Makefile的‘DEVICES=’中,加入‘xxxfb,c,29,0’作為顯示設(shè)備驅(qū)動的入口。其中29是主設(shè)備號,從設(shè)備號可以根據(jù)需要改變,這里將它設(shè)為0。
  (6)使用make工具重新編譯內(nèi)核,就可將圖形顯示的驅(qū)動編譯進(jìn)μClinux內(nèi)核。
  以上六步將顯示硬件驅(qū)動安裝到μClinux的內(nèi)核中,在此基礎(chǔ)上選用合適的圖形包就可以在嵌入式系統(tǒng)中方便地開發(fā)圖形應(yīng)用程序。
4  結(jié)束語
  在某些特殊場合應(yīng)用的嵌入式系統(tǒng)可能需要支持多個顯示硬件的輸出,依照本文的方法可以為不同的顯示硬件設(shè)計輔助函數(shù)來支持多終端圖形輸出。
  至此,本文完成了基于?滋Clinux操作系統(tǒng)的嵌入式設(shè)備的圖形顯示驅(qū)動的探討并給出了部分實現(xiàn)算法。
參考文獻(xiàn)
1   Bovet D P,Cesati M著,陳莉君譯.深入理解Linux內(nèi)核(第二版).北京:中國電力出版社,2004
2   Rubini A,Corbet J著,魏永明譯.Linux設(shè)備驅(qū)動程序(第二版).北京:中國電力出版社,2002
3   毛德操,胡希明.Linux內(nèi)核源代碼情景分析.杭州:浙江大學(xué)出版社,2001

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。