LCDC是将系统需要显示的数据经过处理后输出到LCD显示驱动器的液晶显示控制模块 ,在用户初始化配置后,LCDC将自动进行读取数据、缓存数据、处理数据以及输出符合时序要求的控制和数据信号等操作。
FrameBuffer是Linux内核为显示设备提供的一个接口。这种接口将显示设备抽象为帧缓冲区。用户可以将它看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。 帧缓冲设备是字符设备,主设备号为29,次设备号为帧缓冲的个数(最多32个),对应的设备文件一般是 /dev/fb0、/dev/fb1 等等。假设现在的显示模式是1024x768-8 位色,则可以通过如下的命令清空屏幕
dd if=/dev/zero of=/dev/fb0 bs=1024 count=768
如果应用程序需要知道FrameBuffer设备的相关参数,必须通过ioctl()系统调用来完成。最常用的ioctl命令字是下面这两个: FBIOGET_FSCREENINFO:与FrameBuffer有关的固定的信息,比如图形硬件上实际的帧缓存空间的大小、能否硬件加速等信息 FBIOGET_VSCREENINFO:与FrameBuffer有关的可变信息,之所以可变,是因为对同样的图形硬件,可以工作在不同的模式下,简单来讲,一个支持 1024x768x24图形模式的硬件通常也能工作在800x600x16的图形模式下,可变的信息就是指FrameBuffer的长度、宽度以及颜色深度等信息。
struct fb_info
驱动最关键的结构体,包含了设备属性和操作的完整描述,包括设备的设置参数、状态以及对底层硬件操作的函数指针。在Linux中,每一个帧缓冲设备都必须对应一个fb_info,fb_info在/linux/fb.h中的定义如下 (只列出重要的一些) :
struct fb_info {
int node;
int flags;
struct fb_var_screeninfo var; /*LCD可变参数结构体*/
struct fb_fix_screeninfo fix; /*LCD固定参数结构体*/
struct fb_monspecs monspecs; /*LCD显示器标准*/
struct work_struct queue ; /*帧缓冲事件队列*/
struct fb_pixmap pixmap; /*图像硬件mapper*/
struct fb_pixmap sprite; /*光标硬件mapper*/
struct fb_cmap cmap; /*当前的颜色表*/
struct fb_videomode * mode; /*当前的显示模式*/
# ifdef CONFIG_FB_BACKLIGHT
struct backlight_device * bl_dev;/*对应的背光设备 */
struct mutex bl_curve_mutex;
u8 bl_curve[ FB_BACKLIGHT_LEVELS] ;/*背光调整 */
# endif
# ifdef CONFIG_FB_DEFERRED_IO
struct delayed_work deferred_work;
struct fb_deferred_io * fbdefio;
# endif
struct fb_ops * fbops; /*对底层硬件操作的函数指针*/
struct device * device;
struct device * dev; /*fb设备*/
int class_flag;
# ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops * tileops; /*图块Blitting*/
# endif
char __iomem * screen_base; /*虚拟基地址*/
unsigned long screen_size; /*LCD IO映射的虚拟内存大小*/
void * pseudo_palette; /*伪16色颜色表*/
# define FBINFO_STATE_RUNNING 0
# define FBINFO_STATE_SUSPENDED 1
u32 state; /*LCD的挂起或恢复状态*/
oid * fbcon_par;
void * par;
} ;
其中,比较重要的成员有struct fb_var_screeninfo var、 struct fb_fix_screeninfo fix和structfb_ops * fbops,它们也都是结构体,下面我们一个一个的来看。
struct fb_fix_screeninfo 填充用户不可修改的参数,比如屏幕缓冲区的物理地址和长度等。
struct fb_fix_screeninfo {
char id[ 16] ; /*字符串形式的标示符 */
unsigned long smem_start; /*fb缓存的开始位置 */
__u32 smem_len; /*fb缓存的长度 */
__u32 type; /*看FB_TYPE_* */
__u32 type_aux; /*分界*/
__u32 visual; /*看FB_VISUAL_* */
__u16 xpanstep; /*如果没有硬件panning就赋值为0 */
__u16 ypanstep; /*如果没有硬件panning就赋值为0 */
__u16 ywrapstep; /*如果没有硬件ywrap就赋值为0 */
__u32 line_length; /*一行的字节数 */
unsigned long mmio_start; /*内存映射IO的开始位置*/
__u32 mmio_len; /*内存映射IO的长度*/
__u32 accel;
__u16 reserved[ 3] ; /*保留*/
} ;
struct fb_var_screeninfo 填充用户可以修改的参数,包括屏幕分辨率、每个像素的位宽、帧延时、行延时等
struct fb_var_screeninfo {
__u32 xres; /*可见屏幕一行有多少个像素点*/
__u32 yres; /*可见屏幕一列有多少个像素点*/
__u32 xres_virtual; /*虚拟屏幕一行有多少个像素点*/
__u32 yres_virtual; /*虚拟屏幕一列有多少个像素点*/
__u32 xoffset; /*虚拟到可见屏幕之间的行偏移*/
__u32 yoffset; /*虚拟到可见屏幕之间的列偏移*/
__u32 bits_per_pixel; /*每个像素的位数即BPP*/
__u32 grayscale; /*非0时,指的是灰度*/
struct fb_bitfield red; /*fb缓存的R位域*/
struct fb_bitfield green; /*fb缓存的G位域*/
struct fb_bitfield blue; /*fb缓存的B位域*/
struct fb_bitfield transp; /*透明度*/
__u32 nonstd; /* != 0 非标准像素格式*/
__u32 activate;
__u32 height; /*高度*/
__u32 width; /*宽度*/
__u32 accel_flags;
/*定时:除了pixclock本身外,其他的都以像素时钟为单位*/
__u32 pixclock; /*像素时钟(皮秒)*/
__u32 left_margin; /*行切换,从同步到绘图之间的延迟*/
__u32 right_margin; /*行切换,从绘图到同步之间的延迟*/
__u32 upper_margin; /*帧切换,从同步到绘图之间的延迟*/
__u32 lower_margin; /*帧切换,从绘图到同步之间的延迟*/
__u32 hsync_len; /*水平同步的长度*/
__u32 vsync_len; /*垂直同步的长度*/
__u32 sync;
__u32 vmode;
__u32 rotate ;
__u32 reserved[ 5] ; /*保留*/
} ;
struct fb_ops fb_info的成员变量fops为指向底层操作的函数指针,这些函数是驱动程序开发人员编写。
struct fb_ops {
struct module * owner;
//检查可变参数并进行设置
int ( * fb_check_var) ( struct fb_var_screeninfo * var, struct fb_info * info) ;
//根据设置的值进行更新,使之有效
int ( * fb_set_par) ( struct fb_info * info) ;
//设置颜色寄存器
int ( * fb_setcolreg) ( unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info * info) ;
//显示空白
int ( * fb_blank) ( int blank, struct fb_info * info) ;
//矩形填充
void ( * fb_fillrect) ( struct fb_info * info, const struct fb_fillrect * rect) ;
//复制数据
void ( * fb_copyarea) ( struct fb_info * info, const struct fb_copyarea * region) ;
//图形填充
void ( * fb_imageblit) ( struct fb_info * info, const struct fb_image * image) ;
} ;
struct file_operations fb_fops Framebuffer属于字符设备,用户通过fb_fops结构中定义的文件操作接口函数可以操作Framebuffer设备,文件接口函数统一由fbmem.c实现,一般不需要驱动编写人员再次编写。
static struct file_operations fb_fops = {
owner: THIS_MODULE,
read: fb_read, // 读操作
write: fb_write, // 写操作
ioctl: fb_ioctl, // 控制操作
mmap: fb_mmap, // 映射操作
open: fb_open, // 打开操作
release: fb_release, // 关闭操作
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
get_unmapped_area: get_fb_unmapped_area,
#endif
};
应用程序层对帧缓冲设备的访问同对文件的访问操作类似。在应用程序中,对帧缓冲设备(dev/fb)的操作只需调用文件层的操作函数。首先打开/dev/fb设备文件;随后用ioctl操作取得屏幕的分辨率和bpp值,从而计算出屏幕缓冲区的大小,并将屏幕的缓冲区映射到用户空间;最后就可直接对屏幕缓冲区进行图片显示。对帧缓冲区的打开文件操作是由fb_open()完成等。
驱动文件:linux/drivers/video/目录
int main()
{ int framebuffer_device; int line_size,buffer_size, *i;
int *screen_memory; struct fb_var_screeninfo var_info;
framebuffer_device = open ( "/dev/fb0" , O_RDWR);
ioctl (framebuffer_device, FBIOGET_VSCREENINFO, &var_info);
line_size = var_info.xres * var_info.bits_per_pixel / 8; // 计算一行字节数
buffer_size = line_size * var_info.yres; // 计算显存缓冲区大小
var_info.xoffset = 0; var_info.yoffset = 0;
screen_memory = (char *) mmap (513, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, framebuffer_device, 0);
for (i=0;i < buffer_size ; i++ )
*(screen_memory+i) = i%236;
sleep(2);
munmap(framebuffer_device, buffer_size);
close(framebuffer_device);
return 0;
}
修改内核源码
2.6.30.4内核对LCD的支持已很完善,这里只做少许修改, 修改arch/arm/mach-s3c2440/mach-smdk2440.c的smdk2440_lcd_cfg函数和 smdk2440_fb_info函数,设置LCD参数:
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVCLK |
S3C2410_LCDCON5_INVVD |
S3C2410_LCDCON5_INVVDEN |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_BSWP |
S3C2410_LCDCON5_HWSWP,
#if defined(CONFIG_FB_S3C24X0_PT320240)
.type = S3C2410_LCDCON1_TFT,
.width = 320,
.height = 240,
.pixclock = 80000, /* HCLK 100 MHz, divisor 3 */
.setclkval = 0x3,
.xres = 320,
.yres = 240,
.bpp = 16,
.left_margin = 11, /* for HFPD*/
.right_margin = 70, /* for HBPD*/
.hsync_len = 5, /* for HSPW*/
.upper_margin = 12, /* for VFPD*/
.lower_margin = 5, /* for VBPD*/
.vsync_len = 5, /* for VSPW*
#endif
};
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
.displays = &smdk2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,
#if 0
/* currently setup by downloader */
.gpccon = 0xaa940659,
.gpccon_mask = 0xffffffff,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaa84aaa0,
.gpdcon_mask = 0xffffffff,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,
#endif
// .lpcsel = ((0xCE6) & ~7) | 1<<4,
};
配置内核选项
选上LCD支持和Logo图标。