2/18/2011

LCD Driver (2)

3. FrameBuffer

在把Probe所有的動作搞清楚之前,要開始提及相關LCD的知識了...不然後面的程式會看不懂...

眾所皆知,Linux系統剛起家時並沒有什麼圖形界面,指令就是一切

後面才開始發展出X-window的圖形系統,通過X-server即可操作顯卡硬體.

可是為什麼在開機時,就會有圖形界面出來呢 ? 這時X-windows都還沒運行勒...

靠的就是FrameBuffer(簡稱fb),更簡單來說,它只是一個機制,可以參考下面這段話 :

FrameBuffer不是一個圖形系統,更不是視窗系統。它比X要低級,簡單來說FrameBuffer就是一種機制的實現。這種機制是把螢幕上的每個點對映成一段線性記憶體空間,程式可以簡單的改變這段記憶體的值來改變螢幕上某一點的色彩。X的高度可攜式性就是來自於這種機制,不管是在那種圖形環境下,只要有這種機制的實現就可以執行X。所以在幾乎所有的平台上都有相應的X版本的移植。

聽起來很繞口,說白一點就是...FrameBuffer提供了一組ioctl,讓使用者完全不用考慮顯卡硬體就可以使用這組ioctl來操作了

大致上了解FrameBuffer是啥東西了,接著在繼續往下看 :

info = framebuffer_alloc(sizeof(struct pxa950fb_info), &pdev->dev);
if (info == NULL)
return -ENOMEM;

/* Initialize private data */
fbi = info->par;
fbi->fb_info = info;
platform_set_drvdata(pdev, fbi);
fbi->clk_lcd = clk_lcd;
fbi->clk_axi = clk_axi;
fbi->clk_dsi0 = clk_dsi0;
fbi->clk_dsi1 = clk_dsi1;
fbi->dev = &pdev->dev;
fbi->on = 1;
fbi->is_blanked = 0;
fbi->suspend = 0;
fbi->debug = 0;
fbi->pix_fmt_out = mi->pix_fmt_out;
fbi->active = mi->active;
fbi->invert_pixclock = mi->invert_pixclock;
fbi->panel_rbswap = mi->panel_rbswap;
fbi->panel_type = mi->panel_type;
fbi->mixer[0] = mi->mixer0;
fbi->mixer[1] = mi->mixer1;
fbi->power = mi->pxa950fb_lcd_power;
fbi->dsi_reset = mi->pxa950fb_dsi_reset;
fbi->window = 0; /*wge 9 and channel 0 is used for fb0*/
fbi->user_addr = 0;
fbi->eof_intr_en = 1;
fbi->vsync_en = 0;
fbi->eof_handler = NULL;


很明顯看的出來,全是對pxa950fb_info這個結構初始化,在說明之前,先來看一開始create framebuffer這個function :

struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
{
#define BYTES_PER_LONG (BITS_PER_LONG/8)
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
int fb_info_size = sizeof(struct fb_info);
struct fb_info *info;
char *p;

if (size)
fb_info_size += PADDING;

p = kzalloc(fb_info_size + size, GFP_KERNEL);

if (!p)
return NULL;

info = (struct fb_info *) p;

if (size)
info->par = p + fb_info_size;

info->device = dev;

#ifdef CONFIG_FB_BACKLIGHT
mutex_init(&info->bl_curve_mutex);
#endif

return info;
#undef PADDING
#undef BYTES_PER_LONG
}
EXPORT_SYMBOL(framebuffer_alloc);


除了分配記憶體空間之外,最值得注意的是回傳型態 :

struct fb_info *framebuffer_alloc(size_t size, struct device *dev)

是指向fb_info的sturct,看來它和pxa950fb_info根本是同一伙的 !!

fb_info這個資料結構定義在kernel/include/linux/fb.h,這個結構非常非常之重要,LCD Driver能不能動都看它了.

因為它為FrameBuff定義驅動層的ioctl所在,也就是說,每一個LCD Deivce,基本上都會有相對應的一個專有fb_info資料結構

而pxa950fb_info的結構是存放著LCD的硬體信息,所以也就可以理解為什麼要這麼寫 :

info = framebuffer_alloc(sizeof(struct pxa950fb_info), &pdev->dev);
if (info == NULL)
return -ENOMEM;

/* Initialize private data */
fbi = info->par;
fbi->fb_info = info;
platform_set_drvdata(pdev, fbi);


此時info的資料型態是(struct fb_info*),別搞錯了,而fbi的資料型態是(struct pxa950fb_info*),所以第一和第二步驟就是讓他們結成連理!!!!

至於第三步驟嘛...把它打回原形就一目了然了 :

#define platform_set_drvdata(_dev,data) dev_set_drvdata(&(_dev)->dev, (data))


void dev_set_drvdata(struct device *dev, void *data)
{
int error;

if (!dev)
return;
if (!dev->p) {
error = device_private_init(dev);
if (error)
return;
}
dev->p->driver_data = data;
}
EXPORT_SYMBOL(dev_set_drvdata);


初始化device之後,再把fbi的資料放進該裝置的專有資料裡面 ; 這樣的寫法是很難懂...但Kernel就是靠這樣的做法來保護每個不同裝置所存放的資料

後面的步驟就很簡單了....該需要用到的資料成員一個一個對號入座.

再後面還是針對fb_info的每個成員來定義或者初始化,挑幾個重點來說...

2 comments: