我们设置好了LCD控制器,它就会自动的从显存里面取出一个像素的值,然后发送到LCD上去,然后再取出第二个......取到最后面之后有返回到第一个,周而复始。
显存必须物理地址连续,LCD没那么聪明,你这个显存必须是连续的。怎么分配呢,我们就不能有kmalloc这种函数了。就要用专用的函数来分配这块内存。来看一看内核自带的一些驱动是怎么来分配这块内存的。
我们参考我们内核里面的S3c2410fd.c这个文件
ret = s3c2410fb_map_video_memory(fbinfo);里面有个这个函数,进入这个函数里面去看一看
static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
dma_addr_t map_dma;
unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size);
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
&map_dma, GFP_KERNEL); //就是这个函数分配的
if (info->screen_base) {
/* prevent initial garbage on screen */
dprintk("map_video_memory: clear %p:%08x\n",
info->screen_base, map_size);
memset(info->screen_base, 0x00, map_size);
info->fix.smem_start = map_dma;
dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n",
info->fix.smem_start, info->screen_base, map_size);
}
return info->screen_base ? 0 : -ENOMEM;
}
dma_alloc_writecombine来看一下它需要什么参数
void *dma_alloc_writecombine(struct device *dev, size_t size,dma_addr_t *handle, gfp_t gfp) 第一个参数是设备,第二个是大小,第三个参数是物理地址dma_addr_t,实际上就是个u32.物理地址我们不是想存到var.smem_start这里吗,所以我们把这里的参数设置为这个就行了。还一个就是标记,标记很简单,就一个flage就行了
返回值就是返回这块内存的虚拟地址。
现在我们还只是分配了,但是我们还要把这个告诉我们LCD控制器
什么是调色板:我们这里每个像素需要24位的数据,如果显存里面留3个字节,刚好16位,刚好够。LCD控制器直接把这个数据拿过来用就好了,但是我如果想节省一下内存,我这里只想用1个字节8位,那怎么办呢,我们LCD控制器取到这8位之后它怎么转换成24位的数据呢,怎么转换就是调色板。LCD控制器得到这个8位的数据并不是直接发送给LCD的,而是把8位的数据经过调色板,调色板就是一块内存,调色板里面真正有24位数据,LCD得到数据之后,以这8位作为索引,它就想个数组一样,假如这8位是100,那么LCD就会找到这个100项,把里面的16位数据取出来给LCD。
我们假的调色板由谁来设置呢
由fops里面的//.fb_setcolreg = tiny_lcdfb_setcolreg,这个来设置
我们小时候调颜色就是把红绿蓝透明色放到一个碟子里面,
代码如下
static int s5p_lcdfb_setcolreg(unsigned int regno, unsigned int red,unsigned int green, unsigned int blue,unsigned int transp, struct fb_info *info)
{
}
unsigned int regno这个意思是指明是哪个碟子
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfie ld *bf)
131 {
132 chan &= 0xffff;//保留16位
133 chan >>= 16 - bf->length;//我们的长度是888,16-8=8 //得到高8位
134 return chan << bf->offset;//左移之后得到一个值,这个值就是给你用的
135 }
136
137 static int s5p_lcdfb_setcolreg(unsigned int regno, unsigned int red,unsigned int green, unsigned int blue,unsigned int transp, struct fb_info *info)
138 {
139 unsigned int val;
140 /*因为我那个数组里面只有16个*/
141 if (regno > 16)
142 return 1;
143
144 /*用红绿蓝三个颜色达到一个值*/
145 val = chan_to_field(red, &info->var.red);
146 val |= chan_to_field(green, &info->var.green);
147 val |= chan_to_field(blue, &info->var.blue);
148 /*把这个值放到碟子里面去*/
149 pseudo_pal[regno] = val;
150 }