mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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)

  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