目的:
通过中断的方式,实现按键相应。
app: 打开设备文件,循环读取设备内容。
驱动:注册字符设备, 创建设备节点,申请按键中断,按键处理, 实现设备的读取。
1、驱动框架
2、中断申请
3、中断处理
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <asm/irq.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/arch/regs-gpio.h>
int major = 0;
char * drv_name = "third_drv";
static struct class * third_drv_class = NULL;
static struct class_device *third_dev = NULL;
static unsigned char keyVal = 0;
struct pin_desc {
unsigned int pin;
unsigned int keyVal;
};
/*
键值:按下时, 0x01,0x02,0x03,0x04
键值:松开时, 0x81,0x82,0x83,0x84
*/
struct pin_desc pins_desc[4] = {
{S3C2410_GPF0, 0x01},
{S3C2410_GPF2, 0x02},
{S3C2410_GPG3, 0x03},
{S3C2410_GPG11, 0x04}
};
//wait_queue_head_t algo_queue;
static DECLARE_WAIT_QUEUE_HEAD(third_wait_irq);
/* 中断事件标志, 中断服务程序将它置为1, third_drv_read 将它清零 */
static volatile int ev_press = 0;
static ssize_t third_drv_read (struct file * fp, char __user *buf, size_t size, loff_t *offset)
{
if(size != 1)
{
return -EINVAL;
}
/* 如果没有按键动作发生, 休眠 */
wait_event_interruptible(third_wait_irq, ev_press); // 如果 ev_press == 0 就 休眠
/* 如果有按键动作发生, 直接返回 */
copy_to_user(buf, &keyVal, sizeof(keyVal));
ev_press = 0;
return sizeof(keyVal);
}
/*
确定按键值
*/
static irqreturn_t button_irq(int irq, void *dev_id)
{
struct pin_desc *pinDesc = (struct pin_desc *)dev_id;
unsigned int pinVal = 0;
pinVal = s3c2410_gpio_getpin(pinDesc->pin);
if (pinVal) // 高电平
{
/* 松开 */
keyVal = 0x80 | pinDesc->keyVal;
}else
{
/* 按下 */
keyVal = pinDesc->keyVal;
}
ev_press = 1;
wake_up_interruptible(&third_wait_irq);
return IRQ_RETVAL(IRQ_HANDLED);
}
static int third_drv_open (struct inode * node, struct file *fp)
{
/* 设置 EINT0 EINT2 EINT11 EINT19 : GPF0 GPF2 GPG3 GPG11 为输入模式 */
request_irq(IRQ_EINT0, button_irq, IRQT_BOTHEDGE, "s2", &pins_desc[0]);
request_irq(IRQ_EINT2, button_irq, IRQT_BOTHEDGE, "s3", &pins_desc[1]);
request_irq(IRQ_EINT11, button_irq, IRQT_BOTHEDGE, "s4", &pins_desc[2]);
request_irq(IRQ_EINT19, button_irq, IRQT_BOTHEDGE, "s5", &pins_desc[3]);
return 0;
}
static int third_drv_release(struct inode * inode, struct file * file)
{
free_irq(IRQ_EINT0, &pins_desc[0]);
free_irq(IRQ_EINT2, &pins_desc[1]);
free_irq(IRQ_EINT11, &pins_desc[2]);
free_irq(IRQ_EINT19, &pins_desc[3]);
}
static struct file_operations third_drv_fops = {
.owner = THIS_MODULE,
.open = third_drv_open,
.read = third_drv_read,
.release = third_drv_release
};
//入口函数
int third_drv_init(void)
{
major = register_chrdev(0, "third_drv", &third_drv_fops);
/* 获取 sys 信息 使用udev机制 创建设备节点 */
third_drv_class = class_create(THIS_MODULE, "third_button");
third_dev = class_device_create(third_drv_class, NULL, MKDEV(major, 0), NULL, "butt");
return 0;
}
void third_drv_exit(void)
{
unregister_chrdev(major, "third_drv");
class_device_unregister(third_dev);
class_destroy(third_drv_class);
}
//驱动入口
module_init(third_drv_init);
module_exit(third_drv_exit);
MODULE_LICENSE("GPL");