标签:
总线驱动设备模型:
1. 总线设备驱动模型概述
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求,为适应这宗形势的需求,从linux2.6内核开始提供了全新的设备模型
2. 总线
2.1 描述结构
2.2 注册
2.3 注销
void bus_unregister(struct bus_type *bus)
代码例程:
bus.c
#include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h> #include<linux/device.h> MODULE_LICENSE("GPL"); int my_match(struct device *dev, struct device_driver *drv) { return 0; } struct bus_type my_bus_type = { .name = "my_bus", .match = my_match, }; int my_bus_init(void) { int ret; ret = bus_register(&my_bus_type); return ret; } void my_bus_exit(void) { bus_unregister(&my_bus_type); } module_init(my_bus_init); module_exit(my_bus_exit);
下面向上面的my_bus总线上挂载一个驱动!
3. 驱动
3.1 描述结构
3.2 注册
int drvier_register(struct device *dev)
3.3 注销
void drever_unregister(struct device_driver *drv)
4. 设备
4.1 设备的描述
4.2 设备的注册
int device_register(struct device *dev)
4.3 设备的注销
void device_unregister(struct device *dev)
driver.c
#include<linux/module.h> #include<linux/init.h> #include<linux/device.h> #include<linux/kernel.h> MODULE_LICENSE("GPL"); extern struct bus_type my_bus_type; int my_probe(struct device *dev) { printk(KERN_WARNING"driver found the device!!!\n"); return 0; } struct device_driver my_driver = { .name = "my_dev", .bus = &my_bus_type, .probe = my_probe, //当找到这个设备时将调用这个函数 }; int my_device_init(void) { int ret; ret = driver_register(&my_driver);//注册一个驱动 return 0; } void my_device_exit(void) { driver_unregister(&my_driver); } module_init(my_device_init); module_exit(my_device_exit);Makefile
obj-m := bus.o device.o KDIR := /home/kernel/linux-ok6410 all: make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
下面再在总线上挂载一个设备!
device.c
#include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> MODULE_LICENSE("GPL"); extern struct bus_type my_bus_type; struct device my_dev = { .init_name = "my_dev",//和驱动名字一样 .bus = &my_bus_type, }; int my_device_init(void) { int ret; ret = device_register(&my_dev); return ret; } void my_device_exit(void) { device_unregister(&my_dev); } module_init(my_device_init); module_exit(my_device_exit);
#include<linux/module.h> #include<linux/init.h> #include<linux/device.h> #include<linux/kernel.h> MODULE_LICENSE("GPL"); extern struct bus_type my_bus_type; int my_probe(struct device *dev) { printk(KERN_WARNING"driver found the device!!!\n"); return 0; } struct device_driver my_driver = { .name = "my_dev", .bus = &my_bus_type, .probe = my_probe, //当找到这个设备时将调用这个函数 }; int my_device_init(void) { int ret; ret = driver_register(&my_driver);//注册一个驱动 return 0; } void my_device_exit(void) { driver_unregister(&my_driver); } module_init(my_device_init); module_exit(my_device_exit);bus.c
#include<linux/module.h> #include<linux/init.h> #include<linux/kernel.h> #include<linux/device.h> MODULE_LICENSE("GPL"); int my_match(struct device *dev, struct device_driver *drv) { return !strncmp(dev->kobj.name,drv->name,strlen(drv->name)); } struct bus_type my_bus_type = { .name = "my_bus", .match = my_match, }; EXPORT_SYMBOL(my_bus_type);//输出符号 另一device.c要用到 int my_bus_init(void) { int ret; ret = bus_register(&my_bus_type); return ret; } void my_bus_exit(void) { bus_unregister(&my_bus_type); } module_init(my_bus_init); module_exit(my_bus_exit);
obj-m := bus.o driver.o device.o KDIR := /home/kernel/linux-ok6410 all: make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
平台总线驱动设计:
1. 平台总线概述
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。
2. 平台设备
注册平台设备,使用函数:
int platform_device_register(struct platform_device *pdev)
3. 平台驱动
平台驱动注册使用函数:
int platform_driver_register(struct platform_driver *)
结合上面的基础知识,将案件驱动修改为平台驱动模式!
1. 平台设备注册
2. 平台按键驱动设计
key_dev.c
#include<linux/init.h> #include<linux/module.h> #include<linux/platform_device.h> #include<linux/interrupt.h> MODULE_LICENSE("GPL"); #define GPNCON 0x7F008830 static struct resource key_resource[] = { //定义按键资源 [0] = { .start = GPNCON, .end = GPNCON + 8, .flags = IORESOURCE_MEM,//内存地址资源 }, [1] = { .start = S3C_EINT(0),//按键中断资源 .end = S3C_EINT(5), .flags = IORESOURCE_IRQ,//内存地址资源 }, }; struct platform_device key_device = { .name = "my_key", .id = 0, .num_resources = ARRAY_SIZE(key_resource), .resource = key_resource, }; int keydri_init(void) { platform_device_register(&key_device); return 0; } void keydri_exit(void) { platform_device_unregister(&key_device); } module_init(keydri_init); module_exit(keydri_exit);编译运行截图:
key_dri.c
#include <linux/module.h> #include <linux/init.h> #include <linux/miscdevice.h> /* for struct miscdevice*/ #include <linux/interrupt.h> #include <linux/fs.h> /* for iormap */ #include <linux/io.h> #include <linux/slab.h> /* for kmalloc */ #include<linux/uaccess.h> /* for copy_to_usr */ #include <linux/platform_device.h> //#define GPNCON 0x7F008830 //#define GPNDAT 0x7F008834 MODULE_LICENSE("GPL"); unsigned int *key_base; struct work_struct *work1;//定义一项工作 struct timer_list key_timer; //定义一个定时器key_timer unsigned int key_num; struct resource *res_mem; struct resource *res_irq; int size; void work1_func(struct work_struct *work) { //启动定时器 jiffies是全局变量,用来表示当前系统时间 1S=1000个滴答数 mod_timer(&key_timer,jiffies + HZ/10); //设置100ms超时 1HZ=1S } void key_timer_func(unsigned long data) { unsigned int key_val; key_val = readw(key_base + 1)&0x01; //只读取最后一位 if(key_val == 0) { printk(KERN_WARNING"OK6410 key1 down!\n"); key_num = 0; } key_val = readw(key_base + 1)&0x20; //只读取最后一位 if(key_val == 0) { printk(KERN_WARNING"OK6410 key6 down!\n"); key_num = 6; } } irqreturn_t key_int(int irq, void *dev_id) { //1. 检测是否发生了按键中断 这里可以暂时不做,因为这里没有使用共享中断 //2. 清除已经发生的按键中断 这个是指硬件内部处理,按键CPU内部不需要做处理 //3. 提交下半部 schedule_work(work1); //return 0; return IRQ_HANDLED; } void key_hw_init(void) //按键硬件初始化部分 { //unsigned int *gpio_config; unsigned short data; //gpio_config = ioremap(GPNCON, 4);//将物理地址转化为虚拟地址 data = readw(key_base); data &= ~0b110000000011; //先清零 data |= 0b100000000010; //后两位设置成0b10 writew(data, key_base); //gpio_data = ioremap(GPNDAT, 4);//将物理地址转化为虚拟地址 printk(KERN_WARNING"init ...!\n"); } int key_open(struct inode *node, struct file *filp) { printk(KERN_WARNING"open ...!\n"); return 0; } ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) { //将key_value值返回给用户空间 printk(KERN_WARNING"in kernel :key num is %d\n",key_num); copy_to_user(buf, &key_num, 4); //buf为用户空间传过来的地址 return 4; } struct file_operations key_fops = { .open = key_open, .read = key_read, }; struct miscdevice key_miscdev = //定义一个misdevice结构 { .minor = 200, .name = "6410key", .fops = &key_fops,//这里key_fops是一个struct file_operations结构 }; static int __devinit key_probe(struct platform_device *pdev) { misc_register(&key_miscdev);//注册一个混杂设备驱动设备 res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //取出中断资源 request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"my_key",(void *)1); request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"my_key",(void *)6); res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);//取出地址资源 size = res_mem->end - res_mem->start + 1; key_base = ioremap(res_mem->start,size); key_hw_init(); work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); INIT_WORK(work1 , work1_func ); //初始化定时器 init_timer(&key_timer); key_timer.function = key_timer_func; //将定义的函数赋值给函数指针 //注册定时器 add_timer(&key_timer); return 0; } static int key_remove(struct platform_device *device) { free_irq(S3C_EINT(0), 0);//注销中断 这里irqnumber参数暂时用一个变量来表示(中断号) free_irq(S3C_EINT(5), 0);//注销中断 这里irqnumber参数暂时用一个变量来表示(中断号) misc_deregister(&key_miscdev);//注销一个混杂设备驱动 return 0; } struct platform_driver key_driver = { .driver = { .name = "my_key", .owner = THIS_MODULE, }, .probe = key_probe, .remove = key_remove, }; static int key_init(void) { return platform_driver_register(&key_driver); } static void key_exit(void) { platform_driver_register(&key_driver);//卸载平台驱动 printk(KERN_WARNING"key up!"); } module_init(key_init); module_exit(key_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("key driver");Makefile
obj-m := key_dev.o key_dri.o KDIR := /home/kernel/linux-ok6410 all: make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order编译运行效果截图:
按下按键1或者按下按键6 可以看到驱动程序打印出如下信息! 这里或者创建设备文件,然后用前面博客里面的应用程序来测试也是一样的!
标签:
原文地址:http://blog.csdn.net/coding__madman/article/details/51428400