1. Define "waiting queue head" wait_queue_head_t key_q; 2. Initialize "waiting queue head" init_waitqueue_head(&key_q); 3. Wait for the event to happen wait_event(key_q, key_num); 4. Wake up and wait for an event wake_up(&key_q); |
Query button status
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; //waiting queue wait_queue_head_t key_q; //1, define the work struct work_struct *work; //(Timer) 1. Define the timer structure struct timer_list buttons_timer; void work_func(struct work_struct *work) { /*Start the timer*/ /*Delay 1s/10=100ms */ mod_timer(&buttons_timer, jiffies + (HZ / 10)); } //(timer) 5, function 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) //The key is pressed to low level { leddata = 0xFF; // light up the LED key_num = 1; } else if(key_val == 1) //The key is pressed to low level { leddata = 0x00; // turn off the LED key_num = 2; } writel(leddata, led_data); // wake up the waiting queue wake_up(&key_q); } void timer_init(void) { //(timer) 2, initialization init_timer(&buttons_timer); buttons_timer.function = &buttons_timer_function; //(Timer) 3. Register the timer with the kernel add_timer(&buttons_timer); } static irqreturn_t key_int(int irq, void *dev_id) { //3. Submit the second half to the kernel default work queue 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); //Read the value in the original register data &= ~0xFF; data |= 0xFF; writew(data, gpio_config); printk("key_hw_init!\n"); led_config = (volatile unsigned int *)ioremap(LEDCON, 4); //Convert physical address to virtual address 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) { // enter the waiting queue to sleep wait_event(key_q, key_num); /*When key_num is true, that is, wake up when the key is pressed*/ 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, }; //register function static int __init button_init(void) { int ret = 0; misc_register(&key_miscdev); //register interrupt handler 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); //hardware initialization key_hw_init(); //2, work initialization work = kmalloc(sizeof(struct work_struct), GFP_KERNEL); //(Note: GFP_KERNEL is the most commonly used in kernel memory allocation, it can cause hibernation when no memory is available) INIT_WORK(work, work_func); //Create work, associate work function // Kernel timer initialization timer_init(); //Initialize the waiting queue init_waitqueue_head(&key_q); return 0; } //logout function static void __exit button_exit(void) { misc_deregister(&key_miscdev); // log out of the interrupt program 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: Through the read function, get the key pressed in the kernel *********************************************/ #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> intmain() { 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; }