全面的framebuffer詳解【轉】


轉自:https://blog.csdn.net/wealoong/article/details/7957244

可以同時參考另外幾篇詳細文章:

基於S3C2440的嵌入式Linux驅動——Framebuffer子系統解讀

 

linux LCD驅動(二)--FrameBuffer

 

Linux LCD驅動(三)--圖形顯示

android framebuffer driver 小結[msm7627為例]

 

一、FrameBuffer的原理 
    FrameBuffer 是出現在 2.2.xx 內核當中的一種驅動程序接口。
    Linux是工作在保護模式下,所以用戶態進程是無法象DOS那樣使用顯卡BIOS里提供的中斷調用來實現直接寫屏,Linux抽象出 FrameBuffer這個設備來供用戶態進程實現直接寫屏。Framebuffer機制模仿顯卡的功能,將顯卡硬件結構抽象掉,可以通過 Framebuffer的讀寫直接對顯存進行操作。用戶可以將Framebuffer看成是顯示內存的一個映像,將其映射到進程地址空間之后,就可以直接進行讀寫操作,而寫操作可以立即反應在屏幕上。這種操作是抽象的,統一的。用戶不必關心物理顯存的位置、換頁機制等等具體細節。這些都是由 Framebuffer設備驅動來完成的。
    但Framebuffer本身不具備任何運算數據的能力,就只好比是一個暫時存放水的水池.CPU將運算后的結果放到這個水池,水池再將結果流到顯示器. 中間不會對數據做處理. 應用程序也可以直接讀寫這個水池的內容.在這種機制下,盡管Framebuffer需要真正的顯卡驅動的支持,但所有顯示任務都有CPU完成,因此CPU 負擔很重
framebuffer的設備文件一般是 /dev/fb0、/dev/fb1 等等。
可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕.
如果顯示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;
用命令: #dd if=/dev/fb of=fbfile  可以將fb中的內容保存下來;
可以重新寫回屏幕: #dd if=fbfile of=/dev/fb;
在使用Framebuffer時,Linux是將顯卡置於圖形模式下的.

    在應用程序中,一般通過將 FrameBuffer 設備映射到進程地址空間的方式使用,比如下面的程序就打開 /dev/fb0 設備,並通過 mmap 系統調用進行地址映射,隨后用 memset 將屏幕清空(這里假設顯示模式是 1024x768-8 位色模式,線性內存模式):

int fb;
unsigned char* fb_mem;
fb = open ("/dev/fb0", O_RDWR);
fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
memset (fb_mem, 0, 1024*768); //這個命令應該只有在root可以執行

    FrameBuffer 設備還提供了若干 ioctl 命令,通過這些命令,可以獲得顯示設備的一些固定信息(比如顯示內存大小)、與顯示模式相關的可變信息(比如分辨率、象素結構、每掃描線的字節寬度),以及偽彩色模式下的調色板信息等等。
    通過 FrameBuffer 設備,還可以獲得當前內核所支持的加速顯示卡的類型(通過固定信息得到),這種類型通常是和特定顯示芯片相關的。比如目前最新的內核(2.4.9)中,就包含有對 S3、Matrox、nVidia、3Dfx 等等流行顯示芯片的加速支持。在獲得了加速芯片類型之后,應用程序就可以將 PCI 設備的內存I/O(memio)映射到進程的地址空間。這些 memio 一般是用來控制顯示卡的寄存器,通過對這些寄存器的操作,應用程序就可以控制特定顯卡的加速功能。
    PCI 設備可以將自己的控制寄存器映射到物理內存空間,而后,對這些控制寄存器的訪問,給變成了對物理內存的訪問。因此,這些寄存器又被稱為"memio"。一旦被映射到物理內存,Linux 的普通進程就可以通過 mmap 將這些內存 I/O 映射到進程地址空間,這樣就可以直接訪問這些寄存器了。
    當然,因為不同的顯示芯片具有不同的加速能力,對memio 的使用和定義也各自不同,這時,就需要針對加速芯片的不同類型來編寫實現不同的加速功能。比如大多數芯片都提供了對矩形填充的硬件加速支持,但不同的芯片實現方式不同,這時,就需要針對不同的芯片類型編寫不同的用來完成填充矩形的函數。
    FrameBuffer 只是一個提供顯示內存和顯示芯片寄存器從物理內存映射到進程地址空間中的設備。所以,對於應用程序而言,如果希望在 FrameBuffer 之上進行圖形編程,還需要自己動手完成其他許多工作。

