Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2835808
  • 博文数量: 523
  • 博客积分: 11908
  • 博客等级: 上将
  • 技术积分: 5475
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-03 15:50
文章分类

全部博文(523)

文章存档

2019年(3)

2013年(4)

2012年(71)

2011年(78)

2010年(57)

2009年(310)

分类: LINUX

2009-07-16 21:09:58

LCD设备驱动

此文章应参照linux2.6.24内核源文件和linux设备驱动开发详解进行学习!

 

18.1 LCD硬件原理

利用液晶制成的显示器称为LCD,依据驱动方式可分为静态驱动\简单矩阵驱动以及主动矩阵驱动3.其中,简单矩阵型又可再细分扭转向列型(TN)和超扭转向列型(STN)两种,而主动矩阵型则以薄膜式晶体管型(TFT)为主流。

 

18.2 帧缓冲

18.2.1 概念

帧缓冲(framebuffer)Linux为显示设备提供的一个接口,是把显存抽象后的一种设备,它允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作,这种操作是抽象的,统一的。用户不必关心物理显存的位置,换页机制等等具体细节。这些都由Framebuffer设备驱动程序完成的。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色值会在屏幕上显示。帧缓冲驱动应用广泛,在linux的桌面系统中,Xwindow服务器就是利用帧缓冲进行窗口绘制的。尤其是通过帧缓冲设备可显示汉字点阵,成为linux汉化的唯一可行方案。

帧缓冲设备对应的设备文件为/dev/fb*,如果系统有多个显卡,Linux下还可支持多个帧缓冲设备,最多可达32个,分别为/dev/fb0~/dev/fb31,而/dev/fb则为当前缺省的帧缓冲设备,通常指向/dev/fb0。当然在嵌入式系统中支持一个显示设备就够了。帧缓冲设备为标准字符设备,主设备号为29,次设备号为031,分别对应/dev/fb0~/dev/fb31

 

18.2.2 显示缓冲区与显示点

在帧缓冲设备中,对屏幕显示点的操作通过读写显示缓冲区来完成,在不同的色彩模式下,显示缓冲区和屏幕上的显示点有不同的对应关系。

 

18.2.3 Linux帧缓冲相关数据结构与函数

1fb_info结构体

帧缓冲设备最关键的一个数据结构体是fb_info结构体,FBI中包括了关于帧缓冲设备属性和操作的完整描述。

Struct fb_info

{

 struct fb_var_screeninfo var;    /* Current var */

struct fb_fix_screeninfo fix;       /* Current fix */

 ……

 Struct fb_ops *fbopsfb_ops,帧缓冲操作

……

}

每一个帧缓冲设备都必须对应一个FBI

 

2fb_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则使得用户设置的屏幕参数在硬件上有效。

 

3fb_var_screeninfofb_fix_screeninfo结构体

fb_var_screeninfo记录着用户可修改的显示控制器参数,包括屏幕分辨率和每个像素的比特数,fb_var_screeninfo中的xres定义屏幕一行有对少个点,yres定义屏幕和每个像素点的比特数,bits_per_pixeld定义每个点用多少个字节表示。

fb_fix_screeninfo中记录用户不能修改的显示控制器的参数,如屏幕缓冲区的物理地址,长度,当对缓冲区设备进行映射操作的时候,就是从fb_fix_screeninfo中取得缓冲区物理地址的。这些数据成员都需要在驱动程序中初始化中设置。

 

4fb_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 */

};

 

5fb_cmap结构体

fb_cmap结构体记录设备无关的颜色表信息。用户空间可以通过ioctl()FBIOGETCMAPFBIOPUTCMAP命令读取或设定颜色表。

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.cfile_operations提供,而特定帧缓冲设备的fb_info结构体的注册、注销以及其中成员的维护,尤其是fb_ops中成员函数的实现则对应的xxxfb.c文件实现,fb_ops中的成员函数最终会操作LCD控制器硬件寄存器。

 

 


其中xxxfb.cs3c2410fb.c,应用程序中只要调用openreadwriteioctlnmap,它们对应的函数在fbmem.c中,驱动程序中要完成如xxxfb.c中的函数实现。

 

18.4帧缓冲设备驱动的模块加载与卸载函数

模块加载函数中完成如下工作。

1、申请FBI结构体的内存空间,初始化FBI结构体中固定和可变的屏幕参数。

2、根据具体LCD屏幕的特点,完成LCD控制器硬件的初始化。

3、申请帧缓冲设备的现实缓冲区空间。

4、注册帧缓冲设备。

模块卸载函数完成相反工作。

由于LCD控制器经常被集成在SOC上作为一个独立的硬件模块而存在,(成为platform_device),因此,LCD驱动中经常包含平台驱动,这样,在帧缓冲设备驱动的模块加载函数中完成的工作是注册平台驱动,而初始化FBI结构体中的固定和可变参数、LCD控制器硬件的初始化、申请帧缓冲设备的显示缓冲区空间和注册帧缓冲设备的工作则移交到平台驱动的探测函数中完成。

同样的,卸载函数与之相反。

s3c2410fb初始化和卸载函数,

int __init s3c2410fb_init(void)

{

       return platform_driver_register(&s3c2410fb_driver);

platform_driver_register platform.c

}

 

static void __exit s3c2410fb_cleanup(void)

{

       platform_driver_unregister(&s3c2410fb_driver);

}

 

static struct platform_driver s3c2410fb_driver = {

       .probe           = s3c2410fb_probe,

       .remove         = s3c2410fb_remove,

       .suspend = s3c2410fb_suspend,

       .resume         = s3c2410fb_resume,

       .driver           = {

              .name     = "s3c2410-lcd",

              .owner    = THIS_MODULE,

       },

};

 

static int __init s3c2410fb_probe(struct platform_device *pdev)

{

       struct s3c2410fb_info *info;

       struct s3c2410fb_display *display;

       struct fb_info *fbinfo;

……

ret = register_framebuffer(fbinfo); register_framebufferfbmem.c

……

}

 

18.5帧缓冲设备显示缓冲区的申请与释放

在嵌入式系统中,一种常见的方式是直接在RAM空间中分配一段显示缓冲区。通过dma_alloc_writecombine()分配的显示缓冲区不会出现cache一致性问题。

在分配显示缓冲区时,系统往往会通过DMAdirect memory access直接存储器访问)方式搬移显示数据。

Direct Memory Access(存储器直接访问)。这是指一种高速的数据传输操作,允许在外部设备和之间直接读写数据,既不通过CPU,也不需要CPU干预。整个数据传输操作在一个称为"DMA控制器"的控制下进行的。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中CPU可以进行其他的工作。这样,在大部分时间里,CPU和输入输出都处于并行操作。因此,使整个计算机系统的效率大大提高。

 

18.6帧缓冲设备的参数设置

18.6.1 定时参数

18.6.2 像素时钟

18.6.3 颜色位域

18.6.4 固定参数

 

18.7帧缓冲设备的fb_ops成员函数

FBI中的fb_ops是使得帧缓冲设备工作所需要的集合,它们最终与LCD控制器硬件打交道。

 

18.8 LCD设备驱动的读写、mmapioctl函数

文件操作函数移已经由内核在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图形用户界面

18.10.1 Qt-X11/QtEmbedded/Qtopia

       QtTrolltech(奇趣)公司所开发的一个跨平台的FrameWork环境。

       信号和插槽是Qt中非常有特色的地方,是Qt编程区别于其它编程的标志。

 

18.10.2 Microwindows/Nano-X

       Microwindows的核心基于显示设备接口,因此可移植性很好。

       Microwindows采用分层设计方法。

 

18.10.3 MiniGUI

       MiniGUI是由北京飞漫软件技术有限公司开发的面相实时嵌入式系统的轻量级图形用户界面支持系统。

       MiniGUI下的通信是一种类似于Win32的消息机制,如果有WIN32图形用户界面程序的编程基础,编写MiniGUI程序将没有门槛。

 

18.11 实例:S3C2410 LCD设备驱动

 

18.11.1 S3C2410 LCD控制器硬件描述

 

       S3C2410内部集成了LCD控制器,它支持STNTFT屏。

 

S3C2410 LCD控制器工作原理如下:

 

下图为其内部的逻辑结构图,REGBANKLCD控制器的寄存器组,用来对LCD控制器的各项参数进行设置,而LCDCDMA则是LCD控制器专用的DMA信道,负责将视频资料从系统总线(system bus)上取来,通过VIDPRCSVD[230]发送给LCD屏,同时TIMEGENLPC3600负责产生LCD 屏所需要的控制时序,例如VSYNCHSYNCVDEN,然后从VIDEO MUX送给LCD屏。

 

 

18.11.2 S3C2410 LCD驱动的模块加载与卸载函数

 

       S3C2410中,作为一个相对独立的硬件单元,LCD控制器被认定为平台设备,因此,在驱动的模块加载和卸载函数中,分别注册和注销对应的platform_driver即可。

 

18.11.3 S3C2410 LCD驱动的的探测与移除函数

 

18.11.4 S3C2410 LCD驱动挂起与恢复函数

 

       如果内核配置了能量管理(即定义了CONFIG_PM),平台驱动部分应该增加挂起和恢复函数。在挂起函数中关闭LCD和其时钟源以节省能量,在恢复函数中开启LCD和其时钟源。

 

18.11.5 S3C2410 LCD驱动的fb_ops成员函数

 

 

总结

帧缓冲设备是一种典型的字符设备,它统一了显存,将显示缓冲区直接映射到用户空间,帧缓冲设备驱动file_opersations中的VFS接口函数有fbmen.c文件统一实现,这样驱动工程师的工作重点将是实现针对特定设备fb_info中的fb_ops的成员函数,另外,理解并能灵活的修改fb_info中的varfix参数很重要。fb_info中的var参数直接和LCD控制器的硬件设置以及LCD屏幕对应。

在用户空间。应用程序直接按照预先设置的RGB位数和偏移写经过mmap()映射后的显示缓冲区就可实现图形的显示,省去了内存从用户空间到内核空间的复制过程。

阅读(2086) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-12-07 11:58:06

相当不错