微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > S3C2440上LCD驱动(FrameBuffer)实例开发讲解(二)

S3C2440上LCD驱动(FrameBuffer)实例开发讲解(二)

时间:08-15 来源:互联网 点击:

/*设置透明度*/

var->transp.offset = 0;

var->transp.length = 0;

/*根据色位模式(BPP)来设置可变参数中R、G、B的颜色位域。对于这些参数值的设置请参考CPU数据

手册中"显示缓冲区与显示点对应关系图",例如在上一篇章中我就画出了8BPP和16BPP时的对应关系图*/

switch (var->bits_per_pixel)

{

case 1:

case 2:

case 4:

var->red.offset = 0;

var->red.length = var->bits_per_pixel;

var->green = var->red;

var->blue = var->red;

break;

case 8:/* 8 bpp 332 */

if (display->type != S3C2410_LCDCON1_TFT)

{

var->red.length = 3;

var->red.offset = 5;

var->green.length = 3;

var->green.offset = 2;

var->blue.length = 2;

var->blue.offset = 0;

}else{

var->red.offset = 0;

var->red.length = 8;

var->green = var->red;

var->blue = var->red;

}

break;

case 12:/* 12 bpp 444 */

var->red.length = 4;

var->red.offset = 8;

var->green.length = 4;

var->green.offset = 4;

var->blue.length = 4;

var->blue.offset = 0;

break;

case 16:/* 16 bpp */

if (display->lcdcon5 & S3C2410_LCDCON5_FRM565)

{

/* 565 format */

var->red.offset = 11;

var->green.offset = 5;

var->blue.offset = 0;

var->red.length = 5;

var->green.length = 6;

var->blue.length = 5;

} else {

/* 5551 format */

var->red.offset = 11;

var->green.offset = 6;

var->blue.offset = 1;

var->red.length = 5;

var->green.length = 5;

var->blue.length = 5;

}

break;

case 32:/* 24 bpp 888 and 8 dummy */

var->red.length = 8;

var->red.offset = 16;

var->green.length = 8;

var->green.offset = 8;

var->blue.length = 8;

var->blue.offset = 0;

break;

}

return 0;

}

/*申请帧缓冲设备fb_info的显示缓冲区空间*/

static int __init my2440fb_map_video_memory(struct fb_info *fbinfo)

{

dma_addr_t map_dma;/*用于保存DMA缓冲区总线地址*/

struct my2440fb_var *fbvar = fbinfo->par;/*获得在lcd_fb_probe探测函数中设置的私有结构体数据*/

unsigned map_size = PAGE_ALIGN(fbinfo->fix.smem_len);/*获得FrameBuffer缓存的大小, PAGE_ALIGN定义在mm.h中*/

/*将分配的一个写合并DMA缓存区设置为LCD屏幕的虚拟地址(对于DMA请参考DMA相关知识)

dma_alloc_writecombine定义在arch/arm/mm/dma-mapping.c中*/

fbinfo->screen_base = dma_alloc_writecombine(fbvar->dev, map_size, &map_dma, GFP_KERNEL);

if (fbinfo->screen_base)

{

/*设置这片DMA缓存区的内容为空*/

memset(fbinfo->screen_base, 0x00, map_size);

/*将DMA缓冲区总线地址设成fb_info不可变参数中framebuffer缓存的开始位置*/

fbinfo->fix.smem_start = map_dma;

}

return fbinfo->screen_base ? 0 : -ENOMEM;

}

/*释放帧缓冲设备fb_info的显示缓冲区空间*/

static inline void my2440fb_unmap_video_memory(struct fb_info *fbinfo)

{

struct my2440fb_var *fbvar = fbinfo->par;

unsigned map_size = PAGE_ALIGN(fbinfo->fix.smem_len);

/*跟申请DMA的地方想对应*/

dma_free_writecombine(fbvar->dev, map_size, fbinfo->screen_base, fbinfo->fix.smem_start);

}

/*LCD FrameBuffer设备移除的实现,注意这里使用一个__devexit宏,和lcd_fb_probe接口函数相对应。

在Linux内核中,使用了大量不同的宏来标记具有不同作用的函数和数据结构,这些宏在include/linux/init.h

头文件中定义,编译器通过这些宏可以把代码优化放到合适的内存位置,以减少内存占用和提高内核效率。

__devinit、__devexit就是这些宏之一,在probe()和remove()函数中应该使用__devinit和__devexit宏。

又当remove()函数使用了__devexit宏时,则在驱动结构体中一定要使用__devexit_p宏来引用remove(),

所以在第①步中就用__devexit_p来引用lcd_fb_remove接口函数。*/

static int __devexit lcd_fb_remove(struct platform_device *pdev)

{

struct fb_info *fbinfo = platform_get_drvdata(pdev);

struct my2440fb_var *fbvar = fbinfo->par;

/*从系统中注销帧缓冲设备*/

unregister_framebuffer(fbinfo);

/*停止LCD

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top