Showing posts with label embedded. Show all posts
Showing posts with label embedded. Show all posts

3/10/2011

淺談 ioctl 命令

最近因為某人開始實際碰driver, 每天照三餐靠北我.....

他拿出我二年前在某家公司寫的一份文件, 質疑了一些東西

本來呢, 我想重新整理一遍, 順便導正之前錯誤的觀念重寫一份貼上來

但....似乎想改的地方變動不大只好當作沒看見0.0

其實也只是教如何寫出在Linux虛擬出一個Driver, 仔細研究LDD3這本書就可以應付了.

剛巧他問了ioctl和magic number的問題, 我也在這稍微對這個ioctl分享自己的想法.

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

一般除了使用ioctl來搭建與kernel space橋樑之外, 常見的還有信號量(singel)和socket

談ioctl之前, 有一份kernel文件請一定要看, 通常它的路徑都會在 :

Kernel/Documentation/ioctl/ioctl-number.txt

其實kernel文件有很多寶,像是Kbuild.txt,devices.txt等等,滿多相關知識從那汲取的,值得一讀.

關係及使用到ioctl的頭文件, 它的路徑是在 :

Kernel/include/asm-generic/ioctl.h

其中有一個很重要的定義, 這個定義確保了每個命令都是唯一的"算法" :

#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))


怎麼說是算法呢 ? 因為IOC這個定義, 它把dir, type, nr, size 劃分成4個段

每段都有它自己的意義存在, 但從看上面到, 確保每個命令是系統唯一, 主要是靠type和nr

怎說呢 ? 且看下面.

在頭文件一開始的地方, 定義各個參數的資料段, 可以參考下圖 :



接著看頭文件它描述_IO等行為 :

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))


其中dir代表如下 :

# define _IOC_NONE 0U
# define _IOC_WRITE 1U
# define _IOC_READ 2U

不管是dir或size, 每個使用者都有可能傳相同的方向和大小的"值".

關於type和nr的解釋, 參考LDD3的說明 :

type
The magic number. Just choose one number (after consulting ioctl-number.txt)
and use it throughout the driver. This field is eight bits wide (_IOC_TYPEBITS).

type, LDD3稱它為魔數, 也說明此魔數可以從loctl-number.txt挑選, 佔用1byte

number
The ordinal (sequential) number. It's eight bits (_IOC_NRBITS) wide.

即序號, 也可以是命令的編號, 一般我們定義從0開始, 總共可以定義255個cmd.

簡單來說, type 加 第一個nr 對應 "唯一"一個CMD

舉個例子來說, 假設我定義了一個DICKY_CMD :

#define DICKY_CMD_MAGIC_NUMBER 0xdf
#define DICKY_CMD _lOW(DICKY_CMD_MAGIC,1,unsigned int)

整個展開就會變成這樣 :

01(dir seg) , 1101 1111(Magic seg) , 0000 0000(Nr seg), ... (size就不寫了 ...)

這些就是ioctl的命令碼, 正確的說, 此命令碼, 代表是DICKY_CMD的身份, 系統才會做相對應的事.

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

那個圖似乎有錯 ?? 與頭文件定義的順序不同....size和tyep相反了....

另, file_operations的ioctl要準備消失囉 !!

不過不會那麼快.....一樣還是會保留....就跟舊的register_char_device一樣, 都會存在

但可以的話, 還是用新的方式比較好 ! (不過我還沒看...哭了)

Kill ioctl.file_opreations

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啦....註冊中斷啦....打開什麼一堆東西啦等等..

12/09/2009

【轉】SD card技術瞭解並WINCE下SDHC驅動開發

哎...最近被主管叫去學porting WINCE 6.0...好像真打算把我當全才一樣...

希望我能在大陸那當窗口兼陸幹的軟體leader(其實是因為大陸人聽嘸我們這邊術語兼思維不同很難溝通...)

恩....這大餅看起來似乎滿可口

但通常有80%的機率都是在唬爛

而且感覺公司有點暴風雨前的寧靜...政治的因素搞的越來越大

只好提早做些準備了...嘿嘿

剛好現在在porting freescale的平台:imx31

只是下面文章是用WINCE 5.0,其實WINCE 7.0快出了...據說IE的performance更好,所以不是很多人想跳到6.0,只是大陸市場用6.0的比台灣還多....

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

瞭解SD card

SDSecure Digital Card卡的簡稱,直譯成漢語就是安全數字卡,是由日本松下公司、東芝公司和美國SANDISK公司共同開發研製的全新的存儲卡產品。SD存儲卡是一個完全開放的標準(系統),多用於MP3、數碼攝像機、數碼相機、電子圖書、AV器材等等,尤其是被廣泛應用在超薄數碼相機上。SD卡在外形上同Multimedia Card卡保持一致,大小尺寸比MMC卡略厚,容量也大很多。並且兼容MMC卡接口規範。不由讓人們懷疑SD卡是MMC升級版。另外,SD卡為9引腳,目的是通過把傳輸方式由串行變成並行,以提高傳輸速度。它的讀寫速度比MMC卡要快一些,同時,安全性也更高。SD卡最大的特點就是通過加密功能,可以保證數據資料的安全保密。它還具備版權保護技術,改採用的版權保護技術是DVD中使用的CPRM技術(可刻錄介質內容保護)。

規格


主要特點:

1.精巧而且超薄

SD記憶卡的尺寸只有24毫米x 32毫米 x 2.1毫米。作為「橋樑媒體」的重要特徵,它精緻小巧,方便您在不同設備上使用。兼容SD記憶卡的設備可以採用解碼器軟件來播放音樂、影像短片以及更多其他類型的內容,無需像CD播放機或DVD播放機那樣採用驅動裝置。從而使設備的外形更加精巧,同時也賦予了產品設計者發揮自由創意的全新空間。由於消除了播放音樂時的跳音現象,提高了播放的穩定性。

2.大容量栽體

目前,SD記憶卡已經具備各種容量可供選擇,同時,2GB4GB8GBSDHC也出現了。

3.高速數據傳輸

為了提供快速響應和容易處理數字內容,SD記憶卡可以用每秒10MB的速率寫入和讀取數據。當其能夠用於遠程通信終端,直接下載內容時,記憶卡的高速傳送能力將可使存取時間和通信成本降至最低,同時可減輕網絡壓力。

4.擁有版權保護功能

先進的數碼技術使高保真音樂和其他高質量內容的錄製成為現實。日新月異的數碼技術,借助因特網,實現了全球範圍的信息快速共享。這一進步也帶來了對原版內容的大量複製,因此,作為21世紀的一種切實可行的記憶載體就必須具備高水平的版權保護技術,這樣才能保護大量高質的數碼數據。SD記憶卡可以自由複製各種數碼數據,並採用獨特的內置CPRM技術保存和轉移版權所有的內容,這也是建立一個全新的音樂及其他商業媒體的發布體系的關鍵所在。

硬件結構


(參看附錄中
SD卡和其他卡的一個對比表)

SDIO

SDIO(輸入/輸出)卡是一種擴展帶SD卡插孔設備之功能的接口。正在開發各種SDIO卡,如相機、Bluetooth GPS802.11b等。




如果編寫以上設備的驅動,當然前提是有一個合格的SD Host Controller。如同編寫USB STORAGE/HID設備的驅動一樣,需要USB HCD支持。MX31ADS支持基於SDIOLP1070 SDIO WLAN Card(在Wince 5.0SD卡驅動模型裡,這種驅動稱為client driver)。

SD_SDIO_SPEC.PDF

SDIO features

l Targeted for portable and stationary applications

l Minimal or no modification to SD Physical bus is required

l Minimal change to memory driver software

l Extended physical form factor available for specialized applications

l Plug and play (PnP) support

l Multi-function support including multiple I/O and combined I/O and memory

l Up to 7 I/O functions plus one memory supported on one card.

l Allows card to interrupt host

l Initialization Voltage: 2.0 to 3.6V

l Operational Voltage range: 3.1 to 3.5V

WinCE 5.0SD Stack

一共可以分為3個部分:a bus driver, host controller driver client drivers,現分別介紹:

1 Bus Driver

顧名思義,總線,連接client driverhost controller driver之間的一個管理層。這部分代碼微軟已經寫好了,也就是說定義好了clienthost之間的通訊接口。(是不是可以這麼說:編寫SD WIFI的程序員可以不用知道是什麼SDHC,從而達到驅動的跨硬件性)

參考代碼:

D:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\SDCARD\SDBUSDRIVER\

2 Host Controller

控制硬件並且通過上述的BUS driver來和client進行通訊。

參考代碼:

D:\WINCE500\PLATFORM\Mx31\Src\Drivers\Sdhc

D:\WINCE500\PUBLIC\COMMON\OAK\CSP\ARM\FREESCALE\Mxarm11\Drivers\Sdhc

3 Client Driver

通過BUS driverSD設備進行通訊。

Windows CE 5.0中的SDIO支持如下:

l 動態插入和拔出

l DMA方式 (平台相關)

l SDIO 中斷

l 動態的時鐘控制

l 錯誤恢復

l 喚醒

l v1.0 多功能和組合設備

l CE Power Manager來處理電源管理

l MMC

下圖可以清晰的表達基於WINCE5.0的一個SD STACK模型:


Bus Driver

主要功能如下:

l 枚舉板上的卡,並決定他們的類型(MMC, SD Memory or SDIO

l 配置合適的電流給卡。

l 根據註冊表的值加載clients

l 把總線要求入隊列

l 把來自host controller的異步通知入隊列

l 總線要求完成,SDIO 中斷,設備插入\拔出

l 出錯時重試

參考代碼:

D:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\SDCARD\SDBUSDRIVER


貌似此部分代碼非微軟原創:

// Copyright (c) 2002 BSQUARE Corporation. All rights reserved.

// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE

Host Controller Driver

主要功能:

l HCD通知總線驅動卡的插入和拔出

l 給卡上電,SD定義了可接受的初時電壓範圍。

l 在總線驅動何客戶端設置完時鐘速度後,打開客戶端卡的時鐘(80個週期)

l 初始,把總線寬度設置成1。如果有需要的話(4-bit mode),把總線寬度設成4bit

l 傳輸SD 命令和數據到/來自卡上。

l 負責給槽上電,關電。

l IST 在這裡存在

l 可選的)喚醒支持(插入,拔出,SDIO中斷)

初始化

1. 調用HCD's XXX_Init

2. 調用 SDHCDAllocateContext() 來分配一段HC的上下文

a) Context 是總線驅動和HCD共享的

3. HCD 使用SDHCDSetXxx宏來填充這個上下文結構

a) 這個步驟是把HC向總線驅動描述一下

b) 包括函數指針,支持的電流,最大時鐘,槽數目,SDIO的支持等等。

4. 調用 SDHCDRegisterHostController() 來把自己向總線驅動註冊一下

5. 當總線驅動準備處理SD事件時,它會調用 HCDinit 函數(pContext->pInitHandler) (見SDHCDRegisterHostController__X函數)

6. 在初始化裡,HCD還應該完成硬件和資源的初始化(IST等)

下面代碼抄自MX31 BSPSDHC驅動的SDH_Init函數中:


DWORD SDH_Init(DWORD dwContext)

{

// allocate the context

status = SDHCDAllocateContext(SDH_SLOTS, &pHostContext);

。。。。。。

//Set a unique name for each host controller

if (pController->ControllerIndex == 1)

{

SDHCDSetHCName(pHostContext, TEXT("MXARM11_1"));

}

else

{

SDHCDSetHCName(pHostContext, TEXT("MXARM11_2"));

}

// set init handler

SDHCDSetControllerInitHandler(pHostContext,SDInitialize);

// set deinit handler

SDHCDSetControllerDeinitHandler(pHostContext, SDDeinitialize);

// set the bus request handler

SDHCDSetBusRequestHandler(pHostContext,SDHBusRequestHandler);

// set the cancel I/O handler

SDHCDSetCancelIOHandler(pHostContext, SDHCancelIoHandler);

// set the slot option handler

SDHCDSetSlotOptionHandler(pHostContext, SDHSlotOptionHandler);

// now register the host controller

status = SDHCDRegisterHostController(pHostContext);



Slot Option Handler

l 總線驅動調用HCD SlotOptionHandler

n SDHCDSetSlotPower設置電壓

n SDHCDSetSlotInterface設置時鐘和總線寬度

n SDHCDEnableSDIOInterrupts

n SDHCDAckSDIOInterrupt

n SDHCDDisableSDIOInterrupts

l SDHCDGetWriteProtectStatus – HCD 必須查看SD存儲卡是否開啟寫保護

l SDHCDQueryBlockCapability返回HCD的最大和最小塊長度

總線要求

l 總線驅動把總線要求放入隊列然後把它們傳入HCD BusRequestHandler 函數

l HCD根據要求來做相應的動作—command/read/write, multi-block, .

l HCD 使用某種方式(DMA, PIO, busy-waiting等)來發送命令和數據

l HCD 調用SDHCDIndicateBusRequestComplete() 來通知總線驅動完成

l 總線驅動把完成事件入隊列並提交下一個要求給HCD

l 總線驅動的調度線程將會通知產生要求的起始源事件完成了。

標準的WINCE SDHC驅動支持

l Standard Host Controller v1.0

n Tokyo Electron Devices – Ellen

n Toshiba - Pegasus

n TI PCI 7x21

n Ricoh R5C811 and R5C841

l Non-standard hosts

n Intel PXA-27x SOC (Mainstone II)

n Samsung SMDK-2410

n Freescale MX series


關於Standard Host Controller

SDA Host Working Group (MSFT executive member)

Defined Standard Host Register Specification to standardize the hardware interface from bus to controller

Currently ratified to v1.0 by SDA executive committee

MSFT strongly advocating this standard to all IHVs, ODMs, OEMs and Silicons



中斷

l HCD包括IST

l IST 決定哪個槽中斷

l IST evaluates interrupt

比如現在拔出SD

IST 會調用Bus Driver's SDHCIndicateSlotStateChange() with DeviceEjected parameter

l Bus Driver calls client's SlotEventCallBack routine with SDCardEjected. (Provides async notification about changes in the slot state.)

l Client performs its deinitialization


如何讓鏡像支持SD STACK

SYSGEN_SDBUS – SD bus driver (sdbus.dll)

SYSGEN_SDHC_STANDARD – Standard host controller (sdhc.dll)

SYSGEN_SD_MEMORY – SD Memory client (sdmemory.dll)

SYSGEN_BTH or SYSGEN_BTH_SDIO_ONLY – SDIO Bluetooth client (bthsdio.dll)

BSP variables will be added for CSP-specific host controllers

Client Driver

目前,WINCE5.0所支持的client driver如下:

l SD Memory Class

l SDIO Bluetooth Class - Type A

l SDIO WiFi (vendor specific)

如果需要自己寫client驅動的話可以參考D:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\SDCARD\SDCLIENTDRIVERS目錄下的微軟自帶的SD client驅動來寫。

example1: SD MEMORY DRIVER UNDER WINCE 5.0

Wince自帶的SD存儲卡client驅動,代碼路徑為:

D:\WINCE500\PUBLIC\COMMON\OAK\DRIVERS\SDCARD\SDCLIENTDRIVERS\SDMEMORY

一個SD存儲卡在WINCE裡的驅動架構如下圖所示:
[圖無法插入]

1註冊表和啟動

在註冊表裡告訴Storage Manager

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory]

"Name"="SD Memory Card"

"Folder"="Storage Card"

;"PartitionDriver"="" ; removable storage cannot have partitions

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\MMC]

"Name"="MMC Card"

"Folder"="Storage Card"

;"PartitionDriver"="" ; removable storage cannot have partitions

; SD Memory Storage class driver

[HKEY_LOCAL_MACHINE\Drivers\SDCARD\ClientDrivers\Class\SDMemory_Class]

"Dll"="SDMemory.dll"

"Prefix"="DSK"

"BlockTransferSize"=dword:40 ; send no more than 64 blocks of data per bus transfer

;"SingleBlockWrites"=dword:1 ; alternatively force the driver to use single block access

;"IdleTimeout"=dword:7D0 ; 2000 milliseconds

;"IdlePowerState"=dword:2 ; 0 == D0, 1 == D1, etc.

;"DisablePowerManagement"="" ; if value present, then disable (remove value to enable)

"Profile"="SDMemory"

"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}",

"{A32942B7-920C-486b-B0E6-92A702A99B35}"

; MMC Storage Class Driver

[HKEY_LOCAL_MACHINE\Drivers\SDCARD\ClientDrivers\Class\MMC_Class]

"Dll"="SDMemory.dll"

"Prefix"="DSK"

"BlockTransferSize"=dword:40 ; send no more than 64 blocks of data per bus transfer

;"SingleBlockWrites"=dword:1 ; alternatively force the driver to use single block access

;"IdleTimeout"=dword:7D0 ; milliseconds

;"IdlePowerState"=dword:2 ; 0 == D0, 1 == D1, etc.

;"DisablePowerManagement"="" ; if value present, then disable (remove value to enable)

"Profile"="MMC"

"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}",

"{A32942B7-920C-486b-B0E6-92A702A99B35}"


2 SD命令和總線要求

將所有磁盤的操作轉換成SD的命令和總線要求

NAME SDMEMORY.DLL

EXPORTS

DSK_Close=SMC_Close

DSK_Deinit=SMC_Deinit

DSK_Init=SMC_Init

DSK_IOControl=SMC_IOControl

DSK_Open=SMC_Open

DSK_PowerDown=SMC_PowerDown

DSK_PowerUp=SMC_PowerUp

DSK_Read=SMC_Read

DSK_Seek=SMC_Seek

DSK_Write=SMC_Write



下面為具體的DISK I/O操作函數和CARD I/O操作函數,詳細實現見sdmemdiskio.cppsdmemcardio.cpp

//

// SDDiskIO

//

// SDMemCardConfig - Initialise the memcard structure and card itself

DWORD SDMemCardConfig( PSD_MEMCARD_INFO pMemCard );

// SDMemRead - Read data from card into pSG scatter gather buffers

DWORD SDMemRead( PSD_MEMCARD_INFO pMemCard, PSG_REQ pSG );

// SDMemWrite - Write data to card from pSG scatter gather buffers

DWORD SDMemWrite( PSD_MEMCARD_INFO pMemCard, PSG_REQ pSG );

// SDMemErase - Erase a contiguous set of blocks

DWORD SDMemErase( PSD_MEMCARD_INFO pMemCard, PDELETE_SECTOR_INFO pDSI );

// SDMemEraseAll - Erase all blocks

DWORD SDMemEraseAll( PSD_MEMCARD_INFO pMemCard );

//

// SDCardIO

//

// SDMemDoBusRequest - Perform a bus request, returns Windows Status

DWORD SDMemDoBusRequest( PSD_MEMCARD_INFO pMemcard,

UCHAR Command,

DWORD Argument,

SD_TRANSFER_CLASS TransferClass,

SD_RESPONSE_TYPE ResponseType,

ULONG NumBlocks,

ULONG BlockSize,

PUCHAR pBuffer,

DWORD Flags);

// SDMemSetBlockLen - Sets read/write block length for SD memory card

DWORD SDMemSetBlockLen( PSD_MEMCARD_INFO pMemcard,

DWORD BlockLen );

// SDMemReadMultiple - Read multiple 512 byte blocks of data from card

DWORD SDMemReadMultiple( PSD_MEMCARD_INFO pHandle,

ULONG StartBlock,

ULONG NumBlocks,

PUCHAR pBuffer );

// SDMemWriteMultiple - Write multiple 512 byte blocks of data to card

DWORD SDMemWriteMultiple( PSD_MEMCARD_INFO pHandle,

LONG StartBlock,

LONG NumBlocks,

PUCHAR pBuffer );

// SDMemWriteUsingSingleBlocks - Write using single block writes

DWORD SDMemWriteUsingSingleBlocks( PSD_MEMCARD_INFO pHandle,

LONG StartBlock,

LONG NumBlocks,

PUCHAR pBuffer );

// SDMemDoErase - Erase a contiguous set of blocks

DWORD SDMemDoErase( PSD_MEMCARD_INFO pHandle,

LONG StartBlock,

LONG NumBlocks );

DWORD SDAPIStatusToErrorCode( SD_API_STATUS Status );

DWORD SDGetCardStatus(PSD_MEMCARD_INFO pMemCard , SD_CARD_STATUS *pCardStatus);

VOID HandleIoctlPowerSet(PSD_MEMCARD_INFO pMemCard,

PCEDEVICE_POWER_STATE pDevicePowerState);

VOID InitializePowerManagement(PSD_MEMCARD_INFO pMemCard);

VOID DeinitializePowerManagement(PSD_MEMCARD_INFO pMemCard);

SD_API_STATUS IssueCardSelectDeSelect(PSD_MEMCARD_INFO pMemCard, BOOL Select);

VOID RequestEnd(PSD_MEMCARD_INFO pMemCard);

SD_API_STATUS RequestPrologue(PSD_MEMCARD_INFO pMemCard, DWORD DeviceIoControl);

SD on MX31 ADS

Secure Digital Host Controller

The Secure Digital Host Controller (SDHC) 模塊支持MMCSDSecure Digital I/O and Combo Cards (SDIO)三種。MX31一共有2SDHC硬件模塊。一個host controller 只支持連接上的一個卡。


SDHC.DLL由以下源代碼組成

『────

微軟代碼

c:\macallan\private\winceos\coreos\ceosutil\utiltree.cxx

c:\macallan\public\common\sdk\inc\svsutil.hxx

c:\macallan\private\winceos\coreos\ceosutil\utilmemf.cxx

c:\macallan\public\common\sdk\inc\svsutil.hxx

c:\macallan\private\winceos\coreos\ceosutil\utilmem.cxx

c:\macallan\private\winceos\coreos\ceosutil\svsutil.cxx

c:\macallan\public\common\oak\drivers\sdcard\sdcardlib\sdcardapistubs.cpp

c:\macallan\public\common\oak\drivers\sdcard\sdcardlib\sddebug.cpp

c:\macallan\public\common\oak\drivers\sdcard\sdcardlib\sdmemapi.cpp

c:\macallan\public\common\oak\inc\block_allocator.hxx

c:\macallan\public\common\oak\drivers\sdcard\sdhclib\sdhclib.cpp

─────』

d:\wince500\platform\mx31\src\drivers\sdhc\bspsdhc.c

d:\wince500\public\common\oak\csp\arm\freescale\mxarm11\drivers\sdhc\main.cpp

d:\wince500\public\common\oak\csp\arm\freescale\mxarm11\drivers\sdhc\sdcontrol.cpp

d:\wince500\public\common\sdk\inc\kfuncs.h

SDHC的註冊表設置

#if (defined BSP_SDHC1 || defined BSP_SDHC2)

[HKEY_LOCAL_MACHINE\Drivers\SDCARD\ClientDrivers\Class\SDMemory_Class]

"BlockTransferSize"=dword:100 ; Overwrite from default 64 blocks.

; "SingleBlockWrites"=dword:1 ; alternatively force the driver to use single block

access

[HKEY_LOCAL_MACHINE\Drivers\SDCARD\ClientDrivers\Class\MMC_Class]

"BlockTransferSize"=dword:100 ; Overwrite from default 64 blocks.

; "SingleBlockWrites"=dword:1 ; alternatively force the driver to use single block

access

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\MMC]

"Name"="MMC Card"

"Folder"="MMC"

[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\SDMemory]

"Name"="SD Memory Card"

"Folder"="SD Memory"

#endif

IF BSP_SDHC1

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SDHC_ARM11_1]

"Order"=dword:21

"Dll"="sdhc.dll"

"Prefix"="SDH"

"ControllerISTPriority"=dword:64

"Index"=dword:1

ENDIF ;BSP_SDHC1

IF BSP_SDHC2

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SDHC_ARM11_2]

"Order"=dword:21

"Dll"="sdhc.dll"

"Prefix"="SDH"

"ControllerISTPriority"=dword:64

"Index"=dword:2

ENDIF ;BSP_SDHC

SDHC和DMA

SDHC驅動支持DMA 和非DMA 2種數據傳輸模式,默認是DMAFor every request submitted to it, the driver attempts to build a DMA Scatter Gather Buffer Descriptor list for the buffer passed to it by the upper layer. For cases where this list cannot be built, the driver falls back to the non-DMA mode of transfer. The default configuration is maintained in the file bsp_cfg.h using the parameters BSP_SDMA_SUPPORT_SDHC1 and BSP_SDMA_SUPPORT_SDHC2. A value of TRUE means DMA is the default mode, and for cases where DMA cannot be used, the driver falls back to a non-DMA mode. A value of FALSE means non-DMA mode is the default and DMA mode will not be attempted. For the driver to attempt to build the Scatter Gather DMA Buffer Descriptors, the upper layer should ensure that the buffer meets the following criteria.

Start of the buffer should be a word aligned address.

Number of bytes to transfer should be word aligned.

Due to cache coherency issues arising due to processor and SDMA access of the memory, the above criteria is further stringent for the read or receive operation (it is not applicable for write or transmit):

Start of the buffer should be a cache line size (32 bytes) aligned address.

Number of bytes to transfer should be cache line size (32 bytes) aligned.



電源管理

The primary methods for limiting power in SDHC module is to gate off all clocks to the controllers and to

cut off power to the card slot when no cards are inserted. When a card is inserted to any of the slots, that

slot alone is powered and the clocks to that controller alone are gated on. While using memory cards, the

clock to the host controller and the clock to memory cards are gated off when ever the controller is idle.

For SDIO cards, both the clocks stay on all the time.

SDHC driver supports the full power on and full power off states. In full power off state, the clocks to the

controllers and the power to the inserted cards are turned off. When powered on, all cards inserted before

and after the power down will be detected and mounted.

PowerUp

This function is implemented to support resuming a memory card operation that was previously terminated

by calling PowerDown() API. Power to the card is restored, clocks to the pertaining controller is restarted.

SDHC driver is notified of a device status change. This results in signaling the SD bus driver of a card

removal followed by a card insertion. The card is re-initialized and is mounted so that the all operations

scheduled during a power down resumes. SDIO cards will be initialized on resume.

The details of this architecture and its operation can be found in the Platform Builder Help under the

heading 「Power On and Off Notifications for Secure Digital Card Drivers」, or in the online Microsoft

documentation at the following URL:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceddk5/html/wce50conpoweronoffnot

ificationsforsecuredigitalcarddrivers.asp

Note that this function is intended to be called only by the Power Manager.

PowerDown

This function has been implemented to support suspending all currently active SD operations just before

the entire system enters the low power state. Note that this function is intended to be called only by the

Power Manager. This function gates off all clocks to the controllers and powers down all the card slots.

LP1070 Secure Digital I/O Wi-Fi Driver

SDIO Wi-Fi 驅動是通過Freescale LP1070 SDIO Wi-Fi 卡來連接到一個IEEE 802.11b/g 無限局域網(WLAN) 。驅動支持以54 Mbps的速率和WLAN通訊。


注意:

The LP1070 SDIO Wi-Fi driver is an NDIS 5.0 compliant miniport driver.

LP1070 SDIO Wi-Fi card needs a 3.1~3.3V power supply from on-board Secure Digital Slot.


[HKEY_LOCAL_MACHINE\Drivers\SDCARD\ClientDrivers\Custom\MANF-0325-CARDID-0217-FUNC-1]

"Instance0"="FSL1070NdisSD:FSL1070NdisSD1"

"Prefix"="NDL"

"Dll"="FSL1070NdisSD.dll"

