Kobox:key_wq.c-v1
Description
TQ2440 main drivers, four key-driven handling
KEY_WQ.C and Key.c categories are similar, with the main driving force of the difference between KEY.C:
The KEY.C uses a timer to prevent key jitter when the interrupt occurs with a 100ms call to the timer handler function
KEY_WQ.C Use the Task Force column. Schedule shared work queues in the kernel, delay 100ms in the work queue, and infer key state to prevent key jitter
Problem:
Only the kernel shares the work queue and does not delay the case. The program will run normally:
/* Use the kernel Shared Queue to dispatch immediately. Delay put in the interrupt function */
Schedule_work (&gpio_key_work[key]);//normal operation
Use three other cases. The program will be blown off:
/* Use kernel Shared Queue, delay schedule */
schedule_delayed_work (&gpio_key_work[key], key_timer_delay2);//Will Oops
/* Use a separate queue. Delay Scheduling */
queue_delayed_work (&key_wq[key], &gpio_key_work[key], key_timer_delay2);//the same collapse!
/* Use a kernel Shared queue. Dispatch immediately, delay put into the interrupt function */
queue_work (&key_wq[key], &gpio_key_work[key]);//the same collapse!
It's not clear why now.
Source code such as the following:
#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. Set how interrupts are triggered */unsigned int trigbit;/* interrupt mode register which one, set the triggering mode of the interrupt */unsigned int irqflag;/* shared or not shared, register interrupted flag */char irqname[32] */* Break name */unsigned int gpfpin;/* gpf pin */char reserved[10];/* reserved */}gpiores; #define ARRAY_SIZE (arr) (sizeof (ARR)/si Zeof(arr) [0]) unsigned int presscnt[4] = {0, 0, 0, 0};/* defines a work_queue array */struct work_struct gpio_key_work[4];static struct WORKQUEUE_ struct *KEY_WQ[4] = {NULL, NULL, NULL, null};static void Gpio_key_wq0_handler (struct work_struct *work), static void Gpio_k Ey_wq1_handler (struct work_struct *work), static void Gpio_key_wq2_handler (struct work_struct *work), static void Gpio_ Key_wq3_handler (struct work_struct *work);/* Defines an array of function pointers that handle the above four Work_queue */int (*gpio_key_wq_handler[4]) (struct Work_struct *work) = {Gpio_key_wq0_handler,gpio_key_wq1_handler,gpio_key_wq2_handler,gpio_key_wq3_handler,}; 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, S3c2410_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 _timer_delay1 (HZ/50)//press the button to shake delay 20 milliseconds #define KEY_TIMER_DELAY2 (HZ/10) Press the button to lift the jitter delay 100 ms # define Key_count 4static void Set_gpio_as_eint (void) {int i;unsigned uival = 0;for (i=0; i<arr Ay_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: After the delay of 100ms. Read the key state in the Buttons_timer, assuming it is still pressed. It means that the use of the timer is a normal press, and then using the work queue, tasklet in the way to handle *//* using the kernel Shared Queue, delay scheduling *///schedule_delayed_work (&gpio_key_work[ Key], key_timer_delay2),//oops/* use the kernel Shared Queue, dispatch immediately, delay put into the interrupt function */schedule_work (&gpio_key_work[key]),//Run normal/* use a separate queue. Delay Dispatch *///queue_delayed_work (&key_wq[key], &gpio_key_work[key], key_timer_delay2);//The same collapse!/* use the kernel Shared Queue, dispatch immediately, The delay is put into the interrupt function *///queue_work (&key_wq[key], &gpio_key_work[key]);//The same collapse!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 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*//* the function returns0 means that the key is pressed and the return non-0 means that it is not pressed again, which is caused by a level glitch. It's a noise signal, so. The function returns 0, indicating that a key is pressed and returns a non-0 representation of the 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__, pin); uival = Readl (s3c2410_gpfdat); ret = (0x1 << pin) & Uival;prin TK ("I AM @ [%s][%d], ret:%d\n", __function__,__line__, ret); return ret;} static void Gpio_key_wq0_handler (struct work_struct *work) {int ret;unsigned int pin;/* interrupted after 100ms will not cause, run the function */printk ("I am At [%s][%d]\n, __function__, __line__), Msleep (+);p in = key_gpio_res[0].gpfpin;/* The pin is set by Eintx Gpio */set_gpio_as_ Gpio ();/* Reads the value of the corresponding pin Gpio. Returning 0 means the key is actually pressed, and returning 1 indicates jitter */ret = Get_gpio_portf_value (PIN), if (0 = = ret) {presscnt[0]++;p rintk ("Key0 pressed:presscnt[0]:% D\n ", presscnt[0]);} /* Set pin back to Eintx */set_gpio_as_eint (); return;} The static void Gpio_key_wq1_handler (struct work_struct *work) {int ret;unsigned int pin;/* is interrupted after 100ms is not caused. Run the function */printk ("I am at [%s][%d]\n", __function__, __line__); Msleep (+);p in = key_gpio_res[1].gpfpin;/* The PIN is set by Eintx Gpio */set_gpio_as_gpio ();/* Read the value of the corresponding pin Gpio, return 0 means the key is actually pressed, return 1 for jitter */ret = Get_gpio_portf_value (PIN); if (0 = = ret) {presscnt[1]++;p rintk ("Key1 pressed:presscnt[1]:%d\n", presscnt[1]);} /* Set pin back to Eintx */set_gpio_as_eint (); return;} static void Gpio_key_wq2_handler (struct work_struct *work) {int ret;unsigned int pin;/* interrupted after 100ms will not cause, run the function */printk ("I am At [%s][%d]\n, __function__, __line__), Msleep (+);p in = key_gpio_res[2].gpfpin;/* The pin is set by Eintx Gpio */set_gpio_as_ Gpio ();/* Reads the value of the corresponding PIN Gpio and returns 0 to indicate that the key is actually pressed. Return 1 indicates jitter */ret = Get_gpio_portf_value (PIN), if (0 = = ret) {presscnt[2]++;p rintk ("Key2 pressed:presscnt[2]:%d\n", presscnt [2]);} /* Set pin back to Eintx */set_gpio_as_eint (); return;} static void Gpio_key_wq3_handler (struct work_struct *work) {int ret;unsigned int pin;/* interrupted after 100ms will not cause, run the function */printk ("I am At [%s][%d]\n, __function__, __line__), Msleep (+);p in = key_gpio_res[3].gpfpin;/* The pin is set by Eintx Gpio */set_gpio_as_ Gpio ();/* Reads the value of the corresponding pin Gpio. Returning 0 means the key is actually pressed. Return 1 indicates jitter */ret = Get_gpio_portf_value (PIN); if (0 = = RET) {presscnt[3]++;p rintk ("Key3 pressed:presscnt[3]:%d\n", presscnt[3]);} /* Set pin back to Eintx */set_gpio_as_eint (); return;} 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 + +) {/* Set interrupt Trigger mode: Falling Edge is active, triggering interrupt. To infer whether */uival = Readl (Key_gpio_res[i].trigreg) is still being pressed according to the value of the Gpio, Uival |= (0x1 << (key_gpio_res[i].trigbit)); Uival & amp;= ~ (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); Key_wq[i] = Create_workqueue (Key_gpio_res[i].irqname), if (!key_wq[i]) {PRINTK ("Create_workqueue key_wq[%d] failed!\n", i);} /* Initialize the work queue. Used in response to the second half of the interrupt, after the interrupt response 100ms dispatch to go jitter */init_work (&gpio_key_work[i], gpio_key_wq_handler[i]);} return 0;} 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 ();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_wq.c-v1 How to use the work queue Workqueue