二、FrameBuffer在Linux中的實現和機制
Framebuffer對應的源文件在linux/drivers/video/目錄下。總的抽象設備文件為fbcon.c,在這個目錄下還有與各種顯卡驅動相關的源文件。  //這個文件要好好看看

(一)、分析Framebuffer設備驅動
    需要特別提出的是在INTEL平台上,老式的VESA 1.2 卡,如CGA/EGA卡,是不能支持Framebuffer的,因為Framebuffer要求顯卡支持線性幀緩沖,即CPU可以訪問顯緩沖中的每一位,但是VESA 1.2 卡只能允許CPU一次訪問64K的地址空間。
FrameBuffer設備驅動基於如下兩個文件:
1) linux/include/linux/fb.h
2) linux/drivers/video/fbmem.c

下面分析這兩個文件。
1、fb.h
   幾乎主要的結構都是在這個中文件定義的。這些結構包括:
1)fb_var_screeninfo
   這個結構描述了顯示卡的特性:
NOTE::::    __u32 是表示 unsigned 不帶符號的 32 bits 的數據類型,其余類推。這是 Linux 內核中所用到的數據類型,如果是開發用戶空間(user-space)的程序,可以根據具體計算機平台的情況,用 unsigned long 等等來代替

  1.  
    struct fb_var_screeninfo
  2.  
    {
  3.  
    __u32 xres; /* visible resolution */ //可視區域
  4.  
    __u32 yres;
  5.  
    __u32 xres_virtual; /* virtual resolution */ //可視區域
  6.  
    __u32 yres_virtual;
  7.  
    __u32 xoffset; /* offset from virtual to visible resolution */ //可視區域的偏移
  8.  
    __u32 yoffset;
  9.  
     
  10.  
    __u32 bits_per_pixel; /* guess what */ //每一象素的bit數
  11.  
    __u32 grayscale; /* != 0 Gray levels instead of colors *///等於零就成黑白
  12.  
     
  13.  
    struct fb_bitfield red; /* bitfield in fb mem if true color, */真彩的bit機構
  14.  
    struct fb_bitfield green; /* else only length is significant */
  15.  
    struct fb_bitfield blue;
  16.  
    struct fb_bitfield transp; /* transparency */ 透明
  17.  
     
  18.  
    __u32 nonstd; /* != 0 Non standard pixel format */ 不是標准格式
  19.  
     
  20.  
    __u32 activate; /* see FB_ACTIVATE_* */
  21.  
     
  22.  
    __u32 height; /* height of picture in mm */ 內存中的圖像高度
  23.  
    __u32 width; /* width of picture in mm */ 內存中的圖像寬度
  24.  
     
  25.  
    __u32 accel_flags; /* acceleration flags (hints) */ 加速標志
  26.  
     
  27.  
    /* Timing: All values in pixclocks, except pixclock (of course) */
  28.  
     
  29.  
    時序-_-這些部分就是顯示器的顯示方法了,可以找相關的資料看看
  30.  
    __u32 pixclock; /* pixel clock in ps (pico seconds) */
  31.  
    __u32 left_margin; /* time from sync to picture */
  32.  
    __u32 right_margin; /* time from picture to sync */
  33.  
    __u32 upper_margin; /* time from sync to picture */
  34.  
    __u32 lower_margin;
  35.  
    __u32 hsync_len; /* length of horizontal sync */ 水平可視區域
  36.  
    __u32 vsync_len; /* length of vertical sync */ 垂直可視區域
  37.  
    __u32 sync; /* see FB_SYNC_* */
  38.  
    __u32 vmode; /* see FB_VMODE_* */
  39.  
    __u32 reserved[6]; /* Reserved for future compatibility */ 備用-以后開發
  40.  
    };
  41.  
     


