如果不能成功注册按键驱动,请参考 OK6410 linux设备驱动:Button驱动-轮询的形式。
使用的是查询的方式来获取按键值,此方法简单,但是是非常消耗cpu资源,不建议使用。以下代码是使用中断的方式进行按键值获取。采用了poll和信号量同步的方式实现。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <asm/ioctls.h> /* TIOCOUTQ, TIOCINQ */
#include <asm/uaccess.h>
#include <asm/io.h>
#include <mach/gpio-bank-m.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/sched.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("LEO");
MODULE_DESCRIPTION("This is a Button Device Test by leo");
//S3C64XX_GPMD
volatile unsigned long *gpmcon = NULL;
volatile unsigned long *gpmdat = NULL;
volatile unsigned long *gpncon = NULL;
volatile unsigned long *gpndat = NULL;
static int Button_write(struct file *file,const char __user *buf,size_t count,loff_t * ppos);
static int Button_open(struct inode *inode,struct file *file);
static int Button_ioctl(struct file *file, unsigned int cmd,unsigned long arg );
static int Button_read(struct file *file,const char __user *buf,size_t count,loff_t * ppos);
static int Button_close(struct inode *inode,struct file *file);
static irqreturn_t Buttons_irq(int irq,void *dev_id);
static unsigned Button_poll(struct file *file, poll_table *wait);
static int Button_fasync (int fd, struct file *filp, int on);
/* 中断事件标志, 中断服务程序将它置1,read将它清0 */
static volatile unsigned int ev_press = 0;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static unsigned char key_val;
static struct class *Button_leo_class;
static struct class_device *Button_leo_class_dev;
static struct file_operations Button_fops={
.owner = THIS_MODULE,
.open = Button_open,
.write = Button_write,
.read = Button_read,
//.ioctl = Button_ioctl,
.unlocked_ioctl = Button_ioctl,
.release = Button_close,
.poll = Button_poll,
.fasync = Button_fasync,
};
int major;
static struct irqaction Button0_IRQ={
.name = "button0-3_byleo",
.flags = IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING | IRQF_SHARED,
.handler = Buttons_irq,
};
typedef struct {
int irqNum;
int ButtonNum;
char *name;
}_Button_irq_t;
_Button_irq_t Button_irq_t[4]={
{IRQ_EINT(0), 0, "Button1_leo"},
{IRQ_EINT(1), 1, "Button2_leo"},
{IRQ_EINT(2), 2, "Button3_leo"},
{IRQ_EINT(3), 3, "Button4_leo"},
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "Button_leo",
.fops = &Button_fops,
};
static struct fasync_struct *button_async;
static int Button_init(void)
{
printk( "\n Button module by Button init\n");
int minor;
int val;
#if 0
major=register_chrdev(0, "Button_leo", &Button_fops);
if(major<0)
{
printk("Button_leo Can't register major number \n");
return major;
}
Button_leo_class = class_create (THIS_MODULE, "Button_leo_class");
if(IS_ERR(Button_leo_class))
{
return PTR_ERR (Button_leo_class);
}
Button_leo_class_dev = device_create(Button_leo_class,NULL,MKDEV (major, 0),NULL,"Button_Interrupt_leo");//自动创建设备节点
if(unlikely (IS_ERR(Button_leo_class_dev)))
{
return PTR_ERR (Button_leo_class_dev);
}
#else
val = misc_register (&misc);
#endif
//LED 地址映射
gpmcon = (volatile unsigned long *)ioremap (0x7F008820l, 16);
gpmdat = gpmcon + 1 ;
//Button 地址映射
gpncon = (volatile unsigned long *)ioremap (0x7F008830l, 16);
gpndat = gpncon + 1 ;
return 0;
}
static void Button_exit(void)
{
printk( "Button module by leo exit\n");
int minor;
int i ;
iounmap(gpmcon);
iounmap(gpncon);
for (i = 0; i <4; i++)
{
if (Button_irq_t[i].irqNum < 0)
{
continue;
}
free_irq(Button_irq_t[i].irqNum,(void*)&Button_irq_t[i]);
}
#if 0
device_unregister (Button_leo_class_dev);
class_destroy (Button_leo_class);
unregister_chrdev(major,&Button_fops);
#else
misc_deregister (&misc);
#endif
}
static int Button_open(struct inode *inode,struct file *file)
{
printk( "Button module by leo Open\n");
int i;
int err=0;
/*配置为输出引脚 M0,M1 M2 M3*/
*gpmcon &=~ ((0x0f<<(0*4)) | (0x0f<<(1*4)) | (0x0f<<(2*4)) | (0x0f<<(3*4)));//*gpmcon = (volatile unsigned long *)ioremap (0x7F008820l, 16);
*gpmcon |= ((0x01<<(0*4)) | (0x01<<(1*4)) | (0x01<<(2*4)) | (0x01<<(3*4)));
for(i=0;i<4;++i)
{
if(Button_irq_t[i].irqNum<0)
{
continue;
}
err = request_irq (Button_irq_t[i].irqNum, Buttons_irq , IRQF_TRIGGER_FALLING, Button_irq_t[i].name, (void *)&Button_irq_t[i]);
if(err)
{
printk("request_irq %d return value is %d \n",Button_irq_t[i].irqNum,err);
disable_irq(Button_irq_t[i].irqNum);
free_irq(Button_irq_t[i].irqNum, (void *)&Button_irq_t[i]);
break;
}
}
return 0;
}
static int Button_write(struct file *file,const char __user *buf,size_t count,loff_t * ppos)
{
printk( "Button module by leo Write\n");
return 0;
}
static int Button_read(struct file *file,const char __user *buf,size_t count,loff_t * ppos)
{
if (count != 1)
return -EINVAL;
wait_event_interruptible (button_waitq, ev_press);
copy_to_user(buf,&key_val,1);
ev_press = 0;
return 0;
}
static int Button_ioctl(struct file *file, unsigned int cmd,unsigned long arg )
{
//printk("cmd = %x,arg = %x \n",cmd,arg);
switch (cmd)
{
case 0:
*gpmdat |= arg;
break;
case 1:
*gpmdat &= ~arg;
break;
default:
break;
}
}
static int Button_close(struct inode *inode,struct file *file)
{
int i;
for (i = 0; i <4; i++)
{
if (Button_irq_t[i].irqNum < 0)
{
continue;
}
free_irq(Button_irq_t[i].irqNum,(void*)&Button_irq_t[i]);
}
}
static irqreturn_t Buttons_irq(int irq,void *dev_id)
{
_Button_irq_t *Button_irq_buff=(_Button_irq_t *)dev_id;
key_val=Button_irq_buff->ButtonNum;
printk("enter the button interrupt key_val = %d \n",key_val);
ev_press = 1;
wake_up_interruptible (&button_waitq);
kill_fasync (&button_async, SIGIO, POLL_IN);
return IRQ_RETVAL(IRQ_HANDLED);
}
static unsigned Button_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
poll_wait (file, &button_waitq, wait );
if(ev_press)
{
mask |= POLLIN | POLLRDBAND;
}
return mask;
}
static int Button_fasync (int fd, struct file *filp, int on)
{
printk("driver: Button_fasync\n");
return fasync_helper (fd, filp, on, &button_async);
}
module_init(Button_init);
module_exit(Button_exit);
测试代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fd;
void signal_fun(int signum)
{
unsigned char key_val;
read(fd,&key_val,1);
printf("key_val Value is %x\n",key_val);
}
int main(int argc,int **argv)
{
unsigned char key_val;
int ret;
int i;
int Oflags;
fd = open ("/dev/Button_leo", O_RDWR);
if(fd < 0)
{
printf ("the device can't open !\n");
return 0;
}
signal(SIGIO, signal_fun);
fcntl(fd,F_SETOWN,getpid());
Oflags = fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,Oflags|FASYNC);
while(1)
{
for( i=0;i<4;++i)
{
ioctl(fd,1,1<<i);
ioctl(fd,0,~(1<<i));
//sleep(1);
sleep(1);
}
}
return 0;
}