#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define rGPFCON (*((volatile unsigned *)(ioremap((volatile unsigned *)0x56000050,4))))
#define rGPFDAT (*((volatile unsigned *)(ioremap((volatile unsigned *)0x56000054,4))))
#define rGPGCON (*((volatile unsigned *)(ioremap((volatile unsigned *)0x56000060,4))))
#define rSRCPND (*((volatile unsigned *)(ioremap((volatile unsigned *)0x4a000000,4))))
#define rINTMOD (*((volatile unsigned *)(ioremap((volatile unsigned *)0x4a000004,4))))
#define rINTMSK (*((volatile unsigned *)(ioremap((volatile unsigned *)0x4a000008,4))))
#define rINTPND (*((volatile unsigned *)(ioremap((volatile unsigned *)0x4a000010,4))))
#define rEXTINT0 (*((volatile unsigned *)(ioremap((volatile unsigned *)0x56000088,4))))
#define rEXTINT1 (*((volatile unsigned *)(ioremap((volatile unsigned *)0x5600008c,4))))
#define rEXTINT2 (*((volatile unsigned *)(ioremap((volatile unsigned *)0x56000090,4))))
#define rEINTMASK (*((volatile unsigned *)(ioremap((volatile unsigned *)0x560000a4,4))))
#define rEINTPEND (*((volatile unsigned *)(ioremap((volatile unsigned *)0x560000a8,4))))
#define KEY_1 1
#define KEY_2 2
#define KEY_3 3
#define KEY_4 4
#define NOKEY 0
#define MJNOR 166 //主设备号
#define MINOR 0 //次设备号
void delay(int time); //延时
int get_keyvalue(void); //消抖去重复之后的键值
void key_regeister_init(void); //寄存器的初始化(中断)
static unsigned int key_old = NOKEY; //保存上一次按键的值
static unsigned int key_new = NOKEY; //保存当前按键的值
static unsigned int keyflag,keynumber; //记录按键的状态和按键的值
static irqreturn_t key_irq_1(void) //按键中断1处理函数
{
rSRCPND |= (1<<0); //写1 清除
rINTPND |= (1<<0); //中断能被响应
keynumber = KEY_1;
keyflag = 1;
printk("发生中断EINT0\n");
}
static irqreturn_t key_irq_2(void) //按键中断2处理函数
{
rSRCPND |= (1<<2); //写1 清除
rINTPND |= (1<<2);
keynumber = KEY_2;
keyflag = 1;
printk("发生中断EINT1\n");
}
static irqreturn_t key_irq_34(void) //按键中断3、4处理函数
{
if((rEINTPEND & (1<<11))==1)
{
rEINTPEND |= (1<<11); //写1清楚EINTPEND中的EINT11位
rSRCPND |= (1<<5); //写1 清除
rINTPND |= (1<<5);
keynumber = KEY_3;
keyflag = 1;
printk("发生中断EINT11\n");
}
else
{
rEINTPEND |= (1<<11); //写1清楚EINTPEND中的EINT19位
rSRCPND |= (1<<5); //写1 清除
rINTPND |= (1<<5);
keynumber = KEY_4;
keyflag = 1;
printk("发生中断EINT19\n");
}
}
//设备结构体
struct key_dev
{
struct cdev cdev;
struct semaphore sem; //并发控制用的信号量
unsigned int key_value; //用于判断按键值
};
struct key_dev *key_dev;
int key_major = MJNOR;
static int key_open(struct inode *inode, struct file *filp)
{
struct key_dev *dev;
unsigned int temp;
//获得设备结构体指针
dev = container_of(inode->i_cdev,struct key_dev,cdev);
filp->private_data = dev;
//申请key1中断
temp = request_irq(IRQ_EINT0,key_irq_1,SA_INTERRUPT,"KEY_IRQ",NULL);
//中断号被占用
if(temp)
printk(KERN_ERR"IRQ %d already in use \n",IRQ_EINT0);
//申请key2中断
temp = request_irq(IRQ_EINT2,key_irq_2,SA_INTERRUPT,"KEY_IRQ",NULL);
//中断号被占用
if(temp)
printk(KERN_ERR"IRQ %d already in use \n",IRQ_EINT2);
//申请key3中断
temp = request_irq(IRQ_EINT11,key_irq_34,SA_INTERRUPT,"KEY_IRQ",NULL);
//中断号被占用
if(temp)
printk(KERN_ERR"IRQ %d already in use \n",IRQ_EINT11);
//申请key4中断
temp = request_irq(IRQ_EINT19,key_irq_34,SA_INTERRUPT,"KEY_IRQ",NULL);
//中断号被占用
if(temp)
printk(KERN_ERR"IRQ %d already in use \n",IRQ_EINT19);
//初始化硬件设备
//初始化按键
key_regeister_init();
return 0;
}
int key_release(struct inode *inode, struct file *filp)
{
free_irq(IRQ_EINT0,NULL); //释放中断
free_irq(IRQ_EINT2,NULL);
free_irq(IRQ_EINT11,NULL);
free_irq(IRQ_EINT19,NULL);
return 0;
}
ssize_t key_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)
{
struct key_dev *dev;
dev = filp->private_data;
while(1)
{
dev->key_value = get_keyvalue();
if(dev->key_value == 0)
continue;
else
break;
}
printk("%d\n",dev->key_value);
down(&dev->sem); //获取信号量
if(copy_to_user(buf,(&dev->key_value),sizeof(int)))
{
return -EFAULT;
}
up(&dev->sem); //释放信号量
return 1;
}
struct file_operations key_fops =
{
.owner = THIS_MODULE,
.open = key_open,
.release = key_release,
.read = key_read,
};
static int key_init(void)
{
int result;
dev_t dev;
dev = MKDEV(key_major,MINOR);
//申请字符设备
if(key_major)
result = register_chrdev_region(dev, 1, "LED"); //静态申请设备号
else
{
result = alloc_chrdev_region(&dev,0,1,"LED"); //动态申请设备号
key_major = MAJOR(dev);
}
if(result < 0)
return result;
//分配设备结构体的内存
key_dev = kmalloc(sizeof(struct key_dev),GFP_KERNEL);
if(!key_dev)
{
result = -ENOMEM;
goto fail_malloc;
}
memset(key_dev,0,sizeof(struct key_dev));
cdev_init(&key_dev->cdev,&key_fops);
key_dev->cdev.owner = THIS_MODULE;
key_dev->cdev.ops = &key_fops;
result = cdev_add(&key_dev->cdev,dev,1);//向系统增加一个设备
if(result)
printk("ERROR adding led\n");
init_MUTEX(&key_dev->sem); //初始化信号量
return 0;
fail_malloc: unregister_chrdev_region(dev,key_dev);
return result;
}
static int key_exit(void)
{
dev_t devno = MKDEV(MJNOR, MINOR); //获得主设备号
cdev_del(&key_dev->cdev); //删除字符设备结构体
kfree(key_dev); //释放在light_init中分配的内存
unregister_chrdev_region(devno,1);//删除字符设备
return 0;
}
void delay(int time) //延时
{
int i,j;
for(i=0;i<100;i++)
{
for(j=0;j
int get_keyvalue(void)
{
volatile unsigned int key1,key2;
key1 = keynumber;
delay(50);
key2 = keynumber;
if(key1 != key2) //消抖
{
return NOKEY;
}
key_new = key2; //扫描到一个新值
if(key_old != key_new) //去重复
{
key_old = key_new;
return key_new;
}
return NOKEY;
}
void key_regeister_init(void)
{
volatile unsigned int temp;
temp = rGPFCON; //将I/O口作为EINT的功能
temp &= ~((3<<4) | 3); //SW1--EINT0 SW2--EINT2
temp |= ((1<<5) | (1<<1)); //配置为EINT=10
rGPFCON = temp;
temp = rGPGCON; //SW3-4 对应寄存器
temp &= ~((3<<6) | (3<<22)); //SW3--EINT11 SW4--EINT19
temp |= ((1<<23) | (1<<7)); //配置为EINT=10
rGPGCON = temp;
//SRCPND为中断请求的寄存器 1--accept 0--request
rSRCPND |= ((1<<5) | (1<<2) | (1<<0)); //中断请求
//INTMOD中断模式寄存器 0---IRQ 1---FIQ
rINTMOD &= ~((1<<5) | (1<<2) | (1<<0)); //设置为IRQ中断模式
rINTMSK &= ~((1<<5) | (1<<2) | (1<<0)); //使能中断响应
rINTPND |= ((1<<5) | (1<<2) | (1<<0)); //中断能被响应
//EXTINT* 触发中断方式
//01X= falling edge triggred
temp = rEXTINT0; //EINT0 EINT2为下降沿中断
temp &= ~((7<<8)|(7<<0));
temp |= ((2<<8)|(2<<0));
rEXTINT0 = temp;
temp = rEXTINT1; //EINT11为下降沿中断
temp &= ~(7<<12);
temp |= (2<<12);
rEXTINT1 = temp;
rEXTINT2 = (rEXTINT2& ~(7<<12)) | (2<<12); //EINT19为下降沿中断
rEINTMASK &= ~((1<<11) | (1<<19)); //使能EINT11,EINT19中断
}
MODULE_LICENSE("GPL");
module_init(key_init);
module_exit(key_exit);