10、LCD的framebuffer設備驅動


 

在讀者學習本章以及后續LCD相關章節之前,最好擁有LCD裸機基礎,可以參考:LCD編程

 

在內核中,表示LCD使用的是framebuffer(幀緩沖,簡寫為fb),其內容對應於屏幕上的界面顯示。修改framebuffer中的內容,即修改屏幕上的內容。操作framebuffer可以直接在LCD上觀察到效果。

framebuffer本質上是一段內存,或稱作顯存。

 

在內核中,LCD對應的參數使用struct fb_info存儲,對應的行為使用struct fb_ops存儲。

在以下章節,我會分別討論fb_info和fb_ops。

 

 

一、fb_info

之前說過fb_info定義的是屬性,其結構體定義如下:

struct fb_info {
    ...
    struct fb_var_screeninfo var;        /* LCD可變參數,如屏幕一行像素點個數xres,一列像素點個數yres,每像素點所占位數等 */
    struct fb_fix_screeninfo fix;        /* LCD固定參數,記錄用戶不能修改的顯示控制器的參數,如屏幕緩存區物理地址smem_start,id,type等 */

    ...

    struct backlight_device *bl_dev;    /* 背光設備 */

    ...

    struct fb_ops *fbops;                /* LCD操作函數 */
    struct device *device;        /* This is the parent */
    struct device *dev;            /* This is this fb device */
    
    ...
    
    char __iomem *screen_base;            /* 顯存虛擬地址 */
    unsigned long screen_size;            /* 屏幕大小*每個像素的字節數 */ 
    void *pseudo_palette;                /* Fake palette of 16 colors */ 

    ...
};

其中,我們需要關注的有var、fix、screen_base和pseudo_palette

 

var結構體定義如下:

struct fb_var_screeninfo {
    __u32 xres;              /* LCD物理分辨率    */
    __u32 yres;
    __u32 xres_virtual;      /* LCD虛擬分辨率    */
    __u32 yres_virtual;
    __u32 xoffset;           /* 虛擬和物理分辨率的偏移值 */
    __u32 yoffset;

    __u32 bits_per_pixel;    /* 每一個像素占多少bit    */
    __u32 grayscale;         /* 灰度值,0 = color,1 = grayscale, */
                    /* >1 = FOURCC            */
    struct fb_bitfield red;        /* bitfield in fb mem if true color, */
    struct fb_bitfield green;    /* else only length is significant */
    struct fb_bitfield blue;
    
    ...
    
    __u32 activate;           /* see FB_ACTIVATE_*        */

    ...

    /* Timing指的是LCD上下的黑框的寬度等參數,一般不用設置 */
    __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 rotate;            /* angle we rotate counter clockwise */
    __u32 colorspace;        /* colorspace for FOURCC-based modes */
    __u32 reserved[4];        /* Reserved for future compatibility */
};

其中需要我們了解的有:

1. bits_per_pixel是LCD邏輯中的BPP,一般有24BPP、16BPP和8BPP。BPP的數值越大,顯存所需空間越大,給處理器帶來的負擔也就越重;BPP的數值在8位以下時,所能表達的顏色又太少,不能夠滿足用戶特定的需求。為解決這個問題,就需要采取調色板,也就是pseudo_palette。

2. fb_bitfield結構體用於設置紅色、綠色和藍色在BPP中的位置和長度。比如16BPP,格式為565,則格式示例代碼如下:

    fbinfo->var.red.offset        = 11;
    fbinfo->var.red.length        = 5;
//    fbinfo->var.red.msb_right    = ;        /* 1: 右邊為高位 */
    fbinfo->var.green.offset    = 5;
    fbinfo->var.green.length    = 6;
//    fbinfo->var.green.msb_right    = ;
    fbinfo->var.blue.offset        = 0;
    fbinfo->var.blue.length        = 5;
//    fbinfo->var.blue.msb_right    = ;

3. FB_ACTIVATE宏定義如下:

