summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-01 16:20:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-01 16:20:04 -0400
commit251df49db3327c64bf917bfdba94491fde2b4ee0 (patch)
tree71eef72e1c393057f7b14cc4d8da5e48c7728336 /drivers/tty
parent8a72f3820c4d14b27ad5336aed00063a7a7f1bef (diff)
parentbf61c8840efe60fd8f91446860b63338fb424158 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: "Assorted fixes and cleanups to the existing drivers plus a new driver for IMS Passenger Control Unit device they use for ther in-flight entertainment system." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (44 commits) Input: trackpoint - Optimize trackpoint init to use power-on reset Input: apbps2 - convert to devm_ioremap_resource() Input: ALPS - use %ph to print buffers ARM - shmobile: Armadillo800EVA: Move st1232 reset pin handling Input: st1232 - add reset pin handling Input: st1232 - convert to devm_* infrastructure Input: MT - handle semi-mt devices in core Input: adxl34x - use spi_get_drvdata() Input: ad7877 - use spi_get_drvdata() and spi_set_drvdata() Input: ads7846 - use spi_get_drvdata() and spi_set_drvdata() Input: ims-pcu - fix a memory leak on error Input: sysrq - supplement reset sequence with timeout functionality Input: tegra-kbc - support for defining row/columns based on SoC Input: imx_keypad - switch to using managed resources Input: arc_ps2 - add support for device tree Input: mma8450 - fix signed 12bits to 32bits conversion Input: eeti_ts - remove redundant null check Input: edt-ft5x06 - remove redundant null check before kfree Input: ad714x - add CONFIG_PM_SLEEP to suspend/resume functions Input: adxl34x - add CONFIG_PM_SLEEP to suspend/resume functions ...
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/sysrq.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 0a0de333c765..b51c15408ff3 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -43,6 +43,7 @@
43#include <linux/input.h> 43#include <linux/input.h>
44#include <linux/uaccess.h> 44#include <linux/uaccess.h>
45#include <linux/moduleparam.h> 45#include <linux/moduleparam.h>
46#include <linux/jiffies.h>
46 47
47#include <asm/ptrace.h> 48#include <asm/ptrace.h>
48#include <asm/irq_regs.h> 49#include <asm/irq_regs.h>
@@ -51,6 +52,9 @@
51static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; 52static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
52static bool __read_mostly sysrq_always_enabled; 53static bool __read_mostly sysrq_always_enabled;
53 54
55unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
56int sysrq_reset_downtime_ms __weak;
57
54static bool sysrq_on(void) 58static bool sysrq_on(void)
55{ 59{
56 return sysrq_enabled || sysrq_always_enabled; 60 return sysrq_enabled || sysrq_always_enabled;
@@ -586,6 +590,7 @@ struct sysrq_state {
586 int reset_seq_len; 590 int reset_seq_len;
587 int reset_seq_cnt; 591 int reset_seq_cnt;
588 int reset_seq_version; 592 int reset_seq_version;
593 struct timer_list keyreset_timer;
589}; 594};
590 595
591#define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */ 596#define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */
@@ -619,29 +624,51 @@ static void sysrq_parse_reset_sequence(struct sysrq_state *state)
619 state->reset_seq_version = sysrq_reset_seq_version; 624 state->reset_seq_version = sysrq_reset_seq_version;
620} 625}
621 626
622static bool sysrq_detect_reset_sequence(struct sysrq_state *state, 627static void sysrq_do_reset(unsigned long dummy)
628{
629 __handle_sysrq(sysrq_xlate[KEY_B], false);
630}
631
632static void sysrq_handle_reset_request(struct sysrq_state *state)
633{
634 if (sysrq_reset_downtime_ms)
635 mod_timer(&state->keyreset_timer,
636 jiffies + msecs_to_jiffies(sysrq_reset_downtime_ms));
637 else
638 sysrq_do_reset(0);
639}
640
641static void sysrq_detect_reset_sequence(struct sysrq_state *state,
623 unsigned int code, int value) 642 unsigned int code, int value)
624{ 643{
625 if (!test_bit(code, state->reset_keybit)) { 644 if (!test_bit(code, state->reset_keybit)) {
626 /* 645 /*
627 * Pressing any key _not_ in reset sequence cancels 646 * Pressing any key _not_ in reset sequence cancels
628 * the reset sequence. 647 * the reset sequence. Also cancelling the timer in
648 * case additional keys were pressed after a reset
649 * has been requested.
629 */ 650 */
630 if (value && state->reset_seq_cnt) 651 if (value && state->reset_seq_cnt) {
631 state->reset_canceled = true; 652 state->reset_canceled = true;
653 del_timer(&state->keyreset_timer);
654 }
632 } else if (value == 0) { 655 } else if (value == 0) {
633 /* key release */ 656 /*
657 * Key release - all keys in the reset sequence need
658 * to be pressed and held for the reset timeout
659 * to hold.
660 */
661 del_timer(&state->keyreset_timer);
662
634 if (--state->reset_seq_cnt == 0) 663 if (--state->reset_seq_cnt == 0)
635 state->reset_canceled = false; 664 state->reset_canceled = false;
636 } else if (value == 1) { 665 } else if (value == 1) {
637 /* key press, not autorepeat */ 666 /* key press, not autorepeat */
638 if (++state->reset_seq_cnt == state->reset_seq_len && 667 if (++state->reset_seq_cnt == state->reset_seq_len &&
639 !state->reset_canceled) { 668 !state->reset_canceled) {
640 return true; 669 sysrq_handle_reset_request(state);
641 } 670 }
642 } 671 }
643
644 return false;
645} 672}
646 673
647static void sysrq_reinject_alt_sysrq(struct work_struct *work) 674static void sysrq_reinject_alt_sysrq(struct work_struct *work)
@@ -748,10 +775,8 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
748 if (was_active) 775 if (was_active)
749 schedule_work(&sysrq->reinject_work); 776 schedule_work(&sysrq->reinject_work);
750 777
751 if (sysrq_detect_reset_sequence(sysrq, code, value)) { 778 /* Check for reset sequence */
752 /* Force emergency reboot */ 779 sysrq_detect_reset_sequence(sysrq, code, value);
753 __handle_sysrq(sysrq_xlate[KEY_B], false);
754 }
755 780
756 } else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) { 781 } else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) {
757 /* 782 /*
@@ -812,6 +837,7 @@ static int sysrq_connect(struct input_handler *handler,
812 sysrq->handle.handler = handler; 837 sysrq->handle.handler = handler;
813 sysrq->handle.name = "sysrq"; 838 sysrq->handle.name = "sysrq";
814 sysrq->handle.private = sysrq; 839 sysrq->handle.private = sysrq;
840 setup_timer(&sysrq->keyreset_timer, sysrq_do_reset, 0);
815 841
816 error = input_register_handle(&sysrq->handle); 842 error = input_register_handle(&sysrq->handle);
817 if (error) { 843 if (error) {
@@ -841,6 +867,7 @@ static void sysrq_disconnect(struct input_handle *handle)
841 867
842 input_close_device(handle); 868 input_close_device(handle);
843 cancel_work_sync(&sysrq->reinject_work); 869 cancel_work_sync(&sysrq->reinject_work);
870 del_timer_sync(&sysrq->keyreset_timer);
844 input_unregister_handle(handle); 871 input_unregister_handle(handle);
845 kfree(sysrq); 872 kfree(sysrq);
846} 873}
@@ -870,8 +897,6 @@ static struct input_handler sysrq_handler = {
870 897
871static bool sysrq_handler_registered; 898static bool sysrq_handler_registered;
872 899
873unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
874
875static inline void sysrq_register_handler(void) 900static inline void sysrq_register_handler(void)
876{ 901{
877 unsigned short key; 902 unsigned short key;
@@ -931,6 +956,8 @@ static struct kernel_param_ops param_ops_sysrq_reset_seq = {
931module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq, 956module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
932 &sysrq_reset_seq_len, 0644); 957 &sysrq_reset_seq_len, 0644);
933 958
959module_param_named(sysrq_downtime_ms, sysrq_reset_downtime_ms, int, 0644);
960
934#else 961#else
935 962
936static inline void sysrq_register_handler(void) 963static inline void sysrq_register_handler(void)