看lcd驱动好几天了,一直找不到突破点,感觉无从下手。今天看了一篇介绍lcd驱动编写的文章,写的很详细,对理解frambuffer以及lcd驱动很有帮助。但是英文的,多多少少有点不习惯,翻译下来留着以后复习的时候再看就方便了。
编写基于linux的lcd驱动
作者:JimSheng
翻译:窗外云天 [email protected]
摘要:
本文详细描述怎样编写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结构体里有我们设备需要的,比如分辨率等信息。
struct fb_var_screeninfo {
__u32 xres; /* 视口水平分辨率 */
__u32 yres;
__u32 xres_virtual; /* 虚拟屏幕水平分辨率 */
__u32 yres_virtual;
__u32 xoffset; /* 偏移视口与虚拟屏幕水平分辨率偏移 */
__u32 yoffset;
__u32 bits_per_pixel; /* 像素的位数 */
__u32 grayscale; /* 灰度标志,如果为1代表是灰度 */
struct fb_bitfield red; /* 如果是真彩色,这个是颜色位,如果不是那么只有结构的大小重要,其他表示的信息无关紧要 */
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_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
struct fb_fix_screeninfo {
char id[16]; /* 身份表示符,例如 "TT Builtin" */
unsigned long smem_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; /* 每行的长度,单位字节 */
unsigned long mmio_start; /* I/O 内存的开始地址 */
/* (物理地址) */
__u32 mmio_len; /* I/O内存的长度 */
__u32 accel; /* 对驱动程序的标示:是哪个设备*/
__u16 reserved[3]; /* 保留 */
};
3) fb_cmap
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 */
};
4) fb_info
struct fb_info {
int node;
int flags;
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* set before framebuffer registration,
remove after unregister */
struct backlight_device *bl_dev;
/* Backlight level curve */
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; /* This is the parent */
struct device *dev; /* This is this fb device */
int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
char __iomem *screen_base; /* Virtual address */
unsigned long screen_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
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);
};
6) 主要结构关系
struct fb_info
| | fb_var_screeninfo
| | fb_fix_screeninfo
| | fb_cmap
| | modename[40]
struct fb_ops ---|--->ops on var
| | fb_open
| | fb_release
| | fb_ioctl
| | fb_mmap
struct fbgen_hwswitch -|-> detect
| | encode_fix
| | encode_var
| | decode_fix
| | decode_var
| | get_var
| | set_var
| | getcolreg
| | setcolreg
| | pan_display
| | blank
| | set_disp
struct fbgen_hwswitch 结构是硬件操作的抽象,不是必须的,但有时很重要。
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
这两个变量用来标识系统中正在使用的fb_info结构,fb_info代表了显示设备当前的状态。所有的fb_info结构体都保存在全局数组中。当一个新的frambuffer注册到内核,一个新的项就会加入到这个数组中并且 num_registered_fb加一。
static struct {
const char *name;
int (*init)(void);
int (*setup)(void);
} fb_drivers[] __initdata= { ....};
如果一个frambuffer 驱动模块是静态链接到内核的,那么必须在这个结构中加入新项,如果用动态加载模块的方法,就不用考虑这个结构了。
static struct file_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中实现了这些操作。