#define FB_ACTIVATE_NOW        0    /* 立即設置值,一般選用此選項 */
#define FB_ACTIVATE_NXTOPEN    1    /* 下次打開時激活    */
#define FB_ACTIVATE_TEST    2    /* 不設置 */
#define FB_ACTIVATE_MASK       15
                    /* values            */
#define FB_ACTIVATE_VBL           16    /* 在下一次設置值時激活  */
#define FB_CHANGE_CMAP_VBL     32    /* change colormap on vbl    */
#define FB_ACTIVATE_ALL           64    /* change all VCs on this fb    */
#define FB_ACTIVATE_FORCE     128    /* force apply even when no change*/
#define FB_ACTIVATE_INV_MODE  256       /* invalidate videomode */

 

fix結構體定義如下:

struct fb_fix_screeninfo {
    char id[16];                 /* 屏幕名字,自行設置 */
    unsigned long smem_start;    /* 屏幕緩存區物理地址 */
    __u32 smem_len;              /* 屏幕緩存區長度 */
    __u32 type;                  /* see FB_TYPE_*        */
    __u32 type_aux;              /* 輔助類型,一般設置為0 */
    __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;           /* 一行的字節數    */
    unsigned long mmio_start;    /* 寄存器的起始物理地址,一般不需要設置   */
    __u32 mmio_len;              /* 寄存器的長度,一般不需要設置  */
    __u32 accel;            /* Indicate to driver which    */
                    /*  specific chip/card we have    */
    __u16 reserved[3];      /* Reserved for future compatibility */
};

其中,FB_TYPE宏定義如下:

#define FB_TYPE_PACKED_PIXELS        0    /* 像素填充,一般選用此選項    */
#define FB_TYPE_PLANES            1    /* 非交錯planes */
#define FB_TYPE_INTERLEAVED_PLANES    2    /* 交錯planes    */
#define FB_TYPE_TEXT            3    /*文本/屬性    */
#define FB_TYPE_VGA_PLANES        4    /* EGA/VGA planes    */

FB_VISUAL宏定義如下:

#define FB_VISUAL_MONO01        0    /* 二值圖像,只有黑白 1=Black 0=White */
#define FB_VISUAL_MONO10        1    /* 二值圖像,只有黑白 1=White 0=Black */
#define FB_VISUAL_TRUECOLOR        2    /* 真彩色,一般選用此選項    */
#define FB_VISUAL_PSEUDOCOLOR        3    /* Pseudo color (like atari) */
#define FB_VISUAL_DIRECTCOLOR        4    /* Direct color */
#define FB_VISUAL_STATIC_PSEUDOCOLOR    5    /* Pseudo color readonly */

 

pseudo_palette,又稱調色板,它可以在低位BPP的條件下,在有限的像素值與RGB顏色之間建立擁有對應關系的線性表。比如從所有的16BPP的顏色中抽取一定數量的顏色編制索引。當需要使用某種彩色時,不需要對這種顏色的RGB分量進行描述,只需要引用它的索引號,就可以選取自己需要的顏色。索引號的長度遠遠小於RGB分量的編碼長度,因此在彩色顯示的同時,也減輕了系統的負擔。

若需要調色板,我們需要在LCD操作函數中添加如下代碼:

 1 /* 代碼來源於drivers/video/samsung/s3cfb_ops.c */
 2 
 3 inline unsigned int __chan_to_field(unsigned int chan, struct fb_bitfield bf)
 4 {
 5     chan &= 0xffff;
 6     chan >>= 16 - bf.length;
 7 
 8     return chan << bf.offset;
 9 }
10 
11 int s3cfb_setcolreg(unsigned int regno, unsigned int red,
12             unsigned int green, unsigned int blue,
13             unsigned int transp, struct fb_info *fb)
14 {
15     unsigned int *pal = (unsigned int *)fb->pseudo_palette;
16     unsigned int val = 0;
17 
18     if (regno < 16) {
19         /* fake palette of 16 colors */
20         val |= __chan_to_field(red, fb->var.red);
21         val |= __chan_to_field(green, fb->var.green);
22         val |= __chan_to_field(blue, fb->var.blue);
23         val |= __chan_to_field(transp, fb->var.transp);
24         pal[regno] = val;
25     }
26 
27     return 0;
28 }

 

 

