大家好,我是极客范的本期栏目编辑小友,现在为大家讲解你了解过linux framebuffer 驱动?问题。
帧缓冲设备(fb)提供显示界面的抽象描述。同时,它代表显示界面的存储区域,应用程序可以通过定义的函数访问它,而不需要知道任何底层操作。Framebuffer驱动程序使用的设备节点通常位于/dev目录中,例如/dev/fb*。从用户的角度来看,fb设备与/dev下的其他设备类似:普通字符设备、主设备号29和次设备号定义fb的索引。一般采用以下方法(前面的数字表示子器件编号):0=/dev/fb0第一fb器件,1=/dev/fb1第二fb器件,fb也是普通的存储器件,可以读写其内容。例如,屏幕截图:cp /dev/fb0 myfile,fb可以像存储设备一样读取、写入、查找和mmap它(/dev/mem)。但不同的是,fb并不使用整个存储区域,而是视频存储部分。fb设备的参数可以通过ioctl读取或设置,最重要的是颜色表(cmap)也要通过Ioctl设置。您可以获得一些关于设备的不变信息,例如设备名称、屏幕的组织(平面、像素,),相应存储区的长度和起始地址。您还可以获得可以更改的信息,如位深度、颜色格式、时间顺序等。如果您更改这些值,驱动程序将优化这些值以满足设备特性。帧缓冲区是与LCD控制器相关的驱动,CPU可以通过寻址访问LCD控制器,所以帧缓冲区一般是平台驱动,所以帧缓冲区驱动是用平台驱动的框架编写的。
当我们要写一个FB设备驱动的时候,比较好的方法是注册平台设备,然后把FB设备注册、IO映射操作、硬件初始化等操作放在探针里,这样整体结构就清晰了。
一、重要数据结构
1.帧缓冲区描述符fb_info
structfb_info{
atomic_t计数;
int节点;
int标志;
结构互斥锁;
结构互斥锁mm _ lock/*锁定fb_mmap和smem_*字段*/
struct fb _ var _ screeninfo var//缓冲变量参数
struct fb _ fix _ screeninfo fix//缓冲区修复参数
struct fb _ monspecs monspecs//当前显示器
struct work_struct队列;//事件工作队列
struct fb _ pixmap pixmap//映像硬件映射
struct fb _ pixmap sprite//光标硬件映射
struct fb _ cmap cmap
struct list _ head modelist//视频模式链表
struct fb _ videomode *模式;//当前视频模式
# ifdef CONFIG _ FB _背光//支持背光的参数
struct背光_器件* bl _ dev
结构互斥体bl _ curve _ mutex
u8 bl _ curve[FB _背光_电平];
#endif
#ifdef CONFIG_FB_DEFERRED_IO struct delayed_work deferred_work; struct fb_deferred_io *fbdefio; #endif struct fb_ops *fbops; //帧缓冲区操作函数,framebuffer驱动的核心数据结构 struct device *device; //父设备 struct device *dev; //FB设备 int class_flag; #ifdef CONFIG_FB_TILEBLITTING struct fb_TIle_ops *TIleops; #endif char __iomem *screen_base; unsigned long screen_size; void *pseudo_palette; #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1 u32 state; void *fbcon_par; void *par; struct apertures_struct { unsigned int count; struct aperture { resource_size_t base; resource_size_t size; } ranges[0]; } *apertures; };2. 帧缓冲区操作函数表 fb_ops
struct fb_ops { struct module *owner; //模块所有者 int (*fb_open)(struct fb_info *info, int user); //FB打开操作 int (*fb_release)(struct fb_info *info, int user); //FB释放操作 ssize_t (*fb_read)(struct fb_info *info, char __user *buf,size_t count, loff_t *ppos); //FB读操作 ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,size_t count, loff_t *ppos); //FB写操作 int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);//检查FB可变变量,并调整为可用值 int (*fb_set_par)(struct fb_info *info); //设置视频模式 int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,unsigned blue, unsigned transp, struct fb_info *info); //设置颜色寄存器 int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); //批量设置颜色寄存器,并设置颜色表 int (*fb_blank)(int blank, struct fb_info *info); //空白显示 int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); //面板显示 void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); //画矩形 void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);//把数据拷贝到另外一个区域 void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);//在帧缓冲去中显示一个图片 int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); //绘制光标 void (*fb_rotate)(struct fb_info *info, int angle); //旋转显示 int (*fb_sync)(struct fb_info *info); //等待并同步图像显示完成 int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,unsigned long arg);//FB的IOCTL操作 int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,unsigned long arg); int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); //FB的内存映射MMAP操作 void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,struct fb_var_screeninfo *var); void (*fb_destroy)(struct fb_info *info); int (*fb_debug_enter)(struct fb_info *info); int (*fb_debug_leave)(struct fb_info *info); };
3. 固定参数描述符
struct fb_fix_screeninfo { char id[16]; //FB ID unsigned long smem_start; //FB缓存开始位置 //物理地址相关 __u32 smem_len; //FB缓存长度 __u32 type; /* see FB_TYPE_* */ //FB类型 __u32 type_aux; //FB分界 __u32 visual; /* see FB_VISUAL_* */ //FB色彩模式 __u16 xpanstep; //没有硬件PAN则赋0 __u16 ypanstep; __u16 ywrapstep; __u32 line_length; //1行的字节数 unsigned long mmio_start; //内存IO映射的开始地址 __u32 mmio_len; //IO 长度 __u32 accel; __u16 capabilities; /* see FB_CAP_* */ __u16 reserved[2]; };
4. 可变参数描述符
struct fb_var_screeninfo { __u32 xres; //可见解析度,分辨率的X轴宽度 __u32 yres; //可见解析度,分辨率的Y轴宽度 __u32 xres_virtual; //虚拟解析度X轴宽度 __u32 yres_virtual; //虚拟解析度Y轴宽度 __u32 xoffset; //虚拟与可见解析度之间X轴偏移 __u32 yoffset; //虚拟与可见解析度之间Y轴偏移 __u32 bits_per_pixel; //每像素点的位数 __u32 grayscale; //灰度级别,0表示彩色 struct fb_bitfield red; //RGB位域的红色 struct fb_bitfield green; //RGB位域的绿色 struct fb_bitfield blue; //RGB位域的蓝色 struct fb_bitfield transp; //透明色 __u32 nonstd; //如果该值不为0,非标准像素格式 __u32 activate; /* see FB_ACTIVATE_* */ __u32 height; //图像在屏幕中的高度 __u32 width; //图像在屏幕中的宽度 __u32 accel_flags; __u32 pixclock; //像点时钟 __u32 left_margin; //行切换时,显示与同步间的延时左边空隙 __u32 right_margin; //行切换时,显示与同步间的延时右边空隙 __u32 upper_margin;//帧切换时,显示与同步间的延时上边空隙 __u32 lower_margin; //帧切换时,显示与同步间的延时上边空隙 __u32 hsync_len; //行同步长度 __u32 vsync_len; //帧同步长度 __u32 sync; /* see FB_SYNC_* */ __u32 vmode; /* see FB_VMODE_* */ __u32 rotate; //顺时针旋转角度 __u32 colorspace; //颜色空间 __u32 reserved[5]; };
5. 调色板描述符
struct fb_cmap { __u32 start; //第一个颜色入口 __u32 len; //颜色总数 __u16 *red; //RGB红色值 __u16 *green; //RGB红绿值 __u16 *blue; //RGB红蓝值 __u16 *transp; //透明度值 };
二. 主要函数
1. framebuffer_alloc, 为FB驱动分配内存空间并初始化,这个函数的核心的作用是申请一块空间,并转换为struct fb_info 指针返回,在这个申请过程私有数据空间size并非是必须的,需要的话可以有但并非必须。
struct fb_info *framebuffer_alloc(size_t size, struct device *dev) { #define BYTES_PER_LONG (BITS_PER_LONG/8) #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) int fb_info_size = sizeof(struct fb_info); struct fb_info *info; char *p; if (size) fb_info_size += PADDING; p = kzalloc(fb_info_size + size, GFP_KERNEL); if (!p) return NULL; info = (struct fb_info *) p; if (size) info->par = p + fb_info_size; info->device = dev; #ifdef CONFIG_FB_BACKLIGHT mutex_init(&info->bl_curve_mutex); #endif return info; #undef PADDING #undef BYTES_PER_LONG }
2. register_framebuffer,向系统注册FB。
int register_framebuffer(struct fb_info *fb_info) { int ret; mutex_lock(®istration_lock); ret = do_register_framebuffer(fb_info); mutex_unlock(®istration_lock); return ret; }
三. 实现framebuffer驱动程序的一个例子的步骤
1. 包含头文件
#include
#include
#include
2. 定义及初始化相关FB参数结构体
struct fb_var_screeninfo dnfb_var__devinitdata = { .xres = 1280, .yres = 1024, .xres_virtual = 2048, .yres_virtual = 1024, .bits_per_pixel = 1, .height = -1, .width = -1, .vmode = FB_VMODE_NONINTERLACED, };
static struct fb_fix_screeninfo dnfb_fix__devinitdata = { .id ="Apollo Mono", .smem_start = (FRAME_BUFFER_START + IO_BASE), .smem_len = FRAME_BUFFER_LEN, .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_MONO10, .line_length = 256, };
3. 定义及实现结构 fb_ops与它的成员函数
static int dnfb_blank(int blank, struct fb_info *info) { if (blank) out_8(AP_CONTROL_3A, 0x0); else out_8(AP_CONTROL_3A, 0x1); return 0; }
void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) { unsigned long pat, pat2, fg; unsigned long width = rect->width, height = rect->height; int bits = BITS_PER_LONG, bytes = bits >> 3; u32 bpp = p->var.bits_per_pixel; unsigned long __iomem *dst; int dst_idx, left; if (p->state != FBINFO_STATE_RUNNING) return; if (p->fix.visual == FB_VISUAL_TRUECOLOR || p->fix.visual == FB_VISUAL_DIRECTCOLOR ) fg = ((u32 *) (p->pseudo_palette))[rect->color]; else fg = rect->color; pat = pixel_to_pat(bpp, fg); dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; left = bits % bpp; if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (!left) { u32 bswapmask = fb_compute_bswapmask(p); void (*fill_op32)(struct fb_info *p,unsigned long __iomem *dst, int dst_idx,unsigned long pat, unsigned n, int bits,u32 bswapmask) = NULL;
switch (rect->rop) { case ROP_XOR: fill_op32 = bitfill_aligned_rev; break; case ROP_COPY: fill_op32 = bitfill_aligned; break; default: printk( KERN_ERR"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); fill_op32 = bitfill_aligned; break; } while (height--) { dst += dst_idx >> (ffs(bits) - 1); dst_idx &= (bits - 1); fill_op32(p, dst, dst_idx, pat, width*bpp, bits, bswapmask); dst_idx += p->fix.line_length*8; } } else { int right, r; void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst,int dst_idx, unsigned long pat, int left,int right, unsigned n, int bits) = NULL; right = bpp - left; switch (rect->rop) { case ROP_XOR: fill_op = bitfill_unaligned_rev; break; case ROP_COPY: fill_op = bitfill_unaligned; break; default: printk(KERN_ERR"cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); fill_op = bitfill_unaligned; break; } while (height--) { dst += dst_idx / bits; dst_idx &= (bits - 1); r = dst_idx % bpp; pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp)); fill_op(p, dst, dst_idx, pat2, left, right,width*bpp, bits); dst_idx += p->fix.line_length*8; } } }
static void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) {
}
void cfb_imageblit(struct fb_info *p, const struct fb_image *image) { u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; u32 width = image->width; u32 dx = image->dx, dy = image->dy; u8 __iomem *dst1; if (p->state != FBINFO_STATE_RUNNING) return; bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); start_index = bitstart & (32 - 1); pitch_index = (p->fix.line_length & (bpl - 1)) * 8; bitstart /= 8; bitstart &= ~(bpl - 1); dst1 = p->screen_base + bitstart; if (p->fbops->fb_sync) p->fbops->fb_sync(p); if (image->depth == 1) { if (p->fix.visual == FB_VISUAL_TRUECOLOR || p->fix.visual == FB_VISUAL_DIRECTCOLOR) { fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color]; bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color]; } else { fgcolor = image->fg_color; bgcolor = image->bg_color; } if (32 % bpp == 0 && !start_index && !pitch_index && ((width & (32/bpp-1)) == 0) && bpp >= 8 && bpp <= 32) fast_imageblit(image, p, dst1, fgcolor, bgcolor); else slow_imageblit(image, p, dst1, fgcolor, bgcolor,start_index, pitch_index); } else color_imageblit(image, p, dst1, start_index, pitch_index); }
static struct fb_ops dn_fb_ops = { .owner = THIS_MODULE, .fb_blank = dnfb_blank, .fb_fillrect = cfb_fillrect, .fb_copyarea = dnfb_copyarea, .fb_imageblit = cfb_imageblit, };
4. 定义及实现总线驱动结构体及成员函数,如果FB驱动是挂载在platform总线上,则定义platform_driver结构,如果是别的总线,比如PCI总线,在定义pci_driver结构。一般会在总线驱动成员的probe函数中调用FB的函数framebuffer_alloc与register_framebuffer来申请FB设备及注册到系统。
static int __devinit dnfb_probe(struct platform_device *dev) { struct fb_info *info; int err = 0; info = framebuffer_alloc(0, &dev->dev); if (!info) return -ENOMEM; info->fbops = &dn_fb_ops; info->fix = dnfb_fix; info->var = dnfb_var; info->var.red.length = 1; info->var.red.offset = 0; info->var.green = info->var.blue = info->var.red; info->screen_base = (u_char *) info->fix.smem_start; err = fb_alloc_cmap(&info->cmap, 2, 0); if (err < 0) { framebuffer_release(info); return err; } err = register_framebuffer(info); if (err < 0) { fb_dealloc_cmap(&info->cmap); framebuffer_release(info); return err; } platform_set_drvdata(dev, info); out_8(AP_CONTROL_3A, RESET_CREG); out_be16(AP_WRITE_ENABLE, 0x0); out_8(AP_CONTROL_0, NORMAL_MODE); out_8(AP_CONTROL_1, (AD_BLT | DST_EQ_SRC | NORM_CREG1)); out_8(AP_CONTROL_2, S_DATA_PLN); out_be16(AP_ROP_1, SWAP(0x3)); return err; }
static struct platform_driver dnfb_driver = { .probe = dnfb_probe, .driver = { .name ="dnfb", }, }; static struct platform_device dnfb_device = { .name ="dnfb", };
5. 调用总线驱动注册函数把FB驱动注册到系统。
int __init dnfb_init(void) { int ret; if (!MACH_IS_APOLLO) return -ENODEV; if (fb_get_options("dnfb", NULL)) return -ENODEV; ret = platform_driver_register(&dnfb_driver); if (!ret) { ret = platform_device_register(&dnfb_device); if (ret) platform_driver_unregister(&dnfb_driver); } return ret; } module_init(dnfb_init);