2/22/2011

LCD Driver (4)

從之前的(1)~(3),我都只提到physical layer <-> Kernel space之間而己,並未探討user space該如何運行.

在開始之前,先說明兩個相當重要的code :

kernel/linux/include/fb.h <- 定義許多相關FB的結構,變量和define kernel/driver/video/fbmem.c <- 實現核心層和使用者層之間的ioctl

了解這兩個程式其實對porintg來說幫助並不大,但卻助於理解Linux driver整體架構,也能清楚知道原來應用層一直到實體層是透過怎樣的機制來實現的.

====================

fbmem.c ; 這支程式在/dev創建一個fb0的設備(看有幾個調用register_framebuffer這個function...預設最多創建32個,這個define可以在fb.h看的到)

可以這麼想像,它是介於Kernel與使用者之間的一個橋樑,正確來說,是一個字元(Character)裝置.

使用者可以透過這個字元裝置,利用ioctl方便的直接操控硬體顯示

有寫過字元裝置的driver都知道,一定會有一個major和minor,而且還會有一個裝置節點(node),其中Major(主編號)在程式裡面定義是29,而Minor(次編號)則是隨著count而增加

所以一般來說,你在Linux發行版本上,一定都會看到這個裝置 :

#cat /dev/fb0

如果出現亂碼,表示現在使用的發行版的kernel是有打開FB support

====================

打開fbmem.c,在init中有一個非常熟悉的function :

if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);

字型裝置的註冊函式,而這裡fb_fops當然就是file_operations囉 !

static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
};

就算FrameBuffer是一塊記憶體,不管是內顯還是外顯,Linux通通都看成是一個設備 !

在這裡,fb_fops提供一系列操作函數給使用者去呼叫,其中有一點要特別注意,調用fb_open的時候,除了探測module是否有被使用之外

它還會利用次設備來匹配不同的裝置 :

int fbidx = iminor(inode);
struct fb_info *info;
if (fbidx >= FB_MAX)
return -ENODEV;
info = registered_fb[fbidx];

以及把fb_info的private data存放進該device :

file->private_data = info;

最最重要的是,它會去呼叫該device的fb_info裡面的成員fbops的操作函數 : fd_open !

if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}

從這一刻開始,由上至下,physical laye <-> kernel space <-> user space都銜接了.

而fd.h定義了ioctl的一系列cmd (每個cmd都會對應fbos的function , 除非該功能不需用到硬體資訊):

#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOGETCMAP 0x4604
#define FBIOPUTCMAP 0x4605
#define FBIOPAN_DISPLAY 0x4606
#define FBIOGET_CON2FBMAP 0x460F
#define FBIOPUT_CON2FBMAP 0x4610
#define FBIO_ALLOC 0x4613
#define FBIO_FREE 0x4614
#define FBIOGET_GLYPH 0x4615
#define FBIOGET_HWCINFO 0x4616
#define FBIOPUT_MODEINFO 0x4617
#define FBIOGET_DISPINFO 0x4618

現在馬上就來測試使用它 ! 先用vim新建一個.c檔 :

#vim testfb.c

接著copy下面我寫的code :

#include
#include
#include
#include

/* Frame Buffer Test on Ubuntu 10.4 */

int main()
{
int fp = 0;
struct fb_var_screeninfo varinfo;
struct fb_fix_screeninfo fixinfo;

fp = open("/dev/fb0",O_RDWR);
printf("fp = %d\n",fp);
if(!fp)
{
printf("Error : Can not open /dev/fb0\n");
exit(1);
}
if (ioctl(fp,FBIOGET_FSCREENINFO,&fixinfo))
{
printf("Error reading fixed information\n");
exit(1);
}

if (ioctl(fp,FBIOGET_VSCREENINFO,&varinfo))
{
printf("Error reading variable information\n");
exit(1);
}

printf("The mem is :%d\n",fixinfo.smem_len);
printf("The line_length is :%d\n",fixinfo.line_length);
printf("The xres is :%d\n",varinfo.xres);
printf("The yres is :%d\n",varinfo.yres);
printf("bits_per_pixel is :%d\n",varinfo.bits_per_pixel);
close (fp);
}

儲存離開後,先別急著編譯,因為要開啟/dev底下的設備是需要root權限,所以先切換成root :

#sudo su -

然後再compile/run它 :

#gcc -o testfb testfb.c
#./testfb

這時就可以看到當前LCD(營幕)的屬性 :

fp = 3
The mem is :65536
The line_length is :80
The xres is :640
The yres is :480
bits_per_pixel is :4

因為我是在VitrualBox底下...所以只有640*480(虛擬顯卡通常都很爛).

No comments:

Post a Comment