驱动的分层设计——按键点灯
Posted zhu-g5may
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了驱动的分层设计——按键点灯相关的知识,希望对你有一定的参考价值。
源码附带注释:
key_dev.c
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/delay.h> 6 #include <linux/irq.h> 7 #include <asm/irq.h> 8 #include <asm/io.h> 9 #include <linux/cdev.h> 10 #include <linux/device.h> 11 #include <linux/interrupt.h> 12 #include <linux/input.h> 13 #include <linux/bitmap.h> 14 #include <asm/gpio.h> 15 #include <linux/platform_device.h> 16 17 /*记录硬件相关资源*/ 18 static struct resource key_rsrc[] = { 19 [0] = { /*内存空间*/ 20 .start = 0x56000050, 21 .end = 0x56000050 + 8 -1, 22 .flags = IORESOURCE_MEM 23 }, 24 [1] = { 25 /*GPF4,5,6*/ 26 .start = 4, 27 .end = 6, 28 .flags = IORESOURCE_IO //flag随便取个什么,按照自己的想法来就行了 29 } 30 }; 31 32 static struct platform_device key_dev = { 33 .name = "key_led", 34 .num_resources = ARRAY_SIZE(key_rsrc), 35 .resource = key_rsrc 36 }; 37 38 /*之所以要平台设备要注册进内核,是因为待会平台设备要根据平台name找到相应的设备 39 *然后获得硬件相关的资源 40 */ 41 static int key_dev_init(void) 42 { 43 /*注册*/ 44 platform_device_register(&key_dev); 45 return 0; 46 } 47 48 static void key_dev_exit(void) 49 { 50 platform_device_unregister(&key_dev); 51 } 52 53 module_init(key_dev_init); 54 module_exit(key_dev_exit); 55 56 MODULE_LICENSE("GPL"); 57 MODULE_AUTHOR("[email protected]");
key_drv.c
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/delay.h> 6 #include <linux/irq.h> 7 #include <asm/irq.h> 8 #include <asm/io.h> 9 #include <linux/cdev.h> 10 #include <linux/device.h> 11 #include <linux/interrupt.h> 12 #include <linux/input.h> 13 #include <linux/bitmap.h> 14 #include <asm/gpio.h> 15 #include <linux/platform_device.h> 16 17 static volatile unsigned long *gpfcon; 18 static volatile unsigned long *gpfdat; 19 20 static struct timer_list key_time; 21 22 static struct class *key_class; 23 24 struct input_inode { 25 char *name; 26 unsigned int irq_type; 27 unsigned int pin; 28 unsigned int key_num; 29 }; 30 31 static struct input_inode *irq_pd; 32 static struct resource *key_resource; 33 static struct resource *pin_resource; 34 35 static struct input_inode key[] = { 36 [0] = { 37 "EINT0", 38 IRQ_EINT0, 39 S3C2410_GPF(0), 40 0}, 41 [1] = { 42 "EINT2", 43 IRQ_EINT2, 44 S3C2410_GPF(2), 45 1}, 46 [2] = { 47 "EINT11", 48 IRQ_EINT11, 49 S3C2410_GPG(3), 50 2}, 51 }; 52 53 static irqreturn_t key_irq(int irq, void *dev_id) 54 { 55 irq_pd = (struct input_inode *)dev_id; 56 mod_timer(&key_time,jiffies + HZ/100); //延迟10ms,延迟过程中断仍然可以被触发 57 58 return IRQ_HANDLED; 59 } 60 61 static void key_time_function(unsigned long data) 62 { 63 unsigned int key_val; 64 unsigned int pin_num; 65 66 if(!irq_pd) 67 return; 68 69 key_val = s3c2410_gpio_getpin(irq_pd->pin); 70 pin_num = pin_resource->start + irq_pd->key_num; 71 72 if(key_val){ 73 74 (*gpfdat) |= (1<<pin_num); 75 76 }else{ 77 78 (*gpfdat) &= ~(1<<pin_num); 79 80 } 81 } 82 83 int key_open(struct inode *inode, struct file *file) 84 { 85 int i; 86 int pin_num; 87 pin_num = pin_resource->end - pin_resource->start + 1; 88 /*配置输出引脚*/ 89 for(i = 0; i < pin_num; i++){ 90 *gpfcon &= ~(3<<((pin_resource->start + i)* 2)); 91 *gpfcon |= (1<<((pin_resource->start + i)* 2)); 92 } 93 94 return 0; 95 } 96 97 int key_release(struct inode * inode, struct file * file) 98 { 99 return 0; 100 } 101 102 static int major; 103 104 static struct file_operations key_fops = { 105 .owner = THIS_MODULE, 106 .open = key_open, 107 .release = key_release, 108 }; 109 110 //驱动分离适合用probe函数 111 static int key_probe(struct platform_device *pdev) //需要枚举找到设备里面同名的pdev 112 { 113 int i; 114 int error; 115 /*获得设备里面的硬件资源*/ 116 major = register_chrdev(0,"led_key",&key_fops); //cat /proc/devices 出现led_key 117 key_class = class_create(THIS_MODULE,"key"); 118 device_create(key_class,NULL,MKDEV(major,0),NULL,"key0_led"); //次设备号0,/dev/key0_led 119 120 key_resource = platform_get_resource(pdev, IORESOURCE_MEM,0); 121 gpfcon = ioremap(key_resource->start,key_resource->end-key_resource->start + 1); 122 gpfdat = gpfcon +1; 123 124 pin_resource = platform_get_resource(pdev, IORESOURCE_IO,0); 125 126 for(i = 0; i < 3; i++){ 127 error = request_irq(key[i].irq_type,key_irq,IRQ_TYPE_EDGE_BOTH,key[i].name,&key[i]); 128 if(error){ 129 printk("couldn‘t get irq! "); 130 return -1; 131 } 132 } 133 134 init_timer(&key_time); 135 key_time.function = key_time_function; 136 add_timer(&key_time); 137 138 return 0; 139 } 140 141 static int __devexit key_remove(struct platform_device *pdev) 142 { 143 int i; 144 del_timer(&key_time); 145 for(i = 0; i < 3; i++){ 146 free_irq(key[i].irq_type,&key[i]); 147 } 148 unregister_chrdev(major,"led_key"); 149 class_destroy(key_class); 150 device_destroy(key_class, MKDEV(major,0)); 151 return 0; 152 } 153 154 static struct platform_driver key_driver = { 155 .driver = { 156 .name = "key_led", 157 .owner = THIS_MODULE, 158 }, 159 .probe = key_probe, 160 .remove = __devexit_p(key_remove), 161 }; 162 163 static int key_drv_init(void) 164 { 165 /*注册*/ 166 platform_driver_register(&key_driver); 167 return 0; 168 } 169 170 static void key_drv_exit(void) 171 { 172 platform_driver_unregister(&key_driver); 173 } 174 175 module_init(key_drv_init); 176 module_exit(key_drv_exit); 177 178 MODULE_LICENSE("GPL"); 179 MODULE_AUTHOR("[email protected]");
以上是关于驱动的分层设计——按键点灯的主要内容,如果未能解决你的问题,请参考以下文章
ESP 保姆级教程 疯狂点灯篇 —— 案例:ESP8266 + LED + 按键(模拟按键控制电器设备开关)
ESP 保姆级教程 疯狂点灯篇 —— 案例:ESP8266 + LED + 按键 + PWM调整亮度(模拟按键控制灯亮度)