2008年12月3日 星期三
linux kernel
linux Platform Driver 說明
從2.6版本開始引入了 platform 這個概念,在開發底層驅動程序時,首先要確認的就是設備的資源信息,例如設備的地址,在2.6內核中將每個設備的資源用結構 platform_device 來描述,該結構體定義在linux\ include\linux\platform_device.h 中
struct platform_device {
const char *name;
int id;
struct device dev;
u32 num_resources;
struct resource *resource;
};
該結構一個重要的元素是 resource,該元素存入了最為重要的設備資源信息,定義在linux\include\ linux\ioport.h 中
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
下面舉個例子來說明一下:
在 linux/arch/arm/plat-s3c24xx/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,
}
};
這裡定義了兩組 resource,它描述了一個 lcd 設備的資源,第1組描述了這個 lcd 設備所佔用的地址範圍,IORESOURCE_MEM 表示第 1 組描述的是內存類型的資源信息,第2組描述了這個 lcd 設備的中斷號,
IORESOURCE_IRQ 表示第 2 組描述的是中斷資源信息。設備驅動會根據 flags 來獲取相應的資源信息。
有了 resource 信息,就可以定義 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
}
};
EXPORT_SYMBOL( s3c_device_lcd );
將 s3c_device_lcd expoert 讓其他檔案使用
把 s3c_device_lcd 加到 platform_device 裡面 linux/arch/arm/mach-s3c2440/mach-smdk2440.c:
static struct platform_device *smdk2440_devices[ ] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};
有了 platform_device 就可以使用函數 platform_add_devices 向系統中添加該設備了,這裡的作法是
static void __init smdk2440_machine_init(void)
{
..............
platform_add_devices( smdk2440_devices, ARRAY_SIZE( smdk2440_devices ) );
............
}
MACHINE_START(S3C2440, "SMDK2440")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
驅動程序需要實現結構體 struct platform_driver,參考 linux\driver\video\s3c2410fb.c,
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_driver_register() 註冊 platform_driver
int __init s3c2410fb_init( void )
{
return platform_driver_register( &s3c2410fb_driver );
}
module_init( s3c2410fb_init );
需要注意的是: s3c_device_lcd 結構中 name 元素和 s3c2410fb_driver 結構中 driver 的 name 必須是相同的。
這樣在 platform_driver_register() 註冊時,會對所有已註冊的所有 platform_device 中的 name 和當前注冊的 platform_driver 的 driver->name 進行比較,只有找到相同的名稱的 platfomr_device 才能註冊成功,當註冊成功時會呼叫 platform_driver 結構元素 probe 函數指針,這裡就是 s3c2410fb_probe。
當進入 probe 函數後,需要獲取設備的資源信息,獲取資源的函數有:
struct resource * platform_get_resource( struct platform_device *dev, unsigned int type, unsigned int num );
根據參數 type 所指定類型,例如 IORESOURCE_MEM,來獲取指定的資源。
struct int platform_get_irq( struct platform_device *dev, unsigned int num );
獲取資源中的中斷號。
struct resource * platform_get_resource_byname( struct platform_device *dev, unsigned int type, char *name );
根據參數 name 所指定的名稱,來獲取指定的資源。
int platform_get_irq_byname( struct platform_device *dev, char *name );
根據參數 name 所指定的名稱,來獲取資源中的中斷號。
資料來源: http://top12345tw.blogspot.com/2008/03/linux-kernel-26243-platform-device.html
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言