lcd命令 linux,编写基于Linux的lcd驱动

看lcd驱动好几天了,一直找不到突破点,感觉无从下手。今天看了一篇介绍lcd驱动编写的文章,写的很详细,对理解frambuffer以及lcd驱动很有帮助。但是英文的,多多少少有点不习惯,翻译下来留着以后复习的时候再看就方便了。

摘要:

本文详细描述怎样编写linux frambuffer LCD 驱动程序

1. LCD 驱动/设备/控制器

2. linux frambuffer 驱动

2.1 为什么要用frambuffer?

2.2 什么是frambuffer设备?

2.3 怎样编写frambuffer驱动程序?

3. linux frambuffer 驱动源码分析

3.1 fb.h

3.2 fbmen.c

4. LCD 控制器驱动程序结构

4.1 为lcd显存分配内存

4.2 实现 fb_ops 功能函数

1.LCD 驱动/设备/控制器

除了LCD设备的datasheet,还有两个关于LCD的非常不错的书,并且他们都是中文的。一本叫:《液晶显示技术》,另外一本叫《液晶显示器件》。这两本书详细介绍了LCD的知识,包括对硬件的操作,LCD的底层编程等。这两本书对设计LCD模块和底层编程都很有帮助。

2. linux frambuffer 驱动

2.1 为什么要用frambuffer?

如果我们的系统要用GUI(图形界面接口),比如minigui,MicroWindows.这时LCD设备驱动程序就应该编写成frambuffer接口,而不是编写成仅仅操作底层的LCD控制器接口。

2.2 什么是frambuffer设备?

frambuffer设备层是对图像设备的一种抽象,它代表了视频硬件的帧缓存,使得应用程序通过定义好的接口就可以访问硬件。所以应用程序不需要考虑底层的(寄存器级)的操作。应用程序对设备文件的访问一般在

/dev 目录,如 /dev/fb*。更多关于frambuffer设备的详细信息请阅读内核文档:linux /Documentation /fb /framebuffer.txt and linux /Documentation /fb /interal.txt

2.3 怎样编写frambuffer驱动程序?

关于如何编写frambuffer设备驱动,有很多参考资料。你可以在/linux-fbdev.sourceforge.net /HOWTO /index.html网站上阅读“Linux Frame buffer Driver Writing HOWTO”。

但是我认为这篇文章过于简短。所以分析内核相关部分的源码才是王道。

3.linux frambuffer 驱动源码分析

linux中frambuffer接口的所有功能实现都包括在下面两个文件中

1) linux/include/linux/fb.h

2) linux/drivers/video/fbmem.c

下面详细分析这两个文件:

3.1 fb.h

所有frambuffer重要的结构体都定义在这个文件中。下面逐个分析他们:

1) fb_var_screeninfo

这个结构用来描述一个显卡可以被设置的特性,在fb_var_screeninfo结构体里有我们设备需要的,比如分辨率等信息。

structfb_var_screeninfo {

__u32 xres;/* 视口水平分辨率      */

__u32 yres;

__u32 xres_virtual;/* 虚拟屏幕水平分辨率        */

__u32 yres_virtual;

__u32 xoffset;/* 偏移视口与虚拟屏幕水平分辨率偏移 */

__u32 yoffset;

__u32 bits_per_pixel;/* 像素的位数            */

__u32 grayscale;/* 灰度标志,如果为1代表是灰度 */

structfb_bitfield red;/* 如果是真彩色,这个是颜色位,如果不是那么只有结构的大小重要,其他表示的信息无关紧要 */

structfb_bitfield green;

structfb_bitfield blue;

structfb_bitfield transp;/* 透明度      */

__u32 nonstd;/* 非标准颜色表示标志位 */

__u32 activate;/* 参照 FB_ACTIVATE_*     */

__u32 height;/* 在内存地址空间的长度    */

__u32 width;/* 在内存地址空间的宽度     */

__u32 accel_flags;/* (不用了) 参照 fb_info.flags */

/* 时序: 以下所有的值单位都是pixclock, 当然除了pixclock */

__u32 pixclock;/* 每秒像素值 */

__u32 left_margin;/* 从sync信号到显示真正的像素的时钟个数 */

__u32 right_margin;/* 从真正显示像素到sync信号的时钟个数  */

__u32 upper_margin;/* 上面两个是针对列像素的,这个针对行的   */

__u32 lower_margin;

__u32 hsync_len;/* 水平sync信号的长度  */

__u32 vsync_len;/* 垂直sync信号的长度  */

__u32 sync;/* 参照 FB_SYNC_*     */

__u32 vmode;/* 参照 FB_VMODE_*        */

__u32 rotate;/* angle we rotate counter clockwise */译者注:这个不知道具体是什么

__u32 reserved[5];/* 保留 */

};2) fb_fix_screeninfon

这个结构体定义了一些显示设备的特性,这些特性当设备的工作模式确定之后就不能改变了。例如:frambuffer 内存的起始地址。这个地址是根据模式的不同而不同。一旦你用了一种模式,你就不要在想去改变他的起始地址了。在这种情况下,你可以获得显示设备的内存区域地址,但是你��能更改他。

structfb_fix_screeninfo {

charid[16];/* 身份表示符,例如 "TT Builtin" */

unsignedlongsmem_start;/* frame buffer内存的开始地址 */

/* (物理地址) */

__u32 smem_len;/* frame buffer内存地址的长度 */

__u32 type;/* 参照 FB_TYPE_*     */

__u32 type_aux;/* Interleave for interleaved Planes */

__u32 visual;/* 参照 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;/* 每行的长度,单位字节    */

unsignedlongmmio_start;/* I/O 内存的开始地址   */

/* (物理地址) */

__u32 mmio_len;/* I/O内存的长度  */

__u32 accel;/* 对驱动程序的标示:是哪个设备*/

__u16 reserved[3];/* 保留 */

};3) fb_cmap

调色板信息,这个结构是设备依赖的。应用程序可以通过ioctls的FBIOGETCMAP和FBIOPUTCMAP命令来获得和设置这个结构

structfb_cmap {

__u32 start;/* First entry */

__u32 len;/* Number of entries */

__u16 *red;/* Red values */

__u16 *green;

__u16 *blue;

__u16 *transp;/* transparency, can be NULL */

};4) fb_info

这个结构代表了一个显示设备的当前状态。他仅对内核可见。除了fb_info结构,内核还有一个fb_ops结构,定义了一些驱动必须的操作函数。

structfb_info {

intnode;

intflags;

structmutex lock;/* Lock for open/release/ioctl funcs */

structmutex mm_lock;/* Lock for fb_mmap and smem_* fields */

structfb_var_screeninfo var;/* Current var */

structfb_fix_screeninfo fix;/* Current fix */

structfb_monspecs monspecs;/* Current Monitor specs */

structwork_struct queue;/* Framebuffer event queue */

structfb_pixmap pixmap;/* Image hardware mapper */

structfb_pixmap sprite;/* Cursor hardware mapper */

structfb_cmap cmap;/* Current cmap */

structlist_head modelist;/* mode list */

structfb_videomode *mode;/* current mode */

#ifdef CONFIG_FB_BACKLIGHT

/* assigned backlight device */

/* set before framebuffer registration,

remove after unregister */

structbacklight_device *bl_dev;

/* Backlight level curve */

structmutex bl_curve_mutex;

u8 bl_curve[FB_BACKLIGHT_LEVELS];

#endif

#ifdef CONFIG_FB_DEFERRED_IO

structdelayed_work deferred_work;

structfb_deferred_io *fbdefio;

#endif

structfb_ops *fbops;

structdevice *device;/* This is the parent */

structdevice *dev;/* This is this fb device */

intclass_flag;/* private sysfs flags */

#ifdef CONFIG_FB_TILEBLITTING

structfb_tile_ops *tileops;/* Tile Blitting */

#endif

char__iomem *screen_base;/* Virtual address */

unsignedlongscreen_size;/* Amount of ioremapped VRAM or 0 */

void*pseudo_palette;/* Fake palette of 16 colors */

#define FBINFO_STATE_RUNNING    0

#define FBINFO_STATE_SUSPENDED  1

u32 state;/* Hardware state i.e suspend */

void*fbcon_par;/* fbcon use-only private area */

/* From here on everything is device dependent */

void*par;

/* we need the PCI or similiar aperture base/size not

smem_start/size as smem_start may just be an object

allocated inside the aperture so may not actually overlap */

resource_size_t aperture_base;

resource_size_t aperture_size;

};5) struct fb_ops

