📄 button.c
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2007, 2010 fengGuojin(fgjnew@163.com) */#include <linux/module.h>#include <linux/init.h>#include <linux/input.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/arch-s3c2410/irqs.h>#include <asm/signal.h>#include <asm/hardware.h>#include <asm/uaccess.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-irq.h>#include <asm/dma.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/cdev.h>#include <linux/version.h>#include <linux/vmalloc.h>#include <linux/ctype.h>#include <linux/pagemap.h>#include <linux/poll.h>#include "demo.h"MODULE_AUTHOR("fgj");MODULE_LICENSE("Dual BSD/GPL");static int irqArray[4]={ IRQ_EINT0, IRQ_EINT2, IRQ_EINT11, IRQ_EINT19};struct DEMO_dev *DEMO_devices;static unsigned char demo_inc=0;static int flag = 0;struct timer_list polling_timer;static unsigned long polling_jffs=0;void initButton(void){ writel((readl(S3C2410_GPGCON)&(~((3<<22)|(3<<6))))|((2<<22)|(2<<6)),S3C2410_GPGCON); //GPG11,3 set EINT writel((readl(S3C2410_GPFCON)&(~((3<<4)|(3<<0))))|((2<<4)|(2<<0)),S3C2410_GPFCON) ; //GPF2,0 set EINT writel((readl(S3C2410_EXTINT0)&(~(7|(7<<8)))),S3C2410_EXTINT0); writel((readl(S3C2410_EXTINT0)|(0|(0<<8))),S3C2410_EXTINT0); //set eint0,2 falling edge int writel((readl(S3C2410_EXTINT1)&(~(7<<12))),S3C2410_EXTINT1); writel((readl(S3C2410_EXTINT1)|(0<<12)),S3C2410_EXTINT1); //set eint11 falling edge int writel((readl(S3C2410_EXTINT2)&(~(0xf<<12))),S3C2410_EXTINT2); writel((readl(S3C2410_EXTINT2)|(0<<12)),S3C2410_EXTINT2); //set eint19 falling edge int writel((readl(S3C2410_GPBCON)&(~((3<<12)|(3<<14)))),S3C2410_GPBCON); writel((readl(S3C2410_GPBCON)|(((1<<12)|(1<<14)))),S3C2410_GPBCON); writel((readl(S3C2410_GPBUP)|(3<<6)),S3C2410_GPBUP); writel((readl(S3C2410_GPBDAT)&(~(3<<6))),S3C2410_GPBDAT); writel((readl(S3C2410_EINTPEND)|((1<<11)|(1<<19))),S3C2410_EINTPEND); //clear eint 11,19 writel((readl(S3C2410_EINTMASK)&(~((1<<11)|(1<<19)))),S3C2410_EINTMASK); //enable eint11,19*/}void polling_handler(unsigned long data){ int code=-1; writel(readl(S3C2410_SRCPND)&0xffffffda,S3C2410_SRCPND);//clear srcpnd 0 2 11 19 mdelay(1); //扫描按键表,根据中断号,找出所按下的按键。 writel(readl(S3C2410_GPBDAT)|0x80,S3C2410_GPBDAT);//set GPB76 to 10 writel(readl(S3C2410_GPBDAT)&0xffffffBf,S3C2410_GPBDAT);//... if((readl(S3C2410_GPFDAT)&(1<< 0)) == 0 ) { code=0; goto IRQ_OUT; } else if( (readl(S3C2410_GPFDAT)&(1<< 2)) == 0 ) { code=2; goto IRQ_OUT; } else if( (readl(S3C2410_GPGDAT)&(1<< 3)) ==0 ) { code=4; goto IRQ_OUT; } else if( (readl(S3C2410_GPGDAT)&(1<<11)) == 0 ) { code=6; goto IRQ_OUT; } writel(readl(S3C2410_SRCPND)&0xffffffda,S3C2410_SRCPND);//clear srcpnd 0 2 11 19 mdelay(1); writel(readl(S3C2410_GPBDAT)|0x40,S3C2410_GPBDAT);//set GPB76 to 01 writel(readl(S3C2410_GPBDAT)&0xffffff7f,S3C2410_GPBDAT);//... if((readl(S3C2410_GPFDAT)&(1<< 0)) == 0 ) { code=1; goto IRQ_OUT; } else if( (readl(S3C2410_GPFDAT)&(1<< 2)) == 0 ) { code=3; goto IRQ_OUT; } else if( (readl(S3C2410_GPGDAT)&(1<< 3)) ==0 ) { code=5; goto IRQ_OUT; } else if( (readl(S3C2410_GPGDAT)&(1<<11)) == 0 ) { code=7; goto IRQ_OUT; }IRQ_OUT: enable_irq(IRQ_EINT0); enable_irq(IRQ_EINT2); enable_irq(IRQ_EINT11); enable_irq(IRQ_EINT19); if(code>=0) { //避免中断连续出现 if((jiffies-polling_jffs)>100) { polling_jffs=jiffies; //获取键盘值 DEMO_devices->key=code; printk("get key %d\n",DEMO_devices->key); flag = 1; wake_up_interruptible(&(DEMO_devices->wq)); } } writel(readl(S3C2410_GPBDAT)&0xffffff3f,S3C2410_GPBDAT);}static irqreturn_t simplekey_interrupt(int irq, void *dummy, struct pt_regs *fp){ //if(demo_inc<=0)return IRQ_HANDLED; //printk("enter button interrupt\n"); disable_irq(IRQ_EINT0); disable_irq(IRQ_EINT2); disable_irq(IRQ_EINT11); disable_irq(IRQ_EINT19); polling_timer.expires = jiffies + HZ/5; add_timer(&polling_timer); return IRQ_HANDLED;}int DEMO_open(struct inode *inode, struct file *filp){ struct DEMO_dev *dev; if(demo_inc>0)return -ERESTARTSYS; demo_inc++; dev = container_of(inode->i_cdev, struct DEMO_dev, cdev); filp->private_data = dev; return 0;}int DEMO_release(struct inode *inode, struct file *filp){ demo_inc--; return 0;}ssize_t DEMO_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos){ struct DEMO_dev *dev = filp->private_data; int sum=0; if(flag==1) { flag = 0; sum=1; if (copy_to_user(buf,&dev->key,1)) { sum=-EFAULT; } } else { if (filp->f_flags & O_NONBLOCK) { return -EAGAIN; } else { if(wait_event_interruptible(dev->wq, flag != 0)) { return - ERESTARTSYS; } flag = 0; sum=1; if (copy_to_user(buf,&dev->key,1)) { sum=-EFAULT; } } } return sum;}unsigned int DEMO_poll(struct file *filp, poll_table *wait){ struct DEMO_dev *dev = filp->private_data; poll_wait(filp, &dev->wq, wait); if (flag==1)//数据准备好 return POLLIN | POLLRDNORM; return 0;}struct file_operations DEMO_fops = { .owner = THIS_MODULE, .read = DEMO_read, .open = DEMO_open, .poll= DEMO_poll, .release = DEMO_release,};/******************************************************* MODULE ROUTINE*******************************************************/void DEMO_cleanup_module(void){ dev_t devno = MKDEV(DEMO_MAJOR, DEMO_MINOR); int i; for (i = 0; i <4; i++) { free_irq(irqArray[i],simplekey_interrupt); } if (DEMO_devices) { cdev_del(&DEMO_devices->cdev); kfree(DEMO_devices); } unregister_chrdev_region(devno,1);}int DEMO_init_module(void){ int result; dev_t dev = 0; int i=0; initButton(); dev = MKDEV(DEMO_MAJOR, DEMO_MINOR); result = register_chrdev_region(dev, 1, "DEMO"); if (result < 0) { printk(KERN_WARNING "DEMO: can't get major %d\n", DEMO_MAJOR); return result; } DEMO_devices = kmalloc(sizeof(struct DEMO_dev), GFP_KERNEL); if (!DEMO_devices) { result = -ENOMEM; goto fail; } memset(DEMO_devices, 0, sizeof(struct DEMO_dev)); init_MUTEX(&DEMO_devices->sem); cdev_init(&DEMO_devices->cdev, &DEMO_fops); DEMO_devices->cdev.owner = THIS_MODULE; DEMO_devices->cdev.ops = &DEMO_fops; result = cdev_add (&DEMO_devices->cdev, dev, 1); if(result) { printk(KERN_NOTICE "Error %d adding DEMO\n", result); goto fail; } for (i = 0; i <4; i++) { if (request_irq(irqArray[i], &simplekey_interrupt, SA_INTERRUPT, "simplekey", NULL)) { printk("request button irq failed!\n"); return -1; } } init_waitqueue_head(&DEMO_devices->wq); init_timer(&polling_timer); polling_timer.data = (unsigned long)0; polling_timer.function = polling_handler; return 0;fail: DEMO_cleanup_module(); return result;}module_init(DEMO_init_module);module_exit(DEMO_cleanup_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -