#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) { 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);//按键抬起的时候,重新开中断
} } //中断下半部tasklet
void my_tasklet_func(unsigned long t) { int data=*(int*)t; printk("tasklet is executing %d\n",data); (*(int*)t)++; }
//insmod
static 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; } //rmmod
static 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); */ }
MODULE_AUTHOR("lwcheng"); MODULE_LICENSE("Dual BSD/GPL");
module_init(utukey_init); module_exit(utukey_exit)
|