Kobox:key_waitqueue.c-v1 How kernel threads, how to use the wait queue

Source: Internet
Author: User

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 (&AMP;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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.