LCD设备驱动框架图

如上图所示
- 核心层是通用的,不需要任何修改。驱动开发者只需要实现硬件设备驱动层
- 帧缓冲设备可以看做是一个完整的子系统,主要由核心层的
和硬件设备驱动层构成fbmem.c
- 核心层代码
向上提供了完整的字符设备操作接口,也就是实现注册字符设备,提供通用的fnmem.c
,open
,read
,write
,ioctl
等接口;向下给硬件设备驱动层提供标准的驱动编程接口;mmap
- 在
系统中,一个硬件控制器(显卡)抽象为一个linux
结构,要实现一个fb_info
驱动就是要实现这个结构,并且使用核心层提供的注册函数注册LCD
-
中通过其中的fb_info
结构指针提供了实际硬件操作方法fb_ops
-
中通过其中的fb_info
结构和fb_var_screeninfo
结构提供了具体fb_fix_screeninfo
屏基本信息lcd
- 注册:
register_framebuffer
- 注销:
unregister_framebuffer
LCD驱动数据结构
LCD设备驱动核心结构体struct fb_info
地位等同于杂项设备的
struct misc_dev
结构
路径:
fb.h linux-3.5\include\linux
struct fb_info {
atomic_t count;
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 similar aperture base/size not
smem_start/size as smem_start may just be an object
allocated inside the aperture so may not actually overlap */
struct apertures_struct {
unsigned int count;
struct aperture {
resource_size_t base;
resource_size_t size;
} ranges[];
} *apertures;
};
这个结构中成员很多大部分都是结构体,但写
led
驱动并不需要实现所有的成员,正如写字符设备驱动的
file_operation
那样,用到那个写哪个就可以。这里我们主要关注的是
struct fb_var_screeninfo var; /* LCD屏可变参数 */
struct fb_fix_screeninfo fix; /* LCD屏固定参数 */
struct fb_ops *fbops; /*真正操作硬件寄存器的方法集合*/
char __iomem *screen_base; /* LCD虚拟显存地址 */
void *pseudo_palette; /* 指向16种颜色的调试板,其实就是一块内存 */
void *par; /*私有数据,驱动开发者可以用来存放自己的数据的结构地址*/
var
,
fix
,
fbops
,
screen_base
使用标准的LCD框架编写,这四个成员是一定要实现的。
struct fb_var_screeninfo
- 路径:
fb.h linux-3.5\include\linux
-
表示一个struct fb_var_screeninfo
控制器,记录了用户可以修改的的控制器参数,如屏幕的分辨率和LCD
等,以及一些固定信息bpp
struct fb_var_screeninfo {
__u32 xres; /* 可见屏幕一行有多少像素点 */
__u32 yres; /* 可见屏幕一屏有多少行 也就是列*/
__u32 xres_virtual; /* 虚拟屏幕一行有多少像素点 */
__u32 yres_virtual; /* 虚拟屏幕一屏有多少行 */
//显存大小并不一定等于实际屏幕显示对应的区域
__u32 xoffset; /* 虚拟屏到实际屏的水平偏移量 */
__u32 yoffset; /* 虚拟屏到实际屏的垂直偏移量 */
__u32 bits_per_pixel; /*LCD屏工作时BPP */
__u32 grayscale; /* 0 = 彩色, 1 = 灰度屏, */
struct fb_bitfield red; /* 红色的长度和偏移信息 */
struct fb_bitfield green; /* 绿色的长度和偏移信息 */
struct fb_bitfield blue; /* 蓝色的长度和偏移信息 */
struct fb_bitfield transp; /* 透明色的长度和偏移信息*/
__u32 nonstd; /* ==0,标准像素格式,一般情况基本都是标准像素!= 0 Non standard pixel format */
//定义修改参数生效时刻,一般马上生效,对应值是0,宏名是 FB_ACTIVATE_NOW
__u32 activate; /* see FB_ACTIVATE_* */
/*补充相关宏
#define FB_ACTIVATE_NOW 0 /*修改立即生效*/
#define FB_ACTIVATE_NXTOPEN 1 /* 下次打开时生效*/
#define FB_ACTIVATE_TEST 2 /* 不设置,忽略 */
*/
//存放物理屏的物理尺寸,是外观尺寸,单位是mm,可选择填充的项 非重点
__u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
/*下面是LCD屏的工作时序,对应前面移植LCD传递下来的 struct fb_videomode结构*/
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture HBPD*/
__u32 right_margin; /* time from picture to sync HFPD*/
__u32 upper_margin; /* time from sync to picture VBPD*/
__u32 lower_margin; /* VFPB*/
__u32 hsync_len; /* length of horizontal sync HSPW*/
__u32 vsync_len; /* length of vertical sync VSPW*/
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 colorspace; /* colorspace for FOURCC-based modes */
__u32 reserved[]; /* Reserved for future compatibility */
};
补充struct fb_bitfield
struct fb_bitfield {
__u32 offset; /* 颜色偏移量 */
__u32 length; /* 颜色长度 */
__u32 msb_right; /* != 0 :最高位在右边 */
};
struct fb_fix_screeninfo
- 路径:
fb.h linux-3.5\include\linux
struct fb_fix_screeninfo {
char id[]; /* LCD标识名 填写一个16字符以内字符串即可 */
unsigned long smem_start; /* 显存的物理起始地址,不是虚拟地址 */
__u32 smem_len; /* 显存的内存长度 */
__u32 type; /* see FB_TYPE_* FB_TYPE_PACKED_PIXELS 表示像素类型,一般都是标准像素格式 */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* 表示颜色类型FB_VISUAL_TRUECOLOR 0表示真彩色 */
__u16 xpanstep; /* zero if no hardware panning 硬件x轴平移 没有就为0 */
__u16 ypanstep; /* zero if no hardware panning 硬件y轴平移 没有就为0*/
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes 一行占用字节数 */
//独立显卡相关的
unsigned long mmio_start; /* Start of Memory Mapped I/O 独立显卡 */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 capabilities; /* see FB_CAP_* */
__u16 reserved[]; /* Reserved for future compatibility */
};
重要成员:
id:
lcd
标识名,随便
smem_start:显存的物理起始地址,不是虚拟地址,驱动中定义的变量,普通动态分配内存的方法得到的都是虚拟地址。要得到物理地址必须使用专门的
DMA
内存分配函数
void *dma_alloc_writecombine(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
函数功能:动态分配
DMA
内存,同时可以得到分配内存的虚拟地址和物理地址
参数:
dev:设备指针如果没有赋值
NULL
size:内存大小
dma_handle:作为输出参数使用,存放分配到的内存对应的物理地址
flag:内存分配方式
返回值:分配到的内存的首地址
DMA缓冲区释放函数:
void dma_free_writecombine(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle)
功能:释放由
dma_alloc_writecombine
分配的
dma
内存
参数:
dev:设备指针如果没有赋值
NULL
size:内存大小
cpu_addr:
dma_alloc_writecombine
得到的虚拟地址首地址
dma_handle:作为输出参数使用,存放分配到的内存对应的物理地址
备注:因为
lcd
是利用
DMA
来搬运数据,而
DMA
模块只会使用物理地址,所以
LCD
驱动中需要记录物理地址
line_length:一行占用的内存字节数
LCD设备驱动硬件操作方法结构struct fb_ops
路径:
fb.h linux-3.5\include\linux
这个结构是内核用来描述整整硬件的操作方法和数据结构。
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);
/* called at KDB enter and leave time to prepare the console */
int (*fb_debug_enter)(struct fb_info *info);
int (*fb_debug_leave)(struct fb_info *info);
};
这个结构成员有很多,那么哪些是必须实现的呢?
常用的重要成员:
fb_open:当你的
lcd
不需要做什么特殊的初始化操作,这个方法可以不实现
fb_release:当你的应用程序不使用
lcd
设备的时候,需要做的事情在这里实现,一般不实现
fb_read:当你的
lcd
控制器使用的内存是独立显存的时候才需要使用,直接使用核心层
read
fb_write:当你的
lcd
控制器使用的内存是独立显存的时候才需要使用,直接使用核心层
write
fb_check_var:检测应用程序传递下来的可变参数是否合法。当你不提供给应用程序通过ioctl命令动态修改
LCD
可变参数时不需要实现。
fb_set_par:实现的功能是把可变参数设置到硬件寄存器中去
fb_blank:实现屏幕的黑屏白屏模式(开屏,关屏)
fb_fillrect:实现功能是填充矩形,如果是非独立显卡直接使用内核自带的函数
cfb_fillrect
fb_copyarea:实现功能是区域复制,如果是非独立显卡直接使用内核自带的函数
cfb_copyarea
fb_imageblit:实现功能是绘制位图,如果是非独立显卡直接使用内核自带的函数
cfb_imageblit
fb_ioctl:实现功能是让用户通过
ioctl
接口调用这个函数对
LCD
进行特殊功能控制,如果控制器只实现了一般的标准功能,不需要实现,使用核心层默认的
ioctl
接口就可以了
fb_setcolreg:实现的功能是设置颜色寄存器
fb_mmap:实现的功能是把内核空间的分配的显存映射到用户空间中对应的
mmap
系统调用,当你的控制器是独显的时候才需要
必须实现的:
fb_fillrect
,
fb_copyarea
,
fb_imageblit
一般情况下也会实现
fb_check_var
,
fb_set_par