LCD驱动
fbmem.c是内核自带的LCD驱动程序,它是抽象出来的,依赖于底层提供的fb_info结构体。
fbmem_init(void)
{
create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
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;
}
因为“fbmem.c”是通用的文件,故并不能直接使用这个 file_operations 结构中的.read 等函数。这里 fbmem.c 没有在设备类下创建设备,只有真正有硬件设备时才有必要在这个类下去创建设备。
app: open("/dev/fb0", …)
info = registered_fb[fbidx]得到这个设备节点的次设备号,从这个数组里面registered_fb[0]得到以次设备号为下标的一项,如果它有open函数就调用它,没有返回。
kernel:
fb_open
int fbidx = iminor(inode); //得到次设备号
struct fb_info *info = = registered_fb[0];
app: read("/dev/fb0", …)
假设app想读,得到次设备号,以次设备号为下标在数组registered_fb[fbidx]里得到一项,如果这个数组项里提供了fbops,就调用它的读函数。如果没有从screen_base读,src等于显存的基地址加偏移值,从里面读源(显存基地址screen_base)到数据放到目的(buffer)里。
kernel:
fb_read
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx]; //以次设备号为下标从 registered_fd 数组中得一项赋给"info"结构。
if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos);
src = (u32 __iomem *) (info->screen_base + p); //screen_base 是指显存的基地址。这里是读源 src 等于显存的基地址加上某个偏移值。
dst = buffer;
*dst++ = fb_readl(src++); //读源(从显存基地址+P偏移)那里读到一个数据放到目标“*dst++”里。dst是buffer,buffer是kmalloc()上面分配的空间。
copy_to_user(buf, buffer, c) //把数据拷贝到用户空间
open和read都依赖于fb_info结构体(fb是framebuffe帧缓冲区)结构体),这个结构体从registered_fb[fbidx]数组里得到的,以次设备号为下标得到一项。
问1. registered_fb数组在哪里被设置?
答1. register_framebuffer
把fb_info结构体先找到某个空项,找到空项后device_create,在类下面创建设备,之前只创建了类,真正有硬件设备才去创建设备节点。fbmem.c 提供的都是抽象出来的东西。最终都得依赖这个“registered_fb”数组里的“fb_info”结构体。
register_framebuffer(struct fb_info *fb_info)
{ for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i]) //先找出一个空项
break;
fb_info->dev = device_create(fb_class, fb_info->device,MKDEV(FB_MAJOR, i), "fb%d", i);
}
怎么写LCD驱动程序?
1 分配fb_info结构体: framebuffer_alloc
2 设置fb_info结构体
3 注册fb_info结构体: register_framebuffer
4 硬件相关的操作
1 分配
framebuffer_alloc(size_t size, struct device *dev)
2 设置
struct fb_info {
struct fb_var_screeninfo var; /* 可变参数 */
struct fb_fix_screeninfo fix; /* 固定参数 */
struct fb_ops *fbops; //操作函数
void *pseudo_palette; //Fake palette of 16 colors 假调色板
…
};
固定参数
struct fb_fix_screeninfo {
char id[16]; //名字
unsigned long smem_start; //显存的物理起始地址,分配内存时再设置
__u32 smem_len; //显存长度(看液晶屏)240*320*16 */
__u32 type; // see FB_TYPE_* 宏 默认值
__u32 visual; // see FB_VISUAL_* TFT 真彩色
__u32 line_length; // 一行的长度240*16/8
};
可变参数
struct fb_var_screeninfo {
__u32 xres; // x方向分辨率240
__u32 yres; //y方向分辨率320
__u32 xres_virtual; //虚拟分辨率简单设为和硬件相同
__u32 yres_virtual;
__u32 bits_per_pixel; //每个像素位数16(2440只支持16浪费2位)
struct fb_bitfield red; //红 5
struct fb_bitfield green; //绿 6
struct fb_bitfield blue; //蓝 5
struct fb_bitfield transp; ///透明度 0
…
};
//RGB 565
struct fb_bitfield {
__u32 offset; // 开始位
__u32 length; // 长度
__u32 msb_right; //最重要位在右边,我们最重要位在左边不设置*/
};
显存操作函数
static struct fb_ops s3c_lcdfb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = s3c_lcdfb_setcolreg,
.fb_fillrect = cfb_fillrect, //填充一个矩形
.fb_copyarea = cfb_copyarea, //拷贝一个区域
.fb_imageblit = cfb_imageblit,
};
其它设置
s3c_lcd->pseudo_palette = pseudo_palette; //假调色板
s3c_lcd->screen_base = ; //显存的虚拟地址
s3c_lcd->screen_size = 240*324*16/8; //显存大小
调色板是块内存,像数组一样,里面存放有真正的十六位数据颜色。LCD以内存中8位数据为索引,在调色板中取得16位真正颜色的数据。
3 硬件操作
3.1 配置GPIO用于LCD
3.2 根据LCD手册设置LCD控制器, 比如VCLK的频率等
LCDCON1:像素时钟VCLK,LCD类型TFT,BPP 16,使能LCD信号输出
LCDCON2:垂直方向的时间参数和同步信号:VBPD上等待时间,LINEVAL垂直宽度,VFPD下无效时间,VSPW脉冲宽度
LCDCON3:水平方向的时间参数:HBPD左等待时间,HOZVAL垂直宽度,HFPD右无效时间
LCDCON4:水平方向的同步信号:HSPW信号脉冲宽度
LCDCON5:数据格式565,引脚信号的极性,字节交换使能(16bpp:高低字节2143,1234)
帧内存与视口,帧内存很大,真正要显示的区域为视口,它处于帧内存之中,这3个寄存器用于确定帧内存的起始地址,定位视口在帧内存中的位置。
LCDADDR1:bit29:21帧内存起始地址A30:22,4M对齐。bit20:0保存视口所对应内存的起始地址,A21:1这块内存称为帧缓冲区
LCDADDR2:帧缓冲区结束地址A21:1
LCDADDR3:上一行最后和下一行开始地址差值,视口宽度
3.3 分配显存(framebuffer), 并把地址告诉LCD控制器
dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
第一个参数是设备NULL,第二个参数是大小,第三个参数是存放物理地址,第四个参数是标记,返回值是这块内存的虚拟地址s3c_lcd->screen_base。
4 注册
register_framebuffer(s3c_lcd);
上一篇: 苹果新AirPods曝光:最快年底上架
下一篇: 二逼朋友过生日的happy照片