1. 程式人生 > >Framebuffer原理、使用、測試

Framebuffer原理、使用、測試

*二、FrameBuffer在Linux中的實現和機制*
Framebuffer對應的原始檔在linux/drivers/video/目錄下。總的抽象裝置檔案為fbcon.c,在這個目錄下還有與各種顯示卡驅動相關的原始檔。 
(一)、分析Framebuffer裝置驅動 
    需要特別提出的是在INTEL平臺上,老式的VESA1.2卡,如CGA/EGA卡,是不能支援Framebuffer的,因為Framebuffer要求顯示卡支援線性幀緩衝,即CPU可以訪問顯緩衝中的每一位, 但是VESA1.2 卡只能允許CPU一次訪問64K的地址空間。 
FrameBuffer裝置驅動基於如下兩個檔案: 
1) linux/include/linux/fb.h 
2) linux/drivers/video/fbmem.c 下面分析這兩個檔案。 
1、fb.h 
   幾乎主要的結構都是在這個中檔案定義的。這些結構包括: 
1)fb_var_screeninfo 
   這個結構描述了顯示卡的特性: 
struct fb_var_screeninfo 

__u32 xres; /* visible resolution */ 
__u32 yres; 
__u32 xres_virtual; /* virtual resolution */ 
__u32 yres_virtual; 
__u32 xoffset; /* offset from virtual to visible resolution */ 
__u32 yoffset; 
__u32 bits_per_pixel; /* guess what */ 
__u32 grayscale; /* != 0 Gray levels instead of colors */ 
struct fb_bitfield red; /* bitfield in fb mem if true color, */ 
struct fb_bitfield green; /* else only length is significant */ 
struct fb_bitfield blue; 
struct fb_bitfield transp; /* transparency */ 
__u32 nonstd; /* != 0 Non standard pixel format */ 
__u32 activate; /* see FB_ACTIVATE_* */ 
__u32 height; /* height of picture in mm */ 
__u32 width; /* width of picture in mm */ 
__u32 accel_flags; /* acceleration flags (hints) */ 
/* Timing: All values in pixclocks, except pixclock (of course) */ 
__u32 pixclock; /* pixel clock in ps (pico seconds) */ 
__u32 left_margin; /* time from sync to picture */ 
__u32 right_margin; /* time from picture to sync */ 
__u32 upper_margin; /* time from sync to picture */ 
__u32 lower_margin; 
__u32 hsync_len; /* length of horizontal sync */ 
__u32 vsync_len; /* length of vertical sync */ 
__u32 sync; /* see FB_SYNC_* */ 
__u32 vmode; /* see FB_VMODE_* */ 
__u32 reserved[6]; /* Reserved for future compatibility */ 
}; 
2) fb_fix_screeninfon 
這個結構在顯示卡被設定模式後建立,它描述顯示卡的屬性,並且系統執行時不能被修改;比如FrameBuffer記憶體的起始地址。它依賴於被設定的模式,當一個模 式被設定後,記憶體資訊由顯示卡硬體給出,記憶體的位置等資訊就不可以修改。 
struct fb_fix_screeninfo { 
char id[16]; /* identification string eg "TT Builtin" */ 
unsigned long smem_start; /* Start of frame buffer mem */ 
/* (physical address) */ 
__u32 smem_len; /* Length of frame buffer mem */ 
__u32 type; /* see FB_TYPE_* */ 
__u32 type_aux; /* Interleave for interleaved Planes */ 
__u32 visual; /* see FB_VISUAL_* */ 
__u16 xpanstep; /* zero if no hardware panning */ 
__u16 ypanstep; /* zero if no hardware panning */ 
__u16 ywrapstep; /* zero if no hardware ywrap */ 
__u32 line_length; /* length of a line in bytes */ 
unsigned long mmio_start; /* Start of Memory Mapped I/O */ 
/* (physical address) */ 
__u32 mmio_len; /* Length of Memory Mapped I/O */ 
__u32 accel; /* Type of acceleration available */ 
__u16 reserved[3]; /* Reserved for future compatibility */ 
}; 
3) fb_cmap 
描述裝置無關的顏色對映資訊。可以通過FBIOGETCMAP 和 FBIOPUTCMAP 對應的ioctl操作設定或獲取顏色對映資訊. 
struct fb_cmap { 
__u32 start; /* First entry */ 
__u32 len; /* Number of entries */ 
__u16 *red; /* Red values */ 
__u16 *green; 
__u16 *blue; 
__u16 *transp; /* transparency, can be NULL */ 
}; 
4) fb_info 
定義顯示卡的當前狀態;fb_info結構僅在核心中可見,在這個結構中有一個fb_ops指標, 指向驅動裝置工作所需的函式集。 
struct fb_info { 
char modename[40]; /* default video mode */ 
kdev_t node; 
int flags; 
int open; /* Has this been open already ? */ 
#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */ 
struct fb_var_screeninfo var; /* Current var */ 
struct fb_fix_screeninfo fix; /* Current fix */ 
struct fb_monspecs monspecs; /* Current Monitor specs */ 
struct fb_cmap cmap; /* Current cmap */ 
struct fb_ops *fbops; 
char *screen_base; /* Virtual address */ 
struct display *disp; /* initial display variable */ 
struct vc_data *display_fg; /* Console visible on this display */ 
char fontname[40]; /* default font name */ 
devfs_handle_t devfs_handle; /* Devfs handle for new name */ 
devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */ 
int (*changevar)(int); /* tell console var has changed */ 
int (*switch_con)(int, struct fb_info*); 
/* tell fb to switch consoles */ 
int (*updatevar)(int, struct fb_info*); 
/* tell fb to update the vars */ 
void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */ 
/* arg = 0: unblank */ 
/* arg > 0: VESA level (arg-1) */ 
void *pseudo_palette; /* Fake palette of 16 colors and 
the cursor's color for non 
palette mode */ 
/* From here on everything is device dependent */ 
void *par; 
};
5) struct fb_ops 
使用者應用可以使用ioctl()系統呼叫來操作裝置,這個結構就是用一支援ioctl()的這些操作的。 
struct fb_ops { 
/* open/release and usage marking */ 
struct module *owner; 
int (*fb_open)(struct fb_info *info, int user); 
int (*fb_release)(struct fb_info *info, int user); 
/* get non settable parameters */ 
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, 
struct fb_info *info); 
/* get settable parameters */ 
int (*fb_get_var)(struct fb_var_screeninfo *var, int con, 
struct fb_info *info); 
/* set settable parameters */ 
int (*fb_set_var)(struct fb_var_screeninfo *var, int con, 
struct fb_info *info); 
/* get colormap */ 
int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con, 
struct fb_info *info); 
/* set colormap */ 
int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con, 
struct fb_info *info); 
/* pan display (optional) */ 
int (*fb_pan_display)(struct fb_var_screeninfo *var, int con, 
struct fb_info *info); 
/* perform fb specific ioctl (optional) */ 
int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd, 
unsigned long arg, int con, struct fb_info *info); 
/* perform fb specific mmap */ 
int (*fb_mmap)(struct fb_info *info, struct file *file, struct 
vm_area_struct *vma); 
/* switch to/from raster image mode */ 
int (*fb_rasterimg)(struct fb_info *info, int start); 
}; 
6) structure map 
struct fb_info_gen | struct fb_info | fb_var_screeninfo 
| | fb_fix_screeninfo 
| | fb_cmap 
| | modename[40] 
| | fb_ops ---|--->ops on var 
| | ... | fb_open 
| | | fb_release 
| | | fb_ioctl 
| | | fb_mmap 
| struct fbgen_hwswitch -|-> detect 
| | encode_fix 
| | encode_var 
| | decode_fix 
| | decode_var 
| | get_var 
| | set_var 
| | getcolreg 
| | setcolreg 
| | pan_display 
| | blank 
| | set_disp 
[編排有點困難,第一行的第一條豎線和下面的第一列豎線對齊,第一行的第二條豎線和下面的第二列豎線對齊就可以了] 
這個結構 fbgen_hwswitch抽象了硬體的操作.雖然它不是必需的,但有時候很有用. 
2、 fbmem.c 
fbmem.c 處於Framebuffer裝置驅動技術的中心位置.它為上層應用程式提供系統呼叫也為下一層的特定硬體驅動提供介面;那些底層硬體驅動需要用到這兒的介面來向 系統核心註冊它們自己. 
fbmem.c 為所有支援FrameBuffer的裝置驅動提供了通用的介面,避免重複工作. 
1) 全域性變數 
struct fb_info *registered_fb[FB_MAX]; 
int num_registered_fb; 
這兩變數記錄了所有fb_info 結構的例項,fb_info 結構描述顯示卡的當前狀態,所有裝置對應的fb_info結構都儲存在這個陣列中,當一個FrameBuffer裝置驅動向系統註冊自己時,其對應的fb_info結構就會新增到這個結構中,同時num_registered_fb 為自動加1. static struct { 
const char *name; 
int (*init)(void); 
int (*setup)(void); 
} fb_drivers[] __initdata= { ....}; 
如果FrameBuffer裝置被靜態連結到核心,其對應的入口就會新增到這個表中;如果是動態載入的,即使用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 
}; 
這是一個提供給應用程式的介面. 
2)fbmem.c 實現瞭如下函式. 
register_framebuffer(struct fb_info *fb_info); 
unregister_framebuffer(struct fb_info *fb_info); 
這兩個是提供給下層FrameBuffer裝置驅動的介面,裝置驅動通過這兩函式向系統註冊或登出自己。幾乎底層裝置驅動所要做的所有事情就是填充fb_inf o結構然後向系統註冊或登出它。 
(二)一個LCD顯示晶片的驅動例項 
    以Skeleton LCD控制器驅動為例,在LINUX中存有一個/fb/skeleton.c的skeleton的Framebuffer驅動程式,很簡單,僅僅是填充了fb_info結構,並且註冊/登出自己。裝置驅動是向用戶程式提供系統呼叫介面,所以我們需要實現底層硬體操作並且定義file_operations結構來向系統提供系統呼叫介面,從而實現更有效的LCD控制器驅動程式。 
