【linux设备模型】之platform设备驱动
2014-04-22 13:46
447 查看
一、platform总线、设备和驱动platform是一种虚拟总线,相应的设备称为platform_device,相应的驱动称为platform_driver。platform_device定义在<linux/platform_device.h>中:
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是platform驱动用到的资源,它是定义在<include/linux/ioport.h>中:
1 struct resource { 2 resource_size_t start; 3 resource_size_t end; 4 const char *name; 5 unsigned long flags; 6 struct resource *parent, *sibling, *child; 7 };
platform_driver定义在<linux/platform_device.h>中:
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 };
系统中为platform总线定义了一个实例platform_bus_type,在<linux/platform_device.h>进行了声明:
extern struct bus_type platform_bus_type; 定义在drivers/base/platform.c中:
1 struct bus_type platform_bus_type = { 2 .name = "platform", 3 .dev_attrs = platform_dev_attrs, 4 .match = platform_match, 5 .uevent = platform_uevent, 6 .pm = &platform_dev_pm_ops, 7 }; 8 EXPORT_SYMBOL_GPL(platform_bus_type);
二、具体实现
1、platform_match函数的实现(定义在drivers/base/platform.c中):
1 static const struct platform_device_id *platform_match_id( 2 const struct platform_device_id *id, 3 struct platform_device *pdev) 4 { 5 while (id->name[0]) { 6 if (strcmp(pdev->name, id->name) == 0) { 7 pdev->id_entry = id; 8 return id; 9 } 10 id++; 11 } 12 return NULL; 13 } 14 15 /** 16 * platform_match - bind platform device to platform driver. 17 * @dev: device. 18 * @drv: driver. 19 * 20 * Platform device IDs are assumed to be encoded like this: 21 * "<name><instance>", where <name> is a short description of the type of 22 * device, like "pci" or "floppy", and <instance> is the enumerated 23 * instance of the device, like '0' or '42'. Driver IDs are simply 24 * "<name>". So, extract the <name> from the platform_device structure, 25 * and compare it against the name of the driver. Return whether they match 26 * or not. 27 */ 28 static int platform_match(struct device *dev, struct device_driver *drv) 29 { 30 struct platform_device *pdev = to_platform_device(dev); 31 struct platform_driver *pdrv = to_platform_driver(drv); 32 33 /* Attempt an OF style match first */ 34 if (of_driver_match_device(dev, drv)) 35 return 1; 36 37 /* Then try to match against the id table */ 38 if (pdrv->id_table) 39 return platform_match_id(pdrv->id_table, pdev) != NULL; 40 41 /* fall-back to driver name match */ 42 return (strcmp(pdev->name, drv->name) == 0); 43 }是通过device的name和driver的name进行匹配的。
2、platform_device的定义和注册
(platform_add_devices定义在drivers/base/platform.c中)
1 /** 2 * platform_add_devices - add a numbers of platform devices 3 * @devs: array of platform devices to add 4 * @num: number of platform devices in array 5 */ 6 int platform_add_devices(struct platform_device **devs, int num) 7 { 8 int i, ret = 0; 9 10 for (i = 0; i < num; i++) { 11 ret = platform_device_register(devs[i]); 12 if (ret) { 13 while (--i >= 0) 14 platform_device_unregister(devs[i]); 15 break; 16 } 17 } 18 19 return ret; 20 } 21 EXPORT_SYMBOL_GPL(platform_add_devices);
对于一个指定的板子来说,比如对于ldd6410的globalfifo驱动来说,要在mach-ldd6410.c中定义platform_device globalfifo_device,并将globalfifo_device放入ldd6410_devices数组中,代码如下所示。3、platform_driver的操作
platform_driver的定义和注册在相应驱动文件中实现,下面是《linux驱动开发详解》一书中globalfifo的例子的部分代码:
4、platform设备资源和数据
(1)、resource的定义(<linux/ioport.h>)
1 struct resource {
2 resource_size_t start; 3 resource_size_t end; 4 const char *name; 5 unsigned long flags; 6 struct resource *parent, *sibling, *child; 7 };
当flags是IORESOURCE_MEM时,start和end分别是资源的起始地址和结束地址;
当flags是IORESOURCE_IRQ时,start和end分别是资源的起始中断号和结束中断号;
#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ #define IORESOURCE_IO 0x00000100 #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 #define IORESOURCE_BUS 0x00001000对于同种类型的资源可以有两份或多份。
(2)、获得资源
对resource的定义通常在板文件中,而驱动通过platform_get_resource获得资源(driver/base/platform.c):
1 /** 2 * platform_get_resource - get a resource for a device 3 * @dev: platform device 4 * @type: resource type 5 * @num: resource index 6 */ 7 struct resource *platform_get_resource(struct platform_device *dev, 8 unsigned int type, unsigned int num) 9 { 10 int i; 11 12 for (i = 0; i < dev->num_resources; i++) { 13 struct resource *r = &dev->resource[i]; 14 15 if (type == resource_type(r) && num-- == 0) 16 return r; 17 } 18 return NULL; 19 } 20 EXPORT_SYMBOL_GPL(platform_get_resource);
三、platform驱动的一个例子
以linux-2.6.38内核的dm9000驱动为例说明平台驱动的定义和资源获取。
1、platform_device和resource的定义(mach-mini6410.c)
1 /* DM9000AEP 10/100 ethernet controller */2 /*dm9000的资源*/3 static struct resource mini6410_dm9k_resource[] = {4 [0] = {5 .start = S3C64XX_PA_XM0CSN1,6 .end = S3C64XX_PA_XM0CSN1 + 1,7 .flags = IORESOURCE_MEM8 },9 [1] = {10 .start = S3C64XX_PA_XM0CSN1 + 4,11 .end = S3C64XX_PA_XM0CSN1 + 5,12 .flags = IORESOURCE_MEM13 },14 [2] = {15 .start = S3C_EINT(7),16 .end = S3C_EINT(7),17 .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL18 }19 };20 /*dm9000_plat_data定义在<linux/dm9000.h>*/21 static struct dm9000_plat_data mini6410_dm9k_pdata = {22 .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),23 };2425 static struct platform_device mini6410_device_eth = {26 .name = "dm9000",27 .id = -1,28 .num_resources = ARRAY_SIZE(mini6410_dm9k_resource),29 .resource = mini6410_dm9k_resource,30 .dev = {31 .platform_data = &mini6410_dm9k_pdata,32 },33 };3435 /*所有的设备存放在这个数组里,最后通过platform_add_devices进行注册*/36 static struct platform_device *mini6410_devices[] __initdata = {37 &mini6410_device_eth,38 &s3c_device_hsmmc0,39 &s3c_device_hsmmc1,40 &s3c_device_ohci,41 &s3c_device_nand,42 &s3c_device_fb,43 &mini6410_lcd_powerdev,44 &s3c_device_adc,45 &s3c_device_ts,46 };
2、platform_driver的定义和注册(dm9000.c)
1 static struct platform_driver dm9000_driver = {2 .driver = {3 .name = "dm9000",4 .owner = THIS_MODULE,5 .pm = &dm9000_drv_pm_ops,6 },7 .probe = dm9000_probe,8 .remove = __devexit_p(dm9000_drv_remove),9 };1011 static int __init12 dm9000_init(void)13 {14 printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);1516 return platform_driver_register(&dm9000_driver);17 }1819 static void __exit20 dm9000_cleanup(void)21 {22 platform_driver_unregister(&dm9000_driver);23 }
dm9000驱动获得定义在板文件中的platform_data的方法:
struct platform_device *pdev
struct dm9000_plat_data *pdata = pdev->dev.platform_data;db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
platform_get_resource函数定义在drivers/base/platform.c中:
1 /** 2 * platform_get_resource - get a resource for a device 3 * @dev: platform device 4 * @type: resource type 5 * @num: resource index 6 */ 7 struct resource *platform_get_resource(struct platform_device *dev, 8 unsigned int type, unsigned int num) 9 { 10 int i; 11 12 for (i = 0; i < dev->num_resources; i++) { 13 struct resource *r = &dev->resource[i]; 14 15 if (type == resource_type(r) && num-- == 0) 16 return r; 17 } 18 return NULL; 19 } 20 EXPORT_SYMBOL_GPL(platform_get_resource);参考:《linux驱动开发详解》
相关文章推荐
- Linux驱动之设备模型(9)-platform
- Linux驱动之设备模型(9)-platform
- Linux 内核--总线设备驱动模型(字符/块/网络设备 && platform设备)
- linux设备总线驱动模型 之 platform总线驱动
- Linux驱动设备模型之Platform
- linux驱动中platform设备驱动模型
- Linux驱动之设备模型(9)-platform
- Linux平台设备驱动模型(platform)-以tq2440的按键为例
- [Linux] 内核中 SPI 设备驱动模型(Platform设备驱动方式)
- Linux驱动(七)设备模型介绍以及platform设备驱动
- Linux驱动之设备模型(9)-platform
- 【linux设备模型】之platform设备驱动
- Linux驱动之设备模型(9)-platform
- linux设备总线驱动模型 之 platform总线驱动
- Linux驱动之设备模型(9)-platform
- Linux的总线、设备、驱动模型
- 驱动该如何入门 关于file_operations和Linux设备模型
- LINUX设备驱动之设备模型五--device&driver&bus(三)
- Linux平台设备驱动 platform_device
- Linux内核大讲堂 (一) 设备驱动的基石驱动模型(7)