Linux2.6的內核中引入了一種新的設備驅動模型-平台(platform)設備驅動,平台設備驅動分為平台設備(platform_device)和平台驅動(platform_driver),平台設備的引入使得Linux設備驅動更加便於移植。
一、平台設備
平台設備結構體:
1 struct platform_device { 2 const char * name; /* 設備名 */ 3 int id; 4 struct device dev; /* 設備結構體 */ 5 u32 num_resources; /* 設備資源數量 */ 6 struct resource * resource; /* 設備資源 */ 7 8 const struct platform_device_id *id_entry; 9 10 /* arch specific additions */ 11 struct pdev_archdata archdata; 12 };
平台設備主要是提供設備資源和平台數據給平台驅動,resource為設備資源數組,類型有IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA、IORESOURCE_DMA。下面是一個網卡芯片DM9000的外設資源:
1 static struct resource dm9000_resources[] = { 2 [0] = { 3 .start = S3C64XX_PA_DM9000, 4 .end = S3C64XX_PA_DM9000 + 3, 5 .flags = IORESOURCE_MEM, 6 }, 7 [1] = { 8 .start = S3C64XX_PA_DM9000 + 4, 9 .end = S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1, 10 .flags = IORESOURCE_MEM, 11 }, 12 [2] = { 13 .start = IRQ_EINT(7), 14 .end = IRQ_EINT(7), 15 .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH, 16 }, 17 };
dm9000_resources里面有三個設備資源,第一個為IORESOURCE_MEM類型,指明了第一個資源內存的起始地址為S3C64XX_PA_DM9000結束地址為S3C64XX_PA_DM9000 + 3,第二個同樣為IORESOURCE_MEM類型,指明了第二個資源內存的起始地址為S3C64XX_PA_DM9000 + 4結束地址為S3C64XX_PA_DM9000 + S3C64XX_SZ_DM9000 - 1,第三個為IORESOURCE_IRQ類型,指明了中斷號為IRQ_EINT(7)。
1 struct device { 2 struct device *parent; 3 4 struct device_private *p; 5 6 struct kobject kobj; 7 const char *init_name; /* initial name of the device */ 8 struct device_type *type; 9 10 struct mutex mutex; /* mutex to synchronize calls to 11 * its driver. 12 */ 13 14 struct bus_type *bus; /* type of bus device is on */ 15 struct device_driver *driver; /* which driver has allocated this 16 device */ 17 void *platform_data; /* Platform specific data, device 18 core doesn't touch it */ 19 ... 20 };
struct device結構體里面有一個重要成員platform_data,它是平台設備和平台驅動進行數據傳遞的重要成員。
平台設備注冊:
1 int platform_device_register(struct platform_device *pdev);
platform_device_register()會對平台設備進行相應的初始化之后調用platform_device_register()函數把它添加到子系統中。
平台設備注銷:
1 void platform_device_unregister(struct platform_device *pdev);
platform_device_unregister()函數釋放設備資源之后從子系統中將其移除。
平台設備模板:
1 static struct resource xxx_resource = 2 { 3 [0] = 4 { 5 .start = ..., 6 .end = ..., 7 .flags = ..., 8 }, 9 [1] = 10 { 11 ... 12 } 13 ... 14 }; 15 16 static struct xxx_plat_data xxx_data = 17 { 18 ... 19 }; 20 21 static struct platform_device xxx_platform_device = 22 { 23 .name = NAME, 24 .num_resources = ARRAY_SIZE(xxx_resource), 25 .resource = xxx_resource, 26 .dev = 27 { 28 .platform_data = &xxx_data, 29 } 30 }; 31 32 static int __init xxx_device_init(void) 33 { 34 ... 35 /* 注冊平台設備 */ 36 platform_device_register(&xxx_platform_device); 37 ... 38 } 39 40 static void __exit xxx_device_exit(void) 41 { 42 ... 43 /* 注銷平台設備 */ 44 platform_device_unregister(&xxx_platform_device); 45 ... 46 }
二、平台驅動
平台驅動結構體:
1 struct platform_driver { 2 int (*probe)(struct platform_device *); 3 int (*remove)(struct platform_device *); 4 void (*shutdown)(struct platform_device *); 5 int (*suspend)(struct platform_device *, pm_message_t state); 6 int (*resume)(struct platform_device *); 7 struct device_driver driver; 8 const struct platform_device_id *id_table; 9 };
平台驅動結構體driver成員里面的name必須與平台設備結構體里面的name成員一致,在系統注冊一個設備的時候,會通過設備結構體里面的name成員和平台驅動driver里面的name成員匹配,當匹配成功則調用平台驅動的probe函數,
通常在probe函數中獲取平台設備的資源和私有數據並進行設備的初始化。
獲取設備資源:
1 struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);
platform_get_resource()函數用於獲取平台設備的資源,dev為要平台設備,type為平台設備資源類型,num為平台資源號(比如同一個資源有兩個則資源號為0,1)。
平台驅動注冊:
1 int platform_driver_register(struct platform_driver *drv);
platform_driver_register()函數完成平台驅動的注冊,在驅動模塊加載時調用。
平台驅動注銷:
1 void platform_driver_unregister(struct platform_driver *drv);
platform_driver_unregister()函數完成平台驅動的注銷,在驅動模塊卸載時調用。
平台驅動模板:
1 static int __devinit xxx_probe(struct platform_device *pdev) 2 { 3 struct xxx_plat_data *pdata = pdev->dev.platform_data; /* 獲取私有數據 */ 4 platform_get_resource(pdev,xxx,x); /* 獲取設備資源 */ 5 ... 6 } 7 8 static struct platform_driver xxx_platform_driver = 9 { 10 .probe = xxx_probe, 11 .remove = __devexit_p(xxx_remove), 12 .driver = 13 { 14 .name = NAME, /* 跟平台設備名一致 */ 15 ... 16 }, 17 ... 18 }; 19 20 static int __init xxx_driver_init(void) 21 { 22 ... 23 /* 驅動注冊 */ 24 platform_driver_register(&xxx_platform_driver); 25 ... 26 } 27 28 static void __exit xxx_driver_exit(void) 29 { 30 ... 31 /* 驅動注銷 */ 32 platform_driver_unregister(&xxx_platform_driver); 33 ... 34 }