二、fb_ops

之前說過fb_ops定義的是行為,其結構體定義如下:

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);

    /* For framebuffers with strange non linear layouts or that do not
     * work with normal memory mapped access
     */
    ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
               size_t count, loff_t *ppos);
    ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
                size_t count, loff_t *ppos);

    /* checks var and eventually tweaks it to something supported,
     * DO NOT MODIFY PAR */
    int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);

    /* set the video mode according to info->var */
    int (*fb_set_par)(struct fb_info *info);

    /* set color register */
    int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
                unsigned blue, unsigned transp, struct fb_info *info);

    /* set color registers in batch */
    int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);

    /* blank display */
    int (*fb_blank)(int blank, struct fb_info *info);

    /* pan display */
    int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);

    /* Draws a rectangle */
    void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
    /* Copy data from area to another */
    void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
    /* Draws a image to the display */
    void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);

    /* Draws cursor */
    int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);

    /* Rotates the display */
    void (*fb_rotate)(struct fb_info *info, int angle);

    /* wait for blit idle, optional */
    int (*fb_sync)(struct fb_info *info);

    /* perform fb specific ioctl (optional) */
    int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
            unsigned long arg);

    /* Handle 32bit compat ioctl (optional) */
    int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
            unsigned long arg);

    /* perform fb specific mmap */
    int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);

    /* get capability given var */
    void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
                struct fb_var_screeninfo *var);

    /* teardown any resources to do with this framebuffer */
    void (*fb_destroy)(struct fb_info *info);

    /* called at KDB enter and leave time to prepare the console */
    int (*fb_debug_enter)(struct fb_info *info);
    int (*fb_debug_leave)(struct fb_info *info);
};
View Code

此結構體中函數我們只需要根據實際情況編寫部分函數即可。比如之前的調色板代碼應該設置為fb_setcolreg函數指針:.fb_setcolreg = s3cfb_setcolreg,

 

 

三、framebuffer驅動調用流程

在應用程序使用LCD之前,內核主要需要做以下工作:

1. 初始化framebuffer框架,這個在drivers/video/fbmem.c中實現

2. 注冊LCD設備,也就是注冊fb_info

接下來應用程序需要操作LCD,會調用內核函數:

3. 應用程序open(),調用fb_open()

4. 應用程序write()、mmap()等,調用fb_write()、fb_mmap()等

5. 應用程序close(),調用fb_release()

 

1. 初始化framebuffer框架

 1 static int __init
 2 fbmem_init(void)
 3 {
 4     /* 1. 在proc文件系統中創建fb相關操作接口 */
 5     proc_create("fb", 0, NULL, &fb_proc_fops);
 6 
 7     /* 2. 注冊fb字符驅動 */
 8     if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
 9         printk("unable to get major %d for fb devs\n", FB_MAJOR);
10 
11     /* 3. 創建graphics類 */
12     fb_class = class_create(THIS_MODULE, "graphics");
13     if (IS_ERR(fb_class)) {
14         printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
15         fb_class = NULL;
16     }
17     return 0;
18 }

由代碼可知,fb的主設備號是代碼中定好的,區分各個LCD設備依靠的是次設備號。

 

在框架搭建完成之后,我們就需要注冊自己寫的驅動中的fb_info結構體

2. 注冊fb_info結構體

 1 int
 2 register_framebuffer(struct fb_info *fb_info)
 3 {
 4     int ret;
 5 
 6     mutex_lock(&registration_lock);
 7     ret = do_register_framebuffer(fb_info);
 8     mutex_unlock(&registration_lock);
 9 
10     return ret;
11 }

 

 1 static int do_register_framebuffer(struct fb_info *fb_info)
 2 {
 3 ...
 4     /* 1. 判斷要注冊設備的顯存和已有設備的顯存是否沖突 */
 5     do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
 6                      fb_is_primary_device(fb_info));
 7 
 8     /* 2. FB_MAX = 32,最多支持32個LCD設備 */
 9     if (num_registered_fb == FB_MAX)
10         return -ENXIO;
11 
12 ...
13 
14     /* 3. 創建設備fb0/1/2... */
15     fb_info->dev = device_create(fb_class, fb_info->device,
16                      MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
17 ...
18     
19     /* 4. 若驅動沒有實現fb_info中pixmap,內核使用默認參數 */
20     if (fb_info->pixmap.addr == NULL) {
21         fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
22         if (fb_info->pixmap.addr) {
23             fb_info->pixmap.size = FBPIXMAPSIZE;
24             fb_info->pixmap.buf_align = 1;
25             fb_info->pixmap.scan_align = 1;
26             fb_info->pixmap.access_align = 32;
27             fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
28         }
29     }    
30     fb_info->pixmap.offset = 0;
31 
32 ...
33 
34     /* 5. 使用fbinfo中參數初始化mode */
35     fb_var_to_videomode(&mode, &fb_info->var);
36     fb_add_videomode(&mode, &fb_info->modelist);
37     registered_fb[i] = fb_info;
38 
39     event.info = fb_info;
40     if (!lock_fb_info(fb_info))
41         return -ENODEV;
42     /* 6. 通知fb注冊成功 */
43     fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
44     unlock_fb_info(fb_info);
45     return 0;
46 }

 

3. 應用程序open(),調用fb_open()函數

在初始化framebuffer框架的fbmem_init()函數中register_chrdev(FB_MAJOR,"fb",&fb_fops)的fb_fops定義了fb_open()函數。

 1 static int fb_open(struct inode *inode, struct file *file)
 2 __acquires(&info->lock)
 3 __releases(&info->lock)
 4 {
 5     /* 1. 根據次設備號獲取fb_info */
 6     int fbidx = iminor(inode);
 7     struct fb_info *info;
 8     int res = 0;
 9 
10     info = get_fb_info(fbidx);
11 
12 ...
13 
14     mutex_lock(&info->lock);
15     if (!try_module_get(info->fbops->owner)) {
16         res = -ENODEV;
17         goto out;
18     }
19     file->private_data = info;
20     
21     /* 2. 若驅動程序中定義了fb_open(),則優先調用 */
22     if (info->fbops->fb_open) {
23         res = info->fbops->fb_open(info,1);
24         if (res)
25             module_put(info->fbops->owner);
26     }
27 #ifdef CONFIG_FB_DEFERRED_IO
28     if (info->fbdefio)
29         fb_deferred_io_open(info, inode, file);
30 #endif
31 out:
32     mutex_unlock(&info->lock);
33     if (res)
34         put_fb_info(info);
35     return res;
36 }
View Code

fb_open()函數所做的有私有化數據和調用驅動程序中fb_ops的fb_open()函數。

 

4. 應用程序write(),調用fb_write()函數

看過LED和KEY驅動程序的讀者可以發現write()和read()函數實現差別不大,在此以fb中常用的write()函數為例分析。

 1 static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 2 {
 3     unsigned long p = *ppos;    /* 偏移量 */
 4     struct fb_info *info = file_fb_info(file);
 5     u8 *buffer, *src;
 6     u8 __iomem *dst;
 7     int c, cnt = 0, err = 0;
 8     unsigned long total_size;
 9 
10 ...
11 
12     /* 若驅動程序中定義了fb_write(),則優先調用 */
13     if (info->fbops->fb_write)
14         return info->fbops->fb_write(info, buf, count, ppos);
15     
16     total_size = info->screen_size;
17 
18     if (total_size == 0)
19         total_size = info->fix.smem_len;
20 
21     if (p > total_size)
22         return -EFBIG;
23 
24     if (count > total_size) {
25         err = -EFBIG;
26         count = total_size;
27     }
28 
29     if (count + p > total_size) {
30         if (!err)
31             err = -ENOSPC;
32 
33         count = total_size - p;
34     }
35 
36     buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,
37              GFP_KERNEL);
38     if (!buffer)
39         return -ENOMEM;
40 
41     dst = (u8 __iomem *) (info->screen_base + p);
42 
43     /* 若驅動程序中定義了fb_sync(),則優先調用 */
44     if (info->fbops->fb_sync)
45         info->fbops->fb_sync(info);
46 
47     /* 使用copy_from_user()將數據從用戶空間拷貝到內核空間 */
48     while (count) {
49         c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
50         src = buffer;
51 
52         if (copy_from_user(src, buf, c)) {
53             err = -EFAULT;
54             break;
55         }
56 
57         fb_memcpy_tofb(dst, src, c);
58         dst += c;
59         src += c;
60         *ppos += c;
61         buf += c;
62         cnt += c;
63         count -= c;
64     }
65 
66     kfree(buffer);
67 
68     return (cnt) ? cnt : err;
69 }
View Code

我們可以發現fb_write()函數默認提供的寫操作同樣使用了copy_from_user()拷貝數據。除此之外,它還使用fb_memcpy_tofb()函數把數據寫到顯存。也就是執行兩次拷貝操作。

 

之前我們使用copy_from_user()拷貝數據是因為我們的數據量較小,一般只有幾字節。但是fb顯存一般為幾百KB,copy_from_user()拷貝數據極有可能導致畫面卡頓,導致效率降低。

解決此問題的方式就是使用mmap()函數。

應用程序mmap()函數使用方法可以參考:第七章:進程環境中六、存儲空間的分配mmap()函數。

 

內核使用struct task_struct來表示某個進程,該結構體包含一些進程狀態、調度信息等成員,並使用結構體鏈表來管理所有進程。我們需要關注進程描述符中內存描述符:struct mm_struct。

struct mm_struct中struct vm_area_struct用來表示一個獨立的虛擬內存區域,該結構體包含映射地址、大小、結束地址等成員,並使用結構體鏈表來管理所有虛擬內存區域。

由此我們可以推出:mmap()把設備地址映射到進程虛擬地址(ioremap()把設備地址映射到內核虛擬空間)。指針指向如下圖:

 

mmap()函數首先分配一個struct vm_area_struct放到進程的地址空間,之后實現文件地址和虛擬地址區域的映射關系。

此時映射關系有了,但內存中沒有數據,進程訪問內存會引發引發缺頁異常,最終內核會發起請求調頁過程,它先在交換緩存空間中尋找需要訪問的內存頁,如果沒有則調用nopage()函數把所缺的頁從磁盤裝入到主存中。在這之后進程便可以正常訪問數據。

這樣做的好處是映射過程並沒有拷貝數據,只需要從磁盤到用戶主存的一次拷貝數據過程。而write()函數需要從磁盤到頁緩存再到用戶主存的兩次拷貝數據過程。

 

分析完mmap()后,我們來查看fb_mmap()函數

 1 static int fb_mmap(struct file *file, struct vm_area_struct * vma)
 2 {
 3     struct fb_info *info = file_fb_info(file);
 4     struct fb_ops *fb;
 5     unsigned long off;
 6     unsigned long start;
 7     u32 len;
 8 
 9     if (!info)
10         return -ENODEV;
11     if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
12         return -EINVAL;
13     off = vma->vm_pgoff << PAGE_SHIFT;
14     fb = info->fbops;
15     if (!fb)
16         return -ENODEV;
17     mutex_lock(&info->mm_lock);
18     if (fb->fb_mmap) {
19         int res;
20         res = fb->fb_mmap(info, vma);    /* 若驅動程序中定義了fb_mmap(),則優先調用 */
21         mutex_unlock(&info->mm_lock);
22         return res;
23     }
24 
25     /* frame buffer memory */
26     start = info->fix.smem_start;                                    /* 顯存起始地址 */
27     len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);    /* 顯存大小*/
28     if (off >= len) {
29         /* memory mapped io */
30         off -= len;
31         if (info->var.accel_flags) {
32             mutex_unlock(&info->mm_lock);
33             return -EINVAL;
34         }
35         start = info->fix.mmio_start;
36         len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
37     }
38     mutex_unlock(&info->mm_lock);
39     start &= PAGE_MASK;
40     if ((vma->vm_end - vma->vm_start + off) > len)
41         return -EINVAL;
42     off += start;
43     vma->vm_pgoff = off >> PAGE_SHIFT;
44     /* This is an IO map - tell maydump to skip this VMA */
45     vma->vm_flags |= VM_IO | VM_RESERVED;
46     vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
47     fb_pgprotect(file, vma, off);
48     
49     /* 映射頁I/O,vma為用戶分配的空間 */
50     if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
51                  vma->vm_end - vma->vm_start, vma->vm_page_prot))
52         return -EAGAIN;
53     return 0;
54 }
View Code

 