[HKEY_LOCAL_MACHINE\Comm\FSL1070NdisSD]

"ImagePath"="FSL1070NdisSD.dll"

"Group"="NDIS"

"DisplayName"="WaveBlaster 802.11 SDIO Adapter"

[HKEY_LOCAL_MACHINE\Comm\FSL1070NdisSD\Linkage]

"Route"=hex(7):\

46,53,4c,31,30,37,30,4e,64,69,73,53,44,31,00,00,00,00

[HKEY_LOCAL_MACHINE\Comm\FSL1070NdisSD1]

"ImagePath"="FSL1070NdisSD.dll"

"Group"="NDIS"

"DisplayName"="WaveBlaster 802.11 SDIO Adapter"

[HKEY_LOCAL_MACHINE\Comm\FSL1070NdisSD1\Parms]

"SDIOMaxClockFreq"=dword:017d7840

"SDIOMaxByteNumber"=dword:000003e8

"SDIOMaxBlockNumber"=dword:000003e8

"SDIOBlockSize"=dword:00000040

"SDIOSupportBlockMode"=dword:00000001

"SDIOSupport4BitMode"=dword:00000001

"BluetoothCoexCapability"=dword:00000000

"CcxCapability"=dword:00000000

"RadioMeasurementCapability"=dword:00000000

"MultiDomainCapability"=dword:00000000

"RoamRssiHysteresis80211bg"=dword:0000000a

"RoamRssiThreshold80211bg"=dword:ffffff9d

"ListenInterval"=dword:00000000

"BufferConfig"=dword:00000000

"DbgMaxFileSize"=dword:00019000

"WMMEnabled"=dword:00000000

"ResetEnable"=dword:00000001

"UWASensitivityLockout"=dword:00000000

"ShortPreamble"=dword:00000001

"RTSCTSThreshold"=dword:0000092b\

"FragmentThreshold"=dword:0000092a

"DefaultKey3"="0x0000000000"

"DefaultKey2"="0x0000000000"

"DefaultKey1"="0x0000000000"

"DefaultKey0"="0x0000000000"

"LongKeys"=dword:00000000

"Auth"=dword:00000000

"WEP"=dword:00000000

"PowerSaving"=dword:00000000

"RateSelect"=dword:00000000

"MACID"="0x000000000000"

"IbssChannel"=dword:00000000

"Ibss54g"=dword:00000000

"RestrictedChannel"=dword:00000000

"BSSID"="0x000000000000"

"Manual"=dword:00000000

"ESSID"=""

"Domain"=dword:00000010

"ProtocolType"=dword:00000003

"NetworkType"=dword:00000000

"STAuwa"="uwa_airoha.bin"

"STAupper"="mac_airoha_STA.bin"

"NetworkAddress"=""

"BusType"=dword:00000000

"BusNumber"=dword:00000000

[HKEY_LOCAL_MACHINE\Comm\FSL1070NdisSD1\Parms\Tcpip]

"Subnetmask"=hex(7):\

32,35,35,2e,32,35,35,2e,32,35,35,2e,30,00,00,00,00

"IpAddress"=hex(7):\

30,2e,30,2e,30,2e,30,00,00,00,00

"UseZeroBroadcast"=dword:00000000

"EnableDHCP"=dword:00000001


附錄

SD卡與其他卡的對比

SDHC


Compatibility

* SDHC Host Products can use both SD and SDHC Memory Cards.
* SD Host Products can use only SD Memory Card 2GB or less.

Capacity (4GB SDHC Memory Card)

Still image JPEG
1,880 x 2,160 pixels, 6 Megapixels

Approx. 1,240 images

MPEG-2 Video
704 x 480 pixels, 5 Mbps, 30 fps

Approx. 1 hr 40 min

MPEG-4 Video
QVGA (320 x 240 pixels), 384 kbps, 15 fps

Approx. 19 hrs

Music (SD-Audio/AAC)
128 kbps

Approx. 68 hrs
(About 1,000 songs)

常用網站:

http://www.sdcard.com/

http://www.sdcard.org/