#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");