分类: LINUX
2009-07-16 21:09:58
LCD设备驱动
此文章应参照linux
18.1 LCD硬件原理
利用液晶制成的显示器称为LCD,依据驱动方式可分为静态驱动\简单矩阵驱动以及主动矩阵驱动3种.其中,简单矩阵型又可再细分扭转向列型(TN)和超扭转向列型(STN)两种,而主动矩阵型则以薄膜式晶体管型(TFT)为主流。
18.2 帧缓冲
帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,是把显存抽象后的一种设备,它允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作,这种操作是抽象的,统一的。用户不必关心物理显存的位置,换页机制等等具体细节。这些都由Framebuffer设备驱动程序完成的。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色值会在屏幕上显示。帧缓冲驱动应用广泛,在linux的桌面系统中,Xwindow服务器就是利用帧缓冲进行窗口绘制的。尤其是通过帧缓冲设备可显示汉字点阵,成为linux汉化的唯一可行方案。
帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显卡,Linux下还可支持多个帧缓冲设备,最多可达32个,分别为/dev/fb0~/dev/fb31,而/dev/fb则为当前缺省的帧缓冲设备,通常指向/dev/fb0。当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号为0到31,分别对应/dev/fb0~/dev/fb31。
在帧缓冲设备中,对屏幕显示点的操作通过读写显示缓冲区来完成,在不同的色彩模式下,显示缓冲区和屏幕上的显示点有不同的对应关系。
1、fb_info结构体
帧缓冲设备最关键的一个数据结构体是fb_info结构体,FBI中包括了关于帧缓冲设备属性和操作的完整描述。
Struct fb_info、
{
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
……
Struct fb_ops *fbops;fb_ops,帧缓冲操作
……
}
每一个帧缓冲设备都必须对应一个FBI。
2、fb_ops结构体
FBI的成员变量fbops为指向底层操作的函数的指针,这些函数是需要驱动程序开发人员编写的。
struct fb_ops {
……
/* 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);
……
}
fb_ops的成员函数fb_check_var用于检查可以修改的屏幕参数并调整到合适的值,而fb_set_par则使得用户设置的屏幕参数在硬件上有效。
3、fb_var_screeninfo和fb_fix_screeninfo结构体
fb_var_screeninfo记录着用户可修改的显示控制器参数,包括屏幕分辨率和每个像素的比特数,fb_var_screeninfo中的xres定义屏幕一行有对少个点,yres定义屏幕和每个像素点的比特数,bits_per_pixeld定义每个点用多少个字节表示。
fb_fix_screeninfo中记录用户不能修改的显示控制器的参数,如屏幕缓冲区的物理地址,长度,当对缓冲区设备进行映射操作的时候,就是从fb_fix_screeninfo中取得缓冲区物理地址的。这些数据成员都需要在驱动程序中初始化中设置。
4、fb_bitfield结构体
fb_bitfield结构体描述每一像素显示缓冲区的组织方式,包含位域长度和MSB指示。
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};
5、fb_cmap结构体
fb_cmap结构体记录设备无关的颜色表信息。用户空间可以通过ioctl()的FBIOGETCMAP和FBIOPUTCMAP命令读取或设定颜色表。
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};
6、文件操作结构体
作为一种字符设备,帧缓冲设备的文件操作结构体定义于/linux/drivers/vedio/fbmem.c文件中。
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
};
帧缓冲设备驱动的文件操作接口函数已经在fbmem.c中被统一实现,一般不需要由驱动工程师再编写。
7、注册与注销帧缓冲设备
注册与注销帧缓冲设备:register_framebuffer(),unregister_framebuffer()。
18.3 Linux帧缓冲设备驱动结构
下图为帧缓冲设备驱动的程序结构,帧缓冲设备提供给用户空间的file_operations结构体有fbmem.c中file_operations提供,而特定帧缓冲设备的fb_info结构体的注册、注销以及其中成员的维护,尤其是fb_ops中成员函数的实现则对应的xxxfb.c文件实现,fb_ops中的成员函数最终会操作LCD控制器硬件寄存器。
其中xxxfb.c如s3c2410fb.c,应用程序中只要调用open,read,write,ioctl,nmap,它们对应的函数在fbmem.c中,驱动程序中要完成如xxxfb.c中的函数实现。
18.4帧缓冲设备驱动的模块加载与卸载函数
模块加载函数中完成如下工作。
1、申请FBI结构体的内存空间,初始化FBI结构体中固定和可变的屏幕参数。
2、根据具体LCD屏幕的特点,完成LCD控制器硬件的初始化。
3、申请帧缓冲设备的现实缓冲区空间。
4、注册帧缓冲设备。
模块卸载函数完成相反工作。
由于LCD控制器经常被集成在SOC上作为一个独立的硬件模块而存在,(成为platform_device),因此,LCD驱动中经常包含平台驱动,这样,在帧缓冲设备驱动的模块加载函数中完成的工作是注册平台驱动,而初始化FBI结构体中的固定和可变参数、LCD控制器硬件的初始化、申请帧缓冲设备的显示缓冲区空间和注册帧缓冲设备的工作则移交到平台驱动的探测函数中完成。
同样的,卸载函数与之相反。
s
int __init s
{
return platform_driver_register(&s
platform_driver_register 在platform.c中
}
static void __exit s
{
platform_driver_unregister(&s
}
static struct platform_driver s
.probe = s
.remove = s
.suspend = s
.resume = s
.driver = {
.name = "s
.owner = THIS_MODULE,
},
};
static int __init s
{
struct s
struct s
struct fb_info *fbinfo;
……
ret = register_framebuffer(fbinfo); register_framebuffer在fbmem.c中
……
}
18.5帧缓冲设备显示缓冲区的申请与释放
在嵌入式系统中,一种常见的方式是直接在RAM空间中分配一段显示缓冲区。通过dma_alloc_writecombine()分配的显示缓冲区不会出现cache一致性问题。
在分配显示缓冲区时,系统往往会通过DMA(direct memory access直接存储器访问)方式搬移显示数据。
Direct Memory Access(存储器直接访问)。这是指一种高速的数据传输操作,允许在外部设备和之间直接读写数据,既不通过CPU,也不需要CPU干预。整个数据传输操作在一个称为"DMA控制器"的控制下进行的。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中CPU可以进行其他的工作。这样,在大部分时间里,CPU和输入输出都处于并行操作。因此,使整个计算机系统的效率大大提高。
18.6帧缓冲设备的参数设置
18.7帧缓冲设备的fb_ops成员函数
FBI中的fb_ops是使得帧缓冲设备工作所需要的集合,它们最终与LCD控制器硬件打交道。
18.8 LCD设备驱动的读写、mmap和ioctl函数
文件操作函数移已经由内核在fbmem.c文件中实现。
file_operations中的mmap()函数非常关键,它将显示缓冲区映射到用户空间,从而使得用户空间可以直接操作显示缓冲区而省去一次用户空间到内核空间的内存复制过程,提高效率。
fb_ioctl()函数最终实现对用户IO控制命令的执行。
18.9帧缓冲设备的用户空间访问
通过/dev/fb,应用程序的操作主要有一下几种:
1.读/写(read/write)/dev/fb
相当于读/写屏幕缓冲区。
cp /dev/fb0 tmp 将当前屏幕的内容拷贝到一个文件中
cp tmp > /dev/fb0 则将图形文件tmp显示在屏幕上
2.映射(map)操作
由于Linux工作在保护模式,每个应用程序都有自己的虚拟地址空间,在应用程序不能直接访问物理缓冲区地址的。为此,linux在文件操作file_operations结构中提供了mmap函数,可将文件的内容应身到用户空间。对于帧缓冲设备,则可通过映射操作,可将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就可以通过读写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图了。而且若干个进程可以映射到同一显示缓冲区。实际上,使用帧缓冲设备的应用程序都是通过映射操作来显示图形的。
3.I/O控制
对于帧缓冲设备,对设备文件的ioctl操作可读取/设置显示设备及屏幕参数,如分辨率,显示颜色数,屏幕大小等等。ioctl的操作是有底层的驱动程序来完成的。
在应用程序中,操作/dev/fb的一般步骤如下:
1.打开/dev/fb设备文件
2.用ioctrl操作取得当前显示屏幕参数,根据屏幕参数可计算屏幕缓冲区的大小。
3.将屏幕缓冲区映射到用户空间。
4.映射后就可以直接读写屏幕缓冲区,进行绘图和图片显示了
备注:memset:作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。
memcpy:作用是把一块内存中的字节,不管其中的内容是什么,从内存的一个区域复制到另一个区域。
18.10 Linux图形用户界面
Qt是Trolltech(奇趣)公司所开发的一个跨平台的FrameWork环境。
信号和插槽是Qt中非常有特色的地方,是Qt编程区别于其它编程的标志。
Microwindows的核心基于显示设备接口,因此可移植性很好。
Microwindows采用分层设计方法。
MiniGUI是由北京飞漫软件技术有限公司开发的面相实时嵌入式系统的轻量级图形用户界面支持系统。
MiniGUI下的通信是一种类似于Win32的消息机制,如果有WIN32图形用户界面程序的编程基础,编写MiniGUI程序将没有门槛。
18.11 实例:S
S
S
下图为其内部的逻辑结构图,REGBANK是LCD控制器的寄存器组,用来对LCD控制器的各项参数进行设置,而LCDCDMA则是LCD控制器专用的DMA信道,负责将视频资料从系统总线(system bus)上取来,通过VIDPRCS从VD[23:0]发送给LCD屏,同时TIMEGEN和LPC3600负责产生LCD 屏所需要的控制时序,例如VSYNC、HSYNC、VDEN,然后从VIDEO MUX送给LCD屏。
在S
如果内核配置了能量管理(即定义了CONFIG_PM宏),平台驱动部分应该增加挂起和恢复函数。在挂起函数中关闭LCD和其时钟源以节省能量,在恢复函数中开启LCD和其时钟源。
总结
帧缓冲设备是一种典型的字符设备,它统一了显存,将显示缓冲区直接映射到用户空间,帧缓冲设备驱动file_opersations中的VFS接口函数有fbmen.c文件统一实现,这样驱动工程师的工作重点将是实现针对特定设备fb_info中的fb_ops的成员函数,另外,理解并能灵活的修改fb_info中的var和fix参数很重要。fb_info中的var参数直接和LCD控制器的硬件设置以及LCD屏幕对应。
在用户空间。应用程序直接按照预先设置的R、G、B位数和偏移写经过mmap()映射后的显示缓冲区就可实现图形的显示,省去了内存从用户空间到内核空间的复制过程。