1)在系統記憶體中分配視訊記憶體 
在fbmem.c檔案中可以看到,file_operations結構中的open()和release()操作不需底層支援,但read()、write()和 mmap()操作需要函式fb_get_fix()的支援.因此需要重新實現函式fb_get_fix()。另外還需要在系統記憶體中分配視訊記憶體空間,大多數的LCD控制器都沒有自己的視訊記憶體空間,被分配的地址空間的起 始地址與長度將會被填充到fb_fix_screeninfo結構的smem_start 和smem_len 的兩個變數中.被分配的空間必須是物理連續的。 
2)實現 fb_ops 中的函式 
使用者應用程式通過ioctl()系統呼叫操作硬體,fb_ops 中的函式就用於支援這些操作。(注: fb_ops結構與file_operations結構不同,fb_ops是底層操作的抽象,而file_operations是提供給上層系統呼叫的介面,可以直接呼叫ioctl()系統呼叫在檔案fbmem.c中實現,通過觀察可以發現ioctl()命令與fb_ops's 中函式的關係: 
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_XXX 方法,使用者程式就可以使用FBIOXXXX巨集的ioctl()操作來操作硬體。 
檔案linux/drivers/video/fbgen.c或者linux/drivers/video目錄下的其它裝置驅動是比較好的參考資料。在所有的這 些函式中fb_set_var()是最重要的,它用於設定顯示卡的模式和其它屬性,下面是函式fb_set_var()的執行步驟: 
1)檢測是否必須設定模式 
2)設定模式 
3)設定顏色對映 
4) 根據以前的設定重新設定LCD控制器的各暫存器。