很多设备虽然用途不同,但其接口定义都是一样的 ,因此很多时候我们不需要去为每个设备都写一个驱动 。
因此 Linux 2.6 及以后的内核中虚拟出来的一条总线 ,即 platform 总线。
平台总线模型将设备代码和驱动代码分离, 将和硬件设备相关的都放到 device.c 文件里面,驱动部分代码都放到 driver.c 文件里面。
这样做的好处是, 实现了此类设备和驱动的分离, 增强设备驱动的可移植性。
在 platform 平台下用 platform_device 这个结构体表示 platform 设备。
如果内核支持设备树的话就不用使用 platform_device 来描述设备了, 因为改用设备树去描述了 platform_device。
具体定义在内核源码 /include/linux/platform_device.h
里面, 结构体内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct platform_device { const char *name; int id; bool id_auto; struct device dev ; u32 num_resources; struct resource *resource ; const struct platform_device_id *id_entry ; char *driver_override; struct mfd_cell *mfd_cell ; struct pdev_archdata archdata ; };
✈ resource 结构体 resource 结构体内容如下:
1 2 3 4 5 6 7 struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; struct resource *parent , *sibling , *child ; };
可选的资源类型都定义在了文件 include/linux/ioport.h
里面, 如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 #define IORESOURCE_BITS 0x000000ff #define IORESOURCE_TYPE_BITS 0x00001f00 #define IORESOURCE_IO 0x00000100 #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_REG 0x00000300 #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 #define IORESOURCE_BUS 0x00001000 #define IORESOURCE_PCI_FIXED (1<<4)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> void device_release (struct device *dev) { printk("device_release \n" ); } struct resource device_res [] = { [0 ] = { .start = 0x020AC000 , .end = 0x020AC003 , .flags = IORESOURCE_MEM, .name = "GPIO5_DR" , } }; struct platform_device platform_device = { .name = "platform_test" , .id = -1 , .resource = device_res, .num_resources = ARRAY_SIZE(device_res), .dev = { .release = device_release } }; static int device_init (void ) { platform_device_register(&platform_device); printk("platform_device_register ok \n" ); return 0 ; } static void device_exit (void ) { platform_device_unregister(&platform_device); printk("gooodbye! \n" ); } module_init(device_init); module_exit(device_exit); MODULE_LICENSE("GPL" );
在 Linux 内核中, 用 platform_driver 结构体表示 platform 驱动 。
此结构体定义在文件 include/linux/platform_device.h
中, 内容如下:
1 2 3 4 5 6 7 8 9 10 struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver ; const struct platform_device_id *id_table ; bool prevent_deferred_probe; };
✈ device_driver 结构体 device_driver 结构体定义在 include/linux/device.h
, device_driver 结构体内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct device_driver { const char *name; struct bus_type *bus ; struct module *owner ; const char *mod_name; bool suppress_bind_attrs; const struct of_device_id *of_match_table ; const struct acpi_device_id *acpi_match_table ; int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *dev); int (*suspend) (struct device *dev, pm_message_t state); int (*resume) (struct device *dev); const struct attribute_group **groups ; const struct dev_pm_ops *pm ; struct driver_private *p ; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> int driver_probe (struct platform_device *pdev) { struct resource *res ; printk("driver_probe\n" ); printk("beep_res is %s\n" , pdev->resource[0 ].name); res = platform_get_resource(pdev, IORESOURCE_MEM, 0 ); if (res == NULL ) { printk("platform_get_resource is error\n" ); return -EBUSY; } printk("beep_res start is 0x%x \n" , res->start); printk("beep_res end is 0x%x \n" , res->end); return 0 ; } int driver_remove (struct platform_device *pdev) { printk("driver_remove\n" ); return 0 ; } struct platform_driver platform_driver = { .probe = driver_probe, .remove = driver_remove, .driver = { .owner = THIS_MODULE, .name = "platform_test" } }; static int platform_driver_init (void ) { int ret = 0 ; ret = platform_driver_register(&platform_driver); if (ret < 0 ) { printk("platform_driver_register error \n" ); } printk("platform_driver_register ok \n" ); return 0 ; } static void platform_driver_exit (void ) { platform_driver_unregister(&platform_driver); printk("gooodbye! \n" ); } module_init(platform_driver_init); module_exit(platform_driver_exit); MODULE_LICENSE("GPL" );