// 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, aeb@cwi.nl, 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, aeb@cwi.nl. * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
*/
/* * Notifier list for console keyboard events
*/ static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
int register_keyboard_notifier(struct notifier_block *nb)
{ return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(register_keyboard_notifier);
int unregister_keyboard_notifier(struct notifier_block *nb)
{ return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
/* * 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 { struct input_keymap_entry ke; int error;
};
/* * 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.
*/
val = KVAL(sym); if (val == KVAL(K_CAPSSHIFT))
val = KVAL(K_SHIFT);
shift_down[val]++;
shift_state |= BIT(val);
}
}
/* We still have to export this method to vt.c */ void vt_set_leds_compute_shiftstate(void)
{ unsignedlong 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();
/* * 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.
*/ staticunsignedint handle_diacr(struct vc_data *vc, unsignedint ch)
{ unsignedint d = diacr; unsignedint i;
diacr = 0;
if ((d & ~0xff) == BRL_UC_ROW) { if ((ch & ~0xff) == BRL_UC_ROW) return d | ch;
} else { for (i = 0; i < accent_table_size; i++) if (accent_table[i].diacr == d && accent_table[i].base == ch) return accent_table[i].result;
}
/* * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); * these routines are also activated by ^S/^Q. * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
*/ if (tty->flow.stopped)
start_tty(tty); else
stop_tty(tty);
}
/* * 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.
*/ staticvoid fn_bare_num(struct vc_data *vc)
{ if (!rep)
chg_vc_kbd_led(kbd, VC_NUMLOCK);
}
staticvoid fn_lastcons(struct vc_data *vc)
{ /* switch to the last used console, ChN */
set_console(last_console);
}
staticvoid fn_dec_console(struct vc_data *vc)
{ int i, cur = fg_console;
/* Currently switching? Queue this next switch relative to that. */ if (want_console != -1)
cur = want_console;
for (i = cur - 1; i != cur; i--) { if (i == -1)
i = MAX_NR_CONSOLES - 1; if (vc_cons_allocated(i)) break;
}
set_console(i);
}
staticvoid fn_inc_console(struct vc_data *vc)
{ int i, cur = fg_console;
/* Currently switching? Queue this next switch relative to that. */ if (want_console != -1)
cur = want_console;
for (i = cur+1; i != cur; i++) { if (i == MAX_NR_CONSOLES)
i = 0; if (vc_cons_allocated(i)) break;
}
set_console(i);
}
/* * Handle dead key. Note that we now may have several * dead keys modifying the same character. Very useful * for Vietnamese.
*/ staticvoid k_deadunicode(struct vc_data *vc, unsignedint value, char up_flag)
{ if (up_flag) return;
if (rep) return; /* * Mimic typewriter: * a CapsShift key acts like Shift but undoes CapsLock
*/ if (value == KVAL(K_CAPSSHIFT)) {
value = KVAL(K_SHIFT); if (!up_flag)
clr_vc_kbd_led(kbd, VC_CAPSLOCK);
}
if (up_flag) { /* * handle the case that two shift or control * keys are depressed simultaneously
*/ if (shift_down[value])
shift_down[value]--;
} else
shift_down[value]++;
if (shift_down[value])
shift_state |= BIT(value); else
shift_state &= ~BIT(value);
if (value < 10) { /* decimal input of code, while Alt depressed */
base = 10;
} else { /* hexadecimal input of code, while AltGr depressed */
value -= 10;
base = 16;
}
if (!npadch_active) {
npadch_value = 0;
npadch_active = true;
}
chg_vc_kbd_slock(kbd, value); /* try to make Alt, oops, AltGr and such work */ if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
kbd->slockstate = 0;
chg_vc_kbd_slock(kbd, value);
}
}
/* by default, 300ms interval for combination release */ staticunsigned brl_timeout = 300;
MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
module_param(brl_timeout, uint, 0644);
staticunsigned brl_nbchords = 1;
MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
module_param(brl_nbchords, uint, 0644);
if (test_bit(EV_LED, handle->dev->evbit))
kbd_propagate_led_state(~led_state, led_state);
return 0;
}
staticvoid kbd_init_leds(void)
{ int error; int i;
for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
error = led_trigger_register(&kbd_led_triggers[i].trigger); if (error)
pr_err("error %d while registering trigger %s\n",
error, kbd_led_triggers[i].trigger.name);
}
}
/* * 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.
*/ staticunsignedchar getledstate(void)
{ return ledstate & 0xff;
}
if (kb->ledmode == LED_SHOW_IOCTL) return ledioctl;
return kb->ledflagstate;
}
/** * 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(unsignedint console, int flag)
{ struct kbd_struct *kb = &kbd_table[console]; int ret; unsignedlong flags;
spin_lock_irqsave(&led_lock, flags);
ret = vc_kbd_led(kb, flag);
spin_unlock_irqrestore(&led_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(vt_get_leds);
/** * 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(unsignedint console, int leds)
{ struct kbd_struct *kb = &kbd_table[console];
setledstate(kb, 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(unsignedint console)
{ struct kbd_struct *kb = &kbd_table[console]; unsignedlong flags;
spin_lock_irqsave(&led_lock, flags);
clr_vc_kbd_led(kb, VC_SCROLLOCK);
set_leds();
spin_unlock_irqrestore(&led_lock, flags);
}
/** * 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(unsignedint console)
{ struct kbd_struct *kb = &kbd_table[console]; unsignedlong flags;
spin_lock_irqsave(&led_lock, flags);
set_vc_kbd_led(kb, VC_SCROLLOCK);
set_leds();
spin_unlock_irqrestore(&led_lock, flags);
}
/* * 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.
*/ staticvoid kbd_bh(struct tasklet_struct *unused)
{ unsignedint leds; unsignedlong flags;
if (kbd->kbdmode == VC_MEDIUMRAW) { /* * This is extended medium raw mode, with keys above 127 * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing * the 'up' flag if needed. 0 is reserved, so this shouldn't * interfere with anything else. The two bytes after 0 will * always have the up flag set not to interfere with older * applications. This allows for 16384 different keycodes, * which should be enough.
*/ if (keycode < 128) {
put_queue(vc, keycode | (!down << 7));
} else {
put_queue(vc, !down << 7);
put_queue(vc, (keycode >> 7) | BIT(7));
put_queue(vc, keycode | BIT(7));
}
raw_mode = true;
}
assign_bit(keycode, key_down, down);
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
(tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { /* * Don't repeat a key if the input buffers are not empty and the * characters get aren't echoed locally. This makes key repeat * usable with slow applications and under heavy loads.
*/ return;
}
staticvoid kbd_event(struct input_handle *handle, unsignedint event_type, unsignedint event_code, int value)
{ /* We are called with interrupts disabled, just take the lock */
spin_lock(&kbd_event_lock);
if (test_bit(EV_KEY, dev->evbit)) { if (find_next_bit(dev->keybit, BTN_MISC, KEY_RESERVED) <
BTN_MISC) returntrue; if (find_next_bit(dev->keybit, KEY_BRL_DOT10 + 1,
KEY_BRL_DOT1) <= KEY_BRL_DOT10) returntrue;
}
returnfalse;
}
/* * 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.
*/ staticint kbd_connect(struct input_handler *handler, struct input_dev *dev, conststruct input_device_id *id)
{ struct input_handle *handle; int error;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); if (!handle) return -ENOMEM;
/* * Start keyboard handler on the new keyboard by refreshing LED state to * match the rest of the system.
*/ staticvoid kbd_start(struct input_handle *handle)
{
tasklet_disable(&keyboard_tasklet);
if (ledstate != -1U)
kbd_update_leds_helper(handle, &ledstate);
/** * 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(unsignedint cmd, void __user *udp, int perm)
{ unsignedlong 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); 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);
}
spin_unlock_irqrestore(&kbd_event_lock, flags);
if (put_user(asize, &a->kb_cnt))
ret = -EFAULT; elseif (copy_to_user(a->kbdiacr, dia,
asize * sizeof(struct kbdiacr)))
ret = -EFAULT;
kfree(dia); return ret;
} case KDGKBDIACRUC:
{ struct kbdiacrsuc __user *a = udp; void *buf;
/** * 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(unsignedint console, unsignedint arg)
{ struct kbd_struct *kb = &kbd_table[console]; int ret = 0; unsignedlong flags;
spin_lock_irqsave(&kbd_event_lock, flags); switch(arg) { case K_RAW:
kb->kbdmode = VC_RAW; break; case K_MEDIUMRAW:
kb->kbdmode = VC_MEDIUMRAW; break; case K_XLATE:
kb->kbdmode = VC_XLATE;
do_compute_shiftstate(); break; case K_UNICODE:
kb->kbdmode = VC_UNICODE;
do_compute_shiftstate(); break; case K_OFF:
kb->kbdmode = VC_OFF; break; default:
ret = -EINVAL;
}
spin_unlock_irqrestore(&kbd_event_lock, flags); return ret;
}
/** * 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(unsignedint console, unsignedint arg)
{ struct kbd_struct *kb = &kbd_table[console]; int ret = 0; unsignedlong flags;
spin_lock_irqsave(&kbd_event_lock, flags); switch(arg) { case K_METABIT:
clr_vc_kbd_mode(kb, VC_META); break; case K_ESCPREFIX:
set_vc_kbd_mode(kb, VC_META); break; default:
ret = -EINVAL;
}
spin_unlock_irqrestore(&kbd_event_lock, flags); return ret;
}
int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
{ struct kbkeycode tmp; int kc = 0;
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; case KDSETKEYCODE: if (!perm) return -EPERM;
kc = setkeycode(tmp.scancode, tmp.keycode); break;
} return kc;
}
/* Ensure another thread doesn't free it under us */
spin_lock_irqsave(&kbd_event_lock, flags);
key_map = key_maps[map]; if (key_map) {
val = U(key_map[idx]); if (kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
val = K_HOLE;
} else
val = idx ? K_HOLE : K_NOSUCHMAP;
spin_unlock_irqrestore(&kbd_event_lock, flags);
if (!idx && val == K_NOSUCHMAP) {
spin_lock_irqsave(&kbd_event_lock, flags); /* 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);
return 0;
}
if (KTYP(val) < NR_TYPES) { if (KVAL(val) > max_vals[KTYP(val)]) return -EINVAL;
} elseif (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 (!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[map]; if (key_map == NULL) { int j;
if (len < 0) {
ret = -ENOSPC; break;
}
ret = copy_to_user(user_kdgkb->kb_string, kbs, len + 1) ?
-EFAULT : 0; break;
} case KDSKBSENT: if (!perm || !capable(CAP_SYS_TTY_CONFIG)) return -EPERM;
kbs = strndup_user(user_kdgkb->kb_string, sizeof(user_kdgkb->kb_string)); if (IS_ERR(kbs)) return PTR_ERR(kbs);
spin_lock_irqsave(&func_buf_lock, flags);
kbs = vt_kdskbsent(kbs, kb_func);
spin_unlock_irqrestore(&func_buf_lock, flags);
ret = 0; break;
}
kfree(kbs);
return ret;
}
int vt_do_kdskled(unsignedint console, int cmd, unsignedlong arg, int perm)
{ struct kbd_struct *kb = &kbd_table[console]; unsignedlong flags; unsignedchar 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); return put_user(ucval, (char __user *)arg);
/* the ioctls below only set the lights, not the functions */ /* for those, see KDGKBLED and KDSKBLED above */ case KDGETLED:
ucval = getledstate(); return put_user(ucval, (char __user *)arg);
case KDSETLED: if (!perm) return -EPERM;
setledstate(kb, arg); return 0;
} return -ENOIOCTLCMD;
}
int vt_do_kdgkbmode(unsignedint console)
{ struct kbd_struct *kb = &kbd_table[console]; /* This is a spot read so needs no locking */ switch (kb->kbdmode) { case VC_RAW: return K_RAW; case VC_MEDIUMRAW: return K_MEDIUMRAW; case VC_UNICODE: return K_UNICODE; case VC_OFF: return K_OFF; default: return K_XLATE;
}
}
/** * vt_do_kdgkbmeta - report meta status * @console: console to report * * Report the meta flag status of this console
*/ int vt_do_kdgkbmeta(unsignedint 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;
}
/** * vt_reset_unicode - reset the unicode status * @console: console being reset * * Restore the unicode console state to its default
*/ void vt_reset_unicode(unsignedint console)
{ unsignedlong flags;
/** * 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)
{ /* Don't lock as this is a transient report */ return shift_state;
}
/** * 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(unsignedint console)
{ struct kbd_struct *kb = &kbd_table[console]; unsignedlong flags;
spin_lock_irqsave(&kbd_event_lock, flags);
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);
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);
}
/** * 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(unsignedint console, int bit)
{ struct kbd_struct *kb = &kbd_table[console]; return vc_kbd_mode(kb, 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
*/
/** * 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
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.