怎樣寫 Linux LCD 驅動程序

基本原理

  • 通過 framebuffer ,應用程序用 mmap 把顯存映射到應用程序虛擬地址空間,將要顯示的數據寫入這個內存空間就可以在屏幕上顯示出來;
  • 驅動程序分配系統內存作爲顯存;實現 file_operations 結構中的接口,爲應用程序服務;實現 fb_ops 結構中的接口,控制和操作 LDC 控制器;
  • 驅動程序將顯存的起始地址和長度傳給 LCD 控制器的寄存器 (一般由 fb_set_var 完成) , LDC 控制器會自動的將顯存中的數據顯示在 LCD 屏上。

寫 framebuffer 驅動程序要做什麼

  • 簡單的講,framebuffer 驅動的功能就是分配一塊內存作顯存,然後對 LCD 控制器的寄存器作一些設置。
  • 具體來說:
    1. 填充一個 fbinfo 結構
    2. 用 reigster_framebuffer (fbinfo*) 將 fbinfo 結構註冊到內核
  • 對於 fbinfo 結構,最主要的是它的 fs_ops 成員,需要針對具體設備實現 fs_ops 中的接口
  • 考慮是否使用中斷處理
  • 考慮內存訪問方式
    1. 顯卡不自帶顯存的,分配系統內存作爲顯存
    2. 顯卡自帶顯存的,用 I/O 內存接口進行訪問 (request_mem_region / ioremap),
  • 關於如何寫驅動的參考資料,在網站 http: /linux-fbdev.sourceforge.net/HOWTO/index.html 可以找到 "Linux Frame buffer Driver Writing HOWTO"

LCD 模塊 \ 驅動程序 \ 控制器

關於LCD 設備資料可參考如下資料:

  • Datasheet of LCD device
  • 書:液晶顯示技術
  • 書:液晶顯示器件

什麼是 frame buffer 設備

frame buffer 設備是圖形硬件的抽象,它代表了圖形硬件的偵緩衝區,允許應 用程序通過指定的接口訪問圖形硬件。因此,應用程序不必關心底層硬件細節。

設備通過特定的設備節點訪問,通常在 /dev 目錄下,如 /dev/fb*。

更多關於 frame buffer device 的資料可以在以下兩個文件中找到: linux /Documentation/fb/framebuffer.txt 和 linux /Documentation/fb /interal.txt,但這些資料內容不多,還需要看看結合代碼具體分析。

Linux Frame Buffer 驅動程序層次結構

Frame Buffer 設備驅動可以從三個層次來看:

  1. 應用程序與系統調用;
  2. 適用於所有設備的通用代碼,避免重複,包括 file_operations 結構、register/unregister framebuffer 接口等;
  3. 操作具體硬件的代碼,主要是 fs_ops 結構。

在 Linux 內核中,Frame Buffer 設備驅動的源碼主要在以下兩個文件中,它們 處於 frame buffer 驅動體系結構的中間層,它爲上層的用戶程序提供系統調用, 也爲底層特定硬件驅動提供了接口:

  1. linux/inlcude/fb.h
  2. linux/drivers/video/fbmem.c
數據結構

頭文件 fb.h 定義了所有的數據結構:

  • fb_var_screeninfo:描述了一種顯卡顯示模式的所有信息,如寬、高、顏色深度等,不同的顯示模式對應不同的信息;
  • fb_fix_screeninfo:定義了顯卡信息,如 framebuffer 內存的起始地址,地址長度等;
  • fb_cmap:設備獨立的 colormap 信息,可以通過 ioctl 的 FBIOGETCMAP 和 FBIOPUTCMAP 命令設置 colormap;
  • fb_info:包含當前 video card 的狀態信息,只有 fb_info 對內核可見;
  • fb_ops : 應用程序使用 ioctl 系統調用操作底層的 LCD 硬件,fb_ops 結構中定義的方法用於支持這些操作;
  • 這些結構相互之間的關係如下所示:
framebuffer 驅動主要數據結構
framebuffer 驅動主要數據結構
接口

fbmem.c 實現了所有驅動使用的通用代碼,避免了重複。

全局變量:

     struct fb_info *registered_fb [FB_MAX]
     int num_registered_fb;

這個兩個變量用於記錄正在使用的 fb_info 結構實例。fb_info 代表 video card 的當前狀態,所有的 fb_info 結構都放在數組中。當一個 frame buffer 在內核中登記時,一個新的 fb_info 結構被加入該數組,num_registered_fb 加 1。

