在读者学习本章以及后续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定义的是行为,其结构体定义如下:
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); };