2/25/2011

Chrome 無法開啟設定檔

日前, 因為不知道誤刪了什麼東西...導致每次再開啟Chrome的時候都會出現 :

"Chrome無法開啟設定檔, 請檢查權限"等等之類的提示框

man google-chrome之後, 發現在config底下有些設定檔在裡面...所以我先刪了它之後重新再次安裝Chrome就ok了 !


# rm -rf ~/.config/google-chrome

2/24/2011

iper compile/use

這是去年寫給客戶的一封信...交他如何編譯iperf至不同的平台(with Android)

放上來希望對路過的人有所幫助 :)

How to compile and install iperf for Android platform ? Please follow up below :

1.Please download iperf source code :

http://linux.softpedia.com/get/System/Networking/Iperf-23581.shtml

We can get the iperf-2.0.4 version.

2.Congiure and setting environment then make :

dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ ./configure --host=arm-none-linux-gnueabi ac_cv_func_malloc_0_nonnull=yes CXXFLAGS=-static CFLAGS=-static

dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ make


dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ cd src

Now we can see the iperf execute binary file,please copy to android in file system.

Note : Please check attached file,this is i have compile iperf binaries and source code.

Can use the android platform.

3.How to use iperf

1.If you PC is Windows system,please get the execute file from this site :


http://www.noc.ucf.edu/tools/iperf/iperf.exe


If Linux system,install just download the iperf :

dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ ./configure


dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ make install

2.Host(PC) please command :

dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ iperf -s &

And client please command :

dicky@dicky-ubuntu804:~/3tools/iperf-2.0.4$ iperf -c -t 60

More deatil info,please search and check web site below :

http://dev.firnow.com/course/6_system/linux/Linuxjs/2008912/142232.html

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(虛擬顯卡通常都很爛).

2/21/2011

LCD Driver (3)

剛仔細看了probe的程式...發現LCD Driver在probe所做的事情真的很多...雖然都只是初始化而己

但很多預備工作少不了,而且所需要的相關知職更多....

在上述的fb_info部份成員填進去之後,開始分配記憶體空間了:

/* Map registers.*/
fbi->reg_base = ioremap_nocache(res->start, res->end - res->start);
if (fbi->reg_base == NULL) {
ret = -ENOMEM;
goto failed;
}

/* Allocate framebuffer memory.*/
fbi->fb_size = PAGE_ALIGN(DEFAULT_FB_SIZE);
fbi->fb_start = dma_alloc_writecombine(fbi->dev, fbi->fb_size + PAGE_SIZE,
&fbi->fb_start_dma,
GFP_KERNEL);
if (fbi->fb_start == NULL) {
ret = -ENOMEM;
goto failed;
}

ioremap_nocache和dma,相信這兩個名詞很多人相當熟悉...鑑於我的腦袋...還是把僅存的己知寫上去 XD

首先講敘ioremap_cache是怎麼回事,它的原型是長這樣 :

static inline void __iomem * ioremap_nocache(unsigned long offset,
unsigned long size)
{
return ioremap(offset, size);
}

傳的參數非常簡單,就是取得之前platform的resource的實體io/memory等相關資源之後,再利用ioremap來轉換成核心虛擬記憶體

那為什麼一定要轉成核心虛擬記憶體勒 ? 有個觀念要僅記....任何device的driver,都不可以直接存取實體記憶體 !

分配好對應硬體資源的虛擬記憶體之後,接著就是分配DMA的空間(即顯卡記憶體),其中的DEFAULT_FB_SIZE定義如下 :

/* default fb buffer size VGA-32bits double buffer */
#define DEFAULT_FB_SIZE (640 * 480 * 8 + PAGE_SIZE)

本來我認為FB的SIZE應該是要跟自身定義的解析度有關,這樣才合理

也就是說,video_mode是定義800*480,應該修改成一樣才對....但結果好像不是...很怪

而且查了之前的案子,發現之前的LCD屏幕使用的是HX8369-A

Datasheet裡面有寫,Frame memory area是480*864*24 , 當然這裡指的是最高支持的解析程度..

但如果是我的話...FB SIZE應該要定義最高的解析程度吧.....這樣才能都適用呀... XD

先來看一個很重要的資料結構,在上面分配完之後,有一個function pointer放進fb_info :

info->fbops = &pxa950fb_gfx_ops;


