platform_driver_register
platform_driver_register()是來註冊設備的驅動程序
platform_device_register()是來註冊設備硬件,告訴kernel,當前有什麼裝置。
當某個裝置連結後,必須在device和driver的兩端上都有對應的東西才算是匹配上,
並且開始使用driver的probe等函數進行硬件初始化工作。

以下來自:http://blog.21ic.com/user1/5823/archives/2009/60264.html
二、s3c2410fb_probe 函數分析
2.1
驅動的入口點
擺在面前的第一個問題相信應該是,這個函數是從那裡開始運行的。這裡就應該從long long ago 開始了,
打開 drivers/video/s3c2410fb.c 文件,然後找到 s3c2410fb_init 函數,先不管它裡面是怎麼回事,
再把目光下移就會看到這樣一串字符串module_init(s3c2410fb_init),鬱悶,這和S3C2410fb_probe
有啥關係嘛?
這個問題問的好!不要著急慢慢往下面走。先摸摸 module_init 是何方神聖再說,
網站上面一搜,原來 module_init 老家在 include/linux/init.h,它居然還有兩重身份,其原型如下:
#ifndef MODULE
……
#define module_init(x) __initcall(x);
……
#else
……
#define module_init(initfn) \
static inline initcall_t __inittest(void ) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#c)));
……
#endif
從上面可以看出,module_init 到底用哪個,就取決於MODULE了,那麼MODULE的作用是什麼呢?
我們知道Linux可以將設備當作模塊動態加進內核,也可以直接編譯進內核。
說到這里大概有點明白MODULE的作用了,它就是要控制一個驅動加入內核的方式。
定義了MODULE就表示將設備當作模塊動態加入。

說了這麼多,就是要說明只要用module_init宣告了一個函數,該函數就會被Linux內核在適當的時機運行。
這些時機包括在linux啟動的do_initcalls()時調用(設備被編譯進內核),或者在動態插入時調用。
回到上面的module_init(s3c2410fb_init)處,
也就是說內核與buffer驅動發生關係的第一次地點是在s3c2410fb_init函數,該函數就只有一條語句

platform_driver_register (s3c2410fb_driver);

2.2 platform 是何許人也
platform 可以理解成一種設備類型,就像字符設備、塊設備和網絡設備一樣,而LCD就屬於這種設備。
對於platform設備,Linux為應用添加了相關的接口,在這裡只是簡單的說說這些接口的用法,
而不去深入探討這些接口的實現(我現在還沒有那個能力呢!)。
說到這裡,馬上就有個問題湧上心頭了,那就是Linux提供了那些接口呢?
如果我們需要添加這些設備應該怎麼樣做呢?
platform 中的相關數據結構是應用的關鍵,為了向內核添加一個platform設備,
程序員應該填寫兩個數據結構platform_device和platform_driver,
這兩個數據結構的定義都可以在include/linux/platform_device.h文件中找到。

看看LCD驅動是怎麼做的,第一步是填寫platform_device,
在arch/arm/mach-s3c2410/devs.c可以找到填寫platform_device的代碼,如下:
static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE (s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};

platform_device 的一項重要成員是 resource,在上面的代碼中此域被賦予了s3c_lcd_resource
,s3c_lcd_resource也可以在arch/arm/mach-s3c2410/devs.c找到。
static struct resource s3c_lcd_resource[] = {
[0] = {
.start = S3C24XX_PA_LCD,
.end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
. flags = IORESOURCE_IRQ,
}
};
struct resource 結構實際上描述了該設備佔用的硬件資源(如地址空間,中斷號等),
s3c_lcd_resource 描述了內存空間和中斷分配情況。
最後在smdk2410_devices指針數組中添加上 s3c_device_lcd 的大名,
Linux在初始化platform 的時候就知道系統中有個 s3c_device_lcd 設備了。

這裡只是向Linux描述了設備需要的資源情況,不代表內核會給這些資源的。
如果設備要得到這些設備還需要在自己的初始化函數中去申請。

static struct platform_device *smdk2410_devices[] __initdata = {
s3c_device_usb,
s3c_device_lcd,
s3c_device_wdt,
s3c_device_i2c,
s3c_device_iis,
s3c_device_ts,
};
說到這裡,應該說向Linux
添加一個platform
設備應該很容易。

2.3 回到s3c2410fb_init
回到 s3c2410fb_init 函數所調用 platform_driver_register(s3c2410fb_driver)。
簡單地說 platform_driver_register 要將向內核註冊一個 platform 設備的驅動,
這裡是要註冊 LCD 設備。

上面說過 platform 有兩個重要的數據結構 platform_device 和 platform_driver,
現在是應該提到後者的時候了。

platform_driver 也在include/linux/platform_device.h中,它的各個成員應該再明白不過來吧!
在LCD驅動程序(drivers/video/s3c2410fb.c)中定義了填充了platform_driver這個結構,如下:
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
.name = "s3c2410-lcd",
.owner = THIS_MODULE,
},
};

可以看到該 platform 設備的驅動函數有s3c2410fb_probe、s3c2410fb_remove等等。
通過 platform_driver_register 函數註冊該設備的過程中,它會回叩.probe函數,
說到這裡也就明白 s3c2410fb_probe 是在 platform_driver_registe 中回叩的。

BB 發表在 痞客邦 PIXNET 留言(0) 人氣()