1、定义“等待队列头部” wait_queue_head_t key_q; 2、初始化“等待队列头部” init_waitqueue_head(&key_q); 3、等待事件发生 wait_event(key_q, key_num); 4、唤醒等待事件 wake_up(&key_q); |
查询按键状态
key.c
#include <linux/module.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#define GPH0CON 0xE0200C00
#define GPH0DAT 0xE0200C04
#define DEVICE_NAME "tqkey"
#define LEDCON 0xE0200060
#define LEDDAT 0xE0200064
volatile unsigned int *led_config;
volatile unsigned int *led_data;
volatile unsigned int *key_data;
unsigned int key_num;
//等待队列
wait_queue_head_t key_q;
//1、定义工作
struct work_struct *work;
//(定时器)1、定义定时器结构体
struct timer_list buttons_timer;
void work_func(struct work_struct *work)
{
/*启动定时器*/ /*延时 1s/10=100ms */
mod_timer(&buttons_timer, jiffies + (HZ / 10));
}
//(定时器)5、函数
static void buttons_timer_function(unsigned long data)
{
unsigned int key_val;
volatile unsigned short leddata;
key_val = readw(key_data) & 0x03; //GPH0_0 Key_1引角 //GPH0_0 Key_2引角
if(key_val == 2) //按键按下为低电平
{
leddata = 0xFF; //点亮LED
key_num = 1;
}
else if(key_val == 1) //按键按下为低电平
{
leddata = 0x00; //熄灭LED
key_num = 2;
}
writel(leddata, led_data);
//唤醒等待队列
wake_up(&key_q);
}
void timer_init(void)
{
//(定时器)2、初始化
init_timer(&buttons_timer);
buttons_timer.function = &buttons_timer_function;
//(定时器)3、向内核注册定时器
add_timer(&buttons_timer);
}
static irqreturn_t key_int(int irq, void *dev_id)
{
//3、提交下半部至内核默认工作队列keventd_wq
schedule_work(work);
return 0;
}
void key_hw_init(void)
{
volatile unsigned short data;
volatile unsigned int *gpio_config;
gpio_config = (volatile unsigned int *)ioremap(GPH0CON, 4);
data = readw(gpio_config); //读出原有寄存器中的值
data &= ~0xFF;
data |= 0xFF;
writew(data, gpio_config);
printk("key_hw_init!\n");
led_config = (volatile unsigned int *)ioremap(LEDCON, 4); //物理地址转换为虚拟地址
writel(0x00011000, led_config);
led_data = (volatile unsigned int *)ioremap(LEDDAT, 4);
writel(0xFF, led_data);
key_data = (volatile unsigned int *)ioremap(GPH0DAT, 4);
}
/*static long key_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}*/
static int key_open(struct inode *inode, struct file *file)
{
return 0;
}
static int key_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
//进入等待队列睡眠
wait_event(key_q, key_num); /*当key_num为true,即当按键按下时唤醒*/
if (copy_to_user(buf, &key_num, 4))
{
key_num = 0;
return 4;
}
else
{
key_num = 0;
return 0;
}
}
static struct file_operations key_fops =
{
.owner = THIS_MODULE,
//.unlocked_ioctl = key_ioctl,
.open = key_open,
.read = key_read,
.release = NULL,
};
struct miscdevice key_miscdev =
{
.minor = 200,
.name = DEVICE_NAME,
.fops = &key_fops,
};
//注册函数
static int __init button_init(void)
{
int ret = 0;
misc_register(&key_miscdev);
//注册中断处理程序
ret = request_irq(IRQ_EINT0, key_int, IRQF_TRIGGER_FALLING, DEVICE_NAME, 0);
ret = request_irq(IRQ_EINT1, key_int, IRQF_TRIGGER_FALLING, DEVICE_NAME, 0);
//硬件初始化
key_hw_init();
//2、工作初始化
work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
//(注:GFP_KERNEL是内核内存分配时最常用的,无内存可用时可引起休眠)
INIT_WORK(work, work_func); //创建工作,关联工作函数
//内核定时器初始化
timer_init();
//初始化等待队列
init_waitqueue_head(&key_q);
return 0;
}
//注销函数
static void __exit button_exit(void)
{
misc_deregister(&key_miscdev);
//注销中断程序
free_irq(IRQ_EINT0, 0);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jerry.Gou");
MODULE_DESCRIPTION("TQ210 button driver");
key_app.c
/*********************************************
*File name :key_app.c
*Author :JerryGou
*Date :2017/10/23
*Function :通过read函数,获取内核中是那个按键按下
*********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int fd;
int buf = 0;
fd = open("/dev/tqkey", 0);
if (fd < 0)
printf("open fail\n");
read(fd, &buf, 4);
printf("num is %d\n", buf);
close(fd);
return 0;
}