平台设备驱动之平台设备
平台设备驱动模型分为两个部分:平台设备(platform_device)和平台驱动(platform_driver)
设备层的核心数据结构struct platform_device (include\linux\platform_device.h)
1 struct platform_device { 2 const char * name; 3 int id; 4 struct device dev;//内嵌标准device,一般可以用来传递平台数据 5 u32 num_resources; 6 struct resource * resource;//设备占用资源的首地址 7 8 struct platform_device_id *id_entry; 9 10 /* arch specific additions */ 11 struct pdev_archdata archdata; 12 };
其中struct device用来实现设备模型,其中的*platform_data成员用途很大,一般称为平台数据指针,可以给平台驱动层传递任何需要的信息
结构如下:(include\linux\device.h)
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 semaphore sem; /* semaphore 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 struct dev_pm_info power; 20 21 #ifdef CONFIG_NUMA 22 int numa_node; /* NUMA node this device is close to */ 23 #endif 24 u64 *dma_mask; /* dma mask (if dma'able device) */ 25 u64 coherent_dma_mask;/* Like dma_mask, but for 26 alloc_coherent mappings as 27 not all hardware supports 28 64 bit addresses for consistent 29 allocations such descriptors. */ 30 31 struct device_dma_parameters *dma_parms; 32 33 struct list_head dma_pools; /* dma pools (if dma'ble) */ 34 35 struct dma_coherent_mem *dma_mem; /* internal for coherent mem 36 override */ 37 /* arch specific additions */ 38 struct dev_archdata archdata; 39 40 dev_t devt; /* dev_t, creates the sysfs "dev" */ 41 42 spinlock_t devres_lock; 43 struct list_head devres_head; 44 45 struct klist_node knode_class; 46 struct class *class; 47 const struct attribute_group **groups; /* optional groups */ 48 49 void (*release)(struct device *dev); 50 };
struct resource结构如下:(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;//资源类型,I/O,内存,中断,DMA 6 struct resource *parent, *sibling, *child; 7 }; 8 9 struct resource_list { 10 struct resource_list *next; 11 struct resource *res; 12 struct pci_dev *dev; 13 }; 14 15 /* 16 * IO resources have these defined flags. flags资源类型 17 */ 18 #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ 19 20 #define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */ 21 #define IORESOURCE_IO 0x00000100//I/O空间,一般在X86存在,ARM一般没有 22 #define IORESOURCE_MEM 0x00000200//内存空间,占用的是CPU 4G统一编址空间 23 #define IORESOURCE_IRQ 0x00000400//中断资源,中断号 24 #define IORESOURCE_DMA 0x00000800//DMA空间,占用的是CPU 4G统一编址空间
......
platform设备层API
int platform_device_register(struct platform_device *pdev)注册设备:0成功;负数,失败。(只注册单个平台设备)
void platform_device_unregister(struct platform_device *pdev)从内核中注销
int platform_add_devices(struct platform_device **devs, int num)内部还是调用platform_device_register(struct platform_device *pdev), 但是它可以注册多个平台设备结构。
以LED设备为例,讲述实现设备层的步骤:
1.分析LED设备占用的物理资源,定义struct resource
2.设计LED的平台数据结构,定义平台数据变量并填充
3.定义struct platform_device结构,填充name、resource、num_resources、id,并将2中定义的平台数据指针填充到dev下的platform_data中
4.在模块的初始化函数中,调用platform_device_register(struct platform_device *pdev)注册
5.在模块卸载函数中,调用platform_device_unregister(struct platform_device *pdev)注销
LED平台设备层程序代码如下:
1 #include<linux/module.h> 2 #include<linux/kernel.h> 3 #include<linux/init.h> 4 5 #include<linux/types.h> 6 #include<linux/interrupt.h> 7 #include<linux/platform_device.h> 8 9 /* 10 * 11 * 12 */ 13 struct led_info 14 { 15 unsigned int pin_bit;//定义的平台数据结构 16 }; 17 18 static struct led_info ledpos={ 19 .pin_bit=1<<5|1<<6|1<<7|1<<8, 20 }; 21 22 static struct resource led_resource[]={ 23 [0]={ 24 .start=0x56000010, 25 .end=0x56000010+16-1, 26 .flags=IORESOURCE_MEM, 27 }, 28 }; 29 30 static void led_release(struct device *dev) 31 { 32 printk("remove device\n"); 33 } 34 35 static struct platform_device led_dev={ 36 .name="s3c2440leds", 37 .id=-1, 38 // .num_resources=ARRAY_SIZE(led_resource), 39 .resource=led_resource, 40 .num_resources=ARRAY_SIZE(led_resource), 41 .dev={ 42 .release=led_release, 43 .platform_data=&ledpos, 44 }, 45 }; 46 47 static int leddev_init(void) 48 { 49 platform_device_register(&led_dev); 50 return 0; 51 } 52 53 static void leddev_exit(void) 54 { 55 platform_device_unregister(&led_dev); 56 } 57 58 module_init(leddev_init); 59 module_exit(leddev_exit); 60 61 MODULE_LICENSE("GPL");
注意:代码中43行的platform_data=&ledpos,
参考文献:《嵌入式Linux高级驱动教程》 电子工业出版社 深圳信盈达电子有限公司 陈志发 周中孝 李志超 编著