From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: mathieu.poirier@linaro.org
Cc: linux-kernel@vger.kernel.org, arve@android.com,
kernel-team@android.com, john.stultz@linaro.org,
alan@lxorguk.ukuu.org.uk
Subject: Re: [PATCH v4] drivers/tty: Folding Android's keyreset driver in sysRQ
Date: Sun, 18 Nov 2012 23:25:25 -0800 [thread overview]
Message-ID: <20121119072525.GA16730@core.coreip.homeip.net> (raw)
In-Reply-To: <1352665488-13818-1-git-send-email-mathieu.poirier@linaro.org>
Hi Mathieu,
On Sun, Nov 11, 2012 at 01:24:48PM -0700, mathieu.poirier@linaro.org wrote:
> From: "Mathieu J. Poirier" <mathieu.poirier@linaro.org>
>
> This patch adds keyreset functionality to the sysrq driver. It
> allows certain button/key combinations to be used in order to
> trigger device resets.
>
> The first time the key-combo is detected a work function that syncs
> the filesystems is scheduled and the kernel rebooted. If all the keys
> are released and then pressed again, it calls panic. Reboot on panic
> should be set for this to work.
>
> Redefining the '__weak sysrq_keyreset_get_params' function is required
> to trigger the feature. Alternatively keys can be passed to the
> driver via the "/sys/module/sysrq" interface.
>
> This functionality comes from the keyreset driver submitted by
> Arve Hjønnevåg in the Android kernel.
Thank you for making the changes. This still looks pretty complicated,
how about if we trim it a bit, like in the patch below.
Thanks.
--
Dmitry
Input: sysrq - allow specifying alternate reset sequence
From: Mathieu J. Poirier <mathieu.poirier@linaro.org>
This patch adds keyreset functionality to the sysrq driver. It allows
certain button/key combinations to be used in order to trigger emergency
reboots.
Redefining the '__weak platform_sysrq_reset_seq' variable is required
to trigger the feature. Alternatively keys can be passed to the driver
via a module parameter.
This functionality comes from the keyreset driver submitted by
Arve Hjønnevåg in the Android kernel.
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/tty/sysrq.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 16ee6ce..9dddaf7 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -41,6 +41,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/uaccess.h>
+#include <linux/moduleparam.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -576,8 +577,73 @@ struct sysrq_state {
bool active;
bool need_reinject;
bool reinjecting;
+
+ /* reset sequence handling */
+ bool reset_canceled;
+ unsigned long reset_keybit[BITS_TO_LONGS(KEY_CNT)];
+ int reset_seq_len;
+ int reset_seq_cnt;
+ int reset_seq_version;
};
+#define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */
+static unsigned short sysrq_reset_seq[SYSRQ_KEY_RESET_MAX];
+static unsigned int sysrq_reset_seq_len;
+static unsigned int sysrq_reset_seq_version = 1;
+
+static void sysrq_parse_reset_sequence(struct sysrq_state *state)
+{
+ int i;
+ unsigned short key;
+
+ state->reset_seq_cnt = 0;
+
+ for (i = 0; i < sysrq_reset_seq_len; i++) {
+ key = sysrq_reset_seq[i];
+
+ if (key == KEY_RESERVED || key > KEY_MAX)
+ break;
+
+ __set_bit(key, state->reset_keybit);
+ state->reset_seq_len++;
+
+ if (test_bit(key, state->key_down))
+ state->reset_seq_cnt++;
+ }
+}
+
+static bool sysrq_detect_reset_sequence(struct sysrq_state *state,
+ unsigned int code, int value)
+{
+ if (state->reset_seq_version != sysrq_reset_seq_version) {
+ sysrq_parse_reset_sequence(state);
+ /* Disable reset until old keys are not released */
+ state->reset_canceled = state->reset_seq_cnt != 0;
+ state->reset_seq_version = sysrq_reset_seq_version;
+ }
+
+ if (!test_bit(code, state->reset_keybit)) {
+ /*
+ * Pressing any key _not_ in reset sequence cancels
+ * the reset sequence.
+ */
+ if (value && state->reset_seq_cnt)
+ state->reset_canceled = true;
+ } else if (value == 0) {
+ /* key release */
+ 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;
+ }
+ }
+
+ return false;
+}
+
static void sysrq_reinject_alt_sysrq(struct work_struct *work)
{
struct sysrq_state *sysrq =
@@ -690,6 +756,11 @@ static bool sysrq_filter(struct input_handle *handle,
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);
+ }
+
} else if (value == 0 &&
test_and_clear_bit(code, sysrq->key_down)) {
/*
@@ -785,7 +856,20 @@ static bool sysrq_handler_registered;
static inline void sysrq_register_handler(void)
{
+ extern unsigned short platform_sysrq_reset_seq[] __weak;
+ unsigned short key;
int error;
+ int i;
+
+ if (platform_sysrq_reset_seq) {
+ for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
+ key = platform_sysrq_reset_seq[i];
+ if (key == KEY_RESERVED || key > KEY_MAX)
+ break;
+
+ sysrq_reset_seq[sysrq_reset_seq_len++] = key;
+ }
+ }
error = input_register_handler(&sysrq_handler);
if (error)
@@ -802,6 +886,36 @@ static inline void sysrq_unregister_handler(void)
}
}
+static int sysrq_reset_seq_param_set(const char *buffer,
+ const struct kernel_param *kp)
+{
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buffer, 0, &val);
+ if (error < 0)
+ return error;
+
+ if (val > KEY_MAX)
+ return -EINVAL;
+
+ *((unsigned short *)kp->arg) = val;
+ sysrq_reset_seq_version++;
+
+ return 0;
+}
+
+static struct kernel_param_ops param_ops_sysrq_reset_seq = {
+ .get = param_get_ushort,
+ .set = sysrq_reset_seq_param_set,
+};
+
+#define param_check_sysrq_reset_seq(name, p) \
+ __param_check(name, p, unsigned short)
+
+module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
+ &sysrq_reset_seq_len, 0644);
+
#else
static inline void sysrq_register_handler(void)
next prev parent reply other threads:[~2012-11-19 7:25 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-11 20:24 mathieu.poirier
2012-11-19 7:25 ` Dmitry Torokhov [this message]
[not found] ` <CAPM=9tw8mefcYTqELXFbZWZ44a--SNcPnRMAvMSGTiODzRpDhg@mail.gmail.com>
2013-02-27 8:26 ` Dave Airlie
2013-02-27 11:06 ` Dave Airlie
2013-02-27 11:10 ` Dave Airlie
2013-02-27 11:40 ` Dave Airlie
2013-02-27 16:57 ` Linus Torvalds
2013-02-27 17:58 ` Mathieu Poirier
2013-02-27 18:09 ` Linus Torvalds
2013-02-27 18:26 ` David Howells
2013-02-27 18:49 ` Dmitry Torokhov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20121119072525.GA16730@core.coreip.homeip.net \
--to=dmitry.torokhov@gmail.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=arve@android.com \
--cc=john.stultz@linaro.org \
--cc=kernel-team@android.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mathieu.poirier@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome