diff options
Diffstat (limited to 'drivers/tty/vt/keyboard.c')
| -rw-r--r-- | drivers/tty/vt/keyboard.c | 881 |
1 files changed, 404 insertions, 477 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 88312c6c92cc..d65fc60dd7be 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -26,35 +26,34 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/consolemap.h> -#include <linux/module.h> -#include <linux/sched/signal.h> -#include <linux/sched/debug.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/mm.h> -#include <linux/string.h> #include <linux/init.h> -#include <linux/slab.h> -#include <linux/leds.h> - -#include <linux/kbd_kern.h> -#include <linux/kbd_diacr.h> -#include <linux/vt_kern.h> #include <linux/input.h> -#include <linux/reboot.h> -#include <linux/notifier.h> #include <linux/jiffies.h> +#include <linux/kbd_diacr.h> +#include <linux/kbd_kern.h> +#include <linux/leds.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/nospec.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/sched/debug.h> +#include <linux/sched/signal.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/tty_flip.h> +#include <linux/tty.h> #include <linux/uaccess.h> +#include <linux/vt_kern.h> #include <asm/irq_regs.h> -extern void ctrl_alt_del(void); - /* * Exported functions/variables */ -#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#define KBD_DEFMODE (BIT(VC_REPEAT) | BIT(VC_META)) #if defined(CONFIG_X86) || defined(CONFIG_PARISC) #include <asm/kbdleds.h> @@ -112,28 +111,49 @@ static struct kbd_struct kbd_table[MAX_NR_CONSOLES]; static struct kbd_struct *kbd = kbd_table; /* maximum values each key_handler can handle */ -static const int max_vals[] = { - 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, - NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, - 255, NR_LOCK - 1, 255, NR_BRL - 1 +static const unsigned char max_vals[] = { + [ KT_LATIN ] = 255, + [ KT_FN ] = ARRAY_SIZE(func_table) - 1, + [ KT_SPEC ] = ARRAY_SIZE(fn_handler) - 1, + [ KT_PAD ] = NR_PAD - 1, + [ KT_DEAD ] = NR_DEAD - 1, + [ KT_CONS ] = 255, + [ KT_CUR ] = 3, + [ KT_SHIFT ] = NR_SHIFT - 1, + [ KT_META ] = 255, + [ KT_ASCII ] = NR_ASCII - 1, + [ KT_LOCK ] = NR_LOCK - 1, + [ KT_LETTER ] = 255, + [ KT_SLOCK ] = NR_LOCK - 1, + [ KT_DEAD2 ] = 255, + [ KT_BRL ] = NR_BRL - 1, }; static const int NR_TYPES = ARRAY_SIZE(max_vals); +static void kbd_bh(struct tasklet_struct *unused); +static DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh); + static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); static DEFINE_SPINLOCK(led_lock); -static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ +static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */ +static DECLARE_BITMAP(key_down, KEY_CNT); /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static bool dead_key_next; -static int npadch = -1; /* -1 or number assembled on pad */ + +/* Handles a number being assembled on the number pad */ +static bool npadch_active; +static unsigned int npadch_value; + static unsigned int diacr; -static char rep; /* flag telling character repeat */ +static bool rep; /* flag telling character repeat */ static int shift_state = 0; static unsigned int ledstate = -1U; /* undefined */ static unsigned char ledioctl; +static bool vt_switch; /* * Notifier list for console keyboard events @@ -255,7 +275,7 @@ static DEFINE_TIMER(kd_mksound_timer, kd_nosound); void kd_mksound(unsigned int hz, unsigned int ticks) { - del_timer_sync(&kd_mksound_timer); + timer_delete_sync(&kd_mksound_timer); input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper); @@ -305,16 +325,13 @@ int kbd_rate(struct kbd_repeat *rpt) static void put_queue(struct vc_data *vc, int ch) { tty_insert_flip_char(&vc->port, ch, 0); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } -static void puts_queue(struct vc_data *vc, char *cp) +static void puts_queue(struct vc_data *vc, const char *cp) { - while (*cp) { - tty_insert_flip_char(&vc->port, *cp, 0); - cp++; - } - tty_schedule_flip(&vc->port); + tty_insert_flip_string(&vc->port, cp, strlen(cp)); + tty_flip_buffer_push(&vc->port); } static void applkey(struct vc_data *vc, int key, char mode) @@ -359,6 +376,23 @@ static void to_utf8(struct vc_data *vc, uint c) } } +static void put_queue_utf8(struct vc_data *vc, u32 value) +{ + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, value); + else { + int c = conv_uni_to_8bit(value); + if (c != -1) + put_queue(vc, c); + } +} + +/* FIXME: review locking for vt.c callers */ +static void set_leds(void) +{ + tasklet_schedule(&keyboard_tasklet); +} + /* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is @@ -388,12 +422,18 @@ static void do_compute_shiftstate(void) } /* We still have to export this method to vt.c */ -void compute_shiftstate(void) +void vt_set_leds_compute_shiftstate(void) { - unsigned long flags; - spin_lock_irqsave(&kbd_event_lock, flags); + /* + * When VT is switched, the keyboard led needs to be set once. + * Ensure that after the switch is completed, the state of the + * keyboard LED is consistent with the state of the keyboard lock. + */ + vt_switch = true; + set_leds(); + + guard(spinlock_irqsave)(&kbd_event_lock); do_compute_shiftstate(); - spin_unlock_irqrestore(&kbd_event_lock, flags); } /* @@ -422,13 +462,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) return d; - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, d); - else { - int c = conv_uni_to_8bit(d); - if (c != -1) - put_queue(vc, c); - } + put_queue_utf8(vc, d); return ch; } @@ -439,19 +473,13 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) static void fn_enter(struct vc_data *vc) { if (diacr) { - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, diacr); - else { - int c = conv_uni_to_8bit(diacr); - if (c != -1) - put_queue(vc, c); - } + put_queue_utf8(vc, diacr); diacr = 0; } - put_queue(vc, 13); + put_queue(vc, '\r'); if (vc_kbd_mode(kbd, VC_CRLF)) - put_queue(vc, 10); + put_queue(vc, '\n'); } static void fn_caps_toggle(struct vc_data *vc) @@ -490,7 +518,7 @@ static void fn_hold(struct vc_data *vc) * these routines are also activated by ^S/^Q. * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) */ - if (tty->stopped) + if (tty->flow.stopped) start_tty(tty); else stop_tty(tty); @@ -559,7 +587,7 @@ static void fn_inc_console(struct vc_data *vc) static void fn_send_intr(struct vc_data *vc) { tty_insert_flip_char(&vc->port, 0, TTY_BREAK); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void fn_scroll_forw(struct vc_data *vc) @@ -574,7 +602,7 @@ static void fn_scroll_back(struct vc_data *vc) static void fn_show_mem(struct vc_data *vc) { - show_mem(0, NULL); + show_mem(); } static void fn_show_state(struct vc_data *vc) @@ -594,13 +622,12 @@ static void fn_compose(struct vc_data *vc) static void fn_spawn_con(struct vc_data *vc) { - spin_lock(&vt_spawn_con.lock); + guard(spinlock)(&vt_spawn_con.lock); if (vt_spawn_con.pid) if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { put_pid(vt_spawn_con.pid); vt_spawn_con.pid = NULL; } - spin_unlock(&vt_spawn_con.lock); } static void fn_SAK(struct vc_data *vc) @@ -653,13 +680,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) diacr = value; return; } - if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, value); - else { - int c = conv_uni_to_8bit(value); - if (c != -1) - put_queue(vc, c); - } + put_queue_utf8(vc, value); } /* @@ -737,6 +758,7 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag) return; if ((unsigned)value < ARRAY_SIZE(func_table)) { + guard(spinlock_irqsave)(&func_buf_lock); if (func_table[value]) puts_queue(vc, func_table[value]); } else @@ -809,7 +831,7 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) put_queue(vc, pad_chars[value]); if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) - put_queue(vc, 10); + put_queue(vc, '\n'); } static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) @@ -839,17 +861,17 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) shift_down[value]++; if (shift_down[value]) - shift_state |= (1 << value); + shift_state |= BIT(value); else - shift_state &= ~(1 << value); + shift_state &= ~BIT(value); /* kludge */ - if (up_flag && shift_state != old_state && npadch != -1) { + if (up_flag && shift_state != old_state && npadch_active) { if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, npadch); + to_utf8(vc, npadch_value); else - put_queue(vc, npadch & 0xff); - npadch = -1; + put_queue(vc, npadch_value & 0xff); + npadch_active = false; } } @@ -862,12 +884,12 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) put_queue(vc, '\033'); put_queue(vc, value); } else - put_queue(vc, value | 0x80); + put_queue(vc, value | BIT(7)); } static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { - int base; + unsigned int base; if (up_flag) return; @@ -881,10 +903,12 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) base = 16; } - if (npadch == -1) - npadch = value; - else - npadch = npadch * base + value; + if (!npadch_active) { + npadch_value = 0; + npadch_active = true; + } + + npadch_value = npadch_value * base + value; } static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) @@ -956,7 +980,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) return; if (!up_flag) { - pressed |= 1 << (value - 1); + pressed |= BIT(value - 1); if (!brl_timeout) committing = pressed; } else if (brl_timeout) { @@ -966,7 +990,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) committing = pressed; releasestart = jiffies; } - pressed &= ~(1 << (value - 1)); + pressed &= ~BIT(value - 1); if (!pressed && committing) { k_brlcommit(vc, committing, 0); committing = 0; @@ -976,7 +1000,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) k_brlcommit(vc, committing, 0); committing = 0; } - pressed &= ~(1 << (value - 1)); + pressed &= ~BIT(value - 1); } } @@ -994,9 +1018,7 @@ static int kbd_led_trigger_activate(struct led_classdev *cdev) tasklet_disable(&keyboard_tasklet); if (ledstate != -1U) - led_trigger_event(&trigger->trigger, - ledstate & trigger->mask ? - LED_FULL : LED_OFF); + led_set_brightness(cdev, ledstate & trigger->mask ? LED_FULL : LED_OFF); tasklet_enable(&keyboard_tasklet); return 0; @@ -1076,9 +1098,9 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) unsigned int leds = *(unsigned int *)data; if (test_bit(EV_LED, handle->dev->evbit)) { - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & BIT(0))); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & BIT(1))); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & BIT(2))); input_inject_event(handle, EV_SYN, SYN_REPORT, 0); } @@ -1110,8 +1132,7 @@ static unsigned char getledstate(void) void setledstate(struct kbd_struct *kb, unsigned int led) { - unsigned long flags; - spin_lock_irqsave(&led_lock, flags); + guard(spinlock_irqsave)(&led_lock); if (!(led & ~7)) { ledioctl = led; kb->ledmode = LED_SHOW_IOCTL; @@ -1119,7 +1140,6 @@ void setledstate(struct kbd_struct *kb, unsigned int led) kb->ledmode = LED_SHOW_FLAGS; set_leds(); - spin_unlock_irqrestore(&led_lock, flags); } static inline unsigned char getleds(void) @@ -1139,17 +1159,12 @@ static inline unsigned char getleds(void) * * Check the status of a keyboard led flag and report it back */ -int vt_get_leds(int console, int flag) +int vt_get_leds(unsigned int console, int flag) { - struct kbd_struct *kb = kbd_table + console; - int ret; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; - spin_lock_irqsave(&led_lock, flags); - ret = vc_kbd_led(kb, flag); - spin_unlock_irqrestore(&led_lock, flags); - - return ret; + guard(spinlock_irqsave)(&led_lock); + return vc_kbd_led(kb, flag); } EXPORT_SYMBOL_GPL(vt_get_leds); @@ -1161,9 +1176,9 @@ EXPORT_SYMBOL_GPL(vt_get_leds); * Set the LEDs on a console. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal */ -void vt_set_led_state(int console, int leds) +void vt_set_led_state(unsigned int console, int leds) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; setledstate(kb, leds); } @@ -1180,14 +1195,13 @@ void vt_set_led_state(int console, int leds) * don't hold the lock. We probably need to split out an LED lock * but not during an -rc release! */ -void vt_kbd_con_start(int console) +void vt_kbd_con_start(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; - unsigned long flags; - spin_lock_irqsave(&led_lock, flags); + struct kbd_struct *kb = &kbd_table[console]; + + guard(spinlock_irqsave)(&led_lock); clr_vc_kbd_led(kb, VC_SCROLLOCK); set_leds(); - spin_unlock_irqrestore(&led_lock, flags); } /** @@ -1197,14 +1211,13 @@ void vt_kbd_con_start(int console) * Handle console stop. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal */ -void vt_kbd_con_stop(int console) +void vt_kbd_con_stop(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; - unsigned long flags; - spin_lock_irqsave(&led_lock, flags); + struct kbd_struct *kb = &kbd_table[console]; + + guard(spinlock_irqsave)(&led_lock); set_vc_kbd_led(kb, VC_SCROLLOCK); set_leds(); - spin_unlock_irqrestore(&led_lock, flags); } /* @@ -1213,15 +1226,19 @@ void vt_kbd_con_stop(int console) * handle the scenario when keyboard handler is not registered yet * but we already getting updates from the VT to update led state. */ -static void kbd_bh(unsigned long dummy) +static void kbd_bh(struct tasklet_struct *unused) { unsigned int leds; - unsigned long flags; - spin_lock_irqsave(&led_lock, flags); - leds = getleds(); - leds |= (unsigned int)kbd->lockstate << 8; - spin_unlock_irqrestore(&led_lock, flags); + scoped_guard(spinlock_irqsave, &led_lock) { + leds = getleds(); + leds |= (unsigned int)kbd->lockstate << 8; + } + + if (vt_switch) { + ledstate = ~leds; + vt_switch = false; + } if (leds != ledstate) { kbd_propagate_led_state(ledstate, leds); @@ -1229,15 +1246,19 @@ static void kbd_bh(unsigned long dummy) } } -DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); - -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ +#if defined(CONFIG_X86) || defined(CONFIG_ALPHA) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) -#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ - ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) +static inline bool kbd_is_hw_raw(const struct input_dev *dev) +{ + if (!test_bit(EV_MSC, dev->evbit) || !test_bit(MSC_RAW, dev->mscbit)) + return false; + + return dev->id.bustype == BUS_I8042 && + dev->id.vendor == 0x0001 && dev->id.product == 0x0001; +} static const unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -1322,7 +1343,10 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #else -#define HW_RAW(dev) 0 +static inline bool kbd_is_hw_raw(const struct input_dev *dev) +{ + return false; +} static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { @@ -1338,12 +1362,12 @@ static void kbd_rawcode(unsigned char data) { struct vc_data *vc = vc_cons[fg_console].d; - kbd = kbd_table + vc->vc_num; + kbd = &kbd_table[vc->vc_num]; if (kbd->kbdmode == VC_RAW) put_queue(vc, data); } -static void kbd_keycode(unsigned int keycode, int down, int hw_raw) +static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1361,7 +1385,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) tty->driver_data = vc; } - kbd = kbd_table + vc->vc_num; + kbd = &kbd_table[vc->vc_num]; #ifdef CONFIG_SPARC if (keycode == KEY_STOP) @@ -1398,16 +1422,13 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) put_queue(vc, keycode | (!down << 7)); } else { put_queue(vc, !down << 7); - put_queue(vc, (keycode >> 7) | 0x80); - put_queue(vc, keycode | 0x80); + put_queue(vc, (keycode >> 7) | BIT(7)); + put_queue(vc, keycode | BIT(7)); } raw_mode = true; } - if (down) - set_bit(keycode, key_down); - else - clear_bit(keycode, key_down); + assign_bit(keycode, key_down, down); if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || @@ -1448,8 +1469,8 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) rc = atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, ¶m); if (rc != NOTIFY_STOP) - if (down && !raw_mode) - to_utf8(vc, keysym); + if (down && !(raw_mode || kbd->kbdmode == VC_OFF)) + k_unicode(vc, keysym, !down); return; } @@ -1458,7 +1479,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (type == KT_LETTER) { type = KT_LATIN; if (vc_kbd_led(kbd, VC_CAPSLOCK)) { - key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; + key_map = key_maps[shift_final ^ BIT(KG_SHIFT)]; if (key_map) keysym = key_map[keycode]; } @@ -1473,7 +1494,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT) return; - (*k_handler[type])(vc, keysym & 0xff, !down); + (*k_handler[type])(vc, KVAL(keysym), !down); param.ledstate = kbd->ledflagstate; atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); @@ -1486,14 +1507,13 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, unsigned int event_code, int value) { /* We are called with interrupts disabled, just take the lock */ - spin_lock(&kbd_event_lock); - - if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) - kbd_rawcode(value); - if (event_type == EV_KEY) - kbd_keycode(event_code, value, HW_RAW(handle->dev)); - - spin_unlock(&kbd_event_lock); + scoped_guard(spinlock, &kbd_event_lock) { + if (event_type == EV_MSC && event_code == MSC_RAW && + kbd_is_hw_raw(handle->dev)) + kbd_rawcode(value); + if (event_type == EV_KEY && event_code <= KEY_MAX) + kbd_keycode(event_code, value, kbd_is_hw_raw(handle->dev)); + } tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; @@ -1502,18 +1522,16 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type, static bool kbd_match(struct input_handler *handler, struct input_dev *dev) { - int i; - if (test_bit(EV_SND, dev->evbit)) return true; if (test_bit(EV_KEY, dev->evbit)) { - for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) - return true; - for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++) - if (test_bit(i, dev->keybit)) - return true; + if (find_next_bit(dev->keybit, BTN_MISC, KEY_RESERVED) < + BTN_MISC) + return true; + if (find_next_bit(dev->keybit, KEY_BRL_DOT10 + 1, + KEY_BRL_DOT1) <= KEY_BRL_DOT10) + return true; } return false; @@ -1528,10 +1546,9 @@ static bool kbd_match(struct input_handler *handler, struct input_dev *dev) static int kbd_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { - struct input_handle *handle; int error; - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + struct input_handle __free(kfree) *handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; @@ -1541,18 +1558,18 @@ static int kbd_connect(struct input_handler *handler, struct input_dev *dev, error = input_register_handle(handle); if (error) - goto err_free_handle; + return error; error = input_open_device(handle); if (error) goto err_unregister_handle; + retain_and_null_ptr(handle); + return 0; err_unregister_handle: input_unregister_handle(handle); - err_free_handle: - kfree(handle); return error; } @@ -1643,77 +1660,64 @@ int __init kbd_init(void) */ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) { - unsigned long flags; int asize; - int ret = 0; switch (cmd) { case KDGKBDIACR: { struct kbdiacrs __user *a = udp; - struct kbdiacr *dia; int i; - dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), - GFP_KERNEL); + struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), + GFP_KERNEL); if (!dia) return -ENOMEM; /* Lock the diacriticals table, make a copy and then copy it after we unlock */ - spin_lock_irqsave(&kbd_event_lock, flags); - - asize = accent_table_size; - for (i = 0; i < asize; i++) { - dia[i].diacr = conv_uni_to_8bit( - accent_table[i].diacr); - dia[i].base = conv_uni_to_8bit( - accent_table[i].base); - dia[i].result = conv_uni_to_8bit( - accent_table[i].result); + scoped_guard(spinlock_irqsave, &kbd_event_lock) { + asize = accent_table_size; + for (i = 0; i < asize; i++) { + dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr); + dia[i].base = conv_uni_to_8bit(accent_table[i].base); + dia[i].result = conv_uni_to_8bit(accent_table[i].result); + } } - spin_unlock_irqrestore(&kbd_event_lock, flags); if (put_user(asize, &a->kb_cnt)) - ret = -EFAULT; - else if (copy_to_user(a->kbdiacr, dia, - asize * sizeof(struct kbdiacr))) - ret = -EFAULT; - kfree(dia); - return ret; + return -EFAULT; + if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr))) + return -EFAULT; + return 0; } case KDGKBDIACRUC: { struct kbdiacrsuc __user *a = udp; - void *buf; - buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), - GFP_KERNEL); + void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), + GFP_KERNEL); if (buf == NULL) return -ENOMEM; /* Lock the diacriticals table, make a copy and then copy it after we unlock */ - spin_lock_irqsave(&kbd_event_lock, flags); - - asize = accent_table_size; - memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); - - spin_unlock_irqrestore(&kbd_event_lock, flags); + scoped_guard(spinlock_irqsave, &kbd_event_lock) { + asize = accent_table_size; + memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); + } if (put_user(asize, &a->kb_cnt)) - ret = -EFAULT; - else if (copy_to_user(a->kbdiacruc, buf, - asize*sizeof(struct kbdiacruc))) - ret = -EFAULT; - kfree(buf); - return ret; + return -EFAULT; + if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc))) + return -EFAULT; + + return 0; } case KDSKBDIACR: { struct kbdiacrs __user *a = udp; - struct kbdiacr *dia = NULL; + struct kbdiacr __free(kfree) *dia = NULL; unsigned int ct; int i; @@ -1725,15 +1729,13 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - - dia = memdup_user(a->kbdiacr, - sizeof(struct kbdiacr) * ct); + dia = memdup_array_user(a->kbdiacr, + ct, sizeof(struct kbdiacr)); if (IS_ERR(dia)) return PTR_ERR(dia); - } - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); accent_table_size = ct; for (i = 0; i < ct; i++) { accent_table[i].diacr = @@ -1743,8 +1745,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) accent_table[i].result = conv_8bit_to_uni(dia[i].result); } - spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(dia); + return 0; } @@ -1752,7 +1753,7 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) { struct kbdiacrsuc __user *a = udp; unsigned int ct; - void *buf = NULL; + void __free(kfree) *buf = NULL; if (!perm) return -EPERM; @@ -1764,22 +1765,20 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) return -EINVAL; if (ct) { - buf = memdup_user(a->kbdiacruc, - ct * sizeof(struct kbdiacruc)); + buf = memdup_array_user(a->kbdiacruc, + ct, sizeof(struct kbdiacruc)); if (IS_ERR(buf)) return PTR_ERR(buf); - } - spin_lock_irqsave(&kbd_event_lock, flags); + } + guard(spinlock_irqsave)(&kbd_event_lock); if (ct) memcpy(accent_table, buf, ct * sizeof(struct kbdiacruc)); accent_table_size = ct; - spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(buf); return 0; } } - return ret; + return 0; } /** @@ -1790,36 +1789,32 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) * Update the keyboard mode bits while holding the correct locks. * Return 0 for success or an error code. */ -int vt_do_kdskbmode(int console, unsigned int arg) +int vt_do_kdskbmode(unsigned int console, unsigned int arg) { - struct kbd_struct *kb = kbd_table + console; - int ret = 0; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); switch(arg) { case K_RAW: kb->kbdmode = VC_RAW; - break; + return 0; case K_MEDIUMRAW: kb->kbdmode = VC_MEDIUMRAW; - break; + return 0; case K_XLATE: kb->kbdmode = VC_XLATE; do_compute_shiftstate(); - break; + return 0; case K_UNICODE: kb->kbdmode = VC_UNICODE; do_compute_shiftstate(); - break; + return 0; case K_OFF: kb->kbdmode = VC_OFF; - break; + return 0; default: - ret = -EINVAL; + return -EINVAL; } - spin_unlock_irqrestore(&kbd_event_lock, flags); - return ret; } /** @@ -1830,285 +1825,227 @@ int vt_do_kdskbmode(int console, unsigned int arg) * Update the keyboard meta bits while holding the correct locks. * Return 0 for success or an error code. */ -int vt_do_kdskbmeta(int console, unsigned int arg) +int vt_do_kdskbmeta(unsigned int console, unsigned int arg) { - struct kbd_struct *kb = kbd_table + console; - int ret = 0; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); switch(arg) { case K_METABIT: clr_vc_kbd_mode(kb, VC_META); - break; + return 0; case K_ESCPREFIX: set_vc_kbd_mode(kb, VC_META); - break; + return 0; default: - ret = -EINVAL; + return -EINVAL; } - spin_unlock_irqrestore(&kbd_event_lock, flags); - return ret; } -int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, - int perm) +int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) { struct kbkeycode tmp; - int kc = 0; + int kc; if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) return -EFAULT; + switch (cmd) { case KDGETKEYCODE: kc = getkeycode(tmp.scancode); - if (kc >= 0) - kc = put_user(kc, &user_kbkc->keycode); - break; + if (kc < 0) + return kc; + return put_user(kc, &user_kbkc->keycode); case KDSETKEYCODE: if (!perm) return -EPERM; - kc = setkeycode(tmp.scancode, tmp.keycode); - break; + return setkeycode(tmp.scancode, tmp.keycode); } - return kc; -} -#define i (tmp.kb_index) -#define s (tmp.kb_table) -#define v (tmp.kb_value) + return 0; +} -int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, - int console) +static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx, + unsigned char map) { - struct kbd_struct *kb = kbd_table + console; - struct kbentry tmp; - ushort *key_map, *new_map, val, ov; - unsigned long flags; + unsigned short *key_map; - if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) - return -EFAULT; + /* Ensure another thread doesn't free it under us */ + guard(spinlock_irqsave)(&kbd_event_lock); + key_map = key_maps[map]; + if (key_map) { + unsigned short val = U(key_map[idx]); + if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) + return K_HOLE; + return val; + } - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; + return idx ? K_HOLE : K_NOSUCHMAP; +} - switch (cmd) { - case KDGKBENT: - /* Ensure another thread doesn't free it under us */ - spin_lock_irqsave(&kbd_event_lock, flags); - key_map = key_maps[s]; - if (key_map) { - val = U(key_map[i]); - if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) - val = K_HOLE; - } else - val = (i ? K_HOLE : K_NOSUCHMAP); - spin_unlock_irqrestore(&kbd_event_lock, flags); - return put_user(val, &user_kbe->kb_value); - case KDSKBENT: - if (!perm) - return -EPERM; - if (!i && v == K_NOSUCHMAP) { - spin_lock_irqsave(&kbd_event_lock, flags); - /* deallocate map */ - key_map = key_maps[s]; - if (s && key_map) { - key_maps[s] = NULL; - if (key_map[0] == U(K_ALLOCATED)) { - kfree(key_map); - keymap_count--; - } +static int vt_kdskbent(unsigned char kbdmode, unsigned char idx, + unsigned char map, unsigned short val) +{ + unsigned short *key_map, oldval; + + if (!idx && val == K_NOSUCHMAP) { + guard(spinlock_irqsave)(&kbd_event_lock); + /* deallocate map */ + key_map = key_maps[map]; + if (map && key_map) { + key_maps[map] = NULL; + if (key_map[0] == U(K_ALLOCATED)) { + kfree(key_map); + keymap_count--; } - spin_unlock_irqrestore(&kbd_event_lock, flags); - break; } - if (KTYP(v) < NR_TYPES) { - if (KVAL(v) > max_vals[KTYP(v)]) - return -EINVAL; - } else - if (kb->kbdmode != VC_UNICODE) - return -EINVAL; + return 0; + } - /* ++Geert: non-PC keyboards may generate keycode zero */ + if (KTYP(val) < NR_TYPES) { + if (KVAL(val) > max_vals[KTYP(val)]) + return -EINVAL; + } else if (kbdmode != VC_UNICODE) + return -EINVAL; + + /* ++Geert: non-PC keyboards may generate keycode zero */ #if !defined(__mc68000__) && !defined(__powerpc__) - /* assignment to entry 0 only tests validity of args */ - if (!i) - break; + /* assignment to entry 0 only tests validity of args */ + if (!idx) + return 0; #endif - new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); - if (!new_map) - return -ENOMEM; - spin_lock_irqsave(&kbd_event_lock, flags); - key_map = key_maps[s]; - if (key_map == NULL) { - int j; - - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && - !capable(CAP_SYS_RESOURCE)) { - spin_unlock_irqrestore(&kbd_event_lock, flags); - kfree(new_map); - return -EPERM; - } - key_maps[s] = new_map; - key_map = new_map; - key_map[0] = U(K_ALLOCATED); - for (j = 1; j < NR_KEYS; j++) - key_map[j] = U(K_HOLE); - keymap_count++; - } else - kfree(new_map); - - ov = U(key_map[i]); - if (v == ov) - goto out; - /* - * Attention Key. - */ - if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { - spin_unlock_irqrestore(&kbd_event_lock, flags); + unsigned short __free(kfree) *new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + guard(spinlock_irqsave)(&kbd_event_lock); + key_map = key_maps[map]; + if (key_map == NULL) { + int j; + + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !capable(CAP_SYS_RESOURCE)) return -EPERM; - } - key_map[i] = U(v); - if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) - do_compute_shiftstate(); -out: - spin_unlock_irqrestore(&kbd_event_lock, flags); - break; + + key_map = key_maps[map] = no_free_ptr(new_map); + key_map[0] = U(K_ALLOCATED); + for (j = 1; j < NR_KEYS; j++) + key_map[j] = U(K_HOLE); + keymap_count++; } + + oldval = U(key_map[idx]); + if (val == oldval) + return 0; + + /* Attention Key */ + if ((oldval == K_SAK || val == K_SAK) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + key_map[idx] = U(val); + if (!map && (KTYP(oldval) == KT_SHIFT || KTYP(val) == KT_SHIFT)) + do_compute_shiftstate(); + return 0; } -#undef i -#undef s -#undef v -/* FIXME: This one needs untangling and locking */ -int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) +int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, + unsigned int console) { - struct kbsentry *kbs; - char *p; - u_char *q; - u_char __user *up; - int sz; - int delta; - char *first_free, *fj, *fnw; - int i, j, k; - int ret; - - if (!capable(CAP_SYS_TTY_CONFIG)) - perm = 0; - - kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); - if (!kbs) { - ret = -ENOMEM; - goto reterr; + struct kbd_struct *kb = &kbd_table[console]; + struct kbentry kbe; + + if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry))) + return -EFAULT; + + switch (cmd) { + case KDGKBENT: + return put_user(vt_kdgkbent(kb->kbdmode, kbe.kb_index, + kbe.kb_table), + &user_kbe->kb_value); + case KDSKBENT: + if (!perm || !capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; + return vt_kdskbent(kb->kbdmode, kbe.kb_index, kbe.kb_table, + kbe.kb_value); } + return 0; +} + +static char *vt_kdskbsent(char *kbs, unsigned char cur) +{ + static DECLARE_BITMAP(is_kmalloc, MAX_NR_FUNC); + char *cur_f = func_table[cur]; - /* we mostly copy too much here (512bytes), but who cares ;) */ - if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { - ret = -EFAULT; - goto reterr; + if (cur_f && strlen(cur_f) >= strlen(kbs)) { + strcpy(cur_f, kbs); + return kbs; } - kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; - i = kbs->kb_func; + + func_table[cur] = kbs; + + return __test_and_set_bit(cur, is_kmalloc) ? cur_f : NULL; +} + +int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) +{ + unsigned char kb_func; + + if (get_user(kb_func, &user_kdgkb->kb_func)) + return -EFAULT; + + kb_func = array_index_nospec(kb_func, MAX_NR_FUNC); switch (cmd) { - case KDGKBSENT: - sz = sizeof(kbs->kb_string) - 1; /* sz should have been - a struct member */ - up = user_kdgkb->kb_string; - p = func_table[i]; - if(p) - for ( ; *p && sz; p++, sz--) - if (put_user(*p, up++)) { - ret = -EFAULT; - goto reterr; - } - if (put_user('\0', up)) { - ret = -EFAULT; - goto reterr; - } - kfree(kbs); - return ((p && *p) ? -EOVERFLOW : 0); + case KDGKBSENT: { + /* size should have been a struct member */ + ssize_t len = sizeof(user_kdgkb->kb_string); + + char __free(kfree) *kbs = kmalloc(len, GFP_KERNEL); + if (!kbs) + return -ENOMEM; + + scoped_guard(spinlock_irqsave, &func_buf_lock) + len = strscpy(kbs, func_table[kb_func] ? : "", len); + + if (len < 0) + return -ENOSPC; + + if (copy_to_user(user_kdgkb->kb_string, kbs, len + 1)) + return -EFAULT; + + return 0; + } case KDSKBSENT: - if (!perm) { - ret = -EPERM; - goto reterr; - } + if (!perm || !capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; - q = func_table[i]; - first_free = funcbufptr + (funcbufsize - funcbufleft); - for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) - ; - if (j < MAX_NR_FUNC) - fj = func_table[j]; - else - fj = first_free; - - delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); - if (delta <= funcbufleft) { /* it fits in current buf */ - if (j < MAX_NR_FUNC) { - memmove(fj + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] += delta; - } - if (!q) - func_table[i] = fj; - funcbufleft -= delta; - } else { /* allocate a larger buffer */ - sz = 256; - while (sz < funcbufsize - funcbufleft + delta) - sz <<= 1; - fnw = kmalloc(sz, GFP_KERNEL); - if(!fnw) { - ret = -ENOMEM; - goto reterr; - } - - if (!q) - func_table[i] = fj; - if (fj > funcbufptr) - memmove(fnw, funcbufptr, fj - funcbufptr); - for (k = 0; k < j; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr); - - if (first_free > fj) { - memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); - for (k = j; k < MAX_NR_FUNC; k++) - if (func_table[k]) - func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; - } - if (funcbufptr != func_buf) - kfree(funcbufptr); - funcbufptr = fnw; - funcbufleft = funcbufleft - delta + sz - funcbufsize; - funcbufsize = sz; - } - strcpy(func_table[i], kbs->kb_string); - break; + char __free(kfree) *kbs = strndup_user(user_kdgkb->kb_string, + sizeof(user_kdgkb->kb_string)); + if (IS_ERR(kbs)) + return PTR_ERR(kbs); + + guard(spinlock_irqsave)(&func_buf_lock); + kbs = vt_kdskbsent(kbs, kb_func); + + return 0; } - ret = 0; -reterr: - kfree(kbs); - return ret; + + return 0; } -int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) +int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm) { - struct kbd_struct *kb = kbd_table + console; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; unsigned char ucval; switch(cmd) { /* the ioctls below read/set the flags usually shown in the leds */ /* don't use them - they will go away without warning */ case KDGKBLED: - spin_lock_irqsave(&kbd_event_lock, flags); - ucval = kb->ledflagstate | (kb->default_ledflagstate << 4); - spin_unlock_irqrestore(&kbd_event_lock, flags); + scoped_guard(spinlock_irqsave, &kbd_event_lock) + ucval = kb->ledflagstate | (kb->default_ledflagstate << 4); return put_user(ucval, (char __user *)arg); case KDSKBLED: @@ -2116,11 +2053,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) return -EPERM; if (arg & ~0x77) return -EINVAL; - spin_lock_irqsave(&led_lock, flags); - kb->ledflagstate = (arg & 7); - kb->default_ledflagstate = ((arg >> 4) & 7); - set_leds(); - spin_unlock_irqrestore(&led_lock, flags); + scoped_guard(spinlock_irqsave, &led_lock) { + kb->ledflagstate = (arg & 7); + kb->default_ledflagstate = ((arg >> 4) & 7); + set_leds(); + } return 0; /* the ioctls below only set the lights, not the functions */ @@ -2138,9 +2075,9 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) return -ENOIOCTLCMD; } -int vt_do_kdgkbmode(int console) +int vt_do_kdgkbmode(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; /* This is a spot read so needs no locking */ switch (kb->kbdmode) { case VC_RAW: @@ -2162,9 +2099,9 @@ int vt_do_kdgkbmode(int console) * * Report the meta flag status of this console */ -int vt_do_kdgkbmeta(int console) +int vt_do_kdgkbmeta(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; /* Again a spot read so no locking */ return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT; } @@ -2175,17 +2112,14 @@ int vt_do_kdgkbmeta(int console) * * Restore the unicode console state to its default */ -void vt_reset_unicode(int console) +void vt_reset_unicode(unsigned int console) { - unsigned long flags; - - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; - spin_unlock_irqrestore(&kbd_event_lock, flags); } /** - * vt_get_shiftstate - shift bit state + * vt_get_shift_state - shift bit state * * Report the shift bits from the keyboard state. We have to export * this to support some oddities in the vt layer. @@ -2203,25 +2137,22 @@ int vt_get_shift_state(void) * Reset the keyboard bits for a console as part of a general console * reset event */ -void vt_reset_keyboard(int console) +void vt_reset_keyboard(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); set_vc_kbd_mode(kb, VC_REPEAT); clr_vc_kbd_mode(kb, VC_CKMODE); clr_vc_kbd_mode(kb, VC_APPLIC); clr_vc_kbd_mode(kb, VC_CRLF); kb->lockstate = 0; kb->slockstate = 0; - spin_lock(&led_lock); + guard(spinlock)(&led_lock); kb->ledmode = LED_SHOW_FLAGS; kb->ledflagstate = kb->default_ledflagstate; - spin_unlock(&led_lock); /* do not do set_leds here because this causes an endless tasklet loop when the keyboard hasn't been initialized yet */ - spin_unlock_irqrestore(&kbd_event_lock, flags); } /** @@ -2233,9 +2164,9 @@ void vt_reset_keyboard(int console) * caller must be sure that there are no synchronization needs */ -int vt_get_kbd_mode_bit(int console, int bit) +int vt_get_kbd_mode_bit(unsigned int console, int bit) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; return vc_kbd_mode(kb, bit); } @@ -2248,14 +2179,12 @@ int vt_get_kbd_mode_bit(int console, int bit) * caller must be sure that there are no synchronization needs */ -void vt_set_kbd_mode_bit(int console, int bit) +void vt_set_kbd_mode_bit(unsigned int console, int bit) { - struct kbd_struct *kb = kbd_table + console; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); set_vc_kbd_mode(kb, bit); - spin_unlock_irqrestore(&kbd_event_lock, flags); } /** @@ -2267,12 +2196,10 @@ void vt_set_kbd_mode_bit(int console, int bit) * caller must be sure that there are no synchronization needs */ -void vt_clr_kbd_mode_bit(int console, int bit) +void vt_clr_kbd_mode_bit(unsigned int console, int bit) { - struct kbd_struct *kb = kbd_table + console; - unsigned long flags; + struct kbd_struct *kb = &kbd_table[console]; - spin_lock_irqsave(&kbd_event_lock, flags); + guard(spinlock_irqsave)(&kbd_event_lock); clr_vc_kbd_mode(kb, bit); - spin_unlock_irqrestore(&kbd_event_lock, flags); } |