应用程序可以通过ioctl()系统调用来操作LCD硬件,这些操作需要fb_ops中的函数的支持。

structfb_ops {

/* open/release and usage marking */

structmodule *owner;

int(*fb_open)(structfb_info *info,intuser);

int(*fb_release)(structfb_info *info,intuser);

/* For framebuffers with strange non linear layouts or that do not

* work with normal memory mapped access

*/

ssize_t (*fb_read)(structfb_info *info,char__user *buf,

size_tcount, loff_t *ppos);

ssize_t (*fb_write)(structfb_info *info,constchar__user *buf,

size_tcount, loff_t *ppos);

/* checks var and eventually tweaks it to something supported,

* DO NOT MODIFY PAR */

int(*fb_check_var)(structfb_var_screeninfo *var,structfb_info *info);

/* set the video mode according to info->var */

int(*fb_set_par)(structfb_info *info);

/* set color register */

int(*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,

unsigned blue, unsigned transp,structfb_info *info);

/* set color registers in batch */

int(*fb_setcmap)(structfb_cmap *cmap,structfb_info *info);

/* blank display */

int(*fb_blank)(intblank,structfb_info *info);

/* pan display */

int(*fb_pan_display)(structfb_var_screeninfo *var,structfb_info *info);

/* Draws a rectangle */

void(*fb_fillrect) (structfb_info *info,conststructfb_fillrect *rect);

/* Copy data from area to another */

void(*fb_copyarea) (structfb_info *info,conststructfb_copyarea *region);

/* Draws a image to the display */

void(*fb_imageblit) (structfb_info *info,conststructfb_image *image);

/* Draws cursor */

int(*fb_cursor) (structfb_info *info,structfb_cursor *cursor);

/* Rotates the display */

void(*fb_rotate)(structfb_info *info,intangle);

/* wait for blit idle, optional */

int(*fb_sync)(structfb_info *info);

/* perform fb specific ioctl (optional) */

int(*fb_ioctl)(structfb_info *info, unsignedintcmd,

unsignedlongarg);

/* Handle 32bit compat ioctl (optional) */

int(*fb_compat_ioctl)(structfb_info *info, unsigned cmd,

unsignedlongarg);

/* perform fb specific mmap */

int(*fb_mmap)(structfb_info *info,structvm_area_struct *vma);

/* get capability given var */

void(*fb_get_caps)(structfb_info *info,structfb_blit_caps *caps,

structfb_var_screeninfo *var);

/* teardown any resources to do with this framebuffer */

void(*fb_destroy)(structfb_info *info);

};6) 主要结构关系

structfb_info

| | fb_var_screeninfo

| | fb_fix_screeninfo

| | fb_cmap

| | modename[40]

structfb_ops ---|--->ops on var

| | fb_open

| | fb_release

| | fb_ioctl

| | fb_mmap

structfbgen_hwswitch -|-> detect

| | encode_fix

| | encode_var

| | decode_fix

| | decode_var

| | get_var

| | set_var

| | getcolreg

| | setcolreg

| | pan_display

| | blank

| | set_dispstruct fbgen_hwswitch 结构是硬件操作的抽象,不是必须的,但有时很重要。

3.2 fbmem.c

fbmem.c 是frambuffer驱动的核心,他向上给应用程序提供了系统调用接口,向下对特定的硬件提供底层的驱动接口。底层驱动可以通过接口向内核注册自己。fbmem.c提供了frambuffer驱动的所有接口代码,从而避免重复的工作。

1) 全局变量

structfb_info *registered_fb[FB_MAX];

intnum_registered_fb;这两个变量用来标识系统中正在使用的fb_info结构,fb_info代表了显示设备当前的状态。所有的fb_info结构体都保存在全局数组中。当一个新的frambuffer注册到内核,一个新的项就会加入到这个数组中并且 num_registered_fb加一。

staticstruct{

constchar*name;

int(*init)(void);

int(*setup)(void);

} fb_drivers[] __initdata= { ....};如果一个frambuffer 驱动模块是静态链接到内核的,那么必须在这个结构中加入新项,如果用动态加载模块的方法,就不用考虑这个结构了。

staticstructfile_operations fb_ops ={

owner: THIS_MODULE,

read: fb_read,

write: fb_write,

ioctl: fb_ioctl,

mmap: fb_mmap,

open: fb_open,

release: fb_release

};这是面向应用程序的接口,fbmem.c中实现了这些操作。

