diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 22:20:04 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-01 22:20:04 +0200 |
commit | 251df49db3327c64bf917bfdba94491fde2b4ee0 (patch) | |
tree | 71eef72e1c393057f7b14cc4d8da5e48c7728336 /drivers/tty/sysrq.c | |
parent | Merge git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux-tile (diff) | |
parent | Merge branch 'next' into for-linus (diff) | |
download | linux-251df49db3327c64bf917bfdba94491fde2b4ee0.tar.xz linux-251df49db3327c64bf917bfdba94491fde2b4ee0.zip |
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/sysrq.c')
-rw-r--r-- | drivers/tty/sysrq.c | 53 |
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 @@ #include <linux/input.h> #include <linux/uaccess.h> #include <linux/moduleparam.h> +#include <linux/jiffies.h> #include <asm/ptrace.h> #include <asm/irq_regs.h> @@ -51,6 +52,9 @@ static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE; static bool __read_mostly sysrq_always_enabled; +unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED }; +int sysrq_reset_downtime_ms __weak; + static bool sysrq_on(void) { return sysrq_enabled || sysrq_always_enabled; @@ -586,6 +590,7 @@ struct sysrq_state { int reset_seq_len; int reset_seq_cnt; int reset_seq_version; + struct timer_list keyreset_timer; }; #define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */ @@ -619,29 +624,51 @@ static void sysrq_parse_reset_sequence(struct sysrq_state *state) state->reset_seq_version = sysrq_reset_seq_version; } -static bool sysrq_detect_reset_sequence(struct sysrq_state *state, +static void sysrq_do_reset(unsigned long dummy) +{ + __handle_sysrq(sysrq_xlate[KEY_B], false); +} + +static void sysrq_handle_reset_request(struct sysrq_state *state) +{ + if (sysrq_reset_downtime_ms) + mod_timer(&state->keyreset_timer, + jiffies + msecs_to_jiffies(sysrq_reset_downtime_ms)); + else + sysrq_do_reset(0); +} + +static void sysrq_detect_reset_sequence(struct sysrq_state *state, unsigned int code, int value) { if (!test_bit(code, state->reset_keybit)) { /* * Pressing any key _not_ in reset sequence cancels - * the reset sequence. + * the reset sequence. Also cancelling the timer in + * case additional keys were pressed after a reset + * has been requested. */ - if (value && state->reset_seq_cnt) + if (value && state->reset_seq_cnt) { state->reset_canceled = true; + del_timer(&state->keyreset_timer); + } } else if (value == 0) { - /* key release */ + /* + * Key release - all keys in the reset sequence need + * to be pressed and held for the reset timeout + * to hold. + */ + del_timer(&state->keyreset_timer); + if (--state->reset_seq_cnt == 0) state->reset_canceled = false; } else if (value == 1) { /* key press, not autorepeat */ if (++state->reset_seq_cnt == state->reset_seq_len && !state->reset_canceled) { - return true; + sysrq_handle_reset_request(state); } } - - return false; } static void sysrq_reinject_alt_sysrq(struct work_struct *work) @@ -748,10 +775,8 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, if (was_active) schedule_work(&sysrq->reinject_work); - if (sysrq_detect_reset_sequence(sysrq, code, value)) { - /* Force emergency reboot */ - __handle_sysrq(sysrq_xlate[KEY_B], false); - } + /* Check for reset sequence */ + sysrq_detect_reset_sequence(sysrq, code, value); } else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) { /* @@ -812,6 +837,7 @@ static int sysrq_connect(struct input_handler *handler, sysrq->handle.handler = handler; sysrq->handle.name = "sysrq"; sysrq->handle.private = sysrq; + setup_timer(&sysrq->keyreset_timer, sysrq_do_reset, 0); error = input_register_handle(&sysrq->handle); if (error) { @@ -841,6 +867,7 @@ static void sysrq_disconnect(struct input_handle *handle) input_close_device(handle); cancel_work_sync(&sysrq->reinject_work); + del_timer_sync(&sysrq->keyreset_timer); input_unregister_handle(handle); kfree(sysrq); } @@ -870,8 +897,6 @@ static struct input_handler sysrq_handler = { static bool sysrq_handler_registered; -unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED }; - static inline void sysrq_register_handler(void) { unsigned short key; @@ -931,6 +956,8 @@ static struct kernel_param_ops param_ops_sysrq_reset_seq = { module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq, &sysrq_reset_seq_len, 0644); +module_param_named(sysrq_downtime_ms, sysrq_reset_downtime_ms, int, 0644); + #else static inline void sysrq_register_handler(void) |