(转)Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解
2013-07-11 15:01
387 查看
原文:http://www.arm9home.net/read.php?tid-25938.html
管理提醒: 本帖被 xoom 执行加亮操作(2012-12-13)
如之前所说,一直想知道显示数据都在哪个地方,通常的数据,比如 framebuffer 中的显示数据,和OpenGL 处理的数据有啥关系。
目前为止我还没有弄明白 OpenGL 这块,但是 framebuffer 这部分差不多了。这篇文章记录了 framebuffer 的显示数据相关内容。
1. 关于FIMD
Tiny210v2 开发板属于 s5pv210 的一种,在这块开发板上,显示部分又被叫做 FIMD,我不知道FIMD是什么的缩写,但D应该和Display Controller有关系吧。
FIMD 的主要功能就是获取显示数据,并将数据输出到显示屏。当然期间会对显示数据进行处理:
FIMD一共支持5个layer,在SoC用户手册中,将layer成为window,源代码中也叫做window。
FIMD可以通过AXI总线从内存或者Camera哪里获取到显示数据,并进行合成。
2. 内核配置 framebuffer
通过 make menuconfig 可以配置 framebuffer 相关的内容。
保存以后,在 .config 文件中可以找到相关配置内容。
.config
--------------------------------------------------
复制代码 CONFIG_FB_S3C_DEFAULT_WINDOW=2 CONFIG_FB_S3C_NR_BUFFERS=3 CONFIG_FB_S3C_NUM_OVLY_WIN=1 CONFIG_FB_S3C_NUM_BUF_OVLY_WIN=3 |
include/generated/autoconf.h
--------------------------------------------------
复制代码 #define CONFIG_FB_S3C_DEFAULT_WINDOW 2 #define CONFIG_FB_S3C_NR_BUFFERS 3 #define CONFIG_FB_S3C_NUM_OVLY_WIN 1 #define CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 3 |
CONFIG_FB_S3C_NR_BUFFERS 是指 window 的buffer数,3个就是 trebble-buffer,2个就是double-buffer。
其中第一个是正在显示的数据,又叫onscreen,其他几个是后台描画的数据,又叫offscreen,通过 flip 操作可以将 onscreen 数据和offscreen 数据交换。
CONFIG_FB_S3C_NUM_OVLY_WIN 是 OVERLAY window, 0-4。
CONFIG_FB_S3C_NUM_BUF_OVLY_WIN 是指 OVERLAY window 的buffer数,和 CONFIG_FB_S3C_NR_BUFFERS 一个意思。
3. 显示数据buffer
内核初始话过程中,为这些window 的 buffer 预留了一部分内存。
具体看下面的代码:
初始化函数会首先映射内存空间:
复制代码 MACHINE_START(MINI210, "MINI210") /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ .boot_params = S5P_PA_SDRAM + 0x100, .fixup = mini210_fixup, .init_irq = s5pv210_init_irq, .map_io = mini210_map_io, .init_machine = mini210_machine_init, #ifdef CONFIG_S5P_HIGH_RES_TIMERS .timer = &s5p_systimer, #else .timer = &s5p_timer, #endif MACHINE_END |
大小是 800 x 480 x 2个window x 3个buffer x RGBA的4字节,这是给通常显示数据的,
除此之外,还预留了 YUV 的数据区域,1280 x 720 x 3个buffer x Y的一个字节数据 + 1280 x 720 x 3个buffer x UV的一个字节数据。
另外还有一个 4096 字节大小的 数据。
这些数据我只理解了 RGBA 数据, YUV 的数据不知道是干啥的? 难道是给 HDMI 输出用的?
arch/arm/mach-sp5v210/Mach-mini210.c
--------------------------------------------------
复制代码 /* Multimedia support */ #define LCD_WIDTH 800 #define LCD_HEIGHT 480 #define BYTES_PER_PIXEL 4 #define NUM_BUFFER_OVLY (CONFIG_FB_S3C_NUM_OVLY_WIN * CONFIG_FB_S3C_NUM_BUF_OVLY_WIN) #define NUM_BUFFER (CONFIG_FB_S3C_NR_BUFFERS + NUM_BUFFER_OVLY) #define PXL2FIMD(pixels) ((pixels) * BYTES_PER_PIXEL * NUM_BUFFER) #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD PXL2FIMD(LCD_WIDTH * LCD_HEIGHT) static struct s5p_media_device mini210_media_devs[] = { ......, { .id = S5P_MDEV_FIMD, .name = "fimd", .bank = 1, .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD, .paddr = 0, }, ......, } static void __init mini210_map_io(void) { ...... frame_size = lcd->width * lcd->height * BYTES_PER_PIXEL; fimd_size = ALIGN(frame_size, PAGE_SIZE) * NUM_BUFFER; if (frame_size > 0x200000) { fimd_size += ALIGN(frame_size, PAGE_SIZE) * 2; // Not used } /* Reserve 0x003f6000 bytes for PVR YUV video, and 1 page */ fimd_size += ALIGN(1280*720, PAGE_SIZE) * 3; fimd_size += ALIGN(1280*360, PAGE_SIZE) * 3 + PAGE_SIZE; if (fimd_size != S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD) { mini210_fixup_bootmem(S5P_MDEV_FIMD, fimd_size); } ...... s5p_reserve_bootmem(mini210_media_devs, ARRAY_SIZE(mini210_media_devs), S5P_RANGE_MFC); ...... } |
PAGE_SIZE 大小是 4096。
include/linux/Const.h
--------------------------------------------------
复制代码 #ifdef __ASSEMBLY__ #define _AC(X,Y) X #define _AT(T,X) X #else #define __AC(X,Y) (X##Y) #define _AC(X,Y) __AC(X,Y) #define _AT(T,X) ((T)(X)) #endif |
--------------------------------------------------
复制代码 #define PAGE_SHIFT 12 #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) |
--------------------------------------------------
复制代码 #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) |
在内核的 boot log 中,我们可以找到关于内存预留的log:
dmesg log :
--------------------------------------------------
[ 0.000000] s5p: 13060 kbytes system memory reserved for fimd at 0x3c330000, 1-bank base(0x3c330000)
[ 0.648804] fimd at 0x3c330000
5. 物理内存视图
画了一个简单的物理内存布局图,可以看到 RGBA 部分的数据,其实一共给 2 个 window 预留了。
| |
|--------------|
| |0x3CFF0000 -- 0x3CFF0FFF || ????
|--------------|
| |0x3CF7F000 -- 0x3CFEFFFF ||
|--------------| ||
| |0x3CF0E000 -- 0x3CF7EFFF || treble-buffer YUV( UV ) framebuffer : 1280 x 360 x 1 byte
|--------------| ||
| |0x3CE9D000 -- 0x3CF0DFFF ||
|--------------|
| |0x3CDBC000 -- 0x3CE9EFFF ||
|--------------| ||
| |0x3CCDB000 -- 0x3CDBBFFF || treble-buffer YUV( Y ) framebuffer : 1280 x 720 x 1 byte
|--------------| ||
| |0x3CBFA000 -- 0x3CCDAFFF ||
|--------------|
| |0x3CA83000 -- 0x3CBF9FFF ||
|--------------| ||
| |0x3C90C000 -- 0x3CA82FFF || treble-buffer RGBA framebuffer : 800 x 480 x 4 bytes
|--------------| ||
| |0x3C795000 -- 0x3C90BFFF ||
|--------------|
| |0x3C61E000 -- 0x3C794FFF ||
|--------------| ||
| |0x3C4A7000 -- 0x3C61DFFF || treble-buffer RGBA framebuffer : 800 x 480 x 4 byte
|--------------| ||
| |0x3C330000 -- 0x3C4A6FFF ||
|--------------|
| |
6. 将预留的物理内存记录到platform信息中
这些预留的物理内存,在 platform 初始化过程中,会映射到内存空间。
在开发板初始化过程中,会进行 machine init, 而 machine init 过程中会调用 s3c_fb_set_platdata 初始化 platform 信息。
arch/arm/mach-sp5v210/Mach-mini210.c
--------------------------------------------------
复制代码 static struct s3c_platform_fb mini210_fb_data __initdata = { .hw_ver = 0x62, .clk_name = "sclk_fimd", .nr_wins = 5, .default_win = CONFIG_FB_S3C_DEFAULT_WINDOW, .swap = FB_SWAP_WORD | FB_SWAP_HWORD, .cfg_gpio = lcd_cfg_gpio, .backlight_on = lcd_backlight_on, .backlight_onoff= lcd_backlight_off, .reset_lcd = lcd_reset_lcd, }; static void __init mini210_machine_init(void) { ...... #ifdef CONFIG_FB_S3C_MINI210 { struct s3cfb_lcd *mlcd = mini210_get_lcd(); if (!(mlcd->args & 0x0f)) { if (readl(S5PV210_GPF0_BASE + 0x184) & 0x10) mlcd->args |= (1 << 7); } mini210_fb_data.lcd = mlcd; s3c_fb_set_platdata(&mini210_fb_data); } #endif ...... } MACHINE_START(MINI210, "MINI210") /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ .boot_params = S5P_PA_SDRAM + 0x100, .fixup = mini210_fixup, .init_irq = s5pv210_init_irq, .map_io = mini210_map_io, .init_machine = mini210_machine_init, #ifdef CONFIG_S5P_HIGH_RES_TIMERS .timer = &s5p_systimer, #else .timer = &s5p_timer, #endif MACHINE_END |
注意的是 platform 初始化,相当于是记录系统都有哪些资源。而设备驱动初始化过程中,比如s3cfb这个fb驱动,则会来使用这些资源。
arch/arm/plat-s5p/include/plat/Fb.h
--------------------------------------------------
复制代码 struct s3c_platform_fb { int hw_ver; char clk_name[16]; int nr_wins; int nr_buffers[5]; int default_win; int swap; phys_addr_t pmem_start[5]; /* starting physical address of memory region */ size_t pmem_size[5]; /* size of memory region */ void *lcd; void (*cfg_gpio)(struct platform_device *dev); int (*backlight_on)(struct platform_device *dev); int (*backlight_onoff)(struct platform_device *dev, int onoff); int (*reset_lcd)(struct platform_device *dev); int (*clk_on)(struct platform_device *pdev, struct clk **s3cfb_clk); int (*clk_off)(struct platform_device *pdev, struct clk **clk); }; |
--------------------------------------------------
复制代码 void __init s3c_fb_set_platdata(struct s3c_platform_fb *pd) { struct s3c_platform_fb *npd; struct s3cfb_lcd *lcd; phys_addr_t pmem_start; int i, default_win, num_overlay_win; int frame_size; if (!pd) pd = &default_fb_data; npd = kmemdup(pd, sizeof(struct s3c_platform_fb), GFP_KERNEL); if (!npd) { printk(KERN_ERR "%s: no memory for platform data\n", __func__); } else { for (i = 0; i < npd->nr_wins && i < NR_BUFFERS; i++) { npd->nr_buffers?? = 1; } default_win = npd->default_win; num_overlay_win = CONFIG_FB_S3C_NUM_OVLY_WIN; if (num_overlay_win >= default_win) { printk(KERN_WARNING "%s: NUM_OVLY_WIN should be less than default \ window number. set to 0.\n", __func__); num_overlay_win = 0; } ...... /* set starting physical address & size of memory region for * overlay window and default window */ pmem_start = s5p_get_media_memory_bank(S5P_MDEV_FIMD, 1); printk("fimd at 0x%08x\n", pmem_start); for (i = 0; i < num_overlay_win; i++) { *(npd->nr_buffers+i) = CONFIG_FB_S3C_NUM_BUF_OVLY_WIN; *(npd->pmem_start+i) = pmem_start; *(npd->pmem_size+i) = frame_size * *(npd->nr_buffers+i); pmem_start += *(npd->pmem_size+i); } npd->nr_buffers[default_win] = CONFIG_FB_S3C_NR_BUFFERS; npd->pmem_start[default_win] = pmem_start; npd->pmem_size[default_win] = frame_size * npd->nr_buffers[default_win]; #if defined(CONFIG_MACH_MINI210) npd->pmem_size[default_win] += ALIGN(1280*720, PAGE_SIZE) * 3; npd->pmem_size[default_win] += ALIGN(1280*360, PAGE_SIZE) * 3 + PAGE_SIZE; if (frame_size > 0x200000) { // Not Used : frame_size < 0x200000 pmem_start += npd->pmem_size[default_win]; for (; i < npd->nr_wins; i++) { if (i != default_win) { npd->nr_buffers[i] = 2; npd->pmem_start[i] = pmem_start; npd->pmem_size[i] = frame_size * npd->nr_buffers[i]; break; } } } #endif s3c_device_fb.dev.platform_data = npd; } } |
因为 num_overlay_win 是 CONFIG_FB_S3C_NUM_OVLY_WIN=1,所以 for 循环只执行了一次,那么 window 0 的物理内存地址初始化了。
然后又手工为 default_win 也就是 CONFIG_FB_S3C_DEFAULT_WINDOW=2 进行了初始化。
也就是说: window 0 和 window 2 在platform初始化中记录了数据buffer的物理内存地址。
虽然是 for 循环做的,我认为这个for循环写得不好。
7. 在s3cfb初始化过程中,为window 关联这些内存
在初始化过程中,会分配fb设备相关数据结构,并注册fb设备。
drivers/video/samsung/s3cfb.c
--------------------------------------------------
复制代码 static int __devinit s3cfb_probe(struct platform_device *pdev) { ...... if (s3cfb_alloc_framebuffer(fbdev)) { ret = -ENOMEM; goto err_alloc; } if (s3cfb_register_framebuffer(fbdev)) { ret = -EINVAL; goto err_register; } ...... } |
才会将 window 2 对应的内存映射到内存空间。
虽然预留的物理内存是 window 0 和 window 2 的,但这个时候 window 0 的物理内存是没有被映射的。
drivers/video/samsung/s3cfb.c
--------------------------------------------------
复制代码 static int s3cfb_alloc_framebuffer(struct s3cfb_global *ctrl) { ...... for (i = 0; i < pdata->nr_wins; i++) { ctrl->fb[i] = framebuffer_alloc(sizeof(*ctrl->fb), ctrl->dev); if (!ctrl->fb[i]) { dev_err(ctrl->dev, "not enough memory\n"); ret = -ENOMEM; goto err_alloc_fb; } ...... if (i == pdata->default_win) { if (s3cfb_map_video_memory(ctrl->fb[i])) { dev_err(ctrl->dev, "failed to map video memory " "for default window (%d)\n", i); ret = -ENOMEM; goto err_map_video_mem; } } } ...... } |
虽然只给 window 2 映射了显示数据的内存,但是 for 循环还是将所有的 window 都注册设备文件了。
这就是为什么 /dev 目录下有 fb0 - fb4 5个fb设备。其实每一个 fb 设备对应一个 window。
另外需要注意的是,第一个注册的 fb 是 fb0,然后依次 ++。
下面的代码在注册的时候, 首先注册的是 default window 2,然后是 3, 4, 0, 1。
也就是说 :
fb0 -> window 2
fb1 -> window 3
fb2 -> window 4
fb3 -> window 0
fb4 -> window 1
另外还需要注意的是,如果你直接去 cat /dev/fbX ,只有 fb0 是成功的,其他全部失败,
因为到目前位置,只有 fb0 也就是 default window 2,映射了显示数据的内存。
drivers/video/samsung/s3cfb.c
--------------------------------------------------
复制代码 static int s3cfb_register_framebuffer(struct s3cfb_global *ctrl) { ...... k = 0; for (i = pdata->default_win; i < pdata->nr_wins + pdata->default_win; i++) { j = i % pdata->nr_wins; ret = register_framebuffer(ctrl->fb[j]); if (ret) { dev_err(ctrl->dev, "failed to register " "framebuffer device\n"); ret = -EINVAL; goto err_register_fb; } pdata->fb_file_minor[ j ] = k; k++; #ifndef CONFIG_FRAMEBUFFER_CONSOLE if (j == pdata->default_win) { s3cfb_check_var(&ctrl->fb[j]->var, ctrl->fb[j]); s3cfb_set_par(ctrl->fb[j]); s3cfb_draw_logo(ctrl->fb[j]); } #endif } ...... } |
需要注意一下,部分log中写的是fb2,但这个log是boot阶段的,真正有效的是fb0,
代码中log写错了,fb 很多应该是 window。fb0 -> window 2
dmesg log :
--------------------------------------------------
[ 507.316250] [s3cfb]win 2: pmem_start=0x3c795000
[ 507.316292] [s3cfb][fb2] dma: 0x3c795000, cpu: 0xe1000000, size: 0x0085c000
[ 507.333888] PA FB = 0x3C795000, bits per pixel = 32
[ 507.333933] screen width=800 height=480 va=0xdc795000 pa=0x3c795000
[ 507.333987] xres_virtual = 800, yres_virtual = 1440, xoffset = 0, yoffset = 0
[ 507.336543] fb_size=8765440
[ 507.339351] Back frameBuffer[0].VAddr=dc90c000 PAddr=3c90c000 size=1536000
[ 507.346146] Back frameBuffer[1].VAddr=dca83000 PAddr=3ca83000 size=1536000
[ 507.353014] Video Y Buffer[0].VAddr=dcbfa000 PAddr=3cbfa000 size=921600
[ 507.359576] Video Y Buffer[1].VAddr=dccdb000 PAddr=3ccdb000 size=921600
[ 507.366161] Video Y Buffer[2].VAddr=dcdbc000 PAddr=3cdbc000 size=921600
[ 507.372750] Video UV Buffer[0].VAddr=dce9d000 PAddr=3ce9d000 size=462848
[ 507.379418] Video UV Buffer[1].VAddr=dcf0e000 PAddr=3cf0e000 size=462848
[ 507.386093] Video UV Buffer[2].VAddr=dcf7f000 PAddr=3cf7f000 size=462848
9. 显示数据使用内存映射的一些细节
s3cfb_map_video_memory 这个函数用于映射显示数据的内存地址,
如果是 platform 初始化过程中预留过物理内存,则会使用这个物理内存。
否则就会临时申请一块内存。
也就是说 window 0 和 window 2 会使用预留的物理内存。
window 1 / window 3 / window 4 会使用新申请的内存。
drivers/video/samsung/s3cfb.c
--------------------------------------------------
复制代码 static int s3cfb_map_video_memory(struct fb_info *fb) { ...... if (win->owner == DMA_MEM_OTHER) { fix->smem_start = win->other_mem_addr; fix->smem_len = win->other_mem_size; return 0; } if (fb->screen_base) return 0; if (pdata && pdata->pmem_start[win->id] && (pdata->pmem_size[win->id] >= fix->smem_len)) { fix->smem_start = pdata->pmem_start[win->id]; fix->smem_len = pdata->pmem_size[win->id]; fb->screen_base = ioremap_wc(fix->smem_start, pdata->pmem_size[win->id]); dev_err(fbdev->dev, "[fb%d][win%d]: pmem_start=0x%x\n", pdata->fb_file_minor[win->id],win->id, pdata->pmem_start[win->id]); } else { fb->screen_base = dma_alloc_writecombine(fbdev->dev, PAGE_ALIGN(fix->smem_len), (unsigned int *)&fix->smem_start, GFP_KERNEL); } ...... } |
还可一通过 ioctl 来调用 s3cfb_map_video_memory。
传递的参数是 FBIOPUT_VSCREENINFO。
drivers/video/samsung/s3cfb.c
--------------------------------------------------
复制代码 static int s3cfb_set_par(struct fb_info *fb) { ...... if (win->id != pdata->default_win) { fb->fix.line_length = fb->var.xres_virtual * fb->var.bits_per_pixel / 8; fb->fix.smem_len = fb->fix.line_length * fb->var.yres_virtual; s3cfb_map_video_memory(fb); } ...... } struct fb_ops s3cfb_ops = { .fb_set_par = s3cfb_set_par, }; drivers/video/fbmem.c -------------------------------------------------- int fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) { ...... if (info->fbops->fb_set_par) { ret = info->fbops->fb_set_par(info); ...... } ...... } static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg) { case FBIOPUT_VSCREENINFO: ...... ret = fb_set_var(info, &var); ..... break; } static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { ...... return do_fb_ioctl(info, cmd, arg); ...... } static const struct file_operations fb_fops = { ...... .unlocked_ioctl = fb_ioctl, ...... }; |
FIMD的控制寄存器和内存是统一编址的,因此可以像使用内存一样访问他们,但前提是需要将他们映射到内存空间。
内核代码中的寄存器地址定义都能和 SoC 用户手册对应上,我们看看下面的截图,很一致吧。
但是在看代码的过程中,我发现代码使用的寄存器的一些信息,Soc 用户手册没有,是不是用户手册比较老了?
在 s3cfb 模块初始化的过程中,就会将控制寄存器映射到内存中。
arch/arm/mach-sp5v210/include/mach/map.h
--------------------------------------------------
复制代码 #define S5PV210_PA_LCD (0xF8000000) #define S5P_PA_LCD S5PV210_PA_LCD #define S5PV210_SZ_LCD SZ_1M #define S5P_SZ_LCD S5PV210_SZ_LCD |
--------------------------------------------------
复制代码 static struct resource s3cfb_resource[] = { [0] = { .start = S5P_PA_LCD, .end = S5P_PA_LCD + S5P_SZ_LCD - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_LCD1, .end = IRQ_LCD1, .flags = IORESOURCE_IRQ, }, [2] = { .start = IRQ_LCD0, .end = IRQ_LCD0, .flags = IORESOURCE_IRQ, }, }; static u64 fb_dma_mask = 0xffffffffUL; struct platform_device s3c_device_fb = { .name = "s3cfb", .id = -1, .num_resources = ARRAY_SIZE(s3cfb_resource), .resource = s3cfb_resource, .dev = { .dma_mask = &fb_dma_mask, .coherent_dma_mask = 0xffffffffUL } }; drivers/video/samsung/s3cfb.c -------------------------------------------------- static int __devinit s3cfb_probe(struct platform_device *pdev) { ...... 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; } ...... } |
我理解 6x 可能是对应硬件版本号,因为印象中看到硬件版本号好象是 0x62。
通过设定这些控制寄存器,就能控制比如 window 是否显示啊,显示数据格式是啥啊,显示数据地址在哪里啊,等等。
drivers/video/samsung/s3cfb_fimd6x.c
--------------------------------------------------
复制代码 int s3cfb_display_on(struct s3cfb_global *ctrl) { u32 cfg; cfg = readl(ctrl->regs + S3C_VIDCON0); cfg |= (S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE); writel(cfg, ctrl->regs + S3C_VIDCON0); dev_dbg(ctrl->dev, "global display is on\n"); return 0; } |
这个用例其实是用来确认 /dev 目录下的 fb0 - fb4 是否好用的,以及 window 之间的alpha透过是否正确。
关于 window 之间的层次关系可以参考:
下面的代码,大概意思是:
* 打开 window 0 - window 4 对应的 fb 设备文件。
* 设置这些 window 都是 800 x 480 x RGBA
* 设置这些 window 内部的显示数据,是从 window 0 - window 4 开始的,分别画 500x480, 400x480, 300x480, 200x480, 100x480 这么大块数据。
* 让window 的显示数据显示出来。
s3cfb_test.c
--------------------------------------------------
复制代码 #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <linux/fb.h> #define WIN0 0 #define WIN1 1 #define WIN2 2 #define WIN3 3 #define WIN4 4 #define WIN_MAX 5 const char * fb_file_path[ WIN_MAX ] = { /* WIN0 */"/dev/fb3", /* WIN1 */"/dev/fb4", /* WIN2 */"/dev/fb0", /* WIN3 */"/dev/fb1", /* WIN4 */"/dev/fb2" }; const int fb_x[ WIN_MAX ] = { /* WIN0 */500, /* WIN1 */400, /* WIN2 */300, /* WIN3 */200, /* WIN4 */100 }; const int fb_color[ WIN_MAX ] = { /* WIN0 */0x10FFFFFF, /* WIN1 */0x10FF0000, /* WIN2 */0x1000FF00, /* WIN3 */0x100000FF, /* WIN4 */0x10000000, }; void draw_framebuffer( int win, int fd, int xres, int yres ) { int i, j; int *p; int color; p = mmap( NULL, xres*yres*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 ); if( !p ){ printf( "mmap failed\n" ); return; } /* draw default color with alpha : all pass through*/ for( j = 0; j < yres; j++ ){ for( i = 0; i < xres ; i++ ){ *( p + j * xres + i ) = 0x00FFFFFF; } } /* draw color */ for( j = 0; j < yres; j++ ){ for( i = 0; i < fb_x[win] ; i++ ){ *( p + j * xres + i ) = fb_color[win]; } } munmap( p, xres*yres*4 ); } int main( int argc, char *argv[] ) { int i; int ret; struct fb_var_screeninfo var; int blank; int fd[ WIN_MAX ]; /* initial */ memset( fd, -1, sizeof( fd ) ); /* open framebuffer */ for( i=0; i<WIN_MAX; i++ ){ fd[i] = open( fb_file_path[i], O_RDWR ); if( fd[i] < 0 ){ printf( "open %s failed\n", fb_file_path[i] ); goto end; } } printf( "open framebuffer ok\n" ); /* set screen info */ ret = ioctl( fd[WIN2], FBIOGET_VSCREENINFO, &var ); if( ret < 0 ){ printf( "ioctl %s FBIOGET_VSCREENINFO failed\n", fb_file_path[WIN2] ); goto end; } var.activate = FB_ACTIVATE_FORCE; var.yres_virtual = var.yres; for( i=0; i<WIN_MAX; i++ ){ ret = ioctl( fd[i], FBIOPUT_VSCREENINFO, &var ); if( ret < 0 ){ printf( "ioctl %s FBIOPUT_VSCREENINFO failed\n", fb_file_path[i] ); goto end; } } printf( "set screeninfo ok\n" ); /* draw some color */ for( i=0; i<WIN_MAX; i++ ){ draw_framebuffer( i, fd[i], var.xres, var.yres ); } printf( "draw color ok\n" ); /* show window */ blank = FB_BLANK_UNBLANK; for( i=0; i<WIN_MAX; i++ ){ ret = ioctl( fd[i], FBIOBLANK, blank ); if( ret < 0 ){ printf( "ioctl %s FBIOBLANK failed\n", fb_file_path[i] ); goto end; } } printf( "show window ok\n" ); /* wait input */ getchar(); end: return 0; } |
说明 alpha blending 应该是正常工作了的。
END
相关文章推荐
- Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解
- Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解
- (转)Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解
- 关于S5PV210的 FIMD 对应 的 framebuffer 驱动,fb0,fbx的一篇很好的文章收藏
- Tiny210v2( S5PV210 )平台下创建基本根文件系统
- Tiny210v2( S5PV210 )平台下创建基本根文件系统
- Tiny210v2( S5PV210 )平台下创建基本根文件系统
- 基于tiny210v2的linux-3.9.6内核驱动移植1:led驱动
- 理解io端口和io内存--关于驱动开发的问题
- 关于FBO(FrameBuffer Object)的一些理解
- 基于tiny210v2的linux-3.9.6内核驱动移植2:按键驱动
- 关于新品开发过程对应的工作流类型的进一步理解
- 理解io端口和io内存--关于驱动开发的问题
- 关于用 framebuffer 驱动,在console 模式下的分辨率的参数及配置
- tiny6410按键platform(平台)驱动的实现
- 基于tiny210v2的linux-3.9.6内核驱动移植3:LCD移植
- 关于公司在研发项目中理解平台和产品的区分看法
- tiny210(S5PV210)uboot的顶层Makefile的连接命令理解——记tiny210之uboot移植
- 关于数据驱动和关键字驱动的理解整理
- 基于tiny210v2的linux-3.9.6内核驱动移植4:PWM移植