2) fb_fix_screeninfon
這個結構在顯卡被設定模式后創建,它描述顯示卡的屬性,並且系統運行時不能被修改 ;比如FrameBuffer內存的起始地址。它依賴於被設定的模式,當一個模式被設定后,內存信息由顯示卡硬件給出,內存的位置等信息就不可以修改。

  1.  
    struct fb_fix_screeninfo {
  2.  
    char id[16]; /* identification string eg "TT Builtin" */ID
  3.  
    unsigned long smem_start; /* Start of frame buffer mem */ 內存起始
  4.  
    /* (physical address) */ 物理地址
  5.  
    __u32 smem_len; /* Length of frame buffer mem */ 內存大小
  6.  
    __u32 type; /* see FB_TYPE_* */
  7.  
    __u32 type_aux; /* Interleave for interleaved Planes */插入區域?
  8.  
    __u32 visual; /* see FB_VISUAL_* */
  9.  
    __u16 xpanstep; /* zero if no hardware panning */沒有硬件設備就為零
  10.  
    __u16 ypanstep; /* zero if no hardware panning */
  11.  
    __u16 ywrapstep; /* zero if no hardware ywrap */
  12.  
    __u32 line_length; /* length of a line in bytes */ 一行的字節表示
  13.  
    unsigned long mmio_start; /* Start of Memory Mapped I/O */內存映射的I/O起始
  14.  
    /* (physical address) */
  15.  
    __u32 mmio_len; /* Length of Memory Mapped I/O */ I/O的大小
  16.  
    __u32 accel; /* Type of acceleration available */ 可用的加速類型
  17.  
    __u16 reserved[3]; /* Reserved for future compatibility */
  18.  
    };


3) fb_cmap
描述設備無關的顏色映射信息。可以通過FBIOGETCMAP 和 FBIOPUTCMAP 對應的ioctl操作設定或獲取顏色映射信息.

  1.  
    struct fb_cmap {
  2.  
    __u32 start; /* First entry */ 第一個入口
  3.  
    __u32 len; /* Number of entries */ 入口的數字
  4.  
    __u16 *red; /* Red values */ 紅
  5.  
    __u16 *green;
  6.  
    __u16 *blue;
  7.  
    __u16 *transp; /* transparency, can be NULL */ 透明,可以為零
  8.  
    };


4) fb_info
定義當顯卡的當前狀態;fb_info結構僅在內核中可見,在這個結構中有一個fb_ops指針, 指向驅動設備工作所需的函數集。

  1.  
    struct fb_info {
  2.  
    char modename[40]; /* default video mode */ 默認的視頻卡類型
  3.  
    kdev_t node;
  4.  
    int flags;
  5.  
    int open; /* Has this been open already ? */ 被打開過么?
  6.  
    #define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
  7.  
    struct fb_var_screeninfo var; /* Current var */ 現在的視頻信息
  8.  
    struct fb_fix_screeninfo fix; /* Current fix */ 修正的信息
  9.  
    struct fb_monspecs monspecs; /* Current Monitor specs */ 現在的顯示器模式
  10.  
    struct fb_cmap cmap; /* Current cmap */ 當前優先級
  11.  
    struct fb_ops *fbops;
  12.  
    char *screen_base; /* Virtual address */ 物理基址
  13.  
    struct display *disp; /* initial display variable */初始化
  14.  
    struct vc_data *display_fg; /* Console visible on this display */
  15.  
    char fontname[40]; /* default font name */默認的字體
  16.  
    devfs_handle_t devfs_handle; /* Devfs handle for new name */
  17.  
    devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */兼容
  18.  
    int (*changevar)(int); /* tell console var has changed */ 告訴console變量修改了
  19.  
    int (*switch_con)(int, struct fb_info*);
  20.  
    /* tell fb to switch consoles */ 告訴fb選擇consoles
  21.  
    int (*updatevar)(int, struct fb_info*);
  22.  
    /* tell fb to update the vars */ 告訴fb更新變量
  23.  
    void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */告訴fb使用黑白模式(或者不黑)
  24.  
    /* arg = 0: unblank */arg=0的時候黑白模式
  25.  
    /* arg > 0: VESA level (arg-1) */ arg>0時候選擇VESA模式
  26.  
    void *pseudo_palette; /* Fake palette of 16 colors and
  27.  
    the cursor's color for non
  28.  
    palette mode */ 修正調色板
  29.  
    /* From here on everything is device dependent */ 現在就可以使用了
  30.  
    void *par;
  31.  
    };
  32.  
     