static struct fb_ops pxa950fb_gfx_ops = {
.owner = THIS_MODULE,
.fb_blank = pxa950fb_gfx_blank,
.fb_ioctl = pxa950fb_gfx_ioctl,
.fb_check_var = pxa950fb_check_var,
.fb_set_par = pxa950fb_set_par,
.fb_setcolreg = pxa950fb_setcolreg, /* TODO */
.fb_pan_display = pxa950fb_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};

很眼熟吧 ? 它就是LCD驅動提供給上層設備調用的操作函數,至於這誰會調用,等把整個流程理清之後,後面開始說明重要的資料結構和大體架構.

最後,有三個重要的function來結束整個主要驅動註冊和初始化過程 :

pxa950fb_set_par(info);


register_framebuffer(info);


device_create_file(&pdev->dev, &dev_attr_vsync);

pxa950fb_set_par主要是設置BPP(Bit Per Pixel)屬性和計算Line(行)的長度,而register_framebuffer和device_create_file就很簡單理解了

FrameBuffer真的要能工作起來,這個註冊function不能少,屆時另開章節來講LCD架構和資料結構的說明..

在公司的板子和新的Datasheet來之前,要趕快搞清楚這些東西...不然還真不好porting......

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的每個成員來定義或者初始化,挑幾個重點來說...

LCD Driver (1)

因為打英文很累...打到後面就放棄改打中文= =

第一章理解的都只是初步,未涉及到相關LCD的知識

但為了怕一些細節容易忘記...似懂非懂的

還是記錄下來...

後面的陸續補上,看自己讀code的時間要花多少了 XD

如有錯誤,也請路過的鄉民指點,感激不盡^^

(恩...英文文法有錯的話看看就好,別太在意...意思到就好 !)

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

Written by Dicky

SAARB board init code the path is arch/arm/mach-pxa/saarb.c

First,We check the saarb.c code,because this is configure LCD Controller source,can be find pxa950fb_mach_info struct,such as :


static struct pxa950fb_mach_info saarb_lcd_info __initdata = {
.id = "Base",
.modes = video_modes,
.num_modes = ARRAY_SIZE(video_modes),
.pix_fmt_in = PIX_FMTIN_RGB_16,
.pix_fmt_out = PIX_FMTOUT_24_RGB888,
.panel_type = LCD_Controller_Active,
/* .mixer0 = LCD_M2PARALELL_CONVERTER,*/
.mixer0 = LCD_MIXER_DISABLE,
.mixer1 = LCD_M2DSI1,
.active = 1,
.pxa950fb_lcd_power = espon_lcd_power,
.pxa950fb_dsi_reset = tavorpv2_saarb_dsi_reset,
.invert_pixclock = 1,
};


And also find video modes struct,that is important :

static struct fb_videomode video_modes[] = {
[0] = {
.pixclock = 41701,
.refresh = 60,
.xres = 480,
.yres = 800,
.hsync_len = 19,
.left_margin = 40,
.right_margin = 59,
.vsync_len = 9,
.upper_margin = 4,
.lower_margin = 9,
.sync = 0,
},
};


1. How to register platorm device to kernel

Before discuss that,first look at how to initialize & register LCD driver for saarb board :

static void __init saarb_init(void)
{
.......
#if defined(CONFIG_FB_PXA950)
pxa3xx_mfp_config(ARRAY_AND_SIZE(lcd_mfp_cfg));
saarb_init_lcd();
#endif
........
}


saarb_init_lcd function :

static void __init saarb_init_lcd(void)
{
set_pxa950_fb_info(&saarb_lcd_info);
set_pxa950_fb_ovly_info(&saarb_lcd_ovly_info);
}


To call it :

void __init set_pxa950_fb_info(struct pxa950fb_mach_info *info)
{
pxa_register_device(&pxa950_device_fb, info);
}


See ? We can be find the platform_device struct :

struct platform_device pxa950_device_fb = {
.name = "pxa950-fb",
.id = -1,
.dev = {
.dma_mask = &fb_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(pxa950fb_resources),
.resource = pxa950fb_resources,
};


What is Platform ? That like is character,block,net device,for register to kernel,need write data into the platform_device & platform_driver.

Normal define in the arch/arm/mach-xxx/devices.c

There is another important member of the platform_device :

.resource = pxa950fb_resources,


The mean is description the hardware resource occupied by device(as memory address,IRQ number etc,). :

static struct resource pxa950fb_resources[] = {
[0] = {
.start = 0x44100000,
.end = 0x4410ffff,
.flags= IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCDGLOBAL,
.end = IRQ_LCDGLOBAL,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start= IRQ_LCDPARALLEL,
.end= IRQ_LCDPARALLEL,
.flags= IORESOURCE_IRQ,
},
[3] = {
.start= IRQ_DSI0,
.end = IRQ_DSI0,
.flags = IORESOURCE_IRQ,
}
[4] = {
.start = IRQ_DSI1,
.end = IRQ_DSI1,
.flags = IORESOURCE_IRQ,
},
};


Lastly add device to kernel of complete by call function platform_device register :

void __init set_pxa950_fb_info(struct pxa950fb_mach_info *info)
{
pxa_register_device(&pxa950_device_fb, info);
}

void __init pxa_register_device(struct platform_device *dev, void *data)
{
int ret;

dev->dev.platform_data = data;
ret = platform_device_register(dev);
if (ret)
&dev_err(&dev->dev, "unable to register device: %d\n", ret);
}


As you see,the pxa950fb_mach_info has link to member of dev.platform_data.

What is pxa950fb_mach_info ?
That's main board the LCD controlle register infomation sturct.
Also see the point variable(*dev) will be register to kernel. ( That struct generate by pxa950_device_fb)

2. How to register platform driver to kernel

到目前為止,我們己經完成LCD裝置所需的硬體資源和配置

現在可以為它寫一支驅動程式來驅動它

一般來說,所有Driver的程式碼都會在kernel/driver的路徑下,如MMC Driver是kernel/driver/mmc

所以LCD的driver就在kernel/driver/video底下了

各家不同平台的驅動都會放在這,Marvell平台的LCD驅動就叫pxa950fb.c

一樣,直接先來看它如何做初始化驅動的 :

static int __devinit pxa950fb_gfx_init(void)
{
#ifdef CONFIG_PXA3xx_DVFM
dvfm_register("pxa950-fb", &dvfm_dev_idx);
#endif
return platform_driver_register(&pxa950fb_gfx_driver);
}


DVFM先撇開不談,後續再來討論,因為它只是一種視訊格式而己,

從init function可以發現一個很有趣的結構 :

static struct platform_driver pxa950fb_gfx_driver = {
.driver = {
.name = "pxa950-fb",
.owner = THIS_MODULE,
},
.probe = pxa950fb_gfx_probe,
};


這個結構相當重要,前面有提到,一個Platform有兩個最重要的資料結構,分別是platform_device和platform_driver

這兩個結構都可以在kernel/include/linux/platform_deivce.h找到

在這此結構當中,有兩個成員是必填的,分別是Name和Probe

沒有Name值,Kernel不知道如何把這支驅動對應到哪個裝置

沒有probe functuion pointer,Kernel不知道如何初始化驅動程式..

所以接下來第二個進入點就是probe function了,不管什麼驅動,probe必存在 !

這個LCD driver在probe function裡面做了很多事....一步一步來探討,先列出一部份:

struct pxa950fb_mach_info *mi;
struct fb_info *info = 0;
struct pxa950fb_info *fbi = 0;
struct resource *res;
struct clk *clk_lcd, *clk_dsi0, *clk_dsi1, *clk_axi;
int irq_ctl, irq_conv[2], ret;
int i;
u32 converter;

mi = pdev->dev.platform_data;
if (mi == NULL) {
dev_err(&pdev->dev, "no platform data defined\n");
return -EINVAL;
}


一開始就把pdev->gt;dev.platform_data的Address指向mi,而mi又指向pxa950fb_mach_info.....

也就是說,pxa950fb_mach_info的位址(值)等同於pdev->gt;dev.platform_data...

重點來了 ! pxa950fb_mach_info是什麼呢 !? 前面有提到,它是LCD裝置控制器的結構

可是它幹嘛把pdev->gt;dev.platform_data指向LCD裝置控制器呢 ?

因為在註冊platform_device的時候,就己經把這些LCD控制器的定義都註冊進去了(翻前面的程式碼)

現在驅動需要用到,當然要把它給指過來 ! 不然驅動怎麼知道device到底定義哪些東西,又該如何使用

所以這一步就把下到上的資料結構串起來,驅動程式才可以針對裝置去做其它操作了 !

然後就能看到後面開始去做什麼開啟Clock啦....註冊中斷啦....打開什麼一堆東西啦等等..