接下來簡單舉例在應用程序中使用mmap()函數並把LCD顯示器的背景刷成藍色。此代碼讀者暫時不需要會修改,熟悉即可。我將在接下來的LCD章節中對平台驅動框架對代碼中參數進行分析。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include <string.h>
 6 #include <sys/mman.h>
 7 
 8 /* Usage:
 9  * ./a.out <fb0|fb1|fb2|...>
10  */
11 int main(int argc, char **argv)
12 {
13     if (argc != 2) {
14         printf("Usage:\n");
15         printf("%s <fb0|fb1|fb2|...>\n", argv[0]);
16         return -1;
17     }
18     
19     char path[48] = "/dev/";
20     strcat(path, argv[1]);
21     
22     int fd = open(path, O_RDWR);
23     if (fd < 0)
24         perror("open"), exit(-1);
25     
26     /* 1280*800*4
27      *  1280: xres,x方向分辨率
28      *  800:yres,y方向分辨率
29      *  4:我的內核中默認LCD為24BPP,查手冊可以確定24BPP占32位,也就是4字節
30      */
31     unsigned int *memory = (unsigned int *)mmap(NULL, 1280*800*4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
32     if (memory == (unsigned int *)-1) {
33         close(fd); 
34         perror("mmap");
35         exit(-1);
36     }
37     
38     close(fd);
39     
40     /* 把屏幕刷成藍色 */
41     int i;
42     for (i = 0; i < (1280*800); ++i) {
43         memory[i] = 0x000000ff;
44     }
45     
46     /* 寫回磁盤文件中 */
47     msync(memory, 1280*800*4, MS_SYNC);
48     
49     return 0;
50 }
View Code

 

5. 應用程序close(),調用fb_release()

在此僅給出調用過程:

fb_release(struct inode *inode, struct file *file)
    if (info->fbops->fb_release)
        info->fbops->fb_release(info,1);
 -> put_fb_info(info);
        if (fb_info->fbops->fb_destroy)
            fb_info->fbops->fb_destroy(fb_info);

 

總結起來就是:

1. fb設備本身屬於字符設備,應用程序系統調用函數會調用字符設備中struct file_operations fb_fops的函數

2. fb_info和頂層的字符設備fb使用struct device進行連接,也可以認為一個struct device對應一個fb_info

3. 與之前的輸入子系統或總線的連接不同,fb_info和fb_ops的連接是采用在fb_info中定義fb_ops指針的形式

4. 也就是說,我們只需要向上注冊fb_info,其過程如下:

  a. 分配fb_info(eg: struct fb_info* fbinfo = framebuffer_alloc(0, NULL);)

  b. 設置fb_info(eg: fbinfo->fix.smem_len = 1280 * 800 * 2;)

  c. 分配顯存(eg: fbinfo->screen_base = dma_alloc_writecombine(NULL, fbinfo->fix.smem_len, &fbinfo->fix.smem_start, GFP_KERNEL);)

  d. 硬件設置(如設置GPIO功能為LCD,設置顯存地址)

  e. 注冊fb_info(eg: register_framebuffer(fbinfo);)

5. 注銷fb_info

  a. 注銷fb_info(eg: unregister_framebuffer(fbinfo);)

  b. 釋放fb_info(eg: framebuffer_release(fbinfo);)

 

 

下一章  11、三星平台framebuffer驅動

 


免責聲明!

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



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