按键驱动程序:
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<linux/delay.h>
#include<asm/irq.h>
#include<linux/poll.h>
#include<linux/irq.h>
#include<asm/irq.h>
#include<linux/interrupt.h>
#include<asm/uaccess.h>
#include<mach/regs-gpio.h>
#include<mach/hardware.h>
#include<linux/device.h>
#include<linux/miscdevice.h>
#include<linux/cdev.h>
#define DEVICE_NAME "mybuttons"
struct button_irq_desc{
int irq; //中断号,中断号唯一表示一个中断
int pin; //中断控制的寄存器,该寄存器的值由中断引脚设置,我们希望从该寄存器读出控制信息
int pin_setting; //中断的引脚,该引脚的电平由按键来控制,从而最终我们由按键控制了寄存器的值
int number; //编号
char *name; //名称
};
//用来指定按键所用的外部中断引脚及中断触发方式、名字
static struct button_irq_desc button_irqs[] ={
{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KET1"},
{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, 1, "KET2"},
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KET3"},
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KET4"},
};
//按键值
static volatile int key_values;
//等待队列:当没有按键被按下,即没有触发中断时,如果有进程调用read函数,则该进程进入休眠
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
//定义了一个整型变量用于判定按键是否被按下,0未按下,1按下,中断事件标志,中断服务程序将它置1,read函数将其清0
static volatile int ev_press = 0;
//中断服务程序
static irqreturn_t irq_interrupt(int irq,void *dev_id)
{
struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
int up;
up = s3c2410_gpio_getpin(button_irqs->pin);
if(up)
key_values = (button_irqs->number+1)+0x80;
else
key_values = (button_irqs->number+1);
ev_press = 1; //表示中断发生
wake_up_interruptible(&button_waitq); //唤醒休眠的进程
return IRQ_RETVAL(IRQ_HANDLED);
}
static int irq_open(struct inode *inode,struct file *file)
{
int i;
int err = 0;
for(i = 0;i < sizeof(button_irqs)/sizeof(button_irqs[0]);i++)
{
//设置引脚
s3c2410_gpio_cfgpin(button_irqs[i].pin,button_irqs[i].pin_setting);
//注册中断
err = request_irq(button_irqs[i].irq,irq_interrupt,IRQ_TYPE_EDGE_BOTH,button_irqs[i].name,(void *)&button_irqs[i]);
// request_irq 的返回值: 0 指示成功,或返回一个负的错误码,如 -EBUSY 表示另一个驱动已经占用了你所请求的中断线。
if(err)
break;
}
if(err)
{
i--;
for(;i >= 0; i--)
{
if(button_irqs[i].irq < 0)
continue;
//释放已注册的中断
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
}
return -EBUSY;
}
ev_press = 1;
return 0;
}
static int irq_close(struct inode *inode,struct file *file)
{
int i;
for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
{
//释放已注册的中断
disable_irq(button_irqs[i].irq);
free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
}
return 0;
}
static int irq_read(struct file *file,char __user *buff,size_t count,loff_t *offp)
{
unsigned long err;
if(!ev_press)
{
if(file->f_flags & O_NONBLOCK)
return -EAGAIN;
else
//如果ev_press等于0,则进入休眠
wait_event_interruptible(button_waitq,ev_press);
}
//按键状态复制给用户进程
err = copy_to_user(buff,&key_values,1);
//这里ev_press等于1,将它清0
ev_press = 0;
return 1;
}
//当用户程序调用select函数时,本函数被调用,如果有按键数据,则select函数会立刻返回,如果没有按键数据,本函数使用poll_wait等待
static unsigned int irq_poll(struct file *file,struct poll_table_struct *wait)
{
unsigned int mask = 0;
poll_wait(file,&button_waitq,wait);
if(ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}
static struct file_operations buttons_fops =
{
.owner = THIS_MODULE,
.open = irq_open,
.release = irq_close,
.read = irq_read,
.poll = irq_poll,
};
static struct miscdevice misc = {
.minor =MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &buttons_fops,
};
static int __init buttons_init(void)
{
int reg;
reg = misc_register(&misc);
printk(DEVICE_NAME" initialized\n");
return reg;
}
static void __exit buttons_exit(void)
{
misc_deregister(&misc);
printk("deregister\n");
}
module_init(buttons_init);
module_exit(buttons_exit);
MODULE_AUTHOR("xh");
MODULE_DESCRIPTION("learn");
MODULE_LICENSE("GPL");
Makefile:
ifneq ($(KERNELRELEASE),)
obj-m :=key.o
else
# KERNELDIR :=/lib/modules/2.6.32-21-generic/build
KERNELDIR :=/opt/EmbedSky/linux-2.6.30.4
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
rm -f *.o *.ko
.PHONY:clean
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/select.h>
#include<sys/time.h>
#include<errno.h>
#define DEV "/dev/mybuttons"
int main(void)
{
int i;
int buttons_fd;
int key_value = 0;
struct timeval tv;
//打开设备文件
buttons_fd = open(DEV,O_RDWR);
if(buttons_fd < 0)
{
perror(DEV);
exit(1);
}
while(1)
{
fd_set rds;
int ret;
FD_ZERO(&rds);
FD_SET(buttons_fd,&rds);
//设置select超时时间,1s
tv.tv_sec = 1;
tv.tv_usec = 0;
//调用select
ret = select(buttons_fd+1,&rds,NULL,NULL,&tv);
if(ret < 0)
{
perror("select");
exit(1);
}
if(ret == 0)
{
printf("Timeout\n");
}
//能读到数据
else if(FD_ISSET(buttons_fd,&rds))
{
//调用read,读取键盘数据
int ret = read(buttons_fd,&key_value,1);
if(ret != 1)
{
if(errno != EAGAIN)
perror("read buttons\n");
continue;
}
else
{
//打印
printf("key_val = 0x%x\n",key_value);
}
}
}
return 0;
}