diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-09-09 12:24:20 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2011-09-09 12:25:50 -0400 |
commit | 95439cbad134de58d9ea256e37fd13fbcdc87d08 (patch) | |
tree | 258e1670f91558404c94fe07d062166cc88fc9f1 /drivers/input/keyboard/tegra-kbc.c | |
parent | d0d150ec28ab05eb2ec8cf9fcb7c9753ec95e0d4 (diff) |
Input: tegra-kbc - tighten locking
Take spinlock when entering ISR and timer routine to ensure that we do not
race while enabling/disabling FIFO interrupts.
Also we do not need to take teh spinlock in tegra_kbc_startremove() since
interrupt is completely disabled.
Tested-by: Rakesh Iyer <riyer@nvidia.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/keyboard/tegra-kbc.c')
-rw-r--r-- | drivers/input/keyboard/tegra-kbc.c | 31 |
1 files changed, 12 insertions, 19 deletions
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 8fb474f03940..cf3228b0ab90 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c | |||
@@ -260,12 +260,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) | |||
260 | u32 val = 0; | 260 | u32 val = 0; |
261 | unsigned int i; | 261 | unsigned int i; |
262 | unsigned int num_down = 0; | 262 | unsigned int num_down = 0; |
263 | unsigned long flags; | ||
264 | bool fn_keypress = false; | 263 | bool fn_keypress = false; |
265 | bool key_in_same_row = false; | 264 | bool key_in_same_row = false; |
266 | bool key_in_same_col = false; | 265 | bool key_in_same_col = false; |
267 | 266 | ||
268 | spin_lock_irqsave(&kbc->lock, flags); | ||
269 | for (i = 0; i < KBC_MAX_KPENT; i++) { | 267 | for (i = 0; i < KBC_MAX_KPENT; i++) { |
270 | if ((i % 4) == 0) | 268 | if ((i % 4) == 0) |
271 | val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); | 269 | val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); |
@@ -294,7 +292,7 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) | |||
294 | * any 2 of the 3 keys share a row, and any 2 of them share a column. | 292 | * any 2 of the 3 keys share a row, and any 2 of them share a column. |
295 | * If so ignore the key presses for this iteration. | 293 | * If so ignore the key presses for this iteration. |
296 | */ | 294 | */ |
297 | if ((kbc->use_ghost_filter) && (num_down >= 3)) { | 295 | if (kbc->use_ghost_filter && num_down >= 3) { |
298 | for (i = 0; i < num_down; i++) { | 296 | for (i = 0; i < num_down; i++) { |
299 | unsigned int j; | 297 | unsigned int j; |
300 | u8 curr_col = scancodes[i] & 0x07; | 298 | u8 curr_col = scancodes[i] & 0x07; |
@@ -327,8 +325,6 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) | |||
327 | } | 325 | } |
328 | } | 326 | } |
329 | 327 | ||
330 | spin_unlock_irqrestore(&kbc->lock, flags); | ||
331 | |||
332 | /* Ignore the key presses for this iteration? */ | 328 | /* Ignore the key presses for this iteration? */ |
333 | if (key_in_same_col && key_in_same_row) | 329 | if (key_in_same_col && key_in_same_row) |
334 | return; | 330 | return; |
@@ -362,6 +358,8 @@ static void tegra_kbc_keypress_timer(unsigned long data) | |||
362 | u32 val; | 358 | u32 val; |
363 | unsigned int i; | 359 | unsigned int i; |
364 | 360 | ||
361 | spin_lock_irqsave(&kbc->lock, flags); | ||
362 | |||
365 | val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; | 363 | val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; |
366 | if (val) { | 364 | if (val) { |
367 | unsigned long dly; | 365 | unsigned long dly; |
@@ -383,22 +381,19 @@ static void tegra_kbc_keypress_timer(unsigned long data) | |||
383 | kbc->num_pressed_keys = 0; | 381 | kbc->num_pressed_keys = 0; |
384 | 382 | ||
385 | /* All keys are released so enable the keypress interrupt */ | 383 | /* All keys are released so enable the keypress interrupt */ |
386 | spin_lock_irqsave(&kbc->lock, flags); | ||
387 | tegra_kbc_set_fifo_interrupt(kbc, true); | 384 | tegra_kbc_set_fifo_interrupt(kbc, true); |
388 | spin_unlock_irqrestore(&kbc->lock, flags); | ||
389 | } | 385 | } |
386 | |||
387 | spin_unlock_irqrestore(&kbc->lock, flags); | ||
390 | } | 388 | } |
391 | 389 | ||
392 | static irqreturn_t tegra_kbc_isr(int irq, void *args) | 390 | static irqreturn_t tegra_kbc_isr(int irq, void *args) |
393 | { | 391 | { |
394 | struct tegra_kbc *kbc = args; | 392 | struct tegra_kbc *kbc = args; |
393 | unsigned long flags; | ||
395 | u32 val; | 394 | u32 val; |
396 | 395 | ||
397 | /* | 396 | spin_lock_irqsave(&kbc->lock, flags); |
398 | * Until all keys are released, defer further processing to | ||
399 | * the polling loop in tegra_kbc_keypress_timer | ||
400 | */ | ||
401 | tegra_kbc_set_fifo_interrupt(kbc, false); | ||
402 | 397 | ||
403 | /* | 398 | /* |
404 | * Quickly bail out & reenable interrupts if the fifo threshold | 399 | * Quickly bail out & reenable interrupts if the fifo threshold |
@@ -409,14 +404,15 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) | |||
409 | 404 | ||
410 | if (val & KBC_INT_FIFO_CNT_INT_STATUS) { | 405 | if (val & KBC_INT_FIFO_CNT_INT_STATUS) { |
411 | /* | 406 | /* |
412 | * Schedule timer to run when hardware is in continuous | 407 | * Until all keys are released, defer further processing to |
413 | * polling mode. | 408 | * the polling loop in tegra_kbc_keypress_timer. |
414 | */ | 409 | */ |
410 | tegra_kbc_set_fifo_interrupt(kbc, false); | ||
415 | mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); | 411 | mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); |
416 | } else { | ||
417 | tegra_kbc_set_fifo_interrupt(kbc, true); | ||
418 | } | 412 | } |
419 | 413 | ||
414 | spin_unlock_irqrestore(&kbc->lock, flags); | ||
415 | |||
420 | return IRQ_HANDLED; | 416 | return IRQ_HANDLED; |
421 | } | 417 | } |
422 | 418 | ||
@@ -464,7 +460,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc) | |||
464 | static int tegra_kbc_start(struct tegra_kbc *kbc) | 460 | static int tegra_kbc_start(struct tegra_kbc *kbc) |
465 | { | 461 | { |
466 | const struct tegra_kbc_platform_data *pdata = kbc->pdata; | 462 | const struct tegra_kbc_platform_data *pdata = kbc->pdata; |
467 | unsigned long flags; | ||
468 | unsigned int debounce_cnt; | 463 | unsigned int debounce_cnt; |
469 | u32 val = 0; | 464 | u32 val = 0; |
470 | 465 | ||
@@ -502,7 +497,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) | |||
502 | * Atomically clear out any remaining entries in the key FIFO | 497 | * Atomically clear out any remaining entries in the key FIFO |
503 | * and enable keyboard interrupts. | 498 | * and enable keyboard interrupts. |
504 | */ | 499 | */ |
505 | spin_lock_irqsave(&kbc->lock, flags); | ||
506 | while (1) { | 500 | while (1) { |
507 | val = readl(kbc->mmio + KBC_INT_0); | 501 | val = readl(kbc->mmio + KBC_INT_0); |
508 | val >>= 4; | 502 | val >>= 4; |
@@ -513,7 +507,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) | |||
513 | val = readl(kbc->mmio + KBC_KP_ENT1_0); | 507 | val = readl(kbc->mmio + KBC_KP_ENT1_0); |
514 | } | 508 | } |
515 | writel(0x7, kbc->mmio + KBC_INT_0); | 509 | writel(0x7, kbc->mmio + KBC_INT_0); |
516 | spin_unlock_irqrestore(&kbc->lock, flags); | ||
517 | 510 | ||
518 | enable_irq(kbc->irq); | 511 | enable_irq(kbc->irq); |
519 | 512 | ||