📄 key_tasklet.c~
字号:
#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <linux/input.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/hardware.h>#define DEVICE_NAME "utukey"#define KEY_TIME_DELAY (HZ/5)//200ms#define KEY_TIME_DELAY1 (HZ/250)//4ms#define KEYSTATUS_DOWNX 0 //刚被按下#define KEYSTATUS_DOWN 1 //一直被按着hold#define KEYSTATUS_UP 2 //按键抬起了static void utu2440button_timer_callback(unsigned long data);//时间软中断定时器处理函数static irqreturn_t utu2440_isr_kbd(int irq, void *dev_id, struct pt_regs *reg);//按键中断处理函数static int utukey_open(struct inode *inode, struct file *filp);static int utukey_release(struct inode *inode, struct file *filp);void my_tasklet_func(unsigned long t);int tasklet_time;DECLARE_TASKLET(my_tasklet,my_tasklet_func,&tasklet_time);static dev_t utukey_major=252;//主设备号自设定unsigned int keynumber=6;//只是作为标记所用struct utukey_dev_t{ struct cdev cdev; unsigned int keyStatus;};struct utukey_dev_t utukey_dev;struct timer_list key_timer;static const struct file_operations utukey_fops ={ .owner = THIS_MODULE, .open = utukey_open, .release = utukey_release,};/*打开函数*/static int utukey_open(struct inode *inode, struct file *filp){ filp->private_data = &utukey_dev; printk(KERN_NOTICE "utukey opened\n"); return 0;}/*释放函数*/static int utukey_release(struct inode *inode, struct file *filp){ printk(KERN_NOTICE "utukey released\n"); return 0;}/*中断服务程序*/static irqreturn_t utu2440_isr_kbd(int irq, void *dev_id, struct pt_regs *reg){ // int *key = (int*)dev_id; //printk(KERN_NOTICE "utukey interrupt key number is %d\n",*key);//传进了keynumber printk(KERN_NOTICE "utukey interrupt key number is %d\n",keynumber); if (IRQ_EINT19!= irq) { printk(KERN_NOTICE"bad irq %d in button\n", irq); return IRQ_NONE; } disable_irq(IRQ_EINT19);//先屏蔽此中断 utukey_dev.keyStatus= KEYSTATUS_DOWNX; //表示刚被按下 key_timer.expires = jiffies + KEY_TIME_DELAY1;//通过这个来实现去抖,并判断是否一直被按下,百分之一秒 add_timer(&key_timer); //开始计时 tasklet_schedule(&my_tasklet); return IRQ_HANDLED;//表示处理好了 和 IRQ_NONE对应}/*timer 延时处理函数data参数来自于定时器结构中的data变量*/static void utu2440button_timer_callback(unsigned long data){ if (s3c2410_gpio_getpin(S3C2410_GPG11) == 0) { if (utukey_dev.keyStatus== KEYSTATUS_DOWNX)//从中断进入 { printk(KERN_NOTICE "utukey is down\n"); utukey_dev.keyStatus= KEYSTATUS_DOWN;//从中断进入的,证明按键已经被按下expires时间了,一直在被按着 key_timer.expires = jiffies + KEY_TIME_DELAY; //判断是否还被按着,五分之一秒 add_timer(&key_timer); } else //不是第一次进入定时器,表示按键一直被按着 { printk(KERN_NOTICE "utukey is hold\n"); key_timer.expires = jiffies + KEY_TIME_DELAY;//HOLD key,每隔200MS发送一次 add_timer(&key_timer); } } else { utukey_dev.keyStatus= KEYSTATUS_UP; printk(KERN_NOTICE "utukey is up\n"); enable_irq(IRQ_EINT19);//按键抬起的时候,重新开中断 }}//中断下半部taskletvoid my_tasklet_func(unsigned long t){ int data=*(int*)t; printk("tasklet is executing %d\n",data); (*(int*)t)++;}//insmodstatic int __init utukey_init(void){ int result,ret; dev_t devno = MKDEV(utukey_major,0); if (utukey_major) { result = register_chrdev_region(devno, 1, DEVICE_NAME); /*int register_chrdev_region(dev_t first, unsigned int count, char *name) First :要分配的设备编号范围的初始值(次设备号常设为0); Count:连续编号范围.(被使用只是一个要请求的范围,最终只能分配给你一个号码) Name:编号相关联的设备名称. (/proc/devices); */ } else { result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME); /*Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);动态分配 Firstminor : 通常为0; *dev:存放返回的设备号; */ utukey_major = MAJOR(devno); } if (result < 0) { return result; } cdev_init(&utukey_dev.cdev,&utukey_fops);//字符设备初始化 utukey_dev.cdev.owner = THIS_MODULE; utukey_dev.cdev.ops = &utukey_fops; utukey_dev.keyStatus = KEYSTATUS_UP;//按键初始状态为抬起 ret = cdev_add(&utukey_dev.cdev, devno, 1); if (ret) { printk(KERN_NOTICE "Error %d adding utukey",ret); } s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_EINT19);//申请中断 set_irq_type(IRQ_EINT19, IRQT_FALLING);//设置为下降沿触发 if (ret=request_irq(IRQ_EINT19, utu2440_isr_kbd, SA_INTERRUPT, DEVICE_NAME, NULL))//注册的中断号,中断服务程序,快速中断,设备名,传递的参数 { printk(KERN_NOTICE"request irq in button failed key is %d,return is %d\n",keynumber,ret); return -1; } printk(KERN_NOTICE"request irq in button,successed\n"); /*timer结构初始化*/ key_timer.function = utu2440button_timer_callback;//timer的调用函数 key_timer.data =keynumber; init_timer(&key_timer); return 0;}//rmmodstatic void __exit utukey_exit(void){ cdev_del(&utukey_dev.cdev); del_timer(&key_timer); free_irq(IRQ_EINT19,NULL);//释放irq中断void free_irq(unsigned int irq,void *dev_id); dev_id用于多个设备的中断共享 unregister_chrdev_region(MKDEV(utukey_major,0),1);}/*释放:Void unregist_chrdev_region(dev_t first,unsigned int count);调用Documentation/devices.txt中能够找到已分配的设备号.*/MODULE_AUTHOR("lwcheng");MODULE_LICENSE("Dual BSD/GPL");module_init(utukey_init);module_exit(utukey_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -