/***********************************************************
** 按键中断驱动程序 **
***********************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "keys_eint" //设备文件名
//定义中断使用的结构体
//1.定义外部中断所用的中断号
//2.定义外部中断所对应的GPIO端口
//3.定义键值
//4.定义每个按键的名字
static struct irq_table_data{
int irq;
int pin;
int button_number;
char * button_name;
};
//结构体实体定义
static struct irq_table_data button_irqs[]={
{IRQ_EINT11,S3C2410_GPG(3),0,"KEY1"},
{IRQ_EINT13,S3C2410_GPG(5),1,"KEY2"},
{IRQ_EINT14,S3C2410_GPG(6),2,"KEY3"},
{IRQ_EINT15,S3C2410_GPG(7),3,"KEY4"},
};
//定义按键状态变量
static volatile char key_values[]={'0','0','0','0'};
//创建等待队列
static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue);
//定义中断信息标志
static volatile unsigned int flag_irq=0;
static irqreturn_t button_irq_handler(int irq,void * dev_id)
{
struct irq_table_data *button_irqs=(struct irq_table_data*)dev_id;
int down;
down=!s3c2410_gpio_getpin(button_irqs->pin);
if(down!=(key_values[button_irqs->button_number]&1))
{
key_values[button_irqs->button_number]='0'+down;
flag_irq=1;
wake_up_interruptible(&button_wait_queue);
}
return IRQ_RETVAL(IRQ_HANDLED);
}
//打开文件注册中断,如果失败则返回退出
static int button_open(struct inode *inode,struct file *file)
{
int ret=0;
unsigned int i;
for(i=0;i<4;i++)
{
ret=request_irq(button_irqs[i].irq, button_irq_handler, IRQ_TYPE_EDGE_BOTH, button_irqs[i].button_name, (void *)&button_irqs[i]);
if(ret)
{
break;
}
}
if(ret)
{
i--;
for(;i>=0;i--)
{
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
}
return -EBUSY;
}
else
{
flag_irq=1;
return 0;
}
}
static int button_close(struct inode *inode,struct file *file)
{
int i;
for(i=0;i<4;i++)
{
free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
}
return 0;
}
static int button_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
unsigned long err;
if(flag_irq==0)
{
if(filp->f_flags&O_NONBLOCK)//f_flags为unsigned int类型 当中断标示为0并且以非阻塞方式打开时
return -EAGAIN;
else
wait_event_interruptible(button_wait_queue,flag_irq);//否则就在这里阻塞掉
}
flag_irq=0;
err=copy_to_user(buff,(const void*)key_values,min(sizeof(key_values),count));
return err ? -EFAULT:min(sizeof(key_values),count);
}
static unsigned int button_poll(struct file *file,struct poll_table_struct *wait)
{
unsigned int mask=0;
poll_wait(file,&button_wait_queue,wait);
if(flag_irq)
{
mask=POLLIN|POLLRDNORM;
}
return mask;
}
static struct file_operations dev_fops={
.owner=THIS_MODULE,
.open=button_open,
.release=button_close,
.read=button_read,
.poll=button_poll,
};
static struct miscdevice misc={
.name=DEVICE_NAME,
.minor=MISC_DYNAMIC_MINOR,
.fops=&dev_fops,
};
static int __init dev_init(void)
{
//主要工作是注册模块为混杂设备
int ret;
ret=misc_register(&misc);
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("friendly_arm");
阅读(1384) | 评论(0) | 转发(0) |