5) struct fb_ops
用戶應用可以使用ioctl()系統調用來操作設備,這個結構就是用一支持ioctl()的這些操作的

  1.  
    struct fb_ops {
  2.  
    /* open/release and usage marking */
  3.  
    struct module *owner;
  4.  
    int (*fb_open)(struct fb_info *info, int user);
  5.  
    int (*fb_release)(struct fb_info *info, int user);
  6.  
    /* get non settable parameters */
  7.  
    int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
  8.  
    struct fb_info *info);
  9.  
    /* get settable parameters */
  10.  
    int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
  11.  
    struct fb_info *info);
  12.  
    /* set settable parameters */
  13.  
    int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
  14.  
    struct fb_info *info);
  15.  
    /* get colormap */
  16.  
    int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
  17.  
    struct fb_info *info);
  18.  
    /* set colormap */
  19.  
    int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
  20.  
    struct fb_info *info);
  21.  
    /* pan display (optional) */
  22.  
    int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
  23.  
    struct fb_info *info);
  24.  
    /* perform fb specific ioctl (optional) */
  25.  
    int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
  26.  
    unsigned long arg, int con, struct fb_info *info);
  27.  
    /* perform fb specific mmap */
  28.  
    int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
  29.  
    /* switch to/from raster image mode */
  30.  
    int (*fb_rasterimg)(struct fb_info *info, int start);
  31.  
    };
  32.  
     


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

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.

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


如果FrameBuffer設備被靜態鏈接到內核,其對應的入口就會添加到這個表中;如果是動態加載的,即使用insmod/rmmod,就不需要關心這個表。

  1.  
    static struct file_operations fb_ops ={
  2.  
    owner: THIS_MODULE,
  3.  
    read: fb_read,
  4.  
    write: fb_write,
  5.  
    ioctl: fb_ioctl,
  6.  
    mmap: fb_mmap,
  7.  
    open: fb_open,
  8.  
    release: fb_release
  9.  
    };


這是一個提供給應用程序的接口.

2)fbmem.c 實現了如下函數.

register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info); 
 
這兩個是提供給下層FrameBuffer設備驅動的接口,設備驅動通過這兩函數向系統注冊或注銷自己。幾乎底層設備驅動所要做的所有事情就是填充fb_info結構然后向系統注冊或注銷它。

(二)一個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控制器的各寄存器。

第四步表明了底層操作到底放置在何處。在系統內存中分配顯存后,顯存的起始地址及長度將被設定到 LCD控制器的各寄存器中(一般通過fb_set_var() 函數),顯存中的內容將自動被LCD控制器輸出到屏幕上。另一方面,用戶程序通過函數mmap()將顯存映射到用戶進程地址空間中,然后用戶進程向映射空間發送的所有數據都將會被顯示到LCD顯示器上。

==========================================打開流程

