Linux Platform Device and Driver
從?Linux 2.6?起引入了一套新的驅(qū)動管理和注冊機制?:Platform_device?和?Platform_driver?。
Linux?中大部分的設備驅(qū)動,都可以使用這套機制?,?設備用?Platform_device?表示,驅(qū)動用?Platform_driver?進行注冊。
?
Linux platform driver?機制和傳統(tǒng)的?device driver?機制?(?通過?driver_register?函數(shù)進行注冊?)?相比,一個十分明顯的優(yōu)勢在于?platform?機制將設備本身的資源注冊進內(nèi)核,由內(nèi)核統(tǒng)一管理,在驅(qū)動程序中使用這些資源時通過?platform device?提供的標準接口進行申請并使用。這樣提高了驅(qū)動和資源管理的獨立性,并且擁有較好的可移植性和安全性?(?這些標準接口是安全的?)?。
?
Platform?機制的本身使用并不復雜,由兩部分組成:?platform_device?和?platfrom_driver?。
通過?Platform?機制開發(fā)發(fā)底層驅(qū)動的大致流程為?:??定義?platform_device?--->注冊?platform_device--->?定義?platform_driver?--->注冊platform_driver?。
?
首先要確認的就是設備的資源信息,例如設備的地址,中斷號等。
在?2.6?內(nèi)核中?platform?設備用結(jié)構(gòu)體?platform_device?來描述,該結(jié)構(gòu)體定義在?kernel/include/linux/platform_device.h?中,
struct platform_device {
??const char * name;
??u32??id;
??struct device dev;
??u32??num_resources;
??struct resource * resource;
};
?
該結(jié)構(gòu)一個重要的元素是?resource?,該元素存入了最為重要的設備資源信息,定義在?kernel/include/linux/ioport.h?中,
struct resource {
??const char *name;
??unsigned long start, end;
??unsigned long flags;
??struct resource *parent, *sibling, *child;
};
?
下面舉?s3c2410?平臺的?i2c?驅(qū)動作為例子來說明:
?
| /* arch/arm/mach-s3c2410/devs.c */? |
?
這里定義了兩組?resource?,它描述了一個?I2C?設備的資源,第?1?組描述了這個?I2C?設備所占用的總線地址范圍,?IORESOURCE_MEM?表示第?1?組描述的是內(nèi)存類型的資源信息,第?2?組描述了這個?I2C?設備的中斷號,?IORESOURCE_IRQ?表示第?2?組描述的是中斷資源信息。設備驅(qū)動會根據(jù)?flags?來獲取相應的資源信息。
?
有了?resource?信息,就可以定義?platform_device?了:
?
?
?
| struct?platform_device s3c_device_i2c?=?{? |
定義好了?platform_device?結(jié)構(gòu)體后就可以調(diào)用函數(shù)?platform_add_devices?向系統(tǒng)中添加該設備了,之后可以調(diào)用?platform_driver_register()?進行設備注冊。要注意的是,這里的?platform_device?設備的注冊過程必須在相應設備驅(qū)動加載之前被調(diào)用,即執(zhí)行?platform_driver_register?之前?,?原因是因為驅(qū)動注冊時需要匹配內(nèi)核中所以已注冊的設備名。
?
s3c2410-i2c?的?platform_device?是在系統(tǒng)啟動時,在?cpu.c?里的?s3c_arch_init()?函數(shù)里進行注冊的,這個函數(shù)申明為?arch_initcall(s3c_arch_init);會在系統(tǒng)初始化階段被調(diào)用。
arch_initcall?的優(yōu)先級高于?module_init?。所以會在?Platform?驅(qū)動注冊之前調(diào)用。?(?詳細參考?include/linux/init.h)
?
s3c_arch_init?函數(shù)如下:
| /* arch/arm/mach-3sc2410/cpu.c */? |
?
同時被注冊還有很多其他平臺的?platform_device?,詳細查看?arch/arm/mach-s3c2410/mach-smdk2410.c?里的?smdk2410_devices?結(jié)構(gòu)體。
?
?
驅(qū)動程序需要實現(xiàn)結(jié)構(gòu)體?struct platform_driver?,參考?drivers/i2c/busses
| /* device driver for platform bus bits */
|
?
在驅(qū)動初始化函數(shù)中調(diào)用函數(shù)?platform_driver_register()?注冊?platform_driver?,需要注意的是?s3c_device_i2c?結(jié)構(gòu)中?name?元素和s3c2410_i2c_driver?結(jié)構(gòu)中?driver.name?必須是相同的,這樣在?platform_driver_register()?注冊時會對所有已注冊的所有?platform_device?中的?name和當前注冊的?platform_driver?的?driver.name?進行比較,只有找到相同的名稱的?platfomr_device?才能注冊成功,當注冊成功時會調(diào)用?platform_driver結(jié)構(gòu)元素?probe?函數(shù)指針,這里就是?s3c24xx_i2c_probe,?當進入?probe?函數(shù)后,需要獲取設備的資源信息,常用獲取資源的函數(shù)主要是:
struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);
根據(jù)參數(shù)?type?所指定類型,例如?IORESOURCE_MEM?,來獲取指定的資源。
?
struct int platform_get_irq(struct platform_device *dev, unsigned int num);
獲取資源中的中斷號。
?
?
?
下面舉?s3c24xx_i2c_probe?函數(shù)分析?,?看看這些接口是怎么用的。
前面已經(jīng)講了,?s3c2410_i2c_driver?注冊成功后會調(diào)用?s3c24xx_i2c_probe?執(zhí)行,下面看代碼:
?
?
| /* drivers/i2c/busses/i2c-s3c2410.c */?
|
?
小思考:
那什么情況可以使用?platform driver?機制編寫驅(qū)動呢?
我的理解是只要和內(nèi)核本身運行依賴性不大的外圍設備?(?換句話說只要不在內(nèi)核運行所需的一個最小系統(tǒng)之內(nèi)的設備?),?相對獨立的?,?擁有各自獨自的資源(addresses and IRQs)?,?都可以用?platform_driver?實現(xiàn)。如:?lcd,usb,uart?等,都可以用?platfrom_driver?寫,而?timer,irq?等最小系統(tǒng)之內(nèi)的設備則最好不用?platfrom_driver?機制,實際上內(nèi)核實現(xiàn)也是這樣的。
總結(jié)
以上是生活随笔為你收集整理的Linux Platform Device and Driver的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux内核模块简介
- 下一篇: platform_driver_prob