fb_drivers 數組:

static struct {
    const char *name;
    int (*init)(void);
    int (*setup)(void);
} fb_drivers[] __initdata= { ....};

若 frame buffer 驅動程序是靜態鏈接到內核中,一個新的 entry 必須要加到這個表中。 若該驅動程序是使用 insmod/rmmod 動態加載到內核,則不必關心這個結構。

static struct file_operations fb_ops ={
    owner: THIS_MODULE,
    read: fb_read,
    write: fb_write,
    ioctl: fb_ioctl,
    mmap: fb_mmap,
    open: fb_open,
    release: fb_release
};

這是用戶應用程序的接口,fbmem.c 實現了這些函數。

register/unregister framebuffer:

 register_framebuffer(struct fb_info *fb_info)
 unregister_framebuffer(struct fb_info *fb_info)

這是底層 frame buffer 設備驅動程序的接口。驅動程序使用這對函數實現註冊和撤銷操作。底層驅動程序的工作基本上是填充 fb_info 結構,然後註冊它。

一個 LCD controller 驅動程序

實現一個 LCD controller 驅動程序主要做如下兩步:

  • 分配系統內存作顯存
  • 根據具體的硬件特性,實現 fb_ops 的接口
  • 在 linux/drivers/fb/skeletonfb.c 中有一個 frame buffer 驅動程序的框架,它示例了怎樣用很少的代碼實現一個 frame buffer 驅動程序。
分配系統內存作爲顯存

由於大多數 LDC controller 沒有自己的顯存,需要分配一塊系統內存作爲顯存。 這塊系統內存的起始地址和長度之後會被存放在 fb_fix_screeninfo 的 smem_start 和 smem_len 域中。該內存應該是物理上連續的。

對於帶獨立顯存的顯卡,使用 request_mem_region 和 ioremap 將顯卡外設內存映射到處理器虛擬地址空間。

實現 fb_ops 結構

目前還沒有討論的 file_operations 方法是 ioctl ()。用戶應用程序使用 ioctrl 系統調用操作 LCD 硬件。fb_ops 結構中定義的方法爲這些操作提供支 持。注意, fb_ops 結構不是 file_operations 結構。fb_ops 是底層操作的抽 象,而 file_operations 爲上層系統調用接口提供支持。

下面考慮需要實現哪些方法。ioctl 命令和 fb_ops 結構中的接口之間的關係如 下所示:

    FBIOGET_VSCREENINFO fb_get_var
    FBIOPUT_VSCREENINFO fb_set_var
    FBIOGET_FSCREENINFO fb_get_fix
    FBIOPUTCMAP fb_set_cmap
    FBIOGETCMAP fb_get_cmap
    FBIOPAN_DISPLAY fb_pan_display

只要我們實現了那些 fb_XXX 函數,那麼用戶應用程序就可以使用 FBIOXXXX 宏 來操作 LDC 硬件了。那怎麼實現那些接口呢?可以參考下 linux/drivers/video 目錄下的驅動程序。

在衆多接口中, fb_set_var 是最重要的。它用於設置 video mode 等信息。下 面是實現 fb_set_var 函數的通用步驟:

  1. 檢查是否有必要設置 mode
  2. 設置 mode
  3. 設置 colormap
  4. 根據上面的設置重新配置 LCD controller 寄存器

其中第四步是底層硬件操作。

模板:
1、第1部分:
   a.將LCD設備註冊到系統平臺設備中;
   b.定義LCD平臺設備結構體lcd_fb_driver。
 
2、第2部分:
   a.獲取和設置LCD平臺設備的各種資源;
   b.分配fb_info結構體空間;
   c.初始化fb_info結構體中的各參數;
   d.初始化LCD控制器;
   e.檢查fb_info中可變參數;
   f.申請幀緩衝設備的顯示緩衝區空間;
   g.註冊fb_info。
 
3、第3部分:
   a.實現對fb_info相關參數進行檢查的硬件接口函數;
   b.實現對LCD顯示模式進行設定的硬件接口函數;
   c.實現對LCD顯示開關(空白)的硬件接口函數等。

轉載於http://www.linuxgraphics.cn/graphics/writing_lcd_driver.html

發佈了64 篇原創文章 · 獲贊 3 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章