* [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear [not found] <1267132893-23624-1-git-send-email-jason.wessel@windriver.com> @ 2010-02-25 21:21 ` Jason Wessel 2010-02-26 8:03 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Jason Wessel @ 2010-02-25 21:21 UTC (permalink / raw) To: torvalds Cc: linux-kernel, kgdb-bugreport, Jason Wessel, Dmitry Torokhov, Henrik Rydberg, Greg Kroah-Hartman, Alexey Dobriyan, Kay Sievers, linux-input When using a keyboard with kdb, on resuming the system there needs to be a hook to allow for the keyboard state to get reset. This is mainly because there is no way to force the end user to hold down the original keys that were pressed prior to entering kdb. CC: Dmitry Torokhov <dmitry.torokhov@gmail.com> CC: Henrik Rydberg <rydberg@euromail.se> CC: Greg Kroah-Hartman <gregkh@suse.de> CC: Alexey Dobriyan <adobriyan@gmail.com> CC: Kay Sievers <kay.sievers@vrfy.org> CC: linux-input@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> --- drivers/char/keyboard.c | 29 ++++++++++++++++++++++++----- drivers/input/input.c | 15 +++++++++++++++ drivers/serial/kgdboc.c | 13 +++++++++++++ include/linux/input.h | 10 ++++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index f706b1d..d61145a 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1195,6 +1195,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (keycode < BTN_MISC && printk_ratelimit()) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + if (down) + set_bit(keycode, key_down); + else + clear_bit(keycode, key_down); + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { if (!sysrq_down) { @@ -1237,11 +1242,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) raw_mode = 1; } - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { @@ -1410,6 +1410,22 @@ static const struct input_device_id kbd_ids[] = { MODULE_DEVICE_TABLE(input, kbd_ids); +#ifdef CONFIG_KDB_KEYBOARD +void kbd_clear_keys(void) +{ + int i, j, k; + + for (i = 0; i < ARRAY_SIZE(key_down); i++) { + k = i * BITS_PER_LONG; + for (j = 0; j < BITS_PER_LONG; j++, k++) { + if (test_bit(k, key_down)) { + kbd_keycode(k, 0, 0); + } + } + } +} +#endif + static struct input_handler kbd_handler = { .event = kbd_event, .connect = kbd_connect, @@ -1417,6 +1433,9 @@ static struct input_handler kbd_handler = { .start = kbd_start, .name = "kbd", .id_table = kbd_ids, +#ifdef CONFIG_KDB_KEYBOARD + .dbg_clear_keys = kbd_clear_keys, +#endif }; int __init kbd_init(void) diff --git a/drivers/input/input.c b/drivers/input/input.c index 86cb2d2..7473300 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1692,6 +1692,21 @@ int input_register_handler(struct input_handler *handler) } EXPORT_SYMBOL(input_register_handler); +#ifdef CONFIG_KDB_KEYBOARD +/* input_db_clear_keys - Clear any keyboards if they have a call back, + * after returning from the kernel debugger + */ +void input_dbg_clear_keys(void) +{ + struct input_handler *handler; + + list_for_each_entry(handler, &input_handler_list, node) + if (handler->dbg_clear_keys) + handler->dbg_clear_keys(); +} +EXPORT_SYMBOL_GPL(input_dbg_clear_keys); +#endif + /** * input_unregister_handler - unregisters an input handler * @handler: handler to be unregistered diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index b765ab4..201cdf5 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -17,6 +17,7 @@ #include <linux/kdb.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/input.h> #define MAX_CONFIG_LEN 40 @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_driver; static int kgdb_tty_line; #ifdef CONFIG_KDB_KEYBOARD +static int kgdboc_use_kbd; /* 1 if we use a keyboard */ + static int kgdboc_register_kbd(char **cptr) { + kgdboc_use_kbd = 0; if (strncmp(*cptr, "kbd", 3) == 0) { if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; kdb_poll_idx++; + kgdboc_use_kbd = 1; if (cptr[0][3] == ',') *cptr += 4; else @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) } } } + +static inline void kgdboc_clear_kbd(void) +{ + if (kgdboc_use_kbd) + input_dbg_clear_keys(); /* Release all pressed keys */ +} #else /* ! CONFIG_KDB_KEYBOARD */ #define kgdboc_register_kbd(x) 0 #define kgdboc_unregister_kbd() +#define kgdboc_clear_kbd() #endif /* ! CONFIG_KDB_KEYBOARD */ static int kgdboc_option_setup(char *opt) @@ -213,6 +225,7 @@ static void kgdboc_post_exp_handler(void) /* decrement the module count when the debugger detaches */ if (!kgdb_connected) module_put(THIS_MODULE); + kgdboc_clear_kbd(); } static struct kgdb_io kgdboc_io_ops = { diff --git a/include/linux/input.h b/include/linux/input.h index 663208a..9529b63 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1232,6 +1232,9 @@ struct input_handler { int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); void (*disconnect)(struct input_handle *handle); void (*start)(struct input_handle *handle); +#ifdef CONFIG_KDB_KEYBOARD + void (*dbg_clear_keys)(void); +#endif const struct file_operations *fops; int minor; @@ -1317,6 +1320,13 @@ int input_flush_device(struct input_handle* handle, struct file* file); void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value); +#ifdef CONFIG_KDB_KEYBOARD +void input_dbg_clear_keys(void); +#else +static inline void input_dbg_clear_keys(void) +{} +#endif + static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_KEY, code, !!value); -- 1.6.4.rc1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-02-25 21:21 ` [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear Jason Wessel @ 2010-02-26 8:03 ` Dmitry Torokhov 2010-02-26 16:06 ` Jason Wessel 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2010-02-26 8:03 UTC (permalink / raw) To: Jason Wessel Cc: torvalds, linux-kernel, kgdb-bugreport, Henrik Rydberg, Greg Kroah-Hartman, Alexey Dobriyan, Kay Sievers, linux-input On Thu, Feb 25, 2010 at 03:21:28PM -0600, Jason Wessel wrote: > When using a keyboard with kdb, on resuming the system there needs to > be a hook to allow for the keyboard state to get reset. > > This is mainly because there is no way to force the end user to hold > down the original keys that were pressed prior to entering kdb. > Instead of adding all the new hook can't you copy the bitmap of currently pressed keys when you invoke kdb and theni, on exit, use input_inject_event() to clear bitmasks in the devices? -- Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-02-26 8:03 ` Dmitry Torokhov @ 2010-02-26 16:06 ` Jason Wessel 2010-02-27 7:55 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Jason Wessel @ 2010-02-26 16:06 UTC (permalink / raw) To: Dmitry Torokhov Cc: Kay Sievers, kgdb-bugreport, Greg Kroah-Hartman, linux-kernel, Henrik Rydberg, linux-input, torvalds, Alexey Dobriyan Dmitry Torokhov wrote: > On Thu, Feb 25, 2010 at 03:21:28PM -0600, Jason Wessel wrote: >> When using a keyboard with kdb, on resuming the system there needs to >> be a hook to allow for the keyboard state to get reset. >> >> This is mainly because there is no way to force the end user to hold >> down the original keys that were pressed prior to entering kdb. >> > > Instead of adding all the new hook can't you copy the bitmap of > currently pressed keys when you invoke kdb and theni, on exit, use > input_inject_event() to clear bitmasks in the devices? > I know just a little more about the input system then I did 6 months ago. I am not sure that input_inject_event() is exactly what should be used, but perhaps you had a different idea in mind. I created a new patch which uses the same sort of concept. I moved the key release code from input_disconnect_device() into a common function, so that it could be called by the debugger key free hook. Would you consider acking this version (for which I can apply a delta patch to the kdb code base)? Or let me know what further comments you have? Thanks, Jason. --- From: Jason Wessel <jason.wessel@windriver.com> Subject: [PATCH] input,keyboard,kgdboc: Allow key release on kernel resume When using a keyboard with kdb, a hook point to free all the keystrokes is required for resuming kernel operations. This is mainly because there is no way to force the end user to hold down the original keys that were pressed prior to entering kdb. The change to keyboard.c fixes a defect where the keyboard bitmap map state is not correct while in a sysrq handler. The bitmap needs to be updated before calling the sysrq handler. When resuming the kernel kgdboc's callback will attempt to release all the keys if the locks are available, else tasklet will be schedule to release all the keys when the kernel is full resumed. CC: Dmitry Torokhov <dmitry.torokhov@gmail.com> CC: Henrik Rydberg <rydberg@euromail.se> CC: Greg Kroah-Hartman <gregkh@suse.de> CC: Alexey Dobriyan <adobriyan@gmail.com> CC: Kay Sievers <kay.sievers@vrfy.org> CC: linux-input@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> --- drivers/char/keyboard.c | 10 +++--- drivers/input/input.c | 79 +++++++++++++++++++++++++++++++++++++++--------- drivers/serial/kgdboc.c | 13 +++++++ include/linux/input.h | 7 ++++ 4 files changed, 90 insertions(+), 19 deletions(-) --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1195,6 +1195,11 @@ static void kbd_keycode(unsigned int key if (keycode < BTN_MISC && printk_ratelimit()) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + if (down) + set_bit(keycode, key_down); + else + clear_bit(keycode, key_down); + #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { if (!sysrq_down) { @@ -1237,11 +1242,6 @@ static void kbd_keycode(unsigned int key raw_mode = 1; } - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); - if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -17,6 +17,7 @@ #include <linux/kdb.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/input.h> #define MAX_CONFIG_LEN 40 @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive static int kgdb_tty_line; #ifdef CONFIG_KDB_KEYBOARD +static int kgdboc_use_kbd; /* 1 if we use a keyboard */ + static int kgdboc_register_kbd(char **cptr) { + kgdboc_use_kbd = 0; if (strncmp(*cptr, "kbd", 3) == 0) { if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; kdb_poll_idx++; + kgdboc_use_kbd = 1; if (cptr[0][3] == ',') *cptr += 4; else @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) } } } + +static inline void kgdboc_clear_kbd(void) +{ + if (kgdboc_use_kbd) + input_dbg_clear_keys(); /* Release all pressed keys */ +} #else /* ! CONFIG_KDB_KEYBOARD */ #define kgdboc_register_kbd(x) 0 #define kgdboc_unregister_kbd() +#define kgdboc_clear_kbd() #endif /* ! CONFIG_KDB_KEYBOARD */ static int kgdboc_option_setup(char *opt) @@ -213,6 +225,7 @@ static void kgdboc_post_exp_handler(void /* decrement the module count when the debugger detaches */ if (!kgdb_connected) module_put(THIS_MODULE); + kgdboc_clear_kbd(); } static struct kgdb_io kgdboc_io_ops = { --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1359,6 +1359,13 @@ int input_flush_device(struct input_hand void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value); +#ifdef CONFIG_KDB_KEYBOARD +extern void input_dbg_clear_keys(void); +#else +static inline void input_dbg_clear_keys(void) +{} +#endif + static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) { input_event(dev, EV_KEY, code, !!value); --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -24,6 +24,7 @@ #include <linux/mutex.h> #include <linux/rcupdate.h> #include <linux/smp_lock.h> +#include <linux/interrupt.h> #include "input-compat.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); @@ -511,12 +512,30 @@ void input_close_device(struct input_han EXPORT_SYMBOL(input_close_device); /* + * input_clear_keys - Simulate keyup events for all pressed keys so + * that handlers are not left with "stuck" keys. + */ +static void input_clear_keys(struct input_dev *dev) +{ + int code; + + if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { + for (code = 0; code <= KEY_MAX; code++) { + if (is_event_supported(code, dev->keybit, KEY_MAX) && + __test_and_clear_bit(code, dev->key)) { + input_pass_event(dev, EV_KEY, code, 0); + } + } + input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + } +} + +/* * Prepare device for unregistering */ static void input_disconnect_device(struct input_dev *dev) { struct input_handle *handle; - int code; /* * Mark device as going away. Note that we take dev->mutex here @@ -530,20 +549,10 @@ static void input_disconnect_device(stru spin_lock_irq(&dev->event_lock); /* - * Simulate keyup events for all pressed keys so that handlers - * are not left with "stuck" keys. The driver may continue - * generate events even after we done here but they will not - * reach any handlers. + * The driver may continue generate events even after we done here + * but they will not reach any handlers. */ - if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { - for (code = 0; code <= KEY_MAX; code++) { - if (is_event_supported(code, dev->keybit, KEY_MAX) && - __test_and_clear_bit(code, dev->key)) { - input_pass_event(dev, EV_KEY, code, 0); - } - } - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); - } + input_clear_keys(dev); list_for_each_entry(handle, &dev->h_list, d_node) handle->open = 0; @@ -1692,6 +1701,48 @@ int input_register_handler(struct input_ } EXPORT_SYMBOL(input_register_handler); +#ifdef CONFIG_KDB_KEYBOARD +static bool input_dbg_keys_cleared; + +/* + * input_dbg_clear_keys - Clear any keyboards if they have a call back, + * after returning from the kernel debugger + */ +static void input_clear_keys_task(unsigned long not_used) +{ + struct input_dev *dev; + unsigned long flags; + + if (!input_dbg_keys_cleared) + return; + list_for_each_entry(dev, &input_dev_list, node) { + spin_lock_irqsave(&dev->event_lock, flags); + input_clear_keys(dev); + spin_unlock_irqrestore(&dev->event_lock, flags); + } + input_dbg_keys_cleared = false; +} + +static DECLARE_TASKLET(input_clear_keys_tasklet, input_clear_keys_task, 0); + +void input_dbg_clear_keys(void) +{ + struct input_dev *dev; + + if (input_dbg_keys_cleared) + return; + input_dbg_keys_cleared = true; + /* Schedule a tasklet unless all locks are avaialble */ + list_for_each_entry(dev, &input_dev_list, node) + if (spin_is_locked(&dev->event_lock)) { + tasklet_schedule(&input_clear_keys_tasklet); + return; + } + input_clear_keys_task(0); +} +EXPORT_SYMBOL_GPL(input_dbg_clear_keys); +#endif /* CONFIG_KDB_KEYBOARD */ + /** * input_unregister_handler - unregisters an input handler * @handler: handler to be unregistered ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-02-26 16:06 ` Jason Wessel @ 2010-02-27 7:55 ` Dmitry Torokhov 2010-03-01 3:56 ` Jason Wessel 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2010-02-27 7:55 UTC (permalink / raw) To: Jason Wessel Cc: torvalds, linux-kernel, kgdb-bugreport, Henrik Rydberg, Greg Kroah-Hartman, Alexey Dobriyan, Kay Sievers, linux-input On Fri, Feb 26, 2010 at 10:06:19AM -0600, Jason Wessel wrote: > Dmitry Torokhov wrote: > > On Thu, Feb 25, 2010 at 03:21:28PM -0600, Jason Wessel wrote: > >> When using a keyboard with kdb, on resuming the system there needs to > >> be a hook to allow for the keyboard state to get reset. > >> > >> This is mainly because there is no way to force the end user to hold > >> down the original keys that were pressed prior to entering kdb. > >> > > > > Instead of adding all the new hook can't you copy the bitmap of > > currently pressed keys when you invoke kdb and theni, on exit, use > > input_inject_event() to clear bitmasks in the devices? > > > > I know just a little more about the input system then I did 6 months > ago. I am not sure that input_inject_event() is exactly what should > be used, but perhaps you had a different idea in mind. > > I created a new patch which uses the same sort of concept. I moved > the key release code from input_disconnect_device() into a common > function, so that it could be called by the debugger key free hook. > The problem with your patch is that you end up using input_pass_event() which only passes events to handler, but it does not reset device state. This will cause loss of the first press of the same button after returning from kdb. input_inject_event() should do what you need. You just need to do it from a tasklet or, better yet (there is no performance issue) schedule a work on keventd so you don't deadlock on the event lock. It will also do all necessary locking, which is something you seem to be ignoring. ... > > --- a/drivers/char/keyboard.c > +++ b/drivers/char/keyboard.c > @@ -1195,6 +1195,11 @@ static void kbd_keycode(unsigned int key > if (keycode < BTN_MISC && printk_ratelimit()) > printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); > > + if (down) > + set_bit(keycode, key_down); > + else > + clear_bit(keycode, key_down); > + You sure it is not too early? Right now any key while in SysRq mode is ignored, with your change it will affect the shift state without actually passing the key press to userspace. > #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ > if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { > if (!sysrq_down) { > @@ -1237,11 +1242,6 @@ static void kbd_keycode(unsigned int key > raw_mode = 1; > } > > - if (down) > - set_bit(keycode, key_down); > - else > - clear_bit(keycode, key_down); > - > if (rep && > (!vc_kbd_mode(kbd, VC_REPEAT) || > (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { > --- a/drivers/serial/kgdboc.c > +++ b/drivers/serial/kgdboc.c > @@ -17,6 +17,7 @@ > #include <linux/kdb.h> > #include <linux/tty.h> > #include <linux/console.h> > +#include <linux/input.h> > > #define MAX_CONFIG_LEN 40 > > @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive > static int kgdb_tty_line; > > #ifdef CONFIG_KDB_KEYBOARD > +static int kgdboc_use_kbd; /* 1 if we use a keyboard */ bool? > + > static int kgdboc_register_kbd(char **cptr) > { > + kgdboc_use_kbd = 0; > if (strncmp(*cptr, "kbd", 3) == 0) { > if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { > kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; > kdb_poll_idx++; Hm, no locking here whatsoever? > + kgdboc_use_kbd = 1; > if (cptr[0][3] == ',') > *cptr += 4; > else > @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) > } > } > } > + > +static inline void kgdboc_clear_kbd(void) > +{ > + if (kgdboc_use_kbd) > + input_dbg_clear_keys(); /* Release all pressed keys */ I'd rather have the input_dbg_clear_keys() being implemented right here, along with the tasklet/work handling, instead of puttin it in the input core. -- Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-02-27 7:55 ` Dmitry Torokhov @ 2010-03-01 3:56 ` Jason Wessel 2010-03-01 5:04 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Jason Wessel @ 2010-03-01 3:56 UTC (permalink / raw) To: Dmitry Torokhov Cc: Kay Sievers, kgdb-bugreport, Greg Kroah-Hartman, linux-kernel, Henrik Rydberg, linux-input, torvalds, Alexey Dobriyan Dmitry Torokhov wrote: > The problem with your patch is that you end up using input_pass_event() > which only passes events to handler, but it does not reset device state. > This will cause loss of the first press of the same button after > returning from kdb. input_inject_event() should do what you need. You > just need to do it from a tasklet or, better yet (there is no > performance issue) schedule a work on keventd so you don't deadlock > on the event lock. It will also do all necessary locking, which is > something you seem to be ignoring. > > ... > > For now I am just going to drop this patch from the series, and I think we should pick up the continuation of the discussion on the linux-input. The lack of this patch simply means keys can stuck down sometimes if you go in and out of the kernel debug shell when running X. People were able to live with this a long time in the original kdb v4.4, so they can live with it a while longer while a solution is hashed out to "unstick the keys". This will allow me to re-issue a pull request which has no patches which are in the discussion state. It is not obvious to me how walk through the input device list with the right locks and then obtain the handle required to call the inject input. It does not appear that it is possible to hold the locks while walking through the keycode device bitmap and issue calls to inject input. Is there any kind of input API function to obtain the device bitmaps? >> --- a/drivers/char/keyboard.c >> +++ b/drivers/char/keyboard.c >> @@ -1195,6 +1195,11 @@ static void kbd_keycode(unsigned int key >> if (keycode < BTN_MISC && printk_ratelimit()) >> printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); >> >> + if (down) >> + set_bit(keycode, key_down); >> + else >> + clear_bit(keycode, key_down); >> + >> > > You sure it is not too early? Right now any key while in SysRq mode is > ignored, with your change it will affect the shift state without > actually passing the key press to userspace. > > I think it is possible to drop this chunk and leave it as it was because the work is definitely going to move to a tasklet which occurs after the sysrq and the key events will be synced at that point. Previously the problem was trying to process the key bitmaps inside the sysrq. >> --- a/drivers/serial/kgdboc.c >> +++ b/drivers/serial/kgdboc.c >> @@ -17,6 +17,7 @@ >> #include <linux/kdb.h> >> #include <linux/tty.h> >> #include <linux/console.h> >> +#include <linux/input.h> >> >> #define MAX_CONFIG_LEN 40 >> >> @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive >> static int kgdb_tty_line; >> >> #ifdef CONFIG_KDB_KEYBOARD >> +static int kgdboc_use_kbd; /* 1 if we use a keyboard */ >> > > bool? > > Agreed, I'll fix that in a future iteration. > >> + >> static int kgdboc_register_kbd(char **cptr) >> { >> + kgdboc_use_kbd = 0; >> if (strncmp(*cptr, "kbd", 3) == 0) { >> if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { >> kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; >> kdb_poll_idx++; >> > > Hm, no locking here whatsoever? > > There is no locking needed here. This only takes place at the kernel module configuration. > >> @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) >> } >> } >> } >> + >> +static inline void kgdboc_clear_kbd(void) >> +{ >> + if (kgdboc_use_kbd) >> + input_dbg_clear_keys(); /* Release all pressed keys */ >> > > I'd rather have the input_dbg_clear_keys() being implemented right here, > along with the tasklet/work handling, instead of puttin it in the input > core. > > That is fine with me, it is just not obvious to me which API calls you need in order to be able iterate through the key bit maps and get handles to call the inject input event. Jason ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-03-01 3:56 ` Jason Wessel @ 2010-03-01 5:04 ` Dmitry Torokhov 2010-03-01 16:49 ` Jason Wessel 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2010-03-01 5:04 UTC (permalink / raw) To: Jason Wessel Cc: Kay Sievers, kgdb-bugreport, Greg Kroah-Hartman, linux-kernel, Henrik Rydberg, linux-input, torvalds, Alexey Dobriyan On Sun, Feb 28, 2010 at 09:56:56PM -0600, Jason Wessel wrote: > Dmitry Torokhov wrote: > > The problem with your patch is that you end up using input_pass_event() > > which only passes events to handler, but it does not reset device state. > > This will cause loss of the first press of the same button after > > returning from kdb. input_inject_event() should do what you need. You > > just need to do it from a tasklet or, better yet (there is no > > performance issue) schedule a work on keventd so you don't deadlock > > on the event lock. It will also do all necessary locking, which is > > something you seem to be ignoring. > > > > ... > > > > > > For now I am just going to drop this patch from the series, and I think > we should pick up the continuation of the discussion on the > linux-input. The lack of this patch simply means keys can stuck down > sometimes if you go in and out of the kernel debug shell when running > X. People were able to live with this a long time in the original kdb > v4.4, so they can live with it a while longer while a solution is hashed > out to "unstick the keys". > > This will allow me to re-issue a pull request which has no patches which > are in the discussion state. > OK. > It is not obvious to me how walk through the input device list with the > right locks and then obtain the handle required to call the inject > input. It does not appear that it is possible to hold the locks while > walking through the keycode device bitmap and issue calls to inject > input. Is there any kind of input API function to obtain the device bitmaps? > There is key_down bitmap right there in keyboard.c that reflects all keys that are considered "down" as far as keyboard driver is concerned. You can use input_handler_for_each_handle() for kbd_handler to iterate through all input handles and send "up" events for all keys that keyboard.c is considering as being "down". There is no harm in sending extra "up" events for keys that are not pressed - the event will simply be ignored by input core. Hope this helps. -- Dmitry ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-03-01 5:04 ` Dmitry Torokhov @ 2010-03-01 16:49 ` Jason Wessel 2010-03-01 18:32 ` Dmitry Torokhov 0 siblings, 1 reply; 10+ messages in thread From: Jason Wessel @ 2010-03-01 16:49 UTC (permalink / raw) To: Dmitry Torokhov Cc: kgdb-bugreport, Greg Kroah-Hartman, linux-kernel, linux-input Dmitry Torokhov wrote: > On Sun, Feb 28, 2010 at 09:56:56PM -0600, Jason Wessel wrote: > >> It is not obvious to me how walk through the input device list with the >> right locks and then obtain the handle required to call the inject >> input. It does not appear that it is possible to hold the locks while >> walking through the keycode device bitmap and issue calls to inject >> input. Is there any kind of input API function to obtain the device bitmaps? >> > > There is key_down bitmap right there in keyboard.c that reflects all > keys that are considered "down" as far as keyboard driver is concerned. > You can use input_handler_for_each_handle() for kbd_handler to iterate > through all input handles and send "up" events for all keys that > keyboard.c is considering as being "down". There is no harm in sending > extra "up" events for keys that are not pressed - the event will simply > be ignored by input core. > Thanks for the explanation. Below is the new version. You just have to decide if you want to expose the keyboard bitmap as a global, or use an accessors function inside keyboard.c. In X, it seems there is an unbalenced key up / down because emulate_raw() puts the keys in, but the keyboard bit map is not updated. I worked around it by adding in a keyboard bitmap update prior to invoking the sysrq, so the kdb key free can free all the keys later. I am not sure if there is a better way to fix the bitmap update. I did try moving the emulate_raw() around in a few combinations, but nothing would yield the correct results for still allowing the alt-print-screen work with the window capture in the window manager. Thanks, Jason. --- From: Jason Wessel <jason.wessel@windriver.com> Subject: [PATCH] keyboard,kgdboc: Allow key release on kernel resume When using a keyboard with kdb, a hook point to free all the keystrokes is required for resuming kernel operations. This is mainly because there is no way to force the end user to hold down the original keys that were pressed prior to entering kdb when resuming the kernel. The kgdboc driver will call kdb_clear_keys() just prior to resuming the kernel execution which will create a tasklet to run kbd_dbg_clear_keys() inside the keyboard.c. CC: Dmitry Torokhov <dmitry.torokhov@gmail.com> CC: Greg Kroah-Hartman <gregkh@suse.de> CC: linux-input@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> --- drivers/char/keyboard.c | 27 +++++++++++++++++++++++++++ drivers/serial/kgdboc.c | 13 +++++++++++++ include/linux/kbd_kern.h | 1 + include/linux/kdb.h | 3 +++ kernel/debug/kdb/kdb_keyboard.c | 25 +++++++++++++++++++++++++ 5 files changed, 69 insertions(+) --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -379,6 +379,32 @@ static void to_utf8(struct vc_data *vc, } } +static int kbd_dbg_clear_keys_helper(struct input_handle *handle, void *data) +{ + unsigned int *keycode = data; + input_inject_event(handle, EV_KEY, *keycode, 0); + return 0; +} + +/* Called to clear the any key presses after resuming the kernel. */ +void kbd_dbg_clear_keys(void) { + unsigned int i, j, k; + + for (i = 0; i < ARRAY_SIZE(key_down); i++) { + if (!key_down[i]) + continue; + + k = i * BITS_PER_LONG; + + for (j = 0; j < BITS_PER_LONG; j++, k++) { + if (!test_bit(k, key_down)) + continue; + input_handler_for_each_handle(&kbd_handler, &k, + kbd_dbg_clear_keys_helper); + } + } +} + /* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is @@ -1206,6 +1232,7 @@ static void kbd_keycode(unsigned int key if (sysrq_down && !down && keycode == sysrq_alt_use) sysrq_down = 0; if (sysrq_down && down && !rep) { + set_bit(keycode, key_down); handle_sysrq(kbd_sysrq_xlate[keycode], tty); return; } --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -17,6 +17,7 @@ #include <linux/kdb.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/kbd_kern.h> #define MAX_CONFIG_LEN 40 @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive static int kgdb_tty_line; #ifdef CONFIG_KDB_KEYBOARD +static bool kgdboc_use_kbd; + static int kgdboc_register_kbd(char **cptr) { + kgdboc_use_kbd = false; if (strncmp(*cptr, "kbd", 3) == 0) { if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; kdb_poll_idx++; + kgdboc_use_kbd = true; if (cptr[0][3] == ',') *cptr += 4; else @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) } } } + +static inline void kgdboc_clear_kbd(void) +{ + if (kgdboc_use_kbd) + kdb_clear_keys(); /* Release all pressed keys */ +} #else /* ! CONFIG_KDB_KEYBOARD */ #define kgdboc_register_kbd(x) 0 #define kgdboc_unregister_kbd() +#define kgdboc_clear_kbd() #endif /* ! CONFIG_KDB_KEYBOARD */ static int kgdboc_option_setup(char *opt) @@ -213,6 +225,7 @@ static void kgdboc_post_exp_handler(void /* decrement the module count when the debugger detaches */ if (!kgdb_connected) module_put(THIS_MODULE); + kgdboc_clear_kbd(); } static struct kgdb_io kgdboc_io_ops = { --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -144,6 +144,7 @@ struct console; int getkeycode(unsigned int scancode); int setkeycode(unsigned int scancode, unsigned int keycode); void compute_shiftstate(void); +void kbd_dbg_clear_keys(void); /* defkeymap.c */ --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -93,6 +93,9 @@ typedef int (*get_char_func)(void); extern get_char_func kdb_poll_funcs[]; extern int kdb_get_kbd_char(void); +/* KDB keyboard hooks */ +extern void kdb_clear_keys(void); + static inline int kdb_process_cpu(const struct task_struct *p) { --- a/kernel/debug/kdb/kdb_keyboard.c +++ b/kernel/debug/kdb/kdb_keyboard.c @@ -13,6 +13,7 @@ #include <linux/ctype.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/kbd_kern.h> /* Keyboard Controller Registers on normal PCs. */ @@ -210,3 +211,27 @@ int kdb_get_kbd_char(void) return keychar & 0xff; } EXPORT_SYMBOL_GPL(kdb_get_kbd_char); + +static bool dbg_keys_cleared; +/* + * input_dbg_clear_keys - Clear any keyboards if they have a call back, + * after returning from the kernel debugger + */ +static void kdb_keys_task(unsigned long not_used) +{ + if (!dbg_keys_cleared) + return; + kbd_dbg_clear_keys(); + dbg_keys_cleared = false; +} + +static DECLARE_TASKLET(kdb_keys_tasklet, kdb_keys_task, 0); + +void kdb_clear_keys(void) +{ + if (dbg_keys_cleared) + return; + dbg_keys_cleared = true; + tasklet_schedule(&kdb_keys_tasklet); +} +EXPORT_SYMBOL_GPL(kdb_clear_keys); ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-03-01 16:49 ` Jason Wessel @ 2010-03-01 18:32 ` Dmitry Torokhov 2010-03-01 19:33 ` Jason Wessel 0 siblings, 1 reply; 10+ messages in thread From: Dmitry Torokhov @ 2010-03-01 18:32 UTC (permalink / raw) To: Jason Wessel Cc: linux-kernel, kgdb-bugreport, Greg Kroah-Hartman, linux-input On Mon, Mar 01, 2010 at 10:49:33AM -0600, Jason Wessel wrote: > Dmitry Torokhov wrote: > > On Sun, Feb 28, 2010 at 09:56:56PM -0600, Jason Wessel wrote: > > > >> It is not obvious to me how walk through the input device list with the > >> right locks and then obtain the handle required to call the inject > >> input. It does not appear that it is possible to hold the locks while > >> walking through the keycode device bitmap and issue calls to inject > >> input. Is there any kind of input API function to obtain the device bitmaps? > >> > > > > There is key_down bitmap right there in keyboard.c that reflects all > > keys that are considered "down" as far as keyboard driver is concerned. > > You can use input_handler_for_each_handle() for kbd_handler to iterate > > through all input handles and send "up" events for all keys that > > keyboard.c is considering as being "down". There is no harm in sending > > extra "up" events for keys that are not pressed - the event will simply > > be ignored by input core. > > > > Thanks for the explanation. > > Below is the new version. You just have to decide if you want to > expose the keyboard bitmap as a global, or use an accessors function > inside keyboard.c. Looks much better, thanks. I do prefer accessor functions to exporintg variables. > > In X, it seems there is an unbalenced key up / down because > emulate_raw() puts the keys in, but the keyboard bit map is not > updated. Yes, if keyboard in raw mode (and it is while you are in X), then most of the keyboard.c code is not active. > I worked around it by adding in a keyboard bitmap update > prior to invoking the sysrq, so the kdb key free can free all the keys > later. > > I am not sure if there is a better way to fix the bitmap update. I > did try moving the emulate_raw() around in a few combinations, but > nothing would yield the correct results for still allowing the > alt-print-screen work with the window capture in the window manager. > Maybe we should simply add key_raw_down bitmap? It is not expensive and would untangle the shiftstate computation in case of cooked keyboard from what you need for kdb. Another option would be writing your own tiny input handler that would attach to all keyboards like keyboard.c does and just maintain it's own bitmap of currently active keys. It would work regardless of what mode keyboard.c is (raw, mediumraw, etc). Actually, I like this idea a lot, it nicely decouples kdb from keyboard driver. For an example of really simple handler take a look at drivers/input/apm-power.c > Thanks, > Jason. > > --- > From: Jason Wessel <jason.wessel@windriver.com> > Subject: [PATCH] keyboard,kgdboc: Allow key release on kernel resume > > When using a keyboard with kdb, a hook point to free all the > keystrokes is required for resuming kernel operations. > > This is mainly because there is no way to force the end user to hold > down the original keys that were pressed prior to entering kdb when > resuming the kernel. > > The kgdboc driver will call kdb_clear_keys() just prior to resuming > the kernel execution which will create a tasklet to run > kbd_dbg_clear_keys() inside the keyboard.c. > > CC: Dmitry Torokhov <dmitry.torokhov@gmail.com> > CC: Greg Kroah-Hartman <gregkh@suse.de> > CC: linux-input@vger.kernel.org > Signed-off-by: Jason Wessel <jason.wessel@windriver.com> > > --- > drivers/char/keyboard.c | 27 +++++++++++++++++++++++++++ > drivers/serial/kgdboc.c | 13 +++++++++++++ > include/linux/kbd_kern.h | 1 + > include/linux/kdb.h | 3 +++ > kernel/debug/kdb/kdb_keyboard.c | 25 +++++++++++++++++++++++++ > 5 files changed, 69 insertions(+) > > --- a/drivers/char/keyboard.c > +++ b/drivers/char/keyboard.c > @@ -379,6 +379,32 @@ static void to_utf8(struct vc_data *vc, > } > } > > +static int kbd_dbg_clear_keys_helper(struct input_handle *handle, void *data) > +{ > + unsigned int *keycode = data; > + input_inject_event(handle, EV_KEY, *keycode, 0); > + return 0; > +} > + > +/* Called to clear the any key presses after resuming the kernel. */ > +void kbd_dbg_clear_keys(void) { Style - function opening brace on a separate line please. > + unsigned int i, j, k; > + > + for (i = 0; i < ARRAY_SIZE(key_down); i++) { > + if (!key_down[i]) > + continue; > + > + k = i * BITS_PER_LONG; > + > + for (j = 0; j < BITS_PER_LONG; j++, k++) { > + if (!test_bit(k, key_down)) > + continue; > + input_handler_for_each_handle(&kbd_handler, &k, > + kbd_dbg_clear_keys_helper); > + } > + } > +} > + > /* > * Called after returning from RAW mode or when changing consoles - recompute > * shift_down[] and shift_state from key_down[] maybe called when keymap is > @@ -1206,6 +1232,7 @@ static void kbd_keycode(unsigned int key > if (sysrq_down && !down && keycode == sysrq_alt_use) > sysrq_down = 0; > if (sysrq_down && down && !rep) { > + set_bit(keycode, key_down); > handle_sysrq(kbd_sysrq_xlate[keycode], tty); > return; > } > --- a/drivers/serial/kgdboc.c > +++ b/drivers/serial/kgdboc.c > @@ -17,6 +17,7 @@ > #include <linux/kdb.h> > #include <linux/tty.h> > #include <linux/console.h> > +#include <linux/kbd_kern.h> > > #define MAX_CONFIG_LEN 40 > > @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive > static int kgdb_tty_line; > > #ifdef CONFIG_KDB_KEYBOARD > +static bool kgdboc_use_kbd; > + > static int kgdboc_register_kbd(char **cptr) > { > + kgdboc_use_kbd = false; > if (strncmp(*cptr, "kbd", 3) == 0) { > if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { > kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; > kdb_poll_idx++; > + kgdboc_use_kbd = true; > if (cptr[0][3] == ',') > *cptr += 4; > else > @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) > } > } > } > + > +static inline void kgdboc_clear_kbd(void) > +{ > + if (kgdboc_use_kbd) > + kdb_clear_keys(); /* Release all pressed keys */ > +} > #else /* ! CONFIG_KDB_KEYBOARD */ > #define kgdboc_register_kbd(x) 0 > #define kgdboc_unregister_kbd() > +#define kgdboc_clear_kbd() > #endif /* ! CONFIG_KDB_KEYBOARD */ > > static int kgdboc_option_setup(char *opt) > @@ -213,6 +225,7 @@ static void kgdboc_post_exp_handler(void > /* decrement the module count when the debugger detaches */ > if (!kgdb_connected) > module_put(THIS_MODULE); > + kgdboc_clear_kbd(); > } > > static struct kgdb_io kgdboc_io_ops = { > --- a/include/linux/kbd_kern.h > +++ b/include/linux/kbd_kern.h > @@ -144,6 +144,7 @@ struct console; > int getkeycode(unsigned int scancode); > int setkeycode(unsigned int scancode, unsigned int keycode); > void compute_shiftstate(void); > +void kbd_dbg_clear_keys(void); > > /* defkeymap.c */ > > --- a/include/linux/kdb.h > +++ b/include/linux/kdb.h > @@ -93,6 +93,9 @@ typedef int (*get_char_func)(void); > extern get_char_func kdb_poll_funcs[]; > extern int kdb_get_kbd_char(void); > > +/* KDB keyboard hooks */ > +extern void kdb_clear_keys(void); > + > static inline > int kdb_process_cpu(const struct task_struct *p) > { > --- a/kernel/debug/kdb/kdb_keyboard.c > +++ b/kernel/debug/kdb/kdb_keyboard.c > @@ -13,6 +13,7 @@ > #include <linux/ctype.h> > #include <linux/module.h> > #include <linux/io.h> > +#include <linux/kbd_kern.h> > > /* Keyboard Controller Registers on normal PCs. */ > > @@ -210,3 +211,27 @@ int kdb_get_kbd_char(void) > return keychar & 0xff; > } > EXPORT_SYMBOL_GPL(kdb_get_kbd_char); > + > +static bool dbg_keys_cleared; > +/* > + * input_dbg_clear_keys - Clear any keyboards if they have a call back, > + * after returning from the kernel debugger > + */ > +static void kdb_keys_task(unsigned long not_used) > +{ > + if (!dbg_keys_cleared) > + return; > + kbd_dbg_clear_keys(); > + dbg_keys_cleared = false; > +} > + > +static DECLARE_TASKLET(kdb_keys_tasklet, kdb_keys_task, 0); Do you really need tasklet? Would not regular work_struct do? Also, the logic of dbg_keys_cleared seems to be inverted, not metioned the fact that it does not seem to be needed anymore. If you decide against a new input handler approach may I ask you to move the scheduling to keyboard.c as well - I know I originally said I wanted it in kdb but now that I thought about it some more I think keyboard.c is better. > + > +void kdb_clear_keys(void) > +{ > + if (dbg_keys_cleared) > + return; > + dbg_keys_cleared = true; > + tasklet_schedule(&kdb_keys_tasklet); > +} > +EXPORT_SYMBOL_GPL(kdb_clear_keys); Thanks. -- Dmitry ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-03-01 18:32 ` Dmitry Torokhov @ 2010-03-01 19:33 ` Jason Wessel 2010-03-03 7:39 ` Jason Wessel 0 siblings, 1 reply; 10+ messages in thread From: Jason Wessel @ 2010-03-01 19:33 UTC (permalink / raw) To: Dmitry Torokhov Cc: kgdb-bugreport, Greg Kroah-Hartman, linux-kernel, linux-input Dmitry Torokhov wrote: > On Mon, Mar 01, 2010 at 10:49:33AM -0600, Jason Wessel wrote: > >> Dmitry Torokhov wrote: >> >>> On Sun, Feb 28, 2010 at 09:56:56PM -0600, Jason Wessel wrote: >>> >>> >>>> It is not obvious to me how walk through the input device list with the >>>> right locks and then obtain the handle required to call the inject >>>> input. It does not appear that it is possible to hold the locks while >>>> walking through the keycode device bitmap and issue calls to inject >>>> input. Is there any kind of input API function to obtain the device bitmaps? >>>> >>>> >>> There is key_down bitmap right there in keyboard.c that reflects all >>> keys that are considered "down" as far as keyboard driver is concerned. >>> You can use input_handler_for_each_handle() for kbd_handler to iterate >>> through all input handles and send "up" events for all keys that >>> keyboard.c is considering as being "down". There is no harm in sending >>> extra "up" events for keys that are not pressed - the event will simply >>> be ignored by input core. >>> >>> >> Thanks for the explanation. >> >> Below is the new version. You just have to decide if you want to >> expose the keyboard bitmap as a global, or use an accessors function >> inside keyboard.c. >> > > Looks much better, thanks. I do prefer accessor functions to exporintg > variables. > > >> In X, it seems there is an unbalenced key up / down because >> emulate_raw() puts the keys in, but the keyboard bit map is not >> updated. >> > > Yes, if keyboard in raw mode (and it is while you are in X), then most > of the keyboard.c code is not active. > > >> I worked around it by adding in a keyboard bitmap update >> prior to invoking the sysrq, so the kdb key free can free all the keys >> later. >> >> I am not sure if there is a better way to fix the bitmap update. I >> did try moving the emulate_raw() around in a few combinations, but >> nothing would yield the correct results for still allowing the >> alt-print-screen work with the window capture in the window manager. >> >> > > Maybe we should simply add key_raw_down bitmap? It is not expensive and > would untangle the shiftstate computation in case of cooked keyboard > from what you need for kdb. > > Another option would be writing your own tiny input handler that would > attach to all keyboards like keyboard.c does and just maintain it's own > bitmap of currently active keys. It would work regardless of what mode > keyboard.c is (raw, mediumraw, etc). Actually, I like this idea a lot, > it nicely decouples kdb from keyboard driver. Unfortunately the keyboard driver is what has the problem of its state getting out of sync when the kernel makes use of the kdb_keyboard.c, which is why I was trying to hook it in the first place. If the sysrq code could be moved to its own input driver does this problem go away for all parties? Even without kdb, when running X, the sysrq definitely does not behave so well and a sysrq-KEY_PRESS is passed on to the input queue instead of getting eaten. For example when I do alt-sysrq-h, I see the help menu flash in the terminal because it thinks I pressed alt-h and kept it held down. >> +static void kdb_keys_task(unsigned long not_used) >> +{ >> + if (!dbg_keys_cleared) >> + return; >> + kbd_dbg_clear_keys(); >> + dbg_keys_cleared = false; >> +} >> + >> +static DECLARE_TASKLET(kdb_keys_tasklet, kdb_keys_task, 0); >> > > Do you really need tasklet? Would not regular work_struct do? It was safe to schedule a tasklet from the caller context. I assume it is probably also safe to use a work_struct, but I had not checked. > Also, the > logic of dbg_keys_cleared seems to be inverted, not metioned the fact > that it does not seem to be needed anymore. That is a result of iteration churn. Easy enough to change. > If you decide against a new > input handler approach may I ask you to move the scheduling to > keyboard.c as well - I know I originally said I wanted it in kdb but now > that I thought about it some more I think keyboard.c is better. > > I can move this back into the keyboard.c. As I mentioned before, I am not sure an input handler will solve the higher level problem, that even beyond kdb, keys are getting stuck with X and sysrq. Perhaps we need a generic solution that is not even kdb specific for clearing the state after a sysrq? For kdb it does still need the same sort of hook because if you type in: echo g > /proc/sysrq-trigger And hit enter, the enter key will get repeated over and over because it happened to be depressed when the kernel debugger was entered, while in X. This means we have two cases: 1) Cleanup key strokes or "consume keys" for sysrq 2) Clear keyboard state on a kernel resume from kdb I am open to any reasonable solution. The most recent patch I sent works well for case 2, but never really addressed case 1, which has been a problem with or without kdb. Jason. Jason. ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear 2010-03-01 19:33 ` Jason Wessel @ 2010-03-03 7:39 ` Jason Wessel 0 siblings, 0 replies; 10+ messages in thread From: Jason Wessel @ 2010-03-03 7:39 UTC (permalink / raw) To: Dmitry Torokhov Cc: kgdb-bugreport, Greg Kroah-Hartman, linux-kernel, linux-input Jason Wessel wrote: > This means we have two cases: > > 1) Cleanup key strokes or "consume keys" for sysrq > 2) Clear keyboard state on a kernel resume from kdb > Because we have two separate problems, I created two separate patches which I inlined below. The first patch really has nothing to do with kdb. It is a generic problem that has existed for sometime. I find it annoying that you cannot execute a sysrq without trigging the window capture in gnome because it treats alt-sysrq like alt-PrintScreen. The testing I completed shows that this is no long a problem with this patch. The second patch is a follow on to the original discussion we were having with respect to releasing all the depressed keys when resuming the kernel and modified per your recent comments. Thanks, Jason ----------Patch 1-------------- From: Jason Wessel <jason.wessel@windriver.com> Subject: [PATCH] keyboard: Change alt-sysrq to always discard key events When issuing an alt-sysrq-KEY sequence with the keyboard driver in the raw mode some unbalanced key down and up events can get propagated to the registered input handlers. This leads to strange behavior particularly when running an X server. If handle_sysrq() is called while executing an alt-sysrq-KEY_PRESS, all the key events should get discarded related to the sysrq activation sequence. When handle_sysrq() is not called and the keyboard driver is in the raw mode, a down and up sysrq keycode will get passed to the registered input handlers. CC: Dmitry Torokhov <dmitry.torokhov@gmail.com> CC: Greg Kroah-Hartman <gregkh@suse.de> CC: linux-input@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> --- drivers/char/keyboard.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -160,6 +160,7 @@ unsigned char kbd_sysrq_xlate[KEY_MAX + "\r\000/"; /* 0x60 - 0x6f */ static int sysrq_down; static int sysrq_alt_use; +static int sysrq_sent; #endif static int sysrq_alt; @@ -1158,6 +1159,13 @@ static void kbd_rawcode(unsigned char da put_queue(vc, data); } +#define emulate_raw_keycode(kc, dwn) \ + if (raw_mode && !hw_raw) \ + if (emulate_raw(vc, kc, !dwn << 7)) \ + if (keycode < BTN_MISC && printk_ratelimit()) \ + printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", kc) + + static void kbd_keycode(unsigned int keycode, int down, int hw_raw) { struct vc_data *vc = vc_cons[fg_console].d; @@ -1185,26 +1193,35 @@ static void kbd_keycode(unsigned int key rep = (down == 2); - if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) - if (emulate_raw(vc, keycode, !down << 7)) - if (keycode < BTN_MISC && printk_ratelimit()) - printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); + raw_mode = kbd->kbdmode == VC_RAW; #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) { if (!sysrq_down) { sysrq_down = down; sysrq_alt_use = sysrq_alt; + sysrq_sent = 0; } return; } - if (sysrq_down && !down && keycode == sysrq_alt_use) + if (sysrq_down && !down && keycode == sysrq_alt_use) { sysrq_down = 0; - if (sysrq_down && down && !rep) { - handle_sysrq(kbd_sysrq_xlate[keycode], tty); + if (!sysrq_sent) { + emulate_raw_keycode(KEY_SYSRQ, 1); + emulate_raw_keycode(KEY_SYSRQ, 0); + } + } + if (sysrq_down && !rep) { + if (down) { + handle_sysrq(kbd_sysrq_xlate[keycode], tty); + sysrq_sent = keycode; + } return; } #endif + + emulate_raw_keycode(keycode, down); + #ifdef CONFIG_SPARC if (keycode == KEY_A && sparc_l1_a_state) { sparc_l1_a_state = 0; ----------Patch 2-------------- From: Jason Wessel <jason.wessel@windriver.com> Subject: [PATCH] keyboard,kgdboc: Allow key release on kernel resume When using a keyboard with kdb, a hook point to free all the keystrokes is required for resuming kernel operations. This is mainly because there is no way to force the end user to hold down the original keys that were pressed prior to entering kdb when resuming the kernel. The kgdboc driver will call kbd_dbg_clear_keys() just prior to resuming the kernel execution which will schedule a callback to clear any keys which were depressed prior to the entering the kernel debugger. CC: Dmitry Torokhov <dmitry.torokhov@gmail.com> CC: Greg Kroah-Hartman <gregkh@suse.de> CC: linux-input@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> --- drivers/char/keyboard.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/serial/kgdboc.c | 13 +++++++++++++ include/linux/kbd_kern.h | 1 + 3 files changed, 51 insertions(+) --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -380,6 +380,43 @@ static void to_utf8(struct vc_data *vc, } } +#ifdef CONFIG_KDB_KEYBOARD +static int kbd_clear_keys_helper(struct input_handle *handle, void *data) +{ + unsigned int *keycode = data; + input_inject_event(handle, EV_KEY, *keycode, 0); + return 0; +} + +static void kbd_clear_keys_callback(struct work_struct *dummy) +{ + unsigned int i, j, k; + + for (i = 0; i < ARRAY_SIZE(key_down); i++) { + if (!key_down[i]) + continue; + + k = i * BITS_PER_LONG; + + for (j = 0; j < BITS_PER_LONG; j++, k++) { + if (!test_bit(k, key_down)) + continue; + input_handler_for_each_handle(&kbd_handler, &k, + kbd_clear_keys_helper); + } + } +} + +static DECLARE_WORK(kbd_clear_keys_work, kbd_clear_keys_callback); + +/* Called to clear any key presses after resuming the kernel. */ +void kbd_dbg_clear_keys(void) +{ + schedule_work(&kbd_clear_keys_work); +} +EXPORT_SYMBOL_GPL(kbd_dbg_clear_keys); +#endif /* CONFIG_KDB_KEYBOARD */ + /* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -17,6 +17,7 @@ #include <linux/kdb.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/kbd_kern.h> #define MAX_CONFIG_LEN 40 @@ -35,12 +36,16 @@ static struct tty_driver *kgdb_tty_drive static int kgdb_tty_line; #ifdef CONFIG_KDB_KEYBOARD +static bool kgdboc_use_kbd; + static int kgdboc_register_kbd(char **cptr) { + kgdboc_use_kbd = false; if (strncmp(*cptr, "kbd", 3) == 0) { if (kdb_poll_idx < KDB_POLL_FUNC_MAX) { kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char; kdb_poll_idx++; + kgdboc_use_kbd = true; if (cptr[0][3] == ',') *cptr += 4; else @@ -63,9 +68,16 @@ static void kgdboc_unregister_kbd(void) } } } + +static inline void kgdboc_clear_kbd(void) +{ + if (kgdboc_use_kbd) + kbd_dbg_clear_keys(); /* Release all pressed keys */ +} #else /* ! CONFIG_KDB_KEYBOARD */ #define kgdboc_register_kbd(x) 0 #define kgdboc_unregister_kbd() +#define kgdboc_clear_kbd() #endif /* ! CONFIG_KDB_KEYBOARD */ static int kgdboc_option_setup(char *opt) @@ -213,6 +225,7 @@ static void kgdboc_post_exp_handler(void /* decrement the module count when the debugger detaches */ if (!kgdb_connected) module_put(THIS_MODULE); + kgdboc_clear_kbd(); } static struct kgdb_io kgdboc_io_ops = { --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -144,6 +144,7 @@ struct console; int getkeycode(unsigned int scancode); int setkeycode(unsigned int scancode, unsigned int keycode); void compute_shiftstate(void); +void kbd_dbg_clear_keys(void); /* defkeymap.c */ ------------------------------------------------------------------------------ Download Intel® Parallel Studio Eval Try the new software tools for yourself. Speed compiling, find bugs proactively, and fine-tune applications for parallel performance. See why Intel Parallel Studio got high marks during beta. http://p.sf.net/sfu/intel-sw-dev ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2010-03-03 7:39 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <1267132893-23624-1-git-send-email-jason.wessel@windriver.com> 2010-02-25 21:21 ` [PATCH 23/28] keyboard, input: Add hook to input to allow low level event clear Jason Wessel 2010-02-26 8:03 ` Dmitry Torokhov 2010-02-26 16:06 ` Jason Wessel 2010-02-27 7:55 ` Dmitry Torokhov 2010-03-01 3:56 ` Jason Wessel 2010-03-01 5:04 ` Dmitry Torokhov 2010-03-01 16:49 ` Jason Wessel 2010-03-01 18:32 ` Dmitry Torokhov 2010-03-01 19:33 ` Jason Wessel 2010-03-03 7:39 ` Jason Wessel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).