1平台总线概述
1.1平台总线概述
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,是在linxu系统中最为重要的一种总线。
Linux系统中除了去支持这些实际的总线,USB总线,PCI总线,还支持虚拟总线,之前是自己创建总线并基于总线去创建驱动和设备。
linux提供了虚拟总线,平台总线(Platform bus)是linux为我们创建的虚拟总线,我们只需要去挂载驱动程序和设备。其同样具备总线的优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性
通过平台总线机制开发设备驱动的流程
创建和注册设备,将平台设备挂载到平台总线上
创建驱动
平台总线驱动与设备的匹配机制,前面自己创建总线,通过设备和驱动的名称匹配。platform大多数依然使用平台的设备和驱动名称相同进行匹配。
2.平台设备
平台设备使用struct platform_device来描述:
- struct platform_device {
- const char name; /设备名*/
- int id; /设备编号,配合设备名使用/
- struct device dev;
- u32 num_resources;
- struct resource resource; /设备资源*///基地址,中断号
- }
- struct resource {
- resource_size_t start;
- resource_size_t end;
- const char *name;
- unsigned long flags; /资源的类型///中断号,寄存器
- struct resource *parent, *sibling, *child;
- };
复制代码2.2注册平台设备
注册平台设备,使用函数:
int platform_device_register(struct platform_device *pdev) 4.范例程序
将按键程序进行改写,采用平台设备方式编写。
key_dev.c - #include<linux/module.h>
- #include<linux/init.h>
- #include<linux/platform_device.h>
- #define GPXCON 0x11000C20
- #include<linux/interrupt.h>
- #include<linux/irq.h>
- #define GPXCON 0x11000C20
- #define GPXDAT 0x11000C24
- MODULE_LICENSE("GPL");
- struct resource key_resource[]={
- [0]= {
- .start = GPXCON,
- .end = GPXCON+8,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EINT(9),
- .end = IRQ_EINT(10),
- .flags = IORESOURCE_IRQ,
- },
- };
- struct platform_device key_device = {
- .name = "my-key",
- .id = 0,
- .num_resources = 2,
- .resource = key_resource,
- };
- int keydev_init()
- {
- platform_device_register(&key_device);
- }
- void keydev_exit()
- {
- platform_device_unregister(&key_device);
- }
- module_init(keydev_init);
- module_exit(keydev_exit);
复制代码 nsmod key_dev.ko
ls /sys/bus/platform/device
平台设备已经挂载到平台总线上
现在将平台驱动创建和注册
3.平台驱动
平台总线设备只是起到找到设备的作用,当匹配成功再按设备类型进行相应的注册。
3.1平台驱动描述
平台驱动使用struct platform_driver 描述:
struct platform_driver {
int (probe)(struct platform_device );//加载驱动,总线会将平台设备和设备驱动进行匹配,匹配成功则驱动调用probe。
int (remove)(struct platform_device );当设备移出时,驱动调用
……
}
3.2平台驱动注册
int platform_driver_register(struct platform_driver *)
下面将一个杂项设备采用平台设备的方式改写
key_drv- #include<linux/module.h>
- #include<linux/init.h>
- #include<linux/miscdevice.h>
- #include<linux/fs.h>
- #include<linux/interrupt.h>
- #include<linux/io.h>
- #include<linux/irq.h>
- #include<linux/platform_device.h>
- #include<linux/sched.h>
- #include<linux/uaccess.h>
- #include<linux/vmalloc.h>
- #include<linux/slab.h>
- MODULE_LICENSE("GPL");
- unsigned int key_num = 0;
- wait_queue_head_t key_queue;
- struct work_struct *work1;
- struct resource *res_irq;
- struct resource *res_mem;
- struct timer_list key_timer;
- unsigned int *key_base;
- void work1_fun(struct work_struct *work)
- {
- mod_timer(&key_timer,jiffies+(HZ/10));
- }
- void key_timer_func(unsigned long data)
- {
- unsigned int key_val;
- key_val = readl(key_base+1)&(0x1<<1);
- if(key_val==0)
- {
- key_num = 1;
- }
- key_val = readl(key_base+1)&(0x1<<2);
- if(key_val==0)
- {
- key_num = 2;
- }
- wake_up(&key_queue);
- }
- irqreturn_t key_int(int irq,void *dev_id)
- {
- //检测是否发生了按键中断
- //清除按键中断
- //提交下半部
- schedule_work(work1);
- return 0;
- }
- void keyint()
- {
- writel(readl(key_base)&~(0xff<<4)|(0xff<<4),key_base);
- }
- ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
- {
- wait_event(key_queue,key_num);
- printk("in kernel :key num is %d\n",key_num);
- copy_to_user(buf, &key_num, 4);
- key_num = 0;
- return 4;
- }
- int key_open(struct inode *node,struct file *filp)
- {
- return 0;
- }
- struct file_operations key_fops =
- {
- .open = key_open,
- .read = key_read,
- };
- struct miscdevice key_miscdev = {
- .minor = 200,
- .name = "my-key",
- .fops = &key_fops,
- };
- int key_probe(struct platform_device *pdev)
- {
- int ret,size;
- ret = misc_register(&key_miscdev);
- if(ret!=0)
- printk("register fail!\n");
- res_irq = platform_get_resource(pdev,IORESOURCE_IRQ,0);
- request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"key",(void *)1);
- request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)2);
- size =res_mem->end -res_mem->start;
- key_base = ioremap(res_mem->start,size);//将物理基地址转化为虚拟地址
- keyint();
- work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);//创建工作
- INIT_WORK(work1,work1_fun);
- init_timer(&key_timer);//初始化定时器
- key_timer.function = key_timer_func;//添加超时函数
- add_timer(&key_timer);//向内核注册
- init_waitqueue_head(&key_queue);//初始化等待队列
- return ret;
- }
- int key_remove(struct platform_device *pdev)
- {
- free_irq(res_irq->start, 0);
- free_irq(res_irq->end,0);
- iounmap(key_base);
- misc_deregister(&key_miscdev);
- return 0;
- }
- struct platform_driver key_driver = {
- .probe =key_probe,
- .remove =key_remove,
- .driver = {
- .name = "my-key",
- },
- };
- static int button_init()
- {
- return platform_driver_register(&key_driver);
- }
- static void button_exit()
- {
- platform_driver_unregister(&key_driver);
- }
- module_init(button_init);
- module_exit(button_exit);
复制代码 insmod key_dev.ko
insmod key_drv.ko
mknod /dev/mykey c 10 200
./key_app
应用程序运行成功,平台总线设备模型对程序进行了优化。驱动程序可能包含几个层次,从总线方式看可以分为平台设备,从功能上看属于字符设备。USB从总线看设备上看,从功能上看有属于网络设备。直接放内核。
|