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 的頭像
BB

Welkin小窩

BB 發表在 痞客邦 留言(0) 人氣(8,702)