Platform: TQ2440 Key Driver
(1) Create a kernel thread in init as a processing function for the wait queue, which is a while (1) dead loop, and always detects the trigger condition of the waiting queue
Declare_wait_queue_head (KEY_DRIVER_WQ);
/* Create a kernel thread */kthread_run (key_wait_queue_handler, "Thread_key_waitqueue", "[Key_wait_queue]");
static int key_wait_queue_handler (void *name) {int i = 0;int ret;unsigned int pin;printk ("Thread name:[%s]\n", name); while (1) {wait_event (key_driver_wq, condition = = 1); if (condition = = 1) {...} Msleep (+), if (condition = = 1) {condition = 0;}} return;}
(2) Scheduling wait queue in interrupt
static irqreturn_t kobox_gpio_irq_handle (int irq, void *dev_id) {int key;disable_irq_nosync (IRQ);p RINTK ("IRQ =%d\n", IRQ), if (dev_id) printk ("dev_id:%s\n", dev_id), switch (IRQ) {case Irq_eint1:key = 0;break;case Irq_eint4:key = 1;break; Case Irq_eint2:key = 2;break;case Irq_eint0:key = 3;BREAK;DEFAULT:PRINTK ("Invalid irq:%d\n", IRQ); return irq_handled; }/* to shake: Delay after 100ms, read the key state in the Buttons_timer, assuming or pressed, it is the normal press of the use of the timer is a way, followed by the work queue, tasklet in the way to deal with */condition = 1;wake _UP (&KEY_DRIVER_WQ); Enable_irq (IRQ); return Irq_retval (irq_handled);}
(3) Drive source code:
#include "key.h" #define S3c_addr_base0xf6000000#define s3c_addr (x) (S3c_addr_base + (x)) #define S3C2410_PA_UART ( 0x50000000) #define S3C2410_PA_GPIO (0x56000000) #define S3C_VA_UARTS3C_ADDR (0x01000000)/* UART */#define S3c24xx_pa_ Uarts3c2410_pa_uart#define S3c24xx_va_uarts3c_va_uart#define S3c24xx_pa_gpios3c2410_pa_gpio#define S3C24XX_VA_ GPIO ((S3c24xx_pa_gpio-s3c24xx_pa_uart) + s3c24xx_va_uart) #define S3C2410_GPIOREG (x) ((x) + S3c24xx_va_gpio) #define S3c2410_gpbcon S3c2410_gpioreg (0x10) #define S3c2410_gpbdat s3c2410_gpioreg (0x14) #define S3C2410_GPBUP S3c2410_gpior EG (0x18) #define S3c2410_gpfcon s3c2410_gpioreg (0x50) #define S3c2410_gpfdat s3c2410_gpioreg (0x54) #define S3c2410_ Gpfup S3c2410_gpioreg (0x58) #define S3C2410_EXTINT0 s3c2410_gpioreg (0x88) #define S3C2410_EXTINT1 S3c2410_gpioreg (0x8 C) #define S3C2410_EXTINT2 s3c2410_gpioreg (0x90) #define S3C2410_CPUIRQ_OFFSET (+) #define S3C2410_IRQ (x) ((x) + s3c2410 _CPUIRQ_OFFSET)/* Main CPU Interrupts */#define IRQ_EINT0 s3c2410_IRQ (0)/*/#define IRQ_EINT1 S3C2410_IRQ (1)/* */#define IRQ_EINT2 S3C2410_IRQ (2)/*/#define Irq_e Int4t7 S3C2410_IRQ (4)/*/#define IRQ_EINT4 S3C2410_IRQ (+)//*/#define Irqf_disabled0x00000020#defin E irqf_shared0x00000080#define irqf_probe_shared0x00000100#define __irqf_timer0x00000200#define IRQF_ Percpu0x00000400#define Irqf_nobalancing0x00000800#define Irqf_irqpoll0x00001000#define IRQF_ONESHOT0x00002000# Define Irqf_no_suspend0x00004000#define irqf_force_resume0x00008000#define Irqf_no_thread0x00010000#define IRQF_ early_resume0x00020000typedef struct Gpiores{int irqnum;/* interrupt number */unsigned int ctrlreg;/* control register for setting multiplexing as Gpio */unsigned int ctrlbit; /* Which one of the control registers, used to reuse as Gpio */unsigned int trigreg;/* Interrupt mode register, sets the trigger mode of the interrupt */unsigned int trigbit;/* interrupt mode register which one, set the trigger mode of the interrupt */ unsigned int irqflag;/* shared or not shared, register interrupted flag */char irqname[32];/* interrupt name */unsigned int gpfpin;/* gpf pin */char reserved[1 0];/* reserved */}gpiores;unsigned int presscnt[4] = {0, 0, 0, 0}; #deFine Array_size (arr) (sizeof (arr)/sizeof (arr) [0]) static int kobox_key_open (struct inode *inode, struct file *file) { return 0;} static int kobox_key_release (struct inode *inode, struct file *file) {return 0;} Static long kobox_key_ioctl (struct file *file, unsigned int cmd, unsigned long arg) {return 0;} static int kobox_key_read (struct file *file, char __user *buff, size_t count, loff_t *pos) {PRINTK ("Enter [%s][%d]\n", __fu NCTION__,__LINE__); Copy_to_user (Buff, &presscnt[0], sizeof (PRESSCNT)); return 0;} /*GPF Related registers: Gpfcon 0x56000050 r/w Configures the pins of Port F 0x0gpfdat 0x56000054 r/w The data register for Port F Undef . Gpfup 0x56000058 r/w pull-up Disable register for Port F 0x000k1:gpf1-eint1:gpf1 [3:2] xx = Input01 = Output = Eint [1] one = RESERVEDK2:GPF4-EINT4:GPF4 [9:8] xx = Input01 = Output = eint[4] one = RESERVEDK3:GPF2-EINT2:GPF2 [5:4] xx = Input01 = output = EINT2] one = reservedk4:gpf0-eint0:gpf0 [1:0] = Input01 = output = eint[0] one = Rese RveD*/gpiores key_gpio_res[4] ={{irq_eint1, S3c2410_gpfcon, 2, S3c2410_extint0, 5, NULL, "Key1", 1},/* key1 */{irq_eint4, S3C 2410_gpfcon, 8, s3c2410_extint0, irqf_shared, Key2, 4},/* key2 */{irq_eint2, S3c2410_gpfcon, 4, s3c2410_extint0, 9, NULL, "Key3", 2},/* Key3 */{irq_eint0, S3c2410_gpfcon, 0, s3c2410_extint0, 1, NULL, "Key4", 0},/* Key4 */}; #define Key_tim Er_delay1 (HZ/50)//press the button to shake time delay 20 milliseconds #define KEY_TIMER_DELAY2 (HZ/10)//button lift to shake delay 100 milliseconds #defi Ne key_count 4//static struct timer_list key_timers[key_count]; Define 4 keys to jitter timer//static declare_wait_queue_head (BUTTON_WAITQ); Define and initialize the wait queue static int condition = 0;declare_wait_queue_head (KEY_DRIVER_WQ); static int key_wait_queue_handler (void *name), static void Set_gpio_as_eint (void) {int i;unsigned uival = 0;for (i=0; i< Array_size (Key_gpio_res); i++) {uival = Readl (Key_gpio_res[i].ctrlreg); Uival &= ~ (0x01 << key_gpio_res[i].ctrlbit); Uival |= (0x01 < < (key_gpio_res[i].ctrlbit + 1)); writeL (Uival, Key_gpio_res[i].ctrlreg);} return;} static void Set_gpio_as_gpio (void) {int i;unsigned uival = 0;for (i=0; i<array_size (key_gpio_res); i++) {uival = Readl ( Key_gpio_res[i].ctrlreg) Uival &= ~ (0x01 << key_gpio_res[i].ctrlbit); Uival &= ~ (0x01 << (key_gpio_ Res[i].ctrlbit + 1)); Writel (Uival, Key_gpio_res[i].ctrlreg);} return;} static irqreturn_t kobox_gpio_irq_handle (int irq, void *dev_id) {int key;disable_irq_nosync (IRQ);p RINTK ("IRQ =%d\n", IRQ), if (dev_id) printk ("dev_id:%s\n", dev_id), switch (IRQ) {case Irq_eint1:key = 0;break;case Irq_eint4:key = 1;break; Case Irq_eint2:key = 2;break;case Irq_eint0:key = 3;BREAK;DEFAULT:PRINTK ("Invalid irq:%d\n", IRQ); return irq_handled; }/* to shake: Delay after 100ms, read the key state in the Buttons_timer, assuming or pressed, it is the normal press of the use of the timer is a way, followed by the work queue, tasklet in the way to deal with */condition = 1;wake _UP (&KEY_DRIVER_WQ); Enable_irq (IRQ); return Irq_retval (irq_handled);} /*GPF Related registers: Gpfcon 0x56000050 r/w Configures the pins of port F 0x0gpfdat 0x56000054 r/w The data register for PortF undef.gpfup 0x56000058 r/w pull-up Disable register for Port F 0x000k1:gpf1-eint1:gpf1 [3:2] xx = Input01 = Output 1 0 = eint[1] one = Reservedk2:gpf4-eint4:gpf4 [9:8] xx = Input01 = Output = eint[4] one = RESERVEDK3:GPF2-EINT2:GP F2 [5:4] xx = Input01 = output = EINT2] one = reservedk4:gpf0-eint0:gpf0 [1:0] xx = Input01 = output = Eint[0] 1 1 = reserved*//* The function returns 0 means that the key is pressed and the return non-0 means that it is not pressed again, it is a noise signal because it is a level glitch, so the function returns 0, indicating that a key is pressed, and that a non 0 is a jitter */static int get_gpio_ Portf_value (unsigned int pin) {int ret;unsigned int uival = 0;PRINTK ("I AM @ [%s][%d], pin:%d\n", __function__,__line__, pi n); uival = Readl (s3c2410_gpfdat); ret = (0x1 << pin) & UIVAL;PRINTK ("I AM @ [%s][%d], ret:%d\n", __function__,__l INE__, ret); return ret;} static int Request_irq_for_gpio (void) {int i;int ret;unsigned uival;int nouse;for (i=0; i<array_size (key_gpio_res); I + +) {/* Sets the Interrupt trigger mode: The falling edge is active, triggering an interrupt to infer whether the */uival = Readl (Key_gpio_res[i].trigreg) is still being pressed based on the value of the Gpio; Uival |= (0x1 << Key_ Gpio_res[i].trigbit));Uival &= ~ (0x1 << (key_gpio_res[i].trigbit + 1)) Writel (Uival, Key_gpio_res[i].trigreg);/* Register Interrupt */ret = Request _IRQ (Key_gpio_res[i].irqnum, Kobox_gpio_irq_handle, Key_gpio_res[i].irqflag, Key_gpio_res[i].irqname, (void *) key _gpio_res[i].irqname); if (ret) PRINTK ("[func:%s][line:%d] Request_irq failed, ret:%d!\n", __function__,__line__,ret) ; ELSEPRINTK ("[func:%s][line:%d] request_irq OK, irq:%d!\n", __function__,__line__, Key_gpio_res[i].irqnum);} return 0;} static int key_wait_queue_handler (void *name) {int i = 0;int ret;unsigned int pin;printk ("Thread name:[%s]\n", name); while (1) {wait_event (key_driver_wq, condition = = 1); if (condition = = 1) {/* will pin is set by EINTX will Gpio */set_gpio_as_gpio (); for (i=0; i< Array_size (Key_gpio_res); i++) {pin = key_gpio_res[i].gpfpin;/* reads the value of the corresponding pin Gpio, returns 0 indicating that the key is actually pressed and returns 1 for jitter */ret = Get_gpio_portf_value (PIN); if (0 = = ret) { presscnt[i]++;p rintk ("Key pressed:presscnt[%d]:%d\n", I, Presscnt[i]);}} /* Set pin back to Eintx */set_gpio_as_eint (); condition = 0;} Msleep (1000);} ReTurn;} struct File_operations kobox_key_operations = {. Owner = This_module,.open = Kobox_key_open,.read = Kobo X_key_read,.release = Kobox_key_release,.unlocked_ioctl = Kobox_key_ioctl,};//gpb0int major;int minor;struct cdev C Dev;struct class *kobox_key_class;struct Device *pstdev = NULL, #define GPIO_KEY_NAME "Kobox_key" int __init key_drv_init ( void) {int error;dev_t dev;printk ("# # # #enter key_drv_init!\n"); major = Register_chrdev (0, Gpio_key_name, &kobox_ Key_operations); if (major < 0) {PRINTK ("can ' t register major number\n"); return major;} /* Create class */kobox_key_class = Class_create (This_module, Gpio_key_name), if (Is_err (Kobox_key_class)) {PRINTK (" Class_create failed!\n "); goto fail;} /* Create/dev/kobox_gpio */pstdev = device_create (Kobox_key_class, NULL, MKDEV (major, 0), NULL, gpio_key_name); Pstdev) {PRINTK ("device_create failed!\n"); goto Fail1;} /* Set GPF0/1/2/4 as extern interrupt pins */set_gpio_as_eint (); Request_irq_for_gpio ();/* Create a kernelThread */kthread_run (Key_wait_queue_handler, "Thread_key_waitqueue", "[Key_wait_queue]");p RINTK ("# # # #key_drv_ init ok!\n "); return 0;fail1:class_destroy (Kobox_key_class); Fail:unregister_chrdev (Major, Gpio_key_name); return-1;} void __exit key_drv_exit (void) {PRINTK ("Exit Gpio drv!\n");d Evice_destroy (Kobox_key_class, MKDEV (major, 0)); class_ Destroy (Kobox_key_class); Unregister_chrdev (Major, Gpio_key_name); return;} Module_init (Key_drv_init); Module_exit (Key_drv_exit); Module_license ("GPL");
Kobox:key_waitqueue.c-v1 How kernel threads, how to use the wait queue