在读者学习本章以及后续LCD相关章节之前,最好拥有LCD裸机基础,可以参考:LCD编程

 

在内核中,表示LCD使用的是framebuffer(帧缓冲,简写为fb),其内容对应于屏幕上的界面显示。修改framebuffer中的内容,即修改屏幕上的内容。操作framebuffer可以直接在LCD上观察到效果。

framebuffer本质上是一段内存,或称作显存。

 

在内核中,LCD对应的参数使用struct fb_info存储,对应的行为使用struct fb_ops存储。

在以下章节,我会分别讨论fb_info和fb_ops。

 

 

之前说过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定义的是行为,其结构体定义如下:

10、LCD的framebuffer设备驱动
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

相关文章: