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; }