summaryrefslogtreecommitdiff
path: root/drivers/tty/vt/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/vt/keyboard.c')
-rw-r--r--drivers/tty/vt/keyboard.c881
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, &param);
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, &param);
@@ -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);
}