1. 程式人生 > >LCD驅動程式(3)視訊記憶體與調色盤

LCD驅動程式(3)視訊記憶體與調色盤

我們設定好了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 }