一个现实的Linux 设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI 等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC 系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等确不依附于此类总线。基于这一背景,Linux 发明了一种虚拟的总线,称为platform 总线
SOC系统中集成的独立外设单元(I2C,LCD,SPI,RTC等)都被当作平台设备来处理,而它们本身是字符型设备。
从Linux2.6内核起,引入一套新的驱动管理和注册机制:platform_device 和 platform_driver 。Linux
中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用platform_driver 进行注册。
一.platform_device
在2.6内核中platform设备用结构体platform_device来描述,
该结构体定义在kernel\include\linux\platform_device.h中,
struct platform_device {
const char * name; //名
int id;
struct device dev; //内嵌设备
u32 num_resources; //资源个数
struct resource * resource; //资源结构体
struct platform_device_id *id_entry;
struct pdev_archdata archdata;
};
在使用platform设备之前需要注册和使用完之后需要注销:platform_driver 的注册与注销:
platform_driver_register()
platform_driver_unregister()
device文件模块代码:
1 #include <linux/init.h> 2 #include <linux/thread_info.h> 3 #include <linux/module.h> 4 #include <linux/sched.h> 5 #include <linux/errno.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> 8 #include <linux/slab.h> 9 #include <linux/input.h> 10 #include <linux/init.h> 11 #include <linux/serio.h> 12 #include <linux/delay.h> 13 #include <linux/clk.h> 14 #include <linux/miscdevice.h> 15 #include <linux/io.h> 16 #include <linux/ioport.h> 17 #include <linux/vmalloc.h> 18 #include <linux/dma-mapping.h> 19 #include <linux/export.h> 20 #include <linux/gfp.h> 21 #include <linux/cdev.h> 22 23 #include <asm/dma-mapping.h> 24 #include <asm/uaccess.h> 25 26 #include <linux/gpio.h> 27 #include <mach/gpio.h> 28 #include <plat/gpio-cfg.h> 29 #include <linux/completion.h> 30 #include <linux/miscdevice.h> 31 #include <linux/platform_device.h> 32 33 MODULE_LICENSE("GPL"); 34 MODULE_AUTHOR("bunfly"); 35 36 void test_release(struct device *dev) 37 { 38 } 39 40 struct platform_device test_device = { 41 .name = "test_platform", 42 .dev = { 43 .release = test_release, 44 }, 45 }; 46 47 int test_init(void) 48 { 49 printk("device had regiser!\n"); 50 return platform_device_register(&test_device); 51 //注册platform设备 52 } 53 54 void test_exit(void) 55 { 56 platform_device_unregister(&test_device); 57 } 58 59 module_init(test_init); 60 module_exit(test_exit); 61 ~ ~ ~ ~ ~
二.paltform_driver
platform_driver 结构体 在 include/linux/platform_device.h目录下
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; //内嵌设备驱动
struct platform_device_id *id_table; //驱动支持项
};
其中,比较重要的就是probe和remove函数。
driver代码如下:
1 #include <linux/init.h> 2 #include <linux/thread_info.h> 3 #include <linux/module.h> 4 #include <linux/sched.h> 5 #include <linux/errno.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> 8 #include <linux/slab.h> 9 #include <linux/input.h> 10 #include <linux/init.h> 11 #include <linux/serio.h> 12 #include <linux/delay.h> 13 #include <linux/clk.h> 14 #include <linux/miscdevice.h> 15 #include <linux/io.h> 16 #include <linux/ioport.h> 17 #include <linux/vmalloc.h> 18 #include <linux/dma-mapping.h> 19 #include <linux/export.h> 20 #include <linux/gfp.h> 21 #include <linux/cdev.h> 22 23 #include <asm/dma-mapping.h> 24 #include <asm/uaccess.h> 25 26 #include <linux/gpio.h> 27 #include <mach/gpio.h> 28 #include <plat/gpio-cfg.h> 29 #include <linux/completion.h> 30 #include <linux/miscdevice.h> 31 #include <linux/platform_device.h> 32 33 MODULE_LICENSE("GPL"); 34 MODULE_AUTHOR("bunfly"); 35 36 37 38 int myopen(struct inode *no, struct file *fp) 39 { 40 return 0; 41 } 42 43 int myrelease(struct inode *no, struct file *fp) 44 { 45 return 0; 46 } 47 48 49 int mywrite(struct file *fp, char *buf, int size, int *off) 50 { 51 52 printk("KERNEL: write....\n"); 53 54 return 0; 55 } 56 57 int myread(struct file *fp, char *buf, int size, int *off) 58 { 59 60 return 0; 61 } 62 63 struct file_operations myfops = { 64 .open = myopen, 65 .release = myrelease, 66 .write = mywrite, 67 .read = myread, 68 }; 69 70 struct miscdevice mymisc = { 71 .minor = 22, 72 .name = "mymisc", 73 .fops = &myfops, 74 }; 75 76 int test_probe(struct platform_device *pdev) 77 { 78 int ret = 0; 79 misc_register(&mymisc); 80 printk("match sucessed!\n"); 81 return 0; 82 } 83 //注册设备驱动 84 int test_remove(struct platform_device *pdev) 85 { 86 misc_deregister(&mymisc); 87 return 0; 88 } 89 90 struct platform_driver test_driver = { 91 .driver = { 92 .owner = THIS_MODULE, 93 .name = "test_platform", 94 }, 95 .probe = test_probe, 96 .remove = test_remove, 97 }; 98 int test_init(void) 99 { 100 return platform_driver_register(&test_driver); 101 //驱动注册 102 } 103 104 void test_exit(void) 105 { 106 platform_driver_unregister(&test_driver); 107 //驱动注销 108 } 109 110 module_init(test_init); 111 module_exit(test_exit); 112
三.platform 匹配
platform通过device和driver的name名字来匹配,所以,device和driver的name一定要一样才可以匹配成功,当匹配成功之后,就会到驱动的probe函数里面区探测设备;
起到的左右大概是:
在这里,我们先插入driver模块,再插入device模块,可以在
/sys/bus/platform/devices/目录下查看到设备的插入情况:
接下来:插入driver模块:
发现,插入驱动模块的时候,自动调用了probe函数,打印出了里面的一句话;
总结:
platform总线是虚拟总线,通过name,起到platform_device和platform_driver的匹配工作
,当匹配成功之后就会调用driver里面的probe函数添加设备!