2.3  主要代碼結構以及關鍵代碼分析
2.3.1  FrameBuffer驅動的統一管理
 fbmem.c實現了Linux FrameBuffer的中間層,任何一個FrameBuffer驅動,在系統初始化時,必須向fbmem.c注冊,即需要調用register_framebuffer()函數,在這個過程中,設備驅動的信息將會存放入名稱為registered_fb數組中,這個數組定義為
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
它是類型為fb_info的數組,另外num_register_fb則存放了注冊過的設備數量。
 我們分析一下register_framebuffer的代碼。

  1.  
    int register_framebuffer(struct fb_info *fb_info)
  2.  
    {
  3.  
    int i;
  4.  
    struct fb_event event;
  5.  
    struct fb_videomode mode;
  6.  
     
  7.  
     
  8.  
    if (num_registered_fb == FB_MAX) return -ENXIO; /* 超過最大數量 */
  9.  
    num_registered_fb++;
  10.  
    for (i = 0 ; i < FB_MAX; i++)
  11.  
    if (!registered_fb[i]) break; /* 找到空余的數組空間 */
  12.  
    fb_info->node = i;
  13.  
     
  14.  
    fb_info->dev = device_create(fb_class, fb_info->device,
  15.  
    MKDEV(FB_MAJOR, i), "fb%d", i); /* 為設備建立設備節點 */
  16.  
    if (IS_ERR(fb_info->dev)) {
  17.  
    …………
  18.  
    } else{
  19.  
    fb_init_device(fb_info); /* 初始化改設備 */
  20.  
    }
  21.  
    …………
  22.  
    return 0;
  23.  
    }
  24.  
     

從上面的代碼可知,當FrameBuffer驅動進行注冊的時候,它將驅動的fb_info結構體記錄到全局數組registered_fb中,並動態建立設備節點,進行設備的初始化。注意,這里建立的設備節點的次設備號就是該驅動信息在registered_fb存放的位置,即數組下標i 。在完成注冊之后,fbmem.c就記錄了驅動的fb_info。這樣我們就有可能實現fbmem.c對全部FrameBuffer驅動的統一處理。

2.3.2  實現消息的分派
fbmem.c實現了對系統全部FrameBuffer設備的統一管理。當用戶嘗試使用一個特定的FrameBuffer時,fbmem.c怎么知道該調用那個特定的設備驅動呢?
我們知道,Linux是通過主設備號和次設備號,對設備進行唯一標識。不同的FrameBuffer設備向fbmem.c注冊時,程序分配給它們的主設備號是一樣的,而次設備號是不一樣的。於是我們就可以通過用戶指明的次設備號,來覺得具體該調用哪一個FrameBuffer驅動。下面通過分析fbmem.c的fb_open()函數來說明。(注:一般我們寫FrameBuffer驅動不需要實現open函數,這里只是說明函數流程。)

  1.  
    static int fb_open(struct inode *inode, struct file *file){
  2.  
    int fbidx = iminor(inode);
  3.  
    struct fb_info *info;
  4.  
    int res;
  5.  
    /* 得到真正驅動的函數指針 */
  6.  
    if (!(info = registered_fb[fbidx])) return -ENODEV;
  7.  
    if (info->fbops->fb_open) {
  8.  
    res = info->fbops->fb_open(info,1); //調用驅動的open()
  9.  
    if (res) module_put(info->fbops->owner);
  10.  
    }
  11.  
    return res;
  12.  
    }



當用戶打開一個FrameBuffer設備的時,將調用這里的fb_open()函數。傳進來的inode就是欲打開設備的設備號,包括主設備和次設備號。fb_open函數首先通過iminor()函數取得次設備號,然后查全局數組registered_fb得到設備的fb_info信息,而這里面存放了設備的操作函數集fb_ops。這樣,我們就可以調用具體驅動的fb_open() 函數,實現open的操作。下面給出了一個LCD驅動的open() 函數的調用流程圖,用以說明上面的步驟。
 
 圖2.4

 

 

 

三、FrameBuffer的應用

(一)、一個使用FrameBuffer的例子

  1. FrameBuffer主要是根據VESA標准的實現的,所以只能實現最簡單的功能。
  2. 由於涉及內核的問題,FrameBuffer是不允許在系統起來后修改顯示模式等一系列操作。(好象很多人都想要這樣干,這是不被允許的,當然如果你自己寫驅動的話,是可以實現的).
  3. 對FrameBuffer的操作,會直接影響到本機的所有控制台的輸出,包括XWIN的圖形界面。
  4. 在struct fb_info 中的char fontname[40]; /* default font name */默認的字體
    就可以實現顯示的中文化----難道 籃點linux就是這樣搞得??

