linux/drivers/tty/vt/keyboard.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Written for linux by Johan Myreen as a translation from
 * the assembly version by Linus (with diacriticals added)
 *
 * Some additional features added by Christoph Niemann (ChN), March 1993
 *
 * Loadable keymaps by Risto Kankkunen, May 1993
 *
 * Diacriticals redone & other small changes, [email protected], June 1993
 * Added decr/incr_console, dynamic keymaps, Unicode support,
 * dynamic function/string keys, led setting,  Sept 1994
 * `Sticky' modifier keys, 951006.
 *
 * 11-11-96: SAK should now work in the raw mode (Martin Mares)
 *
 * Modified to provide 'generic' keyboard support by Hamish Macdonald
 * Merge with the m68k keyboard driver and split-off of the PC low-level
 * parts by Geert Uytterhoeven, May 1997
 *
 * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
 * 30-07-98: Dead keys redone, [email protected].
 * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
 */

#define pr_fmt(fmt)

#include <linux/consolemap.h>
#include <linux/init.h>
#include <linux/input.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>

/*
 * Exported functions/variables
 */

#define KBD_DEFMODE

#if defined(CONFIG_X86) || defined(CONFIG_PARISC)
#include <asm/kbdleds.h>
#else
static inline int kbd_defleds(void)
{
	return 0;
}
#endif

#define KBD_DEFLOCK

/*
 * Handler Tables.
 */

#define K_HANDLERS

k_handler_fn;
static k_handler_fn K_HANDLERS;
static k_handler_fn *k_handler[16] =;

#define FN_HANDLERS

fn_handler_fn;
static fn_handler_fn FN_HANDLERS;
static fn_handler_fn *fn_handler[] =;

/*
 * Variables exported for vt_ioctl.c
 */

struct vt_spawn_console vt_spawn_con =;


/*
 * Internal Data.
 */

static struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd =;

/* maximum values each key_handler can handle */
static const unsigned char max_vals[] =;

static const int NR_TYPES =;

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 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;

/* Handles a number being assembled on the number pad */
static bool npadch_active;
static unsigned int npadch_value;

static unsigned int diacr;
static bool rep;			/* flag telling character repeat */

static int shift_state =;

static unsigned int ledstate =;			/* undefined */
static unsigned char ledioctl;
static bool vt_switch;

/*
 * Notifier list for console keyboard events
 */
static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);

int register_keyboard_notifier(struct notifier_block *nb)
{}
EXPORT_SYMBOL_GPL();

int unregister_keyboard_notifier(struct notifier_block *nb)
{}
EXPORT_SYMBOL_GPL();

/*
 * Translation of scancodes to keycodes. We set them on only the first
 * keyboard in the list that accepts the scancode and keycode.
 * Explanation for not choosing the first attached keyboard anymore:
 *  USB keyboards for example have two event devices: one for all "normal"
 *  keys and one for extra function keys (like "volume up", "make coffee",
 *  etc.). So this means that scancodes for the extra function keys won't
 *  be valid for the first event device, but will be for the second.
 */

struct getset_keycode_data {};

static int getkeycode_helper(struct input_handle *handle, void *data)
{}

static int getkeycode(unsigned int scancode)
{}

static int setkeycode_helper(struct input_handle *handle, void *data)
{}

static int setkeycode(unsigned int scancode, unsigned int keycode)
{}

/*
 * Making beeps and bells. Note that we prefer beeps to bells, but when
 * shutting the sound off we do both.
 */

static int kd_sound_helper(struct input_handle *handle, void *data)
{}

static void kd_nosound(struct timer_list *unused)
{}

static DEFINE_TIMER(kd_mksound_timer, kd_nosound);

void kd_mksound(unsigned int hz, unsigned int ticks)
{}
EXPORT_SYMBOL();

/*
 * Setting the keyboard rate.
 */

static int kbd_rate_helper(struct input_handle *handle, void *data)
{}

int kbd_rate(struct kbd_repeat *rpt)
{}

/*
 * Helper Functions.
 */
static void put_queue(struct vc_data *vc, int ch)
{}

static void puts_queue(struct vc_data *vc, const char *cp)
{}

static void applkey(struct vc_data *vc, int key, char mode)
{}

/*
 * Many other routines do put_queue, but I think either
 * they produce ASCII, or they produce some user-assigned
 * string, and in both cases we might assume that it is
 * in utf-8 already.
 */
static void to_utf8(struct vc_data *vc, uint c)
{}

/* FIXME: review locking for vt.c callers */
static void set_leds(void)
{}

/*
 * Called after returning from RAW mode or when changing consoles - recompute
 * shift_down[] and shift_state from key_down[] maybe called when keymap is
 * undefined, so that shiftkey release is seen. The caller must hold the
 * kbd_event_lock.
 */

static void do_compute_shiftstate(void)
{}

/* We still have to export this method to vt.c */
void vt_set_leds_compute_shiftstate(void)
{}

/*
 * We have a combining character DIACR here, followed by the character CH.
 * If the combination occurs in the table, return the corresponding value.
 * Otherwise, if CH is a space or equals DIACR, return DIACR.
 * Otherwise, conclude that DIACR was not combining after all,
 * queue it and return CH.
 */
static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
{}

/*
 * Special function handlers
 */
static void fn_enter(struct vc_data *vc)
{}

static void fn_caps_toggle(struct vc_data *vc)
{}

static void fn_caps_on(struct vc_data *vc)
{}

static void fn_show_ptregs(struct vc_data *vc)
{}

static void fn_hold(struct vc_data *vc)
{}

static void fn_num(struct vc_data *vc)
{}

/*
 * Bind this to Shift-NumLock if you work in application keypad mode
 * but want to be able to change the NumLock flag.
 * Bind this to NumLock if you prefer that the NumLock key always
 * changes the NumLock flag.
 */
static void fn_bare_num(struct vc_data *vc)
{}

static void fn_lastcons(struct vc_data *vc)
{}

static void fn_dec_console(struct vc_data *vc)
{}

static void fn_inc_console(struct vc_data *vc)
{}

static void fn_send_intr(struct vc_data *vc)
{}

static void fn_scroll_forw(struct vc_data *vc)
{}

static void fn_scroll_back(struct vc_data *vc)
{}

static void fn_show_mem(struct vc_data *vc)
{}

static void fn_show_state(struct vc_data *vc)
{}

static void fn_boot_it(struct vc_data *vc)
{}

static void fn_compose(struct vc_data *vc)
{}

static void fn_spawn_con(struct vc_data *vc)
{}

static void fn_SAK(struct vc_data *vc)
{}

static void fn_null(struct vc_data *vc)
{}

/*
 * Special key handlers
 */
static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
{}

/*
 * Handle dead key. Note that we now may have several
 * dead keys modifying the same character. Very useful
 * for Vietnamese.
 */
static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
{}

static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
{}

/*
 * Obsolete - for backwards compatibility only
 */
static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
{}

static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
{}

/* by default, 300ms interval for combination release */
static unsigned brl_timeout =;
MODULE_PARM_DESC();
module_param(brl_timeout, uint, 0644);

static unsigned brl_nbchords =;
MODULE_PARM_DESC();
module_param(brl_nbchords, uint, 0644);

static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
{}

static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
{}

#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS)

struct kbd_led_trigger {};

static int kbd_led_trigger_activate(struct led_classdev *cdev)
{}

#define KBD_LED_TRIGGER(_led_bit, _name)

#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name)

static struct kbd_led_trigger kbd_led_triggers[] =;

static void kbd_propagate_led_state(unsigned int old_state,
				    unsigned int new_state)
{}

static int kbd_update_leds_helper(struct input_handle *handle, void *data)
{}

static void kbd_init_leds(void)
{}

#else

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 & 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);
	}

	return 0;
}

static void kbd_propagate_led_state(unsigned int old_state,
				    unsigned int new_state)
{
	input_handler_for_each_handle(&kbd_handler, &new_state,
				      kbd_update_leds_helper);
}

static void kbd_init_leds(void)
{
}

#endif

/*
 * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
 * or (ii) whatever pattern of lights people want to show using KDSETLED,
 * or (iii) specified bits of specified words in kernel memory.
 */
static unsigned char getledstate(void)
{}

void setledstate(struct kbd_struct *kb, unsigned int led)
{}

static inline unsigned char getleds(void)
{}

/**
 *	vt_get_leds	-	helper for braille console
 *	@console: console to read
 *	@flag: flag we want to check
 *
 *	Check the status of a keyboard led flag and report it back
 */
int vt_get_leds(unsigned int console, int flag)
{}
EXPORT_SYMBOL_GPL();

/**
 *	vt_set_led_state	-	set LED state of a console
 *	@console: console to set
 *	@leds: LED bits
 *
 *	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(unsigned int console, int leds)
{}

/**
 *	vt_kbd_con_start	-	Keyboard side of console start
 *	@console: console
 *
 *	Handle console start. This is a wrapper for the VT layer
 *	so that we can keep kbd knowledge internal
 *
 *	FIXME: We eventually need to hold the kbd lock here to protect
 *	the LED updating. We can't do it yet because fn_hold calls stop_tty
 *	and start_tty under the kbd_event_lock, while normal tty paths
 *	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(unsigned int console)
{}

/**
 *	vt_kbd_con_stop		-	Keyboard side of console stop
 *	@console: 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(unsigned int console)
{}

/*
 * This is the tasklet that updates LED state of LEDs using standard
 * keyboard triggers. The reason we use tasklet is that we need to
 * 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(struct tasklet_struct *unused)
{}

#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))

static inline bool kbd_is_hw_raw(const struct input_dev *dev)
{}

static const unsigned short x86_keycodes[256] =;

#ifdef CONFIG_SPARC
static int sparc_l1_a_state;
extern void sun_do_break(void);
#endif

static int emulate_raw(struct vc_data *vc, unsigned int keycode,
		       unsigned char up_flag)
{}

#else

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)
{
	if (keycode > 127)
		return -1;

	put_queue(vc, keycode | up_flag);
	return 0;
}
#endif

static void kbd_rawcode(unsigned char data)
{}

static void kbd_keycode(unsigned int keycode, int down, bool hw_raw)
{}

static void kbd_event(struct input_handle *handle, unsigned int event_type,
		      unsigned int event_code, int value)
{}

static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
{}

/*
 * When a keyboard (or other input device) is found, the kbd_connect
 * function is called. The function then looks at the device, and if it
 * likes it, it can open it and get events from it. In this (kbd_connect)
 * function, we should decide which VT to bind that keyboard to initially.
 */
static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
			const struct input_device_id *id)
{}

static void kbd_disconnect(struct input_handle *handle)
{}

/*
 * Start keyboard handler on the new keyboard by refreshing LED state to
 * match the rest of the system.
 */
static void kbd_start(struct input_handle *handle)
{}

static const struct input_device_id kbd_ids[] =;

MODULE_DEVICE_TABLE(input, kbd_ids);

static struct input_handler kbd_handler =;

int __init kbd_init(void)
{}

/* Ioctl support code */

/**
 *	vt_do_diacrit		-	diacritical table updates
 *	@cmd: ioctl request
 *	@udp: pointer to user data for ioctl
 *	@perm: permissions check computed by caller
 *
 *	Update the diacritical tables atomically and safely. Lock them
 *	against simultaneous keypresses
 */
int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
{}

/**
 *	vt_do_kdskbmode		-	set keyboard mode ioctl
 *	@console: the console to use
 *	@arg: the requested mode
 *
 *	Update the keyboard mode bits while holding the correct locks.
 *	Return 0 for success or an error code.
 */
int vt_do_kdskbmode(unsigned int console, unsigned int arg)
{}

/**
 *	vt_do_kdskbmeta		-	set keyboard meta state
 *	@console: the console to use
 *	@arg: the requested meta state
 *
 *	Update the keyboard meta bits while holding the correct locks.
 *	Return 0 for success or an error code.
 */
int vt_do_kdskbmeta(unsigned int console, unsigned int arg)
{}

int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc,
								int perm)
{}

static unsigned short vt_kdgkbent(unsigned char kbdmode, unsigned char idx,
		unsigned char map)
{}

static int vt_kdskbent(unsigned char kbdmode, unsigned char idx,
		unsigned char map, unsigned short val)
{}

int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm,
						unsigned int console)
{}

static char *vt_kdskbsent(char *kbs, unsigned char cur)
{}

int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
{}

int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm)
{}

int vt_do_kdgkbmode(unsigned int console)
{}

/**
 *	vt_do_kdgkbmeta		-	report meta status
 *	@console: console to report
 *
 *	Report the meta flag status of this console
 */
int vt_do_kdgkbmeta(unsigned int console)
{}

/**
 *	vt_reset_unicode	-	reset the unicode status
 *	@console: console being reset
 *
 *	Restore the unicode console state to its default
 */
void vt_reset_unicode(unsigned int console)
{}

/**
 *	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.
 */
int vt_get_shift_state(void)
{}

/**
 *	vt_reset_keyboard	-	reset keyboard state
 *	@console: console to reset
 *
 *	Reset the keyboard bits for a console as part of a general console
 *	reset event
 */
void vt_reset_keyboard(unsigned int console)
{}

/**
 *	vt_get_kbd_mode_bit	-	read keyboard status bits
 *	@console: console to read from
 *	@bit: mode bit to read
 *
 *	Report back a vt mode bit. We do this without locking so the
 *	caller must be sure that there are no synchronization needs
 */

int vt_get_kbd_mode_bit(unsigned int console, int bit)
{}

/**
 *	vt_set_kbd_mode_bit	-	read keyboard status bits
 *	@console: console to read from
 *	@bit: mode bit to read
 *
 *	Set a vt mode bit. We do this without locking so the
 *	caller must be sure that there are no synchronization needs
 */

void vt_set_kbd_mode_bit(unsigned int console, int bit)
{}

/**
 *	vt_clr_kbd_mode_bit	-	read keyboard status bits
 *	@console: console to read from
 *	@bit: mode bit to read
 *
 *	Report back a vt mode bit. We do this without locking so the
 *	caller must be sure that there are no synchronization needs
 */

void vt_clr_kbd_mode_bit(unsigned int console, int bit)
{}