以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
一、前言
framebuffer驱动框架包括以下两部分:
1、内核开发者实现的部分(核心层)
root@ubuntu:省略部分路径/x210_kernel/drivers/video# ls *.o built-in.o cfbfillrect.o fbcmap.o fbmem.o fb_notify.o fbsysfs.o cfbcopyarea.o cfbimgblt.o fbcvt.o fbmon.o fb.o modedb.o root@ubuntu:省略部分路径/x210_kernel/drivers/video#
通过检查内核编译结果相应目录中的.o文件,得知驱动框架核心层主要涉及的文件:
(1)drivers/video/fbmem.c(主要文件)
该文件创建graphics类,注册fb设备驱动,提供fb设备注册接口register_framebuffer。
该文件相对于fb设备,就好比misc.c文件相对于杂散类设备,其结构和分析方法类似。
(2)drivers/video/fbsysfs.c
这个文件与fb在/sys目录下的一些属性文件有关。
(3)drivers/video/modedb.c
这个文件与显示模式(比如VGA、720P等)的管理有关。
(4)drivers/video/fb_notify.c
2、驱动工程师实现的部分(操作层)
root@ubuntu:省略部分路径/x210_kernel/drivers/video# cd samsung/ root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung# ls *.o built-in.o s3cfb_fimd6x.o s3cfb.o root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung#
通过检查内核编译结果相应目录中的.o文件,得知具体操作层主要涉及的文件:
(1)drivers/video/samsung/s3cfb.c,这是驱动主要文件。
(2)drivers/video/samsung/s3cfb_fimd6x.c,里面有很多LCD硬件操作的函数。
(3)arch/arm/mach-s5pv210/mach-x210.c,负责提供platform_device。
(4)arch/arm/plat-s5p/devs.c,为platform_device提供一些硬件描述信息。
接下来,我们将对这两部分内容进行源码级别的分析。
二、fb驱动框架核心层分析
1、fbmem_init()函数
此函数位于drivers/video/fbmem.c文件中。
static int __init fbmem_init(void) {proc_create("fb", 0, NULL, &fb_proc_fops);if (register_chrdev(FB_MAJOR,"fb",&fb_fops))printk("unable to get major %d for fb devs\n", FB_MAJOR);fb_class = class_create(THIS_MODULE, "graphics");if (IS_ERR(fb_class)) {printk(KERN_WARNING "Unable to create fb class;errno = %ld\n",\PTR_ERR(fb_class));fb_class = NULL;}return 0; }#ifdef MODULE //MODULE没有定义 module_init(fbmem_init); static void __exit fbmem_exit(void) {remove_proc_entry("fb", NULL);class_destroy(fb_class);unregister_chrdev(FB_MAJOR, "fb"); }module_exit(fbmem_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Framebuffer base"); #else //MODULE没有定义,所以对于fbmem_init而言,执行的是这个 subsys_initcall(fbmem_init); #endif
(1)subsys_initcall(fbmem_init)
对于fbmem_init()函数,因为没有定义MODULE(表示以模块方式安装),因此执行的是subsys_initial(表示直接集成在内核中)。又因为是直接集成的,所以不需要卸载函数。
(2)proc_create("fb", 0, NULL, &fb_proc_fops);
fb_proc_fops和fb在proc文件系统中的表现,即cat /proc/fb的实现;
(3)register_chrdev(FB_MAJOR,"fb",&fb_fops)
利用register_chdev()函数注册fb设备,注册之后在cat /proc/devices时显示有“29 fb”。
其中,FB_MAJOR=29,而变量fb_fops的定义见下文。
(4)fb_class = class_create(THIS_MODULE, "graphics");
利用class_create()函数创建了一个名为“graphics”的类。即在/sys/class/下有graphics目录。
2、变量fb_fops
变量fb_fops定义在drivers/video/fbmem.c文件中,内容如下:
static const struct file_operations fb_fops = {.owner = THIS_MODULE,.read = fb_read,.write = fb_write,.unlocked_ioctl = fb_ioctl,//省略部分代码 };
可知其函数成员所指向的函数,分别为fb_read,fb_write,fb_ioctl。后面将讨论这些函数。
3、register_framebuffer()函数
此函数位于drivers/video/fbmem.c文件中,是fb驱动框架设计的fb设备注册接口,内容如下。
/*** register_framebuffer - registers a frame buffer device* @fb_info: frame buffer info structure* Registers a frame buffer device @fb_info.* Returns negative errno on error, or zero for success.**/int register_framebuffer(struct fb_info *fb_info) {int i;struct fb_event event;struct fb_videomode mode;if (num_registered_fb == FB_MAX)return -ENXIO;if (fb_check_foreignness(fb_info))//判断大小端模式return -ENOSYS;remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,fb_is_primary_device(fb_info));num_registered_fb++;for (i = 0 ; i < FB_MAX; i++)if (!registered_fb[i])break;fb_info->node = i;mutex_init(&fb_info->lock);mutex_init(&fb_info->mm_lock);fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), NULL, "fb%d", i);if (IS_ERR(fb_info->dev)) {/* Not fatal */printk(KERN_WARNING "Unable to create device for framebuffer %d; \errno = %ld\n", i, PTR_ERR(fb_info->dev));fb_info->dev = NULL;} elsefb_init_device(fb_info);if (fb_info->pixmap.addr == NULL) {fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);if (fb_info->pixmap.addr) {fb_info->pixmap.size = FBPIXMAPSIZE;fb_info->pixmap.buf_align = 1;fb_info->pixmap.scan_align = 1;fb_info->pixmap.access_align = 32;fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;}} fb_info->pixmap.offset = 0;if (!fb_info->pixmap.blit_x)fb_info->pixmap.blit_x = ~(u32)0;if (!fb_info->pixmap.blit_y)fb_info->pixmap.blit_y = ~(u32)0;if (!fb_info->modelist.prev || !fb_info->modelist.next)INIT_LIST_HEAD(&fb_info->modelist);fb_var_to_videomode(&mode, &fb_info->var);fb_add_videomode(&mode, &fb_info->modelist);registered_fb[i] = fb_info;event.info = fb_info;if (!lock_fb_info(fb_info))return -ENODEV;fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);unlock_fb_info(fb_info);return 0; }
(1)struct fb_info 结构体
此结构体的定义如下:
struct fb_info {int node; //fb_info在registered_fb数组的下标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 *///省略部分代码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 */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 1u32 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 notsmem_start/size as smem_start may just be an objectallocated 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[0];} *apertures; };
(2)fb_check_foreignness()函数
判断大小端模式。
(3)remove_conflicting_framebuffers()函数
去掉冲突的fb。
(4)device_create()函数
在/sys/class/graphic目录下创建设备?还是说创建设备文件/dev/xxx?应该是后者。
(5)fb_init_device()函数
这是fb在sys文件系统的接口函数。涉及dev_set_drvdata和dev_get_drvdata。有待深入。
(6)fb_var_to_videomode()函数
1)什么是mode?
2)fb_var_to_videomode()函数的内容
/*** fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode* @mode: pointer to struct fb_videomode* @var: pointer to struct fb_var_screeninfo*/ void fb_var_to_videomode(struct fb_videomode *mode,const struct fb_var_screeninfo *var) {u32 pixclock, hfreq, htotal, vtotal;mode->name = NULL;mode->xres = var->xres;mode->yres = var->yres;mode->pixclock = var->pixclock;mode->hsync_len = var->hsync_len;mode->vsync_len = var->vsync_len;mode->left_margin = var->left_margin;mode->right_margin = var->right_margin;mode->upper_margin = var->upper_margin;mode->lower_margin = var->lower_margin;mode->sync = var->sync;mode->vmode = var->vmode & FB_VMODE_MASK;mode->flag = FB_MODE_IS_FROM_VAR;mode->refresh = 0;if (!var->pixclock)return;pixclock = PICOS2KHZ(var->pixclock) * 1000;htotal = var->xres + var->right_margin + var->hsync_len +var->left_margin;vtotal = var->yres + var->lower_margin + var->vsync_len +var->upper_margin;if (var->vmode & FB_VMODE_INTERLACED)vtotal /= 2;if (var->vmode & FB_VMODE_DOUBLE)vtotal *= 2;hfreq = pixclock/htotal;mode->refresh = hfreq/vtotal; }
(7)fb_add_videomode()函数
(8)registered_fb[i] = fb_info
注册与登记该fb设备。结合fb_read等函数中对fb_info的使用。
关键点:数据如何封装、数据由谁准备由谁消费、数据如何传递。
(9)fb_notifier_call_chain()函数
待写。