好,現在可以讓我們開始實現直接寫屏:

1、打開一個FrameBuffer設備

2、通過mmap調用把顯卡的物理內存空間映射到用戶空間

3、直接寫內存。

/********************************
File name : fbtools.h
*/

#ifndef _FBTOOLS_H_
#define _FBTOOLS_H_
#include <linux/fb.h>
//a framebuffer device structure;
typedef struct fbdev{
       int fb;
       unsigned long fb_mem_offset;
       unsigned long fb_mem;
       struct fb_fix_screeninfo fb_fix;
       struct fb_var_screeninfo fb_var;
       char dev[20];
} FBDEV, *PFBDEV;

//open & init a frame buffer
//to use this function,
//you must set FBDEV.dev="/dev/fb0"
//or "/dev/fbX"
//it's your frame buffer.
int fb_open(PFBDEV pFbdev);

//close a frame buffer
int fb_close(PFBDEV pFbdev);

//get display depth
int get_display_depth(PFBDEV pFbdev);

//full screen clear
void fb_memset(void *addr, int c, size_t len);

#endif 

/******************
File name : fbtools.c
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <asm/page.h>
#include "fbtools.h"
#define TRUE        1
#define FALSE       0
#define MAX(x,y)        ((x)>(y)?(x)y))
#define MIN(x,y)        ((x)<(y)?(x)y))

//open & init a frame buffer
int fb_open(PFBDEV pFbdev)
{
       pFbdev->fb = open(pFbdev->dev, O_RDWR);
       if(pFbdev->fb < 0)
       {
              printf("Error opening %s: %m. Check kernel config/n", pFbdev->dev);
              return FALSE;
       }

       if (-1 == ioctl(pFbdev->fb,FBIOGET_VSCREENINFO,&(pFbdev->fb_var)))
       {
              printf("ioctl FBIOGET_VSCREENINFO/n");
              return FALSE;
       }

       if (-1 == ioctl(pFbdev->fb,FBIOGET_FSCREENINFO,&(pFbdev->fb_fix)))
       {
              printf("ioctl FBIOGET_FSCREENINFO/n");
              return FALSE;
       }

       //map physics address to virtual address
       pFbdev->fb_mem_offset = (unsigned long)(pFbdev->fb_fix.smem_start) & (~PAGE_MASK);
       pFbdev->fb_mem = (unsigned long int)mmap(NULL, pFbdev->fb_fix.smem_len + pFbdev->fb_mem_offset,              PROT_READ | PROT_WRITE, MAP_SHARED, pFbdev->fb, 0);

       if (-1L == (long) pFbdev->fb_mem)
       {
              printf("mmap error! mem:%d offset:%d/n", pFbdev->fb_mem, pFbdev->fb_mem_offset);
              return FALSE;
       }
       return TRUE;
}

//close frame buffer
int fb_close(PFBDEV pFbdev)
{
       close(pFbdev->fb);
       pFbdev->fb=-1;
}

//get display depth
int get_display_depth(PFBDEV pFbdev);
{
       if(pFbdev->fb<=0)
       {
              printf("fb device not open, open it first/n");
              return FALSE;
       }
       return pFbdev->fb_var.bits_per_pixel;
}

//full screen clear
void fb_memset (void *addr, int c, size_t len)
{
    memset(addr, c, len);
}

//use by test
#define DEBUG
#ifdef DEBUG
main()
{
       FBDEV fbdev;
       memset(&fbdev, 0, sizeof(FBDEV));
       strcpy(fbdev.dev, "/dev/fb0");
       if(fb_open(&fbdev)==FALSE)
       {
              printf("open frame buffer error/n");
              return;
       }
       fb_memset(fbdev.fb_mem + fbdev.fb_mem_offset, 0, fbdev.fb_fix.smem_len);
              fb_close(&fbdev);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM