framebuffer之s3cfb_probe分析
来源:互联网 发布:python黑客教程 编辑:程序博客网 时间:2024/06/05 11:08
本文主要讲解lcd驱动部分的内容(关于framebuffer的驱动框架分析见 Linux Framebuffer驱动框架、接口实现和使用 ),涉及到以下文件:
(1)drivers/video/samsung/s3cfb.c,驱动主体
(2)drivers/video/samsung/s3cfb_fimd6x.c,里面有很多LCD硬件操作的函数
(2)arch/arm/mach-s5pv210/mach-x210.c,负责提供platform_device的
(3)arch/arm/plat-s5p/devs.c,为platform_device提供一些硬件描述信息的
s3cfb.c中的s3cfb_probe设备探测,是驱动注册的主要函数
/*定义一个结构体用来维护驱动程序中各函数中用到的变量 先别看结构体要定义这些成员,到各函数使用的地方就明白了*/ static int __devinit s3cfb_probe(struct platform_device *pdev) { struct s3c_platform_fb *pdata;/*LCD屏配置信息结构体*/ struct s3cfb_global *fbdev;/*驱动程序全局变量结构体*/ struct resource *res; /*用来保存从LCD平台设备中获取的LCD资源*/ int i, j, ret = 0; printk("%s\n",__func__); 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; } /*获取LCD参数信息*/ 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; /*配置GPIO端口*/ if (pdata->cfg_gpio) pdata->cfg_gpio(pdev); /*设置时钟参数*/ if (pdata->clk_on) pdata->clk_on(pdev, &fbdev->clock); /*获取LCD平台设备所使用的IO端口资源,注意这个IORESOURCE_MEM标志和LCD平台设备定义中的一致*/ 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; } /*申请LCD IO端口所占用的IO空间(注意理解IO空间和内存空间的区别),request_mem_region定义在ioport.h中*/ 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; } /*将LCD的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中 * 注意:IO空间要映射后才能使用,以后对虚拟地址的操作就是对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; } #ifdef CONFIG_FB_S3C_LTE480WV /*设置寄存器初始状态*/ s3cfb_pre_init_para(fbdev); #endif /*设置gamma 值*/ s3cfb_set_gamma(fbdev); /*设置VSYNC中断*/ s3cfb_set_vsync_interrupt(fbdev, 1); /*设置全局中断*/ s3cfb_set_global_interrupt(fbdev, 1); /*fb设备参数信息初始化*/ s3cfb_init_global(fbdev); /*为framebuffer分配空间,进行内存映射,填充fb_info*/ if (s3cfb_alloc_framebuffer(fbdev)) { ret = -ENOMEM; goto err_alloc; } /*注册fb设备到系统中*/ 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_INIT if (pdata->backlight_on) pdata->backlight_on(pdev); if (!bootloaderfb && pdata->reset_lcd) pdata->reset_lcd(pdev); if (pdata->lcd_on) pdata->lcd_on(pdev); #endif #ifdef CONFIG_HAS_EARLYSUSPEND fbdev->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); #endif /*对设备文件系统的支持,创建fb设备文件*/ ret = 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"); /*显示开机logo*/ #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); } #endif return 0; }
1、struct s3c_platform_fb
这个结构体是fb的platform_data结构体,这个结构体变量就是platform设备的私有数据,这个数据在platform_device.device.platform_data中存储。
在mach-x210.c文件中:
static struct s3c_platform_fb ek070tn93_fb_data __initdata = { .hw_ver = 0x62, .nr_wins = 5, .default_win = CONFIG_FB_S3C_DEFAULT_WINDOW, .swap = FB_SWAP_WORD | FB_SWAP_HWORD, .lcd = &ek070tn93, .cfg_gpio = ek070tn93_cfg_gpio, .backlight_on = ek070tn93_backlight_on, .backlight_onoff = ek070tn93_backlight_off, .reset_lcd = ek070tn93_reset_lcd,};
通过这个结构体去填充这些数据,在probe函数中通过传参的platform_device指针取出来。
2、struct s3cfb_global
这个结构体主要作用是在驱动部分的2个文件(s3cfb.c和s3cfb_fimd6x.c)的函数中做数据传递用的。
3、struct resource
/* LCD Controller *///LCD控制器的资源信息static struct resource s3cfb_resource [] = { [0] = { .start = S5P_PA_LCD, //控制器IO端口开始地址(0xf8000000) .end = S5P_PA_LCD + S5P_SZ_LCD - 1,//控制器IO端口结束地址(1M) .flags = IORESOURCE_MEM,//标识为LCD控制器IO端口,在驱动中引用这个就表示引用IO端口 }, [1] = { .start = IRQ_LCD1,//LCD中断 .end = IRQ_LCD1, .flags = IORESOURCE_IRQ,//标识为LCD中断 }};
4、regulator:主要是lcd电源功耗管理的
5、to_fb_plat:取出platform_device中放进去的platform_data数据
6、s3cfb_set_platdata
在struct platform_device s3c_device_fb里并没有设置platdata的内容,其实他并不是没有设置platdata,只是通过s3cfb_set_platdata这个函数来单独设置了。为什么要通过这种方式呢?主要是因为这里的platdata比较复杂,所以被拿出来单独去设置。它在启动时通过smdkc110_machine_init函数加载,保证platdata在内核启动时就已经设置好。
7、s3cfb_lcd
struct s3cfb_lcd { int width; // horizontal resolution int height; // vertical resolution int p_width; // width of lcd in mm int p_height; // height of lcd in mm int bpp; // bits per pixel int freq; // vframe frequency struct s3cfb_lcd_timing timing; // timing values struct s3cfb_lcd_polarity polarity;// polarity settings void (*init_ldi)(void); // pointer to LDI init function void (*deinit_ldi)(void);};
s3cfb_lcd:主要是lcd硬件相关的属性(分辨率、位深度、时序等).
fbdev->lcd = (struct s3cfb_lcd *)pdata->lcd 就是通过函数指针,指向mach-x210.c文件中的platdata数据中的lcd部分(.lcd = &ek070tn93)。
8、pdata->cfg_gpio
static void ek070tn93_cfg_gpio(struct platform_device *pdev){ int i; for (i = 0; i < 8; i++) { s3c_gpio_cfgpin(S5PV210_GPF0(i), S3C_GPIO_SFN(2)); s3c_gpio_setpull(S5PV210_GPF0(i), S3C_GPIO_PULL_NONE); } for (i = 0; i < 8; i++) { s3c_gpio_cfgpin(S5PV210_GPF1(i), S3C_GPIO_SFN(2)); s3c_gpio_setpull(S5PV210_GPF1(i), S3C_GPIO_PULL_NONE); ……}
主要是设置lcd相关的gpio,通过函数指针pdata->cfg_gpio,指向mach-x210.c文件中platdata数据中的gpio相关数据(.cfg_gpio = ek070tn93_cfg_gpio)
9、
platform_get_resource:取出resource
request_mem_region:申请内存
ioremap:动态映射
10、s3cfb_register_framebuffer
在函数里register_framebuffer(ctrl->fb[j])可以注册多个framebuffer,对应/dev/fb0,/dev/fb1等等。主要是设置多个虚拟屏幕。就像电视台的屏幕的左上角是台标,最下面一行可以显示滚动的广告,主画面是人物,他们其实就是对应不同的framebuffer,当他们其中的某一个发生变化时就刷新对应的framebuffer,这样刷新的效率就大大提高了。
11、fb_prepare_logo
linux内核启动时会在lcd左上角显示企鹅。fb_prepare_logo调用fb_find_logo,在fb_find_logo函数中:
#ifdef CONFIG_LOGO_X210_CLUT224logo = &logo_x210_clut224;#endif
logo_x210_clut224就是logo显示数据,它不在源码中,而是在kernel/kernel/drivers/video/logo目录中,里面有很多ppm格式的logo文件,其中就有我们需要的logo_x210_clut224.ppm的文件。
12、fb_show_logo
–>fb_show_logo_line //真正显示logo
–>fb_do_show_logo
–>info->fbops->fb_imageblit //实际操作硬件fb进行显示工作的函数
- framebuffer之s3cfb_probe分析
- Linux FrameBuffer分析之编写基于FrameBuffer接口的应用程序
- framebuffer驱动学习之代码分析
- Linux设备驱动之Framebuffer分析
- Linux内核修炼之framebuffer分析
- Linux设备驱动之Framebuffer分析
- Linux设备驱动之Framebuffer分析
- Linux内核修炼之framebuffer分析
- Android N Graphics之FrameBuffer驱动分析
- android emulator虚拟设备分析第四篇之framebuffer
- framebuffer驱动分析
- s3c6410 framebuffer分析
- 【转】s3c6410 framebuffer分析
- s3c6410 framebuffer分析
- s3c6410 framebuffer分析
- s3c6410 framebuffer分析
- framebuffer驱动分析
- framebuffer 子系统分析
- AtCoder Grand Contest 010 B - Boxes 验证解的存在性 2017/2/6
- 什么是双绞线
- 51NOD 1682 中位数计数
- 理解 Java 的 GC 与 幽灵引用
- HTML5 & CSS3初学者指南(4) – Canvas使用
- framebuffer之s3cfb_probe分析
- Total Order Partitioner
- rsync 命令详解
- 往返狗遇人次数问题
- C语言的 函数
- 画家问题
- T-SQL 语句(四)—— 视图操作
- Javascript创建文件下载
- jdk8带来了哪些新特性