#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/uaccess.h>
static dev_t dev_id;
static struct cdev *button_dev;
static struct class *button_class;
/* 定义并初始化一个等待队列头 */
static DECLARE_WAIT_QUEUE_HEAD(button_wq_head);
static int button_conditon;
static int button_val;
static irqreturn_t button_irq(int irq, void *data)
{
/* 判断等待队列中是否有等待元素 */
//也就是判断一个等待队列是否可用:
if(!waitqueue_active(&button_wq_head))
return IRQ_HANDLED;
/* 读取按键值 */
button_val = gpio_get_value(S5PV210_GPH0(2));
/* 唤醒等待队列 */
/***
wake_up可以唤醒处于TASK_UNINTERRUPTIBLE和TASK_INTERRUPTIBLE
状态的进程
wake_up_interruptible只能唤醒处于TASK_INTERRUPTIBLE状态的进程
TASK_INTERRUPTIBLE:处于等待队伍中,等待资源有效时唤醒
(比方等待键盘输入、socket连接、信号等等),
但能够被中断唤醒.普通情况下,进程列表中的绝大多
数进程都处于TASK_INTERRUPTIBLE状态.毕竟皇帝仅仅有一个
(单个CPU时),后宫佳丽几千;假设不是绝大多数进
程都在睡眠,CPU又怎么响应得过来.
TASK_UNINTERRUPTIBLE:处于等待队伍中,等待资源有效时唤醒
(比方等待键盘输入、socket连接、信号等等),
但不能够被中断唤醒.
***/
button_conditon = 1;
wake_up_interruptible(&button_wq_head);
return IRQ_HANDLED;
}
static int button_open(struct inode *inode, struct file *file)
{
int ret;
ret = request_irq(IRQ_EINT2, button_irq, IRQF_TRIGGER_FALLING, "button_irq", NULL);
return 0;
}
static ssize_t button_read(struct file *file, char __user *data, size_t size, loff_t *loff)
{
int ret;
int val;
/* 睡眠等待 */
button_conditon = 0;
wait_event_interruptible(button_wq_head, button_conditon);
button_conditon = 0;
val = button_val;
ret = copy_to_user(data, &val, sizeof(val));
return sizeof(val);
}
static int button_release(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT2, NULL);
return 0;
}
static struct file_operations button_fops = {
.owner = THIS_MODULE,
.open = button_open,
.read = button_read,
.release = button_release,
};
static __init int button_init(void)
{
/* 申请设备号 */
alloc_chrdev_region(&dev_id, 1, 1, "button");
/* 分配字符设备 */
button_dev = cdev_alloc();
/* 设置字符设备 */
cdev_init(button_dev, &button_fops);
/* 注册字符设备 */
cdev_add(button_dev, dev_id, 1);
/* 创建设备节点 */
button_class = class_create(THIS_MODULE, "button"); //创建类
device_create(button_class, NULL, dev_id, NULL, "button"); //创建设备节点
gpio_request(S5PV210_GPH0(2), "button");
return 0;
}
static __exit void button_exit(void)
{
/* 注销设备节点 */
device_destroy(button_class, dev_id);
class_destroy(button_class);
/* 注销字符设备 */
cdev_del(button_dev);
kfree(button_dev);
/* 注销注册的设备号 */
unregister_chrdev_region(dev_id, 1);
gpio_free(S5PV210_GPH0(2));
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
|