5.6 framebuffer驱动
1. framebuffer介绍
linux系统中把LCD这类设备称为帧缓冲(framebuffer)设备,是linux内核虚拟的一个设备。framebuffer是Linux系统为显示设备提供的一个接口,可以将framebuffer看成LCD设备内存的映射,应用程序通过对framebuffer读写,来简介操作LCD,从而实现LCD的显示功能。
2. 应用程序如何操作framebuffer设备
(1)通过open()函数打开设备文件(dev/fb0、dev/fb1、...)。
(2)通过mmap()函数将内存中的数据映射到framebuffer的显存上。
/*****************************************************************
* @parm:
* @addr:映射的内存基地址
* @length:映射内存的大小(byte)
* @prot:属性:
* ①:PROT_EXEC 映射区可被执行
* ②:PROT_READ 映射区可被读
* ③:PROT_WRITE 映射区可被写
* ④:PROT_NONE 映射区不可读写
* @flags:保护标志。常用的是共享方式 MAP_SHARED
* @fd:open返回的文件描述符
* @offset:是从文件的哪个地方开始映射
********************************************************************/
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
(3)通过ioctl()函数可以获取显示设备的信息(固定信息、可变信息)。
// framebuffer固定信息和可变信息结构体在/include/linux/fb.h文件中// 固定信息结构体
struct fb_fix_screeninfo
{char id[16]; /* identification string eg "TT Builtin" */unsigned long smem_start; /* Start of frame buffer mem *//* (physical address) */__u32 smem_len; /* Length of frame buffer mem */__u32 type; /* see FB_TYPE_* */__u32 type_aux; /* Interleave for interleaved Planes */__u32 visual; /* see 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; /* 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 reserved[3]; /* Reserved for future compatibility */
};// 固定信息读取
struct fb_fix_screeninfo fb_fix_info; //固定参数
ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix_info)//固定参数// 可变信息结构体
struct fb_var_screeninfo
{__u32 xres; /* visible resolution */__u32 yres;__u32 xres_virtual; /* virtual resolution */__u32 yres_virtual;__u32 xoffset; /* offset from virtual to visible */__u32 yoffset; /* resolution */__u32 bits_per_pixel; /* guess what */__u32 grayscale; /* != 0 Graylevels instead of colors */struct fb_bitfield red; /* bitfield in fb mem if true color, */struct fb_bitfield green; /* else only length is significant */struct fb_bitfield blue;struct fb_bitfield transp; /* transparency */ __u32 nonstd; /* != 0 Non standard pixel format */__u32 activate; /* see FB_ACTIVATE_* */__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) */__u32 pixclock; /* pixel clock in ps (pico seconds) */__u32 left_margin; /* time from sync to picture */__u32 right_margin; /* time from picture to sync */__u32 upper_margin; /* time from sync to picture */__u32 lower_margin;__u32 hsync_len; /* length of horizontal sync */__u32 vsync_len; /* length of vertical sync */__u32 sync; /* see FB_SYNC_* */__u32 vmode; /* see FB_VMODE_* */__u32 rotate; /* angle we rotate counter clockwise */__u32 reserved[5]; /* Reserved for future compatibility */
};// 可变信息读取
struct fb_var_screeninfo fb_var_info;
ioctl(fb, FBIOGET_VSCREENINFO, &fb_var_info)//可变参数
3. framebuffer设备驱动结构
4. framebuffer驱动
4.1 framebuffer驱动框架
4.1.1 framebuffer驱动框架源码路径
(1)/drivers/video/fbmem.c 用于创建graphics类,注册fb字符设备驱动,提供framebuffer驱动注册结构
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_init(fbmem_init);
static void __exit
fbmem_exit(void)
{remove_proc_entry("fb", NULL);class_destroy(fb_class);unregister_chrdev(FB_MAJOR, "fb");
}
framebuffer驱动注册接口:
/*** 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;
}/*** unregister_framebuffer - releases a frame buffer device* @fb_info: frame buffer info structure** Unregisters a frame buffer device @fb_info.** Returns negative errno on error, or zero for success.** This function will also notify the framebuffer console* to release the driver.** This is meant to be called within a driver's module_exit()* function. If this is called outside module_exit(), ensure* that the driver implements fb_open() and fb_release() to* check that no processes are using the device.*/int
unregister_framebuffer(struct fb_info *fb_info)
{struct fb_event event;int i, ret = 0;i = fb_info->node;if (!registered_fb[i]) {ret = -EINVAL;goto done;}if (!lock_fb_info(fb_info))return -ENODEV;event.info = fb_info;ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);unlock_fb_info(fb_info);if (ret) {ret = -EINVAL;goto done;}if (fb_info->pixmap.addr &&(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))kfree(fb_info->pixmap.addr);fb_destroy_modelist(&fb_info->modelist);registered_fb[i]=NULL;num_registered_fb--;fb_cleanup_device(fb_info);device_destroy(fb_class, MKDEV(FB_MAJOR, i));event.info = fb_info;fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);/* this may free fb info */if (fb_info->fbops->fb_destroy)fb_info->fbops->fb_destroy(fb_info);
done:return ret;
}
(2)drivers/video/fbsys.c 用于处理fb在/sys目录下的属性文件
(3)drivers/video/modedb.c 管理显示模式(例如:VGA、720P等)
(4)drivers/video/fb_notify.c
4.2 framebuffer驱动
4.2.1 framebuffer驱动源码路径
(1)drivers/video/samsung/s3cfb.c 驱动主体
static int __init s3cfb_register(void)
{platform_driver_register(&s3cfb_driver);return 0;
}
static void __exit s3cfb_unregister(void)
{platform_driver_unregister(&s3cfb_driver);
}module_init(s3cfb_register);
module_exit(s3cfb_unregister);
s3cfb_probe函数
static int __devinit s3cfb_probe(struct platform_device *pdev)
{struct s3c_platform_fb *pdata;struct s3cfb_global *fbdev;struct resource *res;int i, j, ret = 0;fbdev = kzalloc(sizeof(struct s3cfb_global), GFP_KERNEL);if (!fbdev) {dev_err(&pdev->dev, "failed to allocate for ""global fb structure\n");ret = -ENOMEM;goto err_global;}fbdev->dev = &pdev->dev;fbdev->regulator = regulator_get(&pdev->dev, "pd");if (!fbdev->regulator) {dev_err(fbdev->dev, "failed to get regulator\n");ret = -EINVAL;goto err_regulator;}ret = regulator_enable(fbdev->regulator);if (ret < 0) {dev_err(fbdev->dev, "failed to enable regulator\n");ret = -EINVAL;goto err_regulator;}pdata = to_fb_plat(&pdev->dev);if (!pdata) {dev_err(fbdev->dev, "failed to get platform data\n");ret = -EINVAL;goto err_pdata;}fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd;if (pdata->cfg_gpio)pdata->cfg_gpio(pdev);if (pdata->clk_on)pdata->clk_on(pdev, &fbdev->clock);res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {dev_err(fbdev->dev, "failed to get io memory region\n");ret = -EINVAL;goto err_io;}res = request_mem_region(res->start,res->end - res->start + 1, pdev->name);if (!res) {dev_err(fbdev->dev, "failed to request io memory region\n");ret = -EINVAL;goto err_io;}fbdev->regs = ioremap(res->start, res->end - res->start + 1);if (!fbdev->regs) {dev_err(fbdev->dev, "failed to remap io region\n");ret = -EINVAL;goto err_mem;}s3cfb_set_vsync_interrupt(fbdev, 1);s3cfb_set_global_interrupt(fbdev, 1);s3cfb_init_global(fbdev);if (s3cfb_alloc_framebuffer(fbdev)) {ret = -ENOMEM;goto err_alloc;}if (s3cfb_register_framebuffer(fbdev)) {ret = -EINVAL;goto err_register;}s3cfb_set_clock(fbdev);s3cfb_set_window(fbdev, pdata->default_win, 1);s3cfb_display_on(fbdev);fbdev->irq = platform_get_irq(pdev, 0);if (request_irq(fbdev->irq, s3cfb_irq_frame, IRQF_SHARED,pdev->name, fbdev)) {dev_err(fbdev->dev, "request_irq failed\n");ret = -EINVAL;goto err_irq;}#ifdef CONFIG_FB_S3C_LCD_INITif (pdata->backlight_on)pdata->backlight_on(pdev);if (!bootloaderfb && pdata->reset_lcd)pdata->reset_lcd(pdev);
#endif#ifdef CONFIG_HAS_EARLYSUSPENDfbdev->early_suspend.suspend = s3cfb_early_suspend;fbdev->early_suspend.resume = s3cfb_late_resume;fbdev->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;register_early_suspend(&fbdev->early_suspend);
#endifret = device_create_file(&(pdev->dev), &dev_attr_win_power);if (ret < 0)dev_err(fbdev->dev, "failed to add sysfs entries\n");dev_info(fbdev->dev, "registered successfully\n");#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)if (fb_prepare_logo( fbdev->fb[pdata->default_win], FB_ROTATE_UR)) {printk("Start display and show logo\n");/* Start display and show logo on boot */fb_set_cmap(&fbdev->fb[pdata->default_win]->cmap, fbdev->fb[pdata->default_win]);fb_show_logo(fbdev->fb[pdata->default_win], FB_ROTATE_UR);}
#endifmdelay(100);if (pdata->backlight_on)pdata->backlight_on(pdev);return 0;err_irq:s3cfb_display_off(fbdev);s3cfb_set_window(fbdev, pdata->default_win, 0);for (i = pdata->default_win;i < pdata->nr_wins + pdata->default_win; i++) {j = i % pdata->nr_wins;unregister_framebuffer(fbdev->fb[j]);}
err_register:for (i = 0; i < pdata->nr_wins; i++) {if (i == pdata->default_win)s3cfb_unmap_default_video_memory(fbdev->fb[i]);framebuffer_release(fbdev->fb[i]);}kfree(fbdev->fb);err_alloc:iounmap(fbdev->regs);err_mem:release_mem_region(res->start,res->end - res->start + 1);err_io:pdata->clk_off(pdev, &fbdev->clock);err_pdata:regulator_disable(fbdev->regulator);err_regulator:kfree(fbdev);err_global:return ret;
}
(2)drivers/video/samsung/s3cfb_fimd6x.c 提供LCD硬件操作函数
(3)arch/arm/mach-s5pv210/mach-x210.c 提供platfrom_device
(4)arch/arm/plat-s5p/devs.c