2) register_framebuffer(struct fb_info *fb_info) 函数 和 unregister_framebuffer(struct fb_info *fb_info)函数

这个函数是frambuffer设备驱动程序的底层接口。驱动程序用这两个函数向内核注册和注销自己。驱动程序所做的所有底层工作就是填充一个fb_info结构体然后注册自己

4 LCD控制器驱动程序的结构框架

LCD 驱动操作LCD设备。而frambuffer核心(fbmem.c)管理这些驱动。在linux /drivers /fb /skeleton.c中,编写了一个frambuffer驱动结构的框架。他用一些代码展示了如何编写frambuffer驱动。因为这个太简单了,他除了填充一个frambuffer的fb_info结构体并注册到内核外什么都没做。为了编写一个可用的LCD控制器驱动,还必须做其他的一些工作。具体需要做些什么呢,我们知道设备驱动程序将硬件抽象化并向应用程序提供接口。所以根据系统调用接口的需要,我们实现相应的底层硬件操作,那就是我们在3.2小节提到的 file_operations 结构体

4.1 为设备分配一块显示内存

仔细研究fbmem.c后,我们发现 open()和release() 文件操作方法的实现不需要底层硬件的支持。但是 read(),write()和mmap() 需要一个通用的操作函数fb_get_fix(),这个函数必须由驱动程序的作者编写另外驱动程序还必须为设备分配一块内存作为显示缓存,因为大多数LCD控制器都没有自己的缓存。这块内存的开始地址和大小将会填充在fb_fix_screeninfo结构的smem_start和smem_len域。而且内存必须是物理连续的。

4.2 fbops 函数的实现

现在还有个文件操作没有讨论的就是Ioctl()了,应用程序使用系统调用ioctl来操作LCD硬件。在fb_ops定义的方法来支持这些操作。

注意: 这里的fbops结构不是上层的系统调用接口(注:是在fb_info中的)。下面我们讨论该实现什么样的方法。ioctl()系统调用在fbmem.c中实现,因此我们在这个实现中会发现相关的命令与fb_ops方法

FBIOGET_VSCREENINFO fb_get_var

FBIOPUT_VSCREENINFO fb_set_var

FBIOGET_FSCREENINFO fb_get_fix

FBIOPUTCMAP fb_set_cmap

FBIOGETCMAP fb_get_cmap

FBIOPAN_DISPLAY fb_pan_display

现在我们知道应该实现这些fb_XXX_XXX函数。应用程序的作者可以通过调用FBIOXXXX来操作lcd。我们如何来实现这些操作呢?最好是先参考一下linux/drivers/video/fbgen.c和在the linux/drivers/video目录下其他的显示驱动程序。在这些函数中,fb_set_var()最重要。他用来设置显示模式和实现其他功能的。下面是fb_set_var()实现的通用步骤:

1) 检查模式设置是否必须

2) 设置模式

3) 设置调色板

4) 根据先前的配置,设置LCD控制器的寄存器

这四步说明了底层操作的实现。好奇的童鞋会问:应用程序的图像数据是怎样显示在屏幕上的。驱动程序分配一块内存作为显存。然后设置显存的开始地址和长度到对应的LCD控制器的相应寄存器(这个操作一般由fb_set_var())实现。内存中的数据会通过LCD控制器自动显示到屏幕上(详情请参照特定的LCD控制器)。另一方面显存被mmap()到了用户空间。因此,当用户将数据拷贝到映射的内存的时候,数据就会显示到屏幕上了。

参考资料:

1 液晶显示技术

2 液晶显示器件

3 linux/Documentation/fb/framebuffer.txt

4 linux/Documentation/fb/interal.txt

5 Linux Framebuffer Driver Writing HOWTO

http:/linux-fbdev.sourceforge.net/HOWTO /index.html

6 linux/include/linux/fb.h

7 linux/drivers/video/fbmem.c

8 linux/drivers/video/skeletonfb.c

9 linux/drivers/video/fbgen.c

10 linux/drivers/video/tgafb.c

11 s3c2410 microprocessor user manual

s3c2410fb.h, s3c2410fb.c, s3c2410fb.c-pre, s3c2410fb.c-mono

A kind of arm-based widely used MCU, with integrated LCD controller.

12 sed1335 datasheet

A kind of widely used LCD controller0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值