18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Written for linux by Johan Myreen as a translation from 48c2ecf20Sopenharmony_ci * the assembly version by Linus (with diacriticals added) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Some additional features added by Christoph Niemann (ChN), March 1993 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Loadable keymaps by Risto Kankkunen, May 1993 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 118c2ecf20Sopenharmony_ci * Added decr/incr_console, dynamic keymaps, Unicode support, 128c2ecf20Sopenharmony_ci * dynamic function/string keys, led setting, Sept 1994 138c2ecf20Sopenharmony_ci * `Sticky' modifier keys, 951006. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * 11-11-96: SAK should now work in the raw mode (Martin Mares) 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Modified to provide 'generic' keyboard support by Hamish Macdonald 188c2ecf20Sopenharmony_ci * Merge with the m68k keyboard driver and split-off of the PC low-level 198c2ecf20Sopenharmony_ci * parts by Geert Uytterhoeven, May 1997 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) 228c2ecf20Sopenharmony_ci * 30-07-98: Dead keys redone, aeb@cwi.nl. 238c2ecf20Sopenharmony_ci * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/consolemap.h> 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 318c2ecf20Sopenharmony_ci#include <linux/sched/debug.h> 328c2ecf20Sopenharmony_ci#include <linux/tty.h> 338c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 348c2ecf20Sopenharmony_ci#include <linux/mm.h> 358c2ecf20Sopenharmony_ci#include <linux/nospec.h> 368c2ecf20Sopenharmony_ci#include <linux/string.h> 378c2ecf20Sopenharmony_ci#include <linux/init.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/leds.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <linux/kbd_kern.h> 428c2ecf20Sopenharmony_ci#include <linux/kbd_diacr.h> 438c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> 448c2ecf20Sopenharmony_ci#include <linux/input.h> 458c2ecf20Sopenharmony_ci#include <linux/reboot.h> 468c2ecf20Sopenharmony_ci#include <linux/notifier.h> 478c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 488c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include <asm/irq_regs.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciextern void ctrl_alt_del(void); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Exported functions/variables 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#if defined(CONFIG_X86) || defined(CONFIG_PARISC) 618c2ecf20Sopenharmony_ci#include <asm/kbdleds.h> 628c2ecf20Sopenharmony_ci#else 638c2ecf20Sopenharmony_cistatic inline int kbd_defleds(void) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci#endif 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define KBD_DEFLOCK 0 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * Handler Tables. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define K_HANDLERS\ 768c2ecf20Sopenharmony_ci k_self, k_fn, k_spec, k_pad,\ 778c2ecf20Sopenharmony_ci k_dead, k_cons, k_cur, k_shift,\ 788c2ecf20Sopenharmony_ci k_meta, k_ascii, k_lock, k_lowercase,\ 798c2ecf20Sopenharmony_ci k_slock, k_dead2, k_brl, k_ignore 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_citypedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, 828c2ecf20Sopenharmony_ci char up_flag); 838c2ecf20Sopenharmony_cistatic k_handler_fn K_HANDLERS; 848c2ecf20Sopenharmony_cistatic k_handler_fn *k_handler[16] = { K_HANDLERS }; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define FN_HANDLERS\ 878c2ecf20Sopenharmony_ci fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ 888c2ecf20Sopenharmony_ci fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ 898c2ecf20Sopenharmony_ci fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ 908c2ecf20Sopenharmony_ci fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ 918c2ecf20Sopenharmony_ci fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_citypedef void (fn_handler_fn)(struct vc_data *vc); 948c2ecf20Sopenharmony_cistatic fn_handler_fn FN_HANDLERS; 958c2ecf20Sopenharmony_cistatic fn_handler_fn *fn_handler[] = { FN_HANDLERS }; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* 988c2ecf20Sopenharmony_ci * Variables exported for vt_ioctl.c 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistruct vt_spawn_console vt_spawn_con = { 1028c2ecf20Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), 1038c2ecf20Sopenharmony_ci .pid = NULL, 1048c2ecf20Sopenharmony_ci .sig = 0, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* 1098c2ecf20Sopenharmony_ci * Internal Data. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic struct kbd_struct kbd_table[MAX_NR_CONSOLES]; 1138c2ecf20Sopenharmony_cistatic struct kbd_struct *kbd = kbd_table; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* maximum values each key_handler can handle */ 1168c2ecf20Sopenharmony_cistatic const int max_vals[] = { 1178c2ecf20Sopenharmony_ci 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, 1188c2ecf20Sopenharmony_ci NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, 1198c2ecf20Sopenharmony_ci 255, NR_LOCK - 1, 255, NR_BRL - 1 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic const int NR_TYPES = ARRAY_SIZE(max_vals); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic struct input_handler kbd_handler; 1258c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(kbd_event_lock); 1268c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(led_lock); 1278c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */ 1288c2ecf20Sopenharmony_cistatic unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ 1298c2ecf20Sopenharmony_cistatic unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ 1308c2ecf20Sopenharmony_cistatic bool dead_key_next; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* Handles a number being assembled on the number pad */ 1338c2ecf20Sopenharmony_cistatic bool npadch_active; 1348c2ecf20Sopenharmony_cistatic unsigned int npadch_value; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic unsigned int diacr; 1378c2ecf20Sopenharmony_cistatic char rep; /* flag telling character repeat */ 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int shift_state = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic unsigned int ledstate = -1U; /* undefined */ 1428c2ecf20Sopenharmony_cistatic unsigned char ledioctl; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* 1458c2ecf20Sopenharmony_ci * Notifier list for console keyboard events 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_cistatic ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciint register_keyboard_notifier(struct notifier_block *nb) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci return atomic_notifier_chain_register(&keyboard_notifier_list, nb); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(register_keyboard_notifier); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciint unregister_keyboard_notifier(struct notifier_block *nb) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_keyboard_notifier); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * Translation of scancodes to keycodes. We set them on only the first 1638c2ecf20Sopenharmony_ci * keyboard in the list that accepts the scancode and keycode. 1648c2ecf20Sopenharmony_ci * Explanation for not choosing the first attached keyboard anymore: 1658c2ecf20Sopenharmony_ci * USB keyboards for example have two event devices: one for all "normal" 1668c2ecf20Sopenharmony_ci * keys and one for extra function keys (like "volume up", "make coffee", 1678c2ecf20Sopenharmony_ci * etc.). So this means that scancodes for the extra function keys won't 1688c2ecf20Sopenharmony_ci * be valid for the first event device, but will be for the second. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistruct getset_keycode_data { 1728c2ecf20Sopenharmony_ci struct input_keymap_entry ke; 1738c2ecf20Sopenharmony_ci int error; 1748c2ecf20Sopenharmony_ci}; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int getkeycode_helper(struct input_handle *handle, void *data) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct getset_keycode_data *d = data; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci d->error = input_get_keycode(handle->dev, &d->ke); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return d->error == 0; /* stop as soon as we successfully get one */ 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic int getkeycode(unsigned int scancode) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct getset_keycode_data d = { 1888c2ecf20Sopenharmony_ci .ke = { 1898c2ecf20Sopenharmony_ci .flags = 0, 1908c2ecf20Sopenharmony_ci .len = sizeof(scancode), 1918c2ecf20Sopenharmony_ci .keycode = 0, 1928c2ecf20Sopenharmony_ci }, 1938c2ecf20Sopenharmony_ci .error = -ENODEV, 1948c2ecf20Sopenharmony_ci }; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci memcpy(d.ke.scancode, &scancode, sizeof(scancode)); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return d.error ?: d.ke.keycode; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int setkeycode_helper(struct input_handle *handle, void *data) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct getset_keycode_data *d = data; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci d->error = input_set_keycode(handle->dev, &d->ke); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return d->error == 0; /* stop as soon as we successfully set one */ 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int setkeycode(unsigned int scancode, unsigned int keycode) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct getset_keycode_data d = { 2158c2ecf20Sopenharmony_ci .ke = { 2168c2ecf20Sopenharmony_ci .flags = 0, 2178c2ecf20Sopenharmony_ci .len = sizeof(scancode), 2188c2ecf20Sopenharmony_ci .keycode = keycode, 2198c2ecf20Sopenharmony_ci }, 2208c2ecf20Sopenharmony_ci .error = -ENODEV, 2218c2ecf20Sopenharmony_ci }; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci memcpy(d.ke.scancode, &scancode, sizeof(scancode)); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return d.error; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* 2318c2ecf20Sopenharmony_ci * Making beeps and bells. Note that we prefer beeps to bells, but when 2328c2ecf20Sopenharmony_ci * shutting the sound off we do both. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int kd_sound_helper(struct input_handle *handle, void *data) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci unsigned int *hz = data; 2388c2ecf20Sopenharmony_ci struct input_dev *dev = handle->dev; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (test_bit(EV_SND, dev->evbit)) { 2418c2ecf20Sopenharmony_ci if (test_bit(SND_TONE, dev->sndbit)) { 2428c2ecf20Sopenharmony_ci input_inject_event(handle, EV_SND, SND_TONE, *hz); 2438c2ecf20Sopenharmony_ci if (*hz) 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci if (test_bit(SND_BELL, dev->sndbit)) 2478c2ecf20Sopenharmony_ci input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic void kd_nosound(struct timer_list *unused) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci static unsigned int zero; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic DEFINE_TIMER(kd_mksound_timer, kd_nosound); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_civoid kd_mksound(unsigned int hz, unsigned int ticks) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci del_timer_sync(&kd_mksound_timer); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (hz && ticks) 2698c2ecf20Sopenharmony_ci mod_timer(&kd_mksound_timer, jiffies + ticks); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(kd_mksound); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* 2748c2ecf20Sopenharmony_ci * Setting the keyboard rate. 2758c2ecf20Sopenharmony_ci */ 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int kbd_rate_helper(struct input_handle *handle, void *data) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct input_dev *dev = handle->dev; 2808c2ecf20Sopenharmony_ci struct kbd_repeat *rpt = data; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (test_bit(EV_REP, dev->evbit)) { 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (rpt[0].delay > 0) 2858c2ecf20Sopenharmony_ci input_inject_event(handle, 2868c2ecf20Sopenharmony_ci EV_REP, REP_DELAY, rpt[0].delay); 2878c2ecf20Sopenharmony_ci if (rpt[0].period > 0) 2888c2ecf20Sopenharmony_ci input_inject_event(handle, 2898c2ecf20Sopenharmony_ci EV_REP, REP_PERIOD, rpt[0].period); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci rpt[1].delay = dev->rep[REP_DELAY]; 2928c2ecf20Sopenharmony_ci rpt[1].period = dev->rep[REP_PERIOD]; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciint kbd_rate(struct kbd_repeat *rpt) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct kbd_repeat data[2] = { *rpt }; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper); 3038c2ecf20Sopenharmony_ci *rpt = data[1]; /* Copy currently used settings */ 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/* 3098c2ecf20Sopenharmony_ci * Helper Functions. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic void put_queue(struct vc_data *vc, int ch) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci tty_insert_flip_char(&vc->port, ch, 0); 3148c2ecf20Sopenharmony_ci tty_flip_buffer_push(&vc->port); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void puts_queue(struct vc_data *vc, char *cp) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci while (*cp) { 3208c2ecf20Sopenharmony_ci tty_insert_flip_char(&vc->port, *cp, 0); 3218c2ecf20Sopenharmony_ci cp++; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci tty_flip_buffer_push(&vc->port); 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void applkey(struct vc_data *vc, int key, char mode) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci buf[1] = (mode ? 'O' : '['); 3318c2ecf20Sopenharmony_ci buf[2] = key; 3328c2ecf20Sopenharmony_ci puts_queue(vc, buf); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/* 3368c2ecf20Sopenharmony_ci * Many other routines do put_queue, but I think either 3378c2ecf20Sopenharmony_ci * they produce ASCII, or they produce some user-assigned 3388c2ecf20Sopenharmony_ci * string, and in both cases we might assume that it is 3398c2ecf20Sopenharmony_ci * in utf-8 already. 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_cistatic void to_utf8(struct vc_data *vc, uint c) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci if (c < 0x80) 3448c2ecf20Sopenharmony_ci /* 0******* */ 3458c2ecf20Sopenharmony_ci put_queue(vc, c); 3468c2ecf20Sopenharmony_ci else if (c < 0x800) { 3478c2ecf20Sopenharmony_ci /* 110***** 10****** */ 3488c2ecf20Sopenharmony_ci put_queue(vc, 0xc0 | (c >> 6)); 3498c2ecf20Sopenharmony_ci put_queue(vc, 0x80 | (c & 0x3f)); 3508c2ecf20Sopenharmony_ci } else if (c < 0x10000) { 3518c2ecf20Sopenharmony_ci if (c >= 0xD800 && c < 0xE000) 3528c2ecf20Sopenharmony_ci return; 3538c2ecf20Sopenharmony_ci if (c == 0xFFFF) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci /* 1110**** 10****** 10****** */ 3568c2ecf20Sopenharmony_ci put_queue(vc, 0xe0 | (c >> 12)); 3578c2ecf20Sopenharmony_ci put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); 3588c2ecf20Sopenharmony_ci put_queue(vc, 0x80 | (c & 0x3f)); 3598c2ecf20Sopenharmony_ci } else if (c < 0x110000) { 3608c2ecf20Sopenharmony_ci /* 11110*** 10****** 10****** 10****** */ 3618c2ecf20Sopenharmony_ci put_queue(vc, 0xf0 | (c >> 18)); 3628c2ecf20Sopenharmony_ci put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); 3638c2ecf20Sopenharmony_ci put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); 3648c2ecf20Sopenharmony_ci put_queue(vc, 0x80 | (c & 0x3f)); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci/* 3698c2ecf20Sopenharmony_ci * Called after returning from RAW mode or when changing consoles - recompute 3708c2ecf20Sopenharmony_ci * shift_down[] and shift_state from key_down[] maybe called when keymap is 3718c2ecf20Sopenharmony_ci * undefined, so that shiftkey release is seen. The caller must hold the 3728c2ecf20Sopenharmony_ci * kbd_event_lock. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void do_compute_shiftstate(void) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci unsigned int k, sym, val; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci shift_state = 0; 3808c2ecf20Sopenharmony_ci memset(shift_down, 0, sizeof(shift_down)); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci for_each_set_bit(k, key_down, min(NR_KEYS, KEY_CNT)) { 3838c2ecf20Sopenharmony_ci sym = U(key_maps[0][k]); 3848c2ecf20Sopenharmony_ci if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) 3858c2ecf20Sopenharmony_ci continue; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci val = KVAL(sym); 3888c2ecf20Sopenharmony_ci if (val == KVAL(K_CAPSSHIFT)) 3898c2ecf20Sopenharmony_ci val = KVAL(K_SHIFT); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci shift_down[val]++; 3928c2ecf20Sopenharmony_ci shift_state |= BIT(val); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/* We still have to export this method to vt.c */ 3978c2ecf20Sopenharmony_civoid compute_shiftstate(void) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci unsigned long flags; 4008c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 4018c2ecf20Sopenharmony_ci do_compute_shiftstate(); 4028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * We have a combining character DIACR here, followed by the character CH. 4078c2ecf20Sopenharmony_ci * If the combination occurs in the table, return the corresponding value. 4088c2ecf20Sopenharmony_ci * Otherwise, if CH is a space or equals DIACR, return DIACR. 4098c2ecf20Sopenharmony_ci * Otherwise, conclude that DIACR was not combining after all, 4108c2ecf20Sopenharmony_ci * queue it and return CH. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_cistatic unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci unsigned int d = diacr; 4158c2ecf20Sopenharmony_ci unsigned int i; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci diacr = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if ((d & ~0xff) == BRL_UC_ROW) { 4208c2ecf20Sopenharmony_ci if ((ch & ~0xff) == BRL_UC_ROW) 4218c2ecf20Sopenharmony_ci return d | ch; 4228c2ecf20Sopenharmony_ci } else { 4238c2ecf20Sopenharmony_ci for (i = 0; i < accent_table_size; i++) 4248c2ecf20Sopenharmony_ci if (accent_table[i].diacr == d && accent_table[i].base == ch) 4258c2ecf20Sopenharmony_ci return accent_table[i].result; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) 4298c2ecf20Sopenharmony_ci return d; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (kbd->kbdmode == VC_UNICODE) 4328c2ecf20Sopenharmony_ci to_utf8(vc, d); 4338c2ecf20Sopenharmony_ci else { 4348c2ecf20Sopenharmony_ci int c = conv_uni_to_8bit(d); 4358c2ecf20Sopenharmony_ci if (c != -1) 4368c2ecf20Sopenharmony_ci put_queue(vc, c); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return ch; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/* 4438c2ecf20Sopenharmony_ci * Special function handlers 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_cistatic void fn_enter(struct vc_data *vc) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci if (diacr) { 4488c2ecf20Sopenharmony_ci if (kbd->kbdmode == VC_UNICODE) 4498c2ecf20Sopenharmony_ci to_utf8(vc, diacr); 4508c2ecf20Sopenharmony_ci else { 4518c2ecf20Sopenharmony_ci int c = conv_uni_to_8bit(diacr); 4528c2ecf20Sopenharmony_ci if (c != -1) 4538c2ecf20Sopenharmony_ci put_queue(vc, c); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci diacr = 0; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci put_queue(vc, 13); 4598c2ecf20Sopenharmony_ci if (vc_kbd_mode(kbd, VC_CRLF)) 4608c2ecf20Sopenharmony_ci put_queue(vc, 10); 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic void fn_caps_toggle(struct vc_data *vc) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci if (rep) 4668c2ecf20Sopenharmony_ci return; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci chg_vc_kbd_led(kbd, VC_CAPSLOCK); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic void fn_caps_on(struct vc_data *vc) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci if (rep) 4748c2ecf20Sopenharmony_ci return; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci set_vc_kbd_led(kbd, VC_CAPSLOCK); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void fn_show_ptregs(struct vc_data *vc) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct pt_regs *regs = get_irq_regs(); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (regs) 4848c2ecf20Sopenharmony_ci show_regs(regs); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic void fn_hold(struct vc_data *vc) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct tty_struct *tty = vc->port.tty; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (rep || !tty) 4928c2ecf20Sopenharmony_ci return; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* 4958c2ecf20Sopenharmony_ci * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); 4968c2ecf20Sopenharmony_ci * these routines are also activated by ^S/^Q. 4978c2ecf20Sopenharmony_ci * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ci if (tty->stopped) 5008c2ecf20Sopenharmony_ci start_tty(tty); 5018c2ecf20Sopenharmony_ci else 5028c2ecf20Sopenharmony_ci stop_tty(tty); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic void fn_num(struct vc_data *vc) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci if (vc_kbd_mode(kbd, VC_APPLIC)) 5088c2ecf20Sopenharmony_ci applkey(vc, 'P', 1); 5098c2ecf20Sopenharmony_ci else 5108c2ecf20Sopenharmony_ci fn_bare_num(vc); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci/* 5148c2ecf20Sopenharmony_ci * Bind this to Shift-NumLock if you work in application keypad mode 5158c2ecf20Sopenharmony_ci * but want to be able to change the NumLock flag. 5168c2ecf20Sopenharmony_ci * Bind this to NumLock if you prefer that the NumLock key always 5178c2ecf20Sopenharmony_ci * changes the NumLock flag. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_cistatic void fn_bare_num(struct vc_data *vc) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci if (!rep) 5228c2ecf20Sopenharmony_ci chg_vc_kbd_led(kbd, VC_NUMLOCK); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void fn_lastcons(struct vc_data *vc) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci /* switch to the last used console, ChN */ 5288c2ecf20Sopenharmony_ci set_console(last_console); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic void fn_dec_console(struct vc_data *vc) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci int i, cur = fg_console; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* Currently switching? Queue this next switch relative to that. */ 5368c2ecf20Sopenharmony_ci if (want_console != -1) 5378c2ecf20Sopenharmony_ci cur = want_console; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci for (i = cur - 1; i != cur; i--) { 5408c2ecf20Sopenharmony_ci if (i == -1) 5418c2ecf20Sopenharmony_ci i = MAX_NR_CONSOLES - 1; 5428c2ecf20Sopenharmony_ci if (vc_cons_allocated(i)) 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci set_console(i); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void fn_inc_console(struct vc_data *vc) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci int i, cur = fg_console; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Currently switching? Queue this next switch relative to that. */ 5538c2ecf20Sopenharmony_ci if (want_console != -1) 5548c2ecf20Sopenharmony_ci cur = want_console; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci for (i = cur+1; i != cur; i++) { 5578c2ecf20Sopenharmony_ci if (i == MAX_NR_CONSOLES) 5588c2ecf20Sopenharmony_ci i = 0; 5598c2ecf20Sopenharmony_ci if (vc_cons_allocated(i)) 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci set_console(i); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void fn_send_intr(struct vc_data *vc) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci tty_insert_flip_char(&vc->port, 0, TTY_BREAK); 5688c2ecf20Sopenharmony_ci tty_flip_buffer_push(&vc->port); 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void fn_scroll_forw(struct vc_data *vc) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci scrollfront(vc, 0); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic void fn_scroll_back(struct vc_data *vc) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci scrollback(vc); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic void fn_show_mem(struct vc_data *vc) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci show_mem(0, NULL); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic void fn_show_state(struct vc_data *vc) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci show_state(); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void fn_boot_it(struct vc_data *vc) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci ctrl_alt_del(); 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic void fn_compose(struct vc_data *vc) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci dead_key_next = true; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic void fn_spawn_con(struct vc_data *vc) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci spin_lock(&vt_spawn_con.lock); 6048c2ecf20Sopenharmony_ci if (vt_spawn_con.pid) 6058c2ecf20Sopenharmony_ci if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) { 6068c2ecf20Sopenharmony_ci put_pid(vt_spawn_con.pid); 6078c2ecf20Sopenharmony_ci vt_spawn_con.pid = NULL; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci spin_unlock(&vt_spawn_con.lock); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic void fn_SAK(struct vc_data *vc) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; 6158c2ecf20Sopenharmony_ci schedule_work(SAK_work); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic void fn_null(struct vc_data *vc) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci do_compute_shiftstate(); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* 6248c2ecf20Sopenharmony_ci * Special key handlers 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_cistatic void k_ignore(struct vc_data *vc, unsigned char value, char up_flag) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic void k_spec(struct vc_data *vc, unsigned char value, char up_flag) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci if (up_flag) 6338c2ecf20Sopenharmony_ci return; 6348c2ecf20Sopenharmony_ci if (value >= ARRAY_SIZE(fn_handler)) 6358c2ecf20Sopenharmony_ci return; 6368c2ecf20Sopenharmony_ci if ((kbd->kbdmode == VC_RAW || 6378c2ecf20Sopenharmony_ci kbd->kbdmode == VC_MEDIUMRAW || 6388c2ecf20Sopenharmony_ci kbd->kbdmode == VC_OFF) && 6398c2ecf20Sopenharmony_ci value != KVAL(K_SAK)) 6408c2ecf20Sopenharmony_ci return; /* SAK is allowed even in raw mode */ 6418c2ecf20Sopenharmony_ci fn_handler[value](vc); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci pr_err("k_lowercase was called - impossible\n"); 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci if (up_flag) 6528c2ecf20Sopenharmony_ci return; /* no action, if this is a key release */ 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (diacr) 6558c2ecf20Sopenharmony_ci value = handle_diacr(vc, value); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (dead_key_next) { 6588c2ecf20Sopenharmony_ci dead_key_next = false; 6598c2ecf20Sopenharmony_ci diacr = value; 6608c2ecf20Sopenharmony_ci return; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci if (kbd->kbdmode == VC_UNICODE) 6638c2ecf20Sopenharmony_ci to_utf8(vc, value); 6648c2ecf20Sopenharmony_ci else { 6658c2ecf20Sopenharmony_ci int c = conv_uni_to_8bit(value); 6668c2ecf20Sopenharmony_ci if (c != -1) 6678c2ecf20Sopenharmony_ci put_queue(vc, c); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci/* 6728c2ecf20Sopenharmony_ci * Handle dead key. Note that we now may have several 6738c2ecf20Sopenharmony_ci * dead keys modifying the same character. Very useful 6748c2ecf20Sopenharmony_ci * for Vietnamese. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_cistatic void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci if (up_flag) 6798c2ecf20Sopenharmony_ci return; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci diacr = (diacr ? handle_diacr(vc, value) : value); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void k_self(struct vc_data *vc, unsigned char value, char up_flag) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci k_unicode(vc, conv_8bit_to_uni(value), up_flag); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci k_deadunicode(vc, value, up_flag); 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* 6958c2ecf20Sopenharmony_ci * Obsolete - for backwards compatibility only 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_cistatic void k_dead(struct vc_data *vc, unsigned char value, char up_flag) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci static const unsigned char ret_diacr[NR_DEAD] = { 7008c2ecf20Sopenharmony_ci '`', /* dead_grave */ 7018c2ecf20Sopenharmony_ci '\'', /* dead_acute */ 7028c2ecf20Sopenharmony_ci '^', /* dead_circumflex */ 7038c2ecf20Sopenharmony_ci '~', /* dead_tilda */ 7048c2ecf20Sopenharmony_ci '"', /* dead_diaeresis */ 7058c2ecf20Sopenharmony_ci ',', /* dead_cedilla */ 7068c2ecf20Sopenharmony_ci '_', /* dead_macron */ 7078c2ecf20Sopenharmony_ci 'U', /* dead_breve */ 7088c2ecf20Sopenharmony_ci '.', /* dead_abovedot */ 7098c2ecf20Sopenharmony_ci '*', /* dead_abovering */ 7108c2ecf20Sopenharmony_ci '=', /* dead_doubleacute */ 7118c2ecf20Sopenharmony_ci 'c', /* dead_caron */ 7128c2ecf20Sopenharmony_ci 'k', /* dead_ogonek */ 7138c2ecf20Sopenharmony_ci 'i', /* dead_iota */ 7148c2ecf20Sopenharmony_ci '#', /* dead_voiced_sound */ 7158c2ecf20Sopenharmony_ci 'o', /* dead_semivoiced_sound */ 7168c2ecf20Sopenharmony_ci '!', /* dead_belowdot */ 7178c2ecf20Sopenharmony_ci '?', /* dead_hook */ 7188c2ecf20Sopenharmony_ci '+', /* dead_horn */ 7198c2ecf20Sopenharmony_ci '-', /* dead_stroke */ 7208c2ecf20Sopenharmony_ci ')', /* dead_abovecomma */ 7218c2ecf20Sopenharmony_ci '(', /* dead_abovereversedcomma */ 7228c2ecf20Sopenharmony_ci ':', /* dead_doublegrave */ 7238c2ecf20Sopenharmony_ci 'n', /* dead_invertedbreve */ 7248c2ecf20Sopenharmony_ci ';', /* dead_belowcomma */ 7258c2ecf20Sopenharmony_ci '$', /* dead_currency */ 7268c2ecf20Sopenharmony_ci '@', /* dead_greek */ 7278c2ecf20Sopenharmony_ci }; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci k_deadunicode(vc, ret_diacr[value], up_flag); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic void k_cons(struct vc_data *vc, unsigned char value, char up_flag) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci if (up_flag) 7358c2ecf20Sopenharmony_ci return; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci set_console(value); 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_cistatic void k_fn(struct vc_data *vc, unsigned char value, char up_flag) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci if (up_flag) 7438c2ecf20Sopenharmony_ci return; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if ((unsigned)value < ARRAY_SIZE(func_table)) { 7468c2ecf20Sopenharmony_ci unsigned long flags; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci spin_lock_irqsave(&func_buf_lock, flags); 7498c2ecf20Sopenharmony_ci if (func_table[value]) 7508c2ecf20Sopenharmony_ci puts_queue(vc, func_table[value]); 7518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&func_buf_lock, flags); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci } else 7548c2ecf20Sopenharmony_ci pr_err("k_fn called with value=%d\n", value); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic void k_cur(struct vc_data *vc, unsigned char value, char up_flag) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci static const char cur_chars[] = "BDCA"; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (up_flag) 7628c2ecf20Sopenharmony_ci return; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE)); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic void k_pad(struct vc_data *vc, unsigned char value, char up_flag) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci static const char pad_chars[] = "0123456789+-*/\015,.?()#"; 7708c2ecf20Sopenharmony_ci static const char app_map[] = "pqrstuvwxylSRQMnnmPQS"; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (up_flag) 7738c2ecf20Sopenharmony_ci return; /* no action, if this is a key release */ 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* kludge... shift forces cursor/number keys */ 7768c2ecf20Sopenharmony_ci if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) { 7778c2ecf20Sopenharmony_ci applkey(vc, app_map[value], 1); 7788c2ecf20Sopenharmony_ci return; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (!vc_kbd_led(kbd, VC_NUMLOCK)) { 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci switch (value) { 7848c2ecf20Sopenharmony_ci case KVAL(K_PCOMMA): 7858c2ecf20Sopenharmony_ci case KVAL(K_PDOT): 7868c2ecf20Sopenharmony_ci k_fn(vc, KVAL(K_REMOVE), 0); 7878c2ecf20Sopenharmony_ci return; 7888c2ecf20Sopenharmony_ci case KVAL(K_P0): 7898c2ecf20Sopenharmony_ci k_fn(vc, KVAL(K_INSERT), 0); 7908c2ecf20Sopenharmony_ci return; 7918c2ecf20Sopenharmony_ci case KVAL(K_P1): 7928c2ecf20Sopenharmony_ci k_fn(vc, KVAL(K_SELECT), 0); 7938c2ecf20Sopenharmony_ci return; 7948c2ecf20Sopenharmony_ci case KVAL(K_P2): 7958c2ecf20Sopenharmony_ci k_cur(vc, KVAL(K_DOWN), 0); 7968c2ecf20Sopenharmony_ci return; 7978c2ecf20Sopenharmony_ci case KVAL(K_P3): 7988c2ecf20Sopenharmony_ci k_fn(vc, KVAL(K_PGDN), 0); 7998c2ecf20Sopenharmony_ci return; 8008c2ecf20Sopenharmony_ci case KVAL(K_P4): 8018c2ecf20Sopenharmony_ci k_cur(vc, KVAL(K_LEFT), 0); 8028c2ecf20Sopenharmony_ci return; 8038c2ecf20Sopenharmony_ci case KVAL(K_P6): 8048c2ecf20Sopenharmony_ci k_cur(vc, KVAL(K_RIGHT), 0); 8058c2ecf20Sopenharmony_ci return; 8068c2ecf20Sopenharmony_ci case KVAL(K_P7): 8078c2ecf20Sopenharmony_ci k_fn(vc, KVAL(K_FIND), 0); 8088c2ecf20Sopenharmony_ci return; 8098c2ecf20Sopenharmony_ci case KVAL(K_P8): 8108c2ecf20Sopenharmony_ci k_cur(vc, KVAL(K_UP), 0); 8118c2ecf20Sopenharmony_ci return; 8128c2ecf20Sopenharmony_ci case KVAL(K_P9): 8138c2ecf20Sopenharmony_ci k_fn(vc, KVAL(K_PGUP), 0); 8148c2ecf20Sopenharmony_ci return; 8158c2ecf20Sopenharmony_ci case KVAL(K_P5): 8168c2ecf20Sopenharmony_ci applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC)); 8178c2ecf20Sopenharmony_ci return; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci put_queue(vc, pad_chars[value]); 8228c2ecf20Sopenharmony_ci if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) 8238c2ecf20Sopenharmony_ci put_queue(vc, 10); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic void k_shift(struct vc_data *vc, unsigned char value, char up_flag) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci int old_state = shift_state; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (rep) 8318c2ecf20Sopenharmony_ci return; 8328c2ecf20Sopenharmony_ci /* 8338c2ecf20Sopenharmony_ci * Mimic typewriter: 8348c2ecf20Sopenharmony_ci * a CapsShift key acts like Shift but undoes CapsLock 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci if (value == KVAL(K_CAPSSHIFT)) { 8378c2ecf20Sopenharmony_ci value = KVAL(K_SHIFT); 8388c2ecf20Sopenharmony_ci if (!up_flag) 8398c2ecf20Sopenharmony_ci clr_vc_kbd_led(kbd, VC_CAPSLOCK); 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (up_flag) { 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * handle the case that two shift or control 8458c2ecf20Sopenharmony_ci * keys are depressed simultaneously 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_ci if (shift_down[value]) 8488c2ecf20Sopenharmony_ci shift_down[value]--; 8498c2ecf20Sopenharmony_ci } else 8508c2ecf20Sopenharmony_ci shift_down[value]++; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (shift_down[value]) 8538c2ecf20Sopenharmony_ci shift_state |= (1 << value); 8548c2ecf20Sopenharmony_ci else 8558c2ecf20Sopenharmony_ci shift_state &= ~(1 << value); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* kludge */ 8588c2ecf20Sopenharmony_ci if (up_flag && shift_state != old_state && npadch_active) { 8598c2ecf20Sopenharmony_ci if (kbd->kbdmode == VC_UNICODE) 8608c2ecf20Sopenharmony_ci to_utf8(vc, npadch_value); 8618c2ecf20Sopenharmony_ci else 8628c2ecf20Sopenharmony_ci put_queue(vc, npadch_value & 0xff); 8638c2ecf20Sopenharmony_ci npadch_active = false; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic void k_meta(struct vc_data *vc, unsigned char value, char up_flag) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci if (up_flag) 8708c2ecf20Sopenharmony_ci return; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (vc_kbd_mode(kbd, VC_META)) { 8738c2ecf20Sopenharmony_ci put_queue(vc, '\033'); 8748c2ecf20Sopenharmony_ci put_queue(vc, value); 8758c2ecf20Sopenharmony_ci } else 8768c2ecf20Sopenharmony_ci put_queue(vc, value | 0x80); 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci unsigned int base; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (up_flag) 8848c2ecf20Sopenharmony_ci return; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (value < 10) { 8878c2ecf20Sopenharmony_ci /* decimal input of code, while Alt depressed */ 8888c2ecf20Sopenharmony_ci base = 10; 8898c2ecf20Sopenharmony_ci } else { 8908c2ecf20Sopenharmony_ci /* hexadecimal input of code, while AltGr depressed */ 8918c2ecf20Sopenharmony_ci value -= 10; 8928c2ecf20Sopenharmony_ci base = 16; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (!npadch_active) { 8968c2ecf20Sopenharmony_ci npadch_value = 0; 8978c2ecf20Sopenharmony_ci npadch_active = true; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci npadch_value = npadch_value * base + value; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic void k_lock(struct vc_data *vc, unsigned char value, char up_flag) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci if (up_flag || rep) 9068c2ecf20Sopenharmony_ci return; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci chg_vc_kbd_lock(kbd, value); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistatic void k_slock(struct vc_data *vc, unsigned char value, char up_flag) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci k_shift(vc, value, up_flag); 9148c2ecf20Sopenharmony_ci if (up_flag || rep) 9158c2ecf20Sopenharmony_ci return; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci chg_vc_kbd_slock(kbd, value); 9188c2ecf20Sopenharmony_ci /* try to make Alt, oops, AltGr and such work */ 9198c2ecf20Sopenharmony_ci if (!key_maps[kbd->lockstate ^ kbd->slockstate]) { 9208c2ecf20Sopenharmony_ci kbd->slockstate = 0; 9218c2ecf20Sopenharmony_ci chg_vc_kbd_slock(kbd, value); 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci/* by default, 300ms interval for combination release */ 9268c2ecf20Sopenharmony_cistatic unsigned brl_timeout = 300; 9278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)"); 9288c2ecf20Sopenharmony_cimodule_param(brl_timeout, uint, 0644); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic unsigned brl_nbchords = 1; 9318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)"); 9328c2ecf20Sopenharmony_cimodule_param(brl_nbchords, uint, 0644); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci static unsigned long chords; 9378c2ecf20Sopenharmony_ci static unsigned committed; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (!brl_nbchords) 9408c2ecf20Sopenharmony_ci k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag); 9418c2ecf20Sopenharmony_ci else { 9428c2ecf20Sopenharmony_ci committed |= pattern; 9438c2ecf20Sopenharmony_ci chords++; 9448c2ecf20Sopenharmony_ci if (chords == brl_nbchords) { 9458c2ecf20Sopenharmony_ci k_unicode(vc, BRL_UC_ROW | committed, up_flag); 9468c2ecf20Sopenharmony_ci chords = 0; 9478c2ecf20Sopenharmony_ci committed = 0; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic void k_brl(struct vc_data *vc, unsigned char value, char up_flag) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci static unsigned pressed, committing; 9558c2ecf20Sopenharmony_ci static unsigned long releasestart; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (kbd->kbdmode != VC_UNICODE) { 9588c2ecf20Sopenharmony_ci if (!up_flag) 9598c2ecf20Sopenharmony_ci pr_warn("keyboard mode must be unicode for braille patterns\n"); 9608c2ecf20Sopenharmony_ci return; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (!value) { 9648c2ecf20Sopenharmony_ci k_unicode(vc, BRL_UC_ROW, up_flag); 9658c2ecf20Sopenharmony_ci return; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (value > 8) 9698c2ecf20Sopenharmony_ci return; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (!up_flag) { 9728c2ecf20Sopenharmony_ci pressed |= 1 << (value - 1); 9738c2ecf20Sopenharmony_ci if (!brl_timeout) 9748c2ecf20Sopenharmony_ci committing = pressed; 9758c2ecf20Sopenharmony_ci } else if (brl_timeout) { 9768c2ecf20Sopenharmony_ci if (!committing || 9778c2ecf20Sopenharmony_ci time_after(jiffies, 9788c2ecf20Sopenharmony_ci releasestart + msecs_to_jiffies(brl_timeout))) { 9798c2ecf20Sopenharmony_ci committing = pressed; 9808c2ecf20Sopenharmony_ci releasestart = jiffies; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci pressed &= ~(1 << (value - 1)); 9838c2ecf20Sopenharmony_ci if (!pressed && committing) { 9848c2ecf20Sopenharmony_ci k_brlcommit(vc, committing, 0); 9858c2ecf20Sopenharmony_ci committing = 0; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci } else { 9888c2ecf20Sopenharmony_ci if (committing) { 9898c2ecf20Sopenharmony_ci k_brlcommit(vc, committing, 0); 9908c2ecf20Sopenharmony_ci committing = 0; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci pressed &= ~(1 << (value - 1)); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS) 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistruct kbd_led_trigger { 9998c2ecf20Sopenharmony_ci struct led_trigger trigger; 10008c2ecf20Sopenharmony_ci unsigned int mask; 10018c2ecf20Sopenharmony_ci}; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic int kbd_led_trigger_activate(struct led_classdev *cdev) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct kbd_led_trigger *trigger = 10068c2ecf20Sopenharmony_ci container_of(cdev->trigger, struct kbd_led_trigger, trigger); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci tasklet_disable(&keyboard_tasklet); 10098c2ecf20Sopenharmony_ci if (ledstate != -1U) 10108c2ecf20Sopenharmony_ci led_trigger_event(&trigger->trigger, 10118c2ecf20Sopenharmony_ci ledstate & trigger->mask ? 10128c2ecf20Sopenharmony_ci LED_FULL : LED_OFF); 10138c2ecf20Sopenharmony_ci tasklet_enable(&keyboard_tasklet); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci#define KBD_LED_TRIGGER(_led_bit, _name) { \ 10198c2ecf20Sopenharmony_ci .trigger = { \ 10208c2ecf20Sopenharmony_ci .name = _name, \ 10218c2ecf20Sopenharmony_ci .activate = kbd_led_trigger_activate, \ 10228c2ecf20Sopenharmony_ci }, \ 10238c2ecf20Sopenharmony_ci .mask = BIT(_led_bit), \ 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name) \ 10278c2ecf20Sopenharmony_ci KBD_LED_TRIGGER((_led_bit) + 8, _name) 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic struct kbd_led_trigger kbd_led_triggers[] = { 10308c2ecf20Sopenharmony_ci KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrolllock"), 10318c2ecf20Sopenharmony_ci KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"), 10328c2ecf20Sopenharmony_ci KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"), 10338c2ecf20Sopenharmony_ci KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"), 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK, "kbd-shiftlock"), 10368c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK, "kbd-altgrlock"), 10378c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK, "kbd-ctrllock"), 10388c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK, "kbd-altlock"), 10398c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"), 10408c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"), 10418c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK, "kbd-ctrlllock"), 10428c2ecf20Sopenharmony_ci KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK, "kbd-ctrlrlock"), 10438c2ecf20Sopenharmony_ci}; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void kbd_propagate_led_state(unsigned int old_state, 10468c2ecf20Sopenharmony_ci unsigned int new_state) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct kbd_led_trigger *trigger; 10498c2ecf20Sopenharmony_ci unsigned int changed = old_state ^ new_state; 10508c2ecf20Sopenharmony_ci int i; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { 10538c2ecf20Sopenharmony_ci trigger = &kbd_led_triggers[i]; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (changed & trigger->mask) 10568c2ecf20Sopenharmony_ci led_trigger_event(&trigger->trigger, 10578c2ecf20Sopenharmony_ci new_state & trigger->mask ? 10588c2ecf20Sopenharmony_ci LED_FULL : LED_OFF); 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic int kbd_update_leds_helper(struct input_handle *handle, void *data) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci unsigned int led_state = *(unsigned int *)data; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci if (test_bit(EV_LED, handle->dev->evbit)) 10678c2ecf20Sopenharmony_ci kbd_propagate_led_state(~led_state, led_state); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci return 0; 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic void kbd_init_leds(void) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci int error; 10758c2ecf20Sopenharmony_ci int i; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { 10788c2ecf20Sopenharmony_ci error = led_trigger_register(&kbd_led_triggers[i].trigger); 10798c2ecf20Sopenharmony_ci if (error) 10808c2ecf20Sopenharmony_ci pr_err("error %d while registering trigger %s\n", 10818c2ecf20Sopenharmony_ci error, kbd_led_triggers[i].trigger.name); 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci#else 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic int kbd_update_leds_helper(struct input_handle *handle, void *data) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci unsigned int leds = *(unsigned int *)data; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (test_bit(EV_LED, handle->dev->evbit)) { 10928c2ecf20Sopenharmony_ci input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); 10938c2ecf20Sopenharmony_ci input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); 10948c2ecf20Sopenharmony_ci input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); 10958c2ecf20Sopenharmony_ci input_inject_event(handle, EV_SYN, SYN_REPORT, 0); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return 0; 10998c2ecf20Sopenharmony_ci} 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_cistatic void kbd_propagate_led_state(unsigned int old_state, 11028c2ecf20Sopenharmony_ci unsigned int new_state) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci input_handler_for_each_handle(&kbd_handler, &new_state, 11058c2ecf20Sopenharmony_ci kbd_update_leds_helper); 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic void kbd_init_leds(void) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci#endif 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci/* 11158c2ecf20Sopenharmony_ci * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, 11168c2ecf20Sopenharmony_ci * or (ii) whatever pattern of lights people want to show using KDSETLED, 11178c2ecf20Sopenharmony_ci * or (iii) specified bits of specified words in kernel memory. 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_cistatic unsigned char getledstate(void) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci return ledstate & 0xff; 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_civoid setledstate(struct kbd_struct *kb, unsigned int led) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci unsigned long flags; 11278c2ecf20Sopenharmony_ci spin_lock_irqsave(&led_lock, flags); 11288c2ecf20Sopenharmony_ci if (!(led & ~7)) { 11298c2ecf20Sopenharmony_ci ledioctl = led; 11308c2ecf20Sopenharmony_ci kb->ledmode = LED_SHOW_IOCTL; 11318c2ecf20Sopenharmony_ci } else 11328c2ecf20Sopenharmony_ci kb->ledmode = LED_SHOW_FLAGS; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci set_leds(); 11358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&led_lock, flags); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic inline unsigned char getleds(void) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + fg_console; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (kb->ledmode == LED_SHOW_IOCTL) 11438c2ecf20Sopenharmony_ci return ledioctl; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci return kb->ledflagstate; 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci/** 11498c2ecf20Sopenharmony_ci * vt_get_leds - helper for braille console 11508c2ecf20Sopenharmony_ci * @console: console to read 11518c2ecf20Sopenharmony_ci * @flag: flag we want to check 11528c2ecf20Sopenharmony_ci * 11538c2ecf20Sopenharmony_ci * Check the status of a keyboard led flag and report it back 11548c2ecf20Sopenharmony_ci */ 11558c2ecf20Sopenharmony_ciint vt_get_leds(int console, int flag) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 11588c2ecf20Sopenharmony_ci int ret; 11598c2ecf20Sopenharmony_ci unsigned long flags; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci spin_lock_irqsave(&led_lock, flags); 11628c2ecf20Sopenharmony_ci ret = vc_kbd_led(kb, flag); 11638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&led_lock, flags); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci return ret; 11668c2ecf20Sopenharmony_ci} 11678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(vt_get_leds); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci/** 11708c2ecf20Sopenharmony_ci * vt_set_led_state - set LED state of a console 11718c2ecf20Sopenharmony_ci * @console: console to set 11728c2ecf20Sopenharmony_ci * @leds: LED bits 11738c2ecf20Sopenharmony_ci * 11748c2ecf20Sopenharmony_ci * Set the LEDs on a console. This is a wrapper for the VT layer 11758c2ecf20Sopenharmony_ci * so that we can keep kbd knowledge internal 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_civoid vt_set_led_state(int console, int leds) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 11808c2ecf20Sopenharmony_ci setledstate(kb, leds); 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci/** 11848c2ecf20Sopenharmony_ci * vt_kbd_con_start - Keyboard side of console start 11858c2ecf20Sopenharmony_ci * @console: console 11868c2ecf20Sopenharmony_ci * 11878c2ecf20Sopenharmony_ci * Handle console start. This is a wrapper for the VT layer 11888c2ecf20Sopenharmony_ci * so that we can keep kbd knowledge internal 11898c2ecf20Sopenharmony_ci * 11908c2ecf20Sopenharmony_ci * FIXME: We eventually need to hold the kbd lock here to protect 11918c2ecf20Sopenharmony_ci * the LED updating. We can't do it yet because fn_hold calls stop_tty 11928c2ecf20Sopenharmony_ci * and start_tty under the kbd_event_lock, while normal tty paths 11938c2ecf20Sopenharmony_ci * don't hold the lock. We probably need to split out an LED lock 11948c2ecf20Sopenharmony_ci * but not during an -rc release! 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_civoid vt_kbd_con_start(int console) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 11998c2ecf20Sopenharmony_ci unsigned long flags; 12008c2ecf20Sopenharmony_ci spin_lock_irqsave(&led_lock, flags); 12018c2ecf20Sopenharmony_ci clr_vc_kbd_led(kb, VC_SCROLLOCK); 12028c2ecf20Sopenharmony_ci set_leds(); 12038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&led_lock, flags); 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci/** 12078c2ecf20Sopenharmony_ci * vt_kbd_con_stop - Keyboard side of console stop 12088c2ecf20Sopenharmony_ci * @console: console 12098c2ecf20Sopenharmony_ci * 12108c2ecf20Sopenharmony_ci * Handle console stop. This is a wrapper for the VT layer 12118c2ecf20Sopenharmony_ci * so that we can keep kbd knowledge internal 12128c2ecf20Sopenharmony_ci */ 12138c2ecf20Sopenharmony_civoid vt_kbd_con_stop(int console) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 12168c2ecf20Sopenharmony_ci unsigned long flags; 12178c2ecf20Sopenharmony_ci spin_lock_irqsave(&led_lock, flags); 12188c2ecf20Sopenharmony_ci set_vc_kbd_led(kb, VC_SCROLLOCK); 12198c2ecf20Sopenharmony_ci set_leds(); 12208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&led_lock, flags); 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci/* 12248c2ecf20Sopenharmony_ci * This is the tasklet that updates LED state of LEDs using standard 12258c2ecf20Sopenharmony_ci * keyboard triggers. The reason we use tasklet is that we need to 12268c2ecf20Sopenharmony_ci * handle the scenario when keyboard handler is not registered yet 12278c2ecf20Sopenharmony_ci * but we already getting updates from the VT to update led state. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_cistatic void kbd_bh(unsigned long dummy) 12308c2ecf20Sopenharmony_ci{ 12318c2ecf20Sopenharmony_ci unsigned int leds; 12328c2ecf20Sopenharmony_ci unsigned long flags; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci spin_lock_irqsave(&led_lock, flags); 12358c2ecf20Sopenharmony_ci leds = getleds(); 12368c2ecf20Sopenharmony_ci leds |= (unsigned int)kbd->lockstate << 8; 12378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&led_lock, flags); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (leds != ledstate) { 12408c2ecf20Sopenharmony_ci kbd_propagate_led_state(ledstate, leds); 12418c2ecf20Sopenharmony_ci ledstate = leds; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ciDECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ 12488c2ecf20Sopenharmony_ci defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ 12498c2ecf20Sopenharmony_ci defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ 12508c2ecf20Sopenharmony_ci (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ 12538c2ecf20Sopenharmony_ci ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic const unsigned short x86_keycodes[256] = 12568c2ecf20Sopenharmony_ci { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 12578c2ecf20Sopenharmony_ci 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 12588c2ecf20Sopenharmony_ci 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 12598c2ecf20Sopenharmony_ci 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 12608c2ecf20Sopenharmony_ci 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 12618c2ecf20Sopenharmony_ci 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, 12628c2ecf20Sopenharmony_ci 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339, 12638c2ecf20Sopenharmony_ci 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, 12648c2ecf20Sopenharmony_ci 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, 12658c2ecf20Sopenharmony_ci 103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361, 12668c2ecf20Sopenharmony_ci 291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114, 12678c2ecf20Sopenharmony_ci 264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116, 12688c2ecf20Sopenharmony_ci 377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307, 12698c2ecf20Sopenharmony_ci 308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330, 12708c2ecf20Sopenharmony_ci 332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 }; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 12738c2ecf20Sopenharmony_cistatic int sparc_l1_a_state; 12748c2ecf20Sopenharmony_ciextern void sun_do_break(void); 12758c2ecf20Sopenharmony_ci#endif 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic int emulate_raw(struct vc_data *vc, unsigned int keycode, 12788c2ecf20Sopenharmony_ci unsigned char up_flag) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci int code; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci switch (keycode) { 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci case KEY_PAUSE: 12858c2ecf20Sopenharmony_ci put_queue(vc, 0xe1); 12868c2ecf20Sopenharmony_ci put_queue(vc, 0x1d | up_flag); 12878c2ecf20Sopenharmony_ci put_queue(vc, 0x45 | up_flag); 12888c2ecf20Sopenharmony_ci break; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci case KEY_HANGEUL: 12918c2ecf20Sopenharmony_ci if (!up_flag) 12928c2ecf20Sopenharmony_ci put_queue(vc, 0xf2); 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci case KEY_HANJA: 12968c2ecf20Sopenharmony_ci if (!up_flag) 12978c2ecf20Sopenharmony_ci put_queue(vc, 0xf1); 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci case KEY_SYSRQ: 13018c2ecf20Sopenharmony_ci /* 13028c2ecf20Sopenharmony_ci * Real AT keyboards (that's what we're trying 13038c2ecf20Sopenharmony_ci * to emulate here) emit 0xe0 0x2a 0xe0 0x37 when 13048c2ecf20Sopenharmony_ci * pressing PrtSc/SysRq alone, but simply 0x54 13058c2ecf20Sopenharmony_ci * when pressing Alt+PrtSc/SysRq. 13068c2ecf20Sopenharmony_ci */ 13078c2ecf20Sopenharmony_ci if (test_bit(KEY_LEFTALT, key_down) || 13088c2ecf20Sopenharmony_ci test_bit(KEY_RIGHTALT, key_down)) { 13098c2ecf20Sopenharmony_ci put_queue(vc, 0x54 | up_flag); 13108c2ecf20Sopenharmony_ci } else { 13118c2ecf20Sopenharmony_ci put_queue(vc, 0xe0); 13128c2ecf20Sopenharmony_ci put_queue(vc, 0x2a | up_flag); 13138c2ecf20Sopenharmony_ci put_queue(vc, 0xe0); 13148c2ecf20Sopenharmony_ci put_queue(vc, 0x37 | up_flag); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci default: 13198c2ecf20Sopenharmony_ci if (keycode > 255) 13208c2ecf20Sopenharmony_ci return -1; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci code = x86_keycodes[keycode]; 13238c2ecf20Sopenharmony_ci if (!code) 13248c2ecf20Sopenharmony_ci return -1; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (code & 0x100) 13278c2ecf20Sopenharmony_ci put_queue(vc, 0xe0); 13288c2ecf20Sopenharmony_ci put_queue(vc, (code & 0x7f) | up_flag); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci break; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci return 0; 13348c2ecf20Sopenharmony_ci} 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci#else 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci#define HW_RAW(dev) 0 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci if (keycode > 127) 13438c2ecf20Sopenharmony_ci return -1; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci put_queue(vc, keycode | up_flag); 13468c2ecf20Sopenharmony_ci return 0; 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci#endif 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic void kbd_rawcode(unsigned char data) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci struct vc_data *vc = vc_cons[fg_console].d; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci kbd = kbd_table + vc->vc_num; 13558c2ecf20Sopenharmony_ci if (kbd->kbdmode == VC_RAW) 13568c2ecf20Sopenharmony_ci put_queue(vc, data); 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic void kbd_keycode(unsigned int keycode, int down, int hw_raw) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci struct vc_data *vc = vc_cons[fg_console].d; 13628c2ecf20Sopenharmony_ci unsigned short keysym, *key_map; 13638c2ecf20Sopenharmony_ci unsigned char type; 13648c2ecf20Sopenharmony_ci bool raw_mode; 13658c2ecf20Sopenharmony_ci struct tty_struct *tty; 13668c2ecf20Sopenharmony_ci int shift_final; 13678c2ecf20Sopenharmony_ci struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; 13688c2ecf20Sopenharmony_ci int rc; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci tty = vc->port.tty; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (tty && (!tty->driver_data)) { 13738c2ecf20Sopenharmony_ci /* No driver data? Strange. Okay we fix it then. */ 13748c2ecf20Sopenharmony_ci tty->driver_data = vc; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci kbd = kbd_table + vc->vc_num; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 13808c2ecf20Sopenharmony_ci if (keycode == KEY_STOP) 13818c2ecf20Sopenharmony_ci sparc_l1_a_state = down; 13828c2ecf20Sopenharmony_ci#endif 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci rep = (down == 2); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci raw_mode = (kbd->kbdmode == VC_RAW); 13878c2ecf20Sopenharmony_ci if (raw_mode && !hw_raw) 13888c2ecf20Sopenharmony_ci if (emulate_raw(vc, keycode, !down << 7)) 13898c2ecf20Sopenharmony_ci if (keycode < BTN_MISC && printk_ratelimit()) 13908c2ecf20Sopenharmony_ci pr_warn("can't emulate rawmode for keycode %d\n", 13918c2ecf20Sopenharmony_ci keycode); 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 13948c2ecf20Sopenharmony_ci if (keycode == KEY_A && sparc_l1_a_state) { 13958c2ecf20Sopenharmony_ci sparc_l1_a_state = false; 13968c2ecf20Sopenharmony_ci sun_do_break(); 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci#endif 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (kbd->kbdmode == VC_MEDIUMRAW) { 14018c2ecf20Sopenharmony_ci /* 14028c2ecf20Sopenharmony_ci * This is extended medium raw mode, with keys above 127 14038c2ecf20Sopenharmony_ci * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing 14048c2ecf20Sopenharmony_ci * the 'up' flag if needed. 0 is reserved, so this shouldn't 14058c2ecf20Sopenharmony_ci * interfere with anything else. The two bytes after 0 will 14068c2ecf20Sopenharmony_ci * always have the up flag set not to interfere with older 14078c2ecf20Sopenharmony_ci * applications. This allows for 16384 different keycodes, 14088c2ecf20Sopenharmony_ci * which should be enough. 14098c2ecf20Sopenharmony_ci */ 14108c2ecf20Sopenharmony_ci if (keycode < 128) { 14118c2ecf20Sopenharmony_ci put_queue(vc, keycode | (!down << 7)); 14128c2ecf20Sopenharmony_ci } else { 14138c2ecf20Sopenharmony_ci put_queue(vc, !down << 7); 14148c2ecf20Sopenharmony_ci put_queue(vc, (keycode >> 7) | 0x80); 14158c2ecf20Sopenharmony_ci put_queue(vc, keycode | 0x80); 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci raw_mode = true; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (down) 14218c2ecf20Sopenharmony_ci set_bit(keycode, key_down); 14228c2ecf20Sopenharmony_ci else 14238c2ecf20Sopenharmony_ci clear_bit(keycode, key_down); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (rep && 14268c2ecf20Sopenharmony_ci (!vc_kbd_mode(kbd, VC_REPEAT) || 14278c2ecf20Sopenharmony_ci (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { 14288c2ecf20Sopenharmony_ci /* 14298c2ecf20Sopenharmony_ci * Don't repeat a key if the input buffers are not empty and the 14308c2ecf20Sopenharmony_ci * characters get aren't echoed locally. This makes key repeat 14318c2ecf20Sopenharmony_ci * usable with slow applications and under heavy loads. 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci return; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate; 14378c2ecf20Sopenharmony_ci param.ledstate = kbd->ledflagstate; 14388c2ecf20Sopenharmony_ci key_map = key_maps[shift_final]; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci rc = atomic_notifier_call_chain(&keyboard_notifier_list, 14418c2ecf20Sopenharmony_ci KBD_KEYCODE, ¶m); 14428c2ecf20Sopenharmony_ci if (rc == NOTIFY_STOP || !key_map) { 14438c2ecf20Sopenharmony_ci atomic_notifier_call_chain(&keyboard_notifier_list, 14448c2ecf20Sopenharmony_ci KBD_UNBOUND_KEYCODE, ¶m); 14458c2ecf20Sopenharmony_ci do_compute_shiftstate(); 14468c2ecf20Sopenharmony_ci kbd->slockstate = 0; 14478c2ecf20Sopenharmony_ci return; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (keycode < NR_KEYS) 14518c2ecf20Sopenharmony_ci keysym = key_map[keycode]; 14528c2ecf20Sopenharmony_ci else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) 14538c2ecf20Sopenharmony_ci keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1)); 14548c2ecf20Sopenharmony_ci else 14558c2ecf20Sopenharmony_ci return; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci type = KTYP(keysym); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (type < 0xf0) { 14608c2ecf20Sopenharmony_ci param.value = keysym; 14618c2ecf20Sopenharmony_ci rc = atomic_notifier_call_chain(&keyboard_notifier_list, 14628c2ecf20Sopenharmony_ci KBD_UNICODE, ¶m); 14638c2ecf20Sopenharmony_ci if (rc != NOTIFY_STOP) 14648c2ecf20Sopenharmony_ci if (down && !raw_mode) 14658c2ecf20Sopenharmony_ci k_unicode(vc, keysym, !down); 14668c2ecf20Sopenharmony_ci return; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci type -= 0xf0; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (type == KT_LETTER) { 14728c2ecf20Sopenharmony_ci type = KT_LATIN; 14738c2ecf20Sopenharmony_ci if (vc_kbd_led(kbd, VC_CAPSLOCK)) { 14748c2ecf20Sopenharmony_ci key_map = key_maps[shift_final ^ (1 << KG_SHIFT)]; 14758c2ecf20Sopenharmony_ci if (key_map) 14768c2ecf20Sopenharmony_ci keysym = key_map[keycode]; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci param.value = keysym; 14818c2ecf20Sopenharmony_ci rc = atomic_notifier_call_chain(&keyboard_notifier_list, 14828c2ecf20Sopenharmony_ci KBD_KEYSYM, ¶m); 14838c2ecf20Sopenharmony_ci if (rc == NOTIFY_STOP) 14848c2ecf20Sopenharmony_ci return; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if ((raw_mode || kbd->kbdmode == VC_OFF) && type != KT_SPEC && type != KT_SHIFT) 14878c2ecf20Sopenharmony_ci return; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci (*k_handler[type])(vc, keysym & 0xff, !down); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci param.ledstate = kbd->ledflagstate; 14928c2ecf20Sopenharmony_ci atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, ¶m); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (type != KT_SLOCK) 14958c2ecf20Sopenharmony_ci kbd->slockstate = 0; 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_cistatic void kbd_event(struct input_handle *handle, unsigned int event_type, 14998c2ecf20Sopenharmony_ci unsigned int event_code, int value) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci /* We are called with interrupts disabled, just take the lock */ 15028c2ecf20Sopenharmony_ci spin_lock(&kbd_event_lock); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) 15058c2ecf20Sopenharmony_ci kbd_rawcode(value); 15068c2ecf20Sopenharmony_ci if (event_type == EV_KEY && event_code <= KEY_MAX) 15078c2ecf20Sopenharmony_ci kbd_keycode(event_code, value, HW_RAW(handle->dev)); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci spin_unlock(&kbd_event_lock); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci tasklet_schedule(&keyboard_tasklet); 15128c2ecf20Sopenharmony_ci do_poke_blanked_console = 1; 15138c2ecf20Sopenharmony_ci schedule_console_callback(); 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_cistatic bool kbd_match(struct input_handler *handler, struct input_dev *dev) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci int i; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (test_bit(EV_SND, dev->evbit)) 15218c2ecf20Sopenharmony_ci return true; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (test_bit(EV_KEY, dev->evbit)) { 15248c2ecf20Sopenharmony_ci for (i = KEY_RESERVED; i < BTN_MISC; i++) 15258c2ecf20Sopenharmony_ci if (test_bit(i, dev->keybit)) 15268c2ecf20Sopenharmony_ci return true; 15278c2ecf20Sopenharmony_ci for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++) 15288c2ecf20Sopenharmony_ci if (test_bit(i, dev->keybit)) 15298c2ecf20Sopenharmony_ci return true; 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci return false; 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci/* 15368c2ecf20Sopenharmony_ci * When a keyboard (or other input device) is found, the kbd_connect 15378c2ecf20Sopenharmony_ci * function is called. The function then looks at the device, and if it 15388c2ecf20Sopenharmony_ci * likes it, it can open it and get events from it. In this (kbd_connect) 15398c2ecf20Sopenharmony_ci * function, we should decide which VT to bind that keyboard to initially. 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_cistatic int kbd_connect(struct input_handler *handler, struct input_dev *dev, 15428c2ecf20Sopenharmony_ci const struct input_device_id *id) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci struct input_handle *handle; 15458c2ecf20Sopenharmony_ci int error; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); 15488c2ecf20Sopenharmony_ci if (!handle) 15498c2ecf20Sopenharmony_ci return -ENOMEM; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci handle->dev = dev; 15528c2ecf20Sopenharmony_ci handle->handler = handler; 15538c2ecf20Sopenharmony_ci handle->name = "kbd"; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci error = input_register_handle(handle); 15568c2ecf20Sopenharmony_ci if (error) 15578c2ecf20Sopenharmony_ci goto err_free_handle; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci error = input_open_device(handle); 15608c2ecf20Sopenharmony_ci if (error) 15618c2ecf20Sopenharmony_ci goto err_unregister_handle; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci err_unregister_handle: 15668c2ecf20Sopenharmony_ci input_unregister_handle(handle); 15678c2ecf20Sopenharmony_ci err_free_handle: 15688c2ecf20Sopenharmony_ci kfree(handle); 15698c2ecf20Sopenharmony_ci return error; 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_cistatic void kbd_disconnect(struct input_handle *handle) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci input_close_device(handle); 15758c2ecf20Sopenharmony_ci input_unregister_handle(handle); 15768c2ecf20Sopenharmony_ci kfree(handle); 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci/* 15808c2ecf20Sopenharmony_ci * Start keyboard handler on the new keyboard by refreshing LED state to 15818c2ecf20Sopenharmony_ci * match the rest of the system. 15828c2ecf20Sopenharmony_ci */ 15838c2ecf20Sopenharmony_cistatic void kbd_start(struct input_handle *handle) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci tasklet_disable(&keyboard_tasklet); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (ledstate != -1U) 15888c2ecf20Sopenharmony_ci kbd_update_leds_helper(handle, &ledstate); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci tasklet_enable(&keyboard_tasklet); 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_cistatic const struct input_device_id kbd_ids[] = { 15948c2ecf20Sopenharmony_ci { 15958c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 15968c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 15978c2ecf20Sopenharmony_ci }, 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci { 16008c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT, 16018c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_SND) }, 16028c2ecf20Sopenharmony_ci }, 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci { }, /* Terminating entry */ 16058c2ecf20Sopenharmony_ci}; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(input, kbd_ids); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_cistatic struct input_handler kbd_handler = { 16108c2ecf20Sopenharmony_ci .event = kbd_event, 16118c2ecf20Sopenharmony_ci .match = kbd_match, 16128c2ecf20Sopenharmony_ci .connect = kbd_connect, 16138c2ecf20Sopenharmony_ci .disconnect = kbd_disconnect, 16148c2ecf20Sopenharmony_ci .start = kbd_start, 16158c2ecf20Sopenharmony_ci .name = "kbd", 16168c2ecf20Sopenharmony_ci .id_table = kbd_ids, 16178c2ecf20Sopenharmony_ci}; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ciint __init kbd_init(void) 16208c2ecf20Sopenharmony_ci{ 16218c2ecf20Sopenharmony_ci int i; 16228c2ecf20Sopenharmony_ci int error; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) { 16258c2ecf20Sopenharmony_ci kbd_table[i].ledflagstate = kbd_defleds(); 16268c2ecf20Sopenharmony_ci kbd_table[i].default_ledflagstate = kbd_defleds(); 16278c2ecf20Sopenharmony_ci kbd_table[i].ledmode = LED_SHOW_FLAGS; 16288c2ecf20Sopenharmony_ci kbd_table[i].lockstate = KBD_DEFLOCK; 16298c2ecf20Sopenharmony_ci kbd_table[i].slockstate = 0; 16308c2ecf20Sopenharmony_ci kbd_table[i].modeflags = KBD_DEFMODE; 16318c2ecf20Sopenharmony_ci kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; 16328c2ecf20Sopenharmony_ci } 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci kbd_init_leds(); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci error = input_register_handler(&kbd_handler); 16378c2ecf20Sopenharmony_ci if (error) 16388c2ecf20Sopenharmony_ci return error; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci tasklet_enable(&keyboard_tasklet); 16418c2ecf20Sopenharmony_ci tasklet_schedule(&keyboard_tasklet); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci return 0; 16448c2ecf20Sopenharmony_ci} 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci/* Ioctl support code */ 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci/** 16498c2ecf20Sopenharmony_ci * vt_do_diacrit - diacritical table updates 16508c2ecf20Sopenharmony_ci * @cmd: ioctl request 16518c2ecf20Sopenharmony_ci * @udp: pointer to user data for ioctl 16528c2ecf20Sopenharmony_ci * @perm: permissions check computed by caller 16538c2ecf20Sopenharmony_ci * 16548c2ecf20Sopenharmony_ci * Update the diacritical tables atomically and safely. Lock them 16558c2ecf20Sopenharmony_ci * against simultaneous keypresses 16568c2ecf20Sopenharmony_ci */ 16578c2ecf20Sopenharmony_ciint vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci unsigned long flags; 16608c2ecf20Sopenharmony_ci int asize; 16618c2ecf20Sopenharmony_ci int ret = 0; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci switch (cmd) { 16648c2ecf20Sopenharmony_ci case KDGKBDIACR: 16658c2ecf20Sopenharmony_ci { 16668c2ecf20Sopenharmony_ci struct kbdiacrs __user *a = udp; 16678c2ecf20Sopenharmony_ci struct kbdiacr *dia; 16688c2ecf20Sopenharmony_ci int i; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), 16718c2ecf20Sopenharmony_ci GFP_KERNEL); 16728c2ecf20Sopenharmony_ci if (!dia) 16738c2ecf20Sopenharmony_ci return -ENOMEM; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci /* Lock the diacriticals table, make a copy and then 16768c2ecf20Sopenharmony_ci copy it after we unlock */ 16778c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci asize = accent_table_size; 16808c2ecf20Sopenharmony_ci for (i = 0; i < asize; i++) { 16818c2ecf20Sopenharmony_ci dia[i].diacr = conv_uni_to_8bit( 16828c2ecf20Sopenharmony_ci accent_table[i].diacr); 16838c2ecf20Sopenharmony_ci dia[i].base = conv_uni_to_8bit( 16848c2ecf20Sopenharmony_ci accent_table[i].base); 16858c2ecf20Sopenharmony_ci dia[i].result = conv_uni_to_8bit( 16868c2ecf20Sopenharmony_ci accent_table[i].result); 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (put_user(asize, &a->kb_cnt)) 16918c2ecf20Sopenharmony_ci ret = -EFAULT; 16928c2ecf20Sopenharmony_ci else if (copy_to_user(a->kbdiacr, dia, 16938c2ecf20Sopenharmony_ci asize * sizeof(struct kbdiacr))) 16948c2ecf20Sopenharmony_ci ret = -EFAULT; 16958c2ecf20Sopenharmony_ci kfree(dia); 16968c2ecf20Sopenharmony_ci return ret; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci case KDGKBDIACRUC: 16998c2ecf20Sopenharmony_ci { 17008c2ecf20Sopenharmony_ci struct kbdiacrsuc __user *a = udp; 17018c2ecf20Sopenharmony_ci void *buf; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), 17048c2ecf20Sopenharmony_ci GFP_KERNEL); 17058c2ecf20Sopenharmony_ci if (buf == NULL) 17068c2ecf20Sopenharmony_ci return -ENOMEM; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* Lock the diacriticals table, make a copy and then 17098c2ecf20Sopenharmony_ci copy it after we unlock */ 17108c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci asize = accent_table_size; 17138c2ecf20Sopenharmony_ci memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (put_user(asize, &a->kb_cnt)) 17188c2ecf20Sopenharmony_ci ret = -EFAULT; 17198c2ecf20Sopenharmony_ci else if (copy_to_user(a->kbdiacruc, buf, 17208c2ecf20Sopenharmony_ci asize*sizeof(struct kbdiacruc))) 17218c2ecf20Sopenharmony_ci ret = -EFAULT; 17228c2ecf20Sopenharmony_ci kfree(buf); 17238c2ecf20Sopenharmony_ci return ret; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci case KDSKBDIACR: 17278c2ecf20Sopenharmony_ci { 17288c2ecf20Sopenharmony_ci struct kbdiacrs __user *a = udp; 17298c2ecf20Sopenharmony_ci struct kbdiacr *dia = NULL; 17308c2ecf20Sopenharmony_ci unsigned int ct; 17318c2ecf20Sopenharmony_ci int i; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (!perm) 17348c2ecf20Sopenharmony_ci return -EPERM; 17358c2ecf20Sopenharmony_ci if (get_user(ct, &a->kb_cnt)) 17368c2ecf20Sopenharmony_ci return -EFAULT; 17378c2ecf20Sopenharmony_ci if (ct >= MAX_DIACR) 17388c2ecf20Sopenharmony_ci return -EINVAL; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (ct) { 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci dia = memdup_user(a->kbdiacr, 17438c2ecf20Sopenharmony_ci sizeof(struct kbdiacr) * ct); 17448c2ecf20Sopenharmony_ci if (IS_ERR(dia)) 17458c2ecf20Sopenharmony_ci return PTR_ERR(dia); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci } 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 17508c2ecf20Sopenharmony_ci accent_table_size = ct; 17518c2ecf20Sopenharmony_ci for (i = 0; i < ct; i++) { 17528c2ecf20Sopenharmony_ci accent_table[i].diacr = 17538c2ecf20Sopenharmony_ci conv_8bit_to_uni(dia[i].diacr); 17548c2ecf20Sopenharmony_ci accent_table[i].base = 17558c2ecf20Sopenharmony_ci conv_8bit_to_uni(dia[i].base); 17568c2ecf20Sopenharmony_ci accent_table[i].result = 17578c2ecf20Sopenharmony_ci conv_8bit_to_uni(dia[i].result); 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 17608c2ecf20Sopenharmony_ci kfree(dia); 17618c2ecf20Sopenharmony_ci return 0; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci case KDSKBDIACRUC: 17658c2ecf20Sopenharmony_ci { 17668c2ecf20Sopenharmony_ci struct kbdiacrsuc __user *a = udp; 17678c2ecf20Sopenharmony_ci unsigned int ct; 17688c2ecf20Sopenharmony_ci void *buf = NULL; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci if (!perm) 17718c2ecf20Sopenharmony_ci return -EPERM; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci if (get_user(ct, &a->kb_cnt)) 17748c2ecf20Sopenharmony_ci return -EFAULT; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci if (ct >= MAX_DIACR) 17778c2ecf20Sopenharmony_ci return -EINVAL; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci if (ct) { 17808c2ecf20Sopenharmony_ci buf = memdup_user(a->kbdiacruc, 17818c2ecf20Sopenharmony_ci ct * sizeof(struct kbdiacruc)); 17828c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 17838c2ecf20Sopenharmony_ci return PTR_ERR(buf); 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 17868c2ecf20Sopenharmony_ci if (ct) 17878c2ecf20Sopenharmony_ci memcpy(accent_table, buf, 17888c2ecf20Sopenharmony_ci ct * sizeof(struct kbdiacruc)); 17898c2ecf20Sopenharmony_ci accent_table_size = ct; 17908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 17918c2ecf20Sopenharmony_ci kfree(buf); 17928c2ecf20Sopenharmony_ci return 0; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci return ret; 17968c2ecf20Sopenharmony_ci} 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci/** 17998c2ecf20Sopenharmony_ci * vt_do_kdskbmode - set keyboard mode ioctl 18008c2ecf20Sopenharmony_ci * @console: the console to use 18018c2ecf20Sopenharmony_ci * @arg: the requested mode 18028c2ecf20Sopenharmony_ci * 18038c2ecf20Sopenharmony_ci * Update the keyboard mode bits while holding the correct locks. 18048c2ecf20Sopenharmony_ci * Return 0 for success or an error code. 18058c2ecf20Sopenharmony_ci */ 18068c2ecf20Sopenharmony_ciint vt_do_kdskbmode(int console, unsigned int arg) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 18098c2ecf20Sopenharmony_ci int ret = 0; 18108c2ecf20Sopenharmony_ci unsigned long flags; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 18138c2ecf20Sopenharmony_ci switch(arg) { 18148c2ecf20Sopenharmony_ci case K_RAW: 18158c2ecf20Sopenharmony_ci kb->kbdmode = VC_RAW; 18168c2ecf20Sopenharmony_ci break; 18178c2ecf20Sopenharmony_ci case K_MEDIUMRAW: 18188c2ecf20Sopenharmony_ci kb->kbdmode = VC_MEDIUMRAW; 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci case K_XLATE: 18218c2ecf20Sopenharmony_ci kb->kbdmode = VC_XLATE; 18228c2ecf20Sopenharmony_ci do_compute_shiftstate(); 18238c2ecf20Sopenharmony_ci break; 18248c2ecf20Sopenharmony_ci case K_UNICODE: 18258c2ecf20Sopenharmony_ci kb->kbdmode = VC_UNICODE; 18268c2ecf20Sopenharmony_ci do_compute_shiftstate(); 18278c2ecf20Sopenharmony_ci break; 18288c2ecf20Sopenharmony_ci case K_OFF: 18298c2ecf20Sopenharmony_ci kb->kbdmode = VC_OFF; 18308c2ecf20Sopenharmony_ci break; 18318c2ecf20Sopenharmony_ci default: 18328c2ecf20Sopenharmony_ci ret = -EINVAL; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 18358c2ecf20Sopenharmony_ci return ret; 18368c2ecf20Sopenharmony_ci} 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci/** 18398c2ecf20Sopenharmony_ci * vt_do_kdskbmeta - set keyboard meta state 18408c2ecf20Sopenharmony_ci * @console: the console to use 18418c2ecf20Sopenharmony_ci * @arg: the requested meta state 18428c2ecf20Sopenharmony_ci * 18438c2ecf20Sopenharmony_ci * Update the keyboard meta bits while holding the correct locks. 18448c2ecf20Sopenharmony_ci * Return 0 for success or an error code. 18458c2ecf20Sopenharmony_ci */ 18468c2ecf20Sopenharmony_ciint vt_do_kdskbmeta(int console, unsigned int arg) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 18498c2ecf20Sopenharmony_ci int ret = 0; 18508c2ecf20Sopenharmony_ci unsigned long flags; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 18538c2ecf20Sopenharmony_ci switch(arg) { 18548c2ecf20Sopenharmony_ci case K_METABIT: 18558c2ecf20Sopenharmony_ci clr_vc_kbd_mode(kb, VC_META); 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci case K_ESCPREFIX: 18588c2ecf20Sopenharmony_ci set_vc_kbd_mode(kb, VC_META); 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci default: 18618c2ecf20Sopenharmony_ci ret = -EINVAL; 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 18648c2ecf20Sopenharmony_ci return ret; 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ciint vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, 18688c2ecf20Sopenharmony_ci int perm) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci struct kbkeycode tmp; 18718c2ecf20Sopenharmony_ci int kc = 0; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) 18748c2ecf20Sopenharmony_ci return -EFAULT; 18758c2ecf20Sopenharmony_ci switch (cmd) { 18768c2ecf20Sopenharmony_ci case KDGETKEYCODE: 18778c2ecf20Sopenharmony_ci kc = getkeycode(tmp.scancode); 18788c2ecf20Sopenharmony_ci if (kc >= 0) 18798c2ecf20Sopenharmony_ci kc = put_user(kc, &user_kbkc->keycode); 18808c2ecf20Sopenharmony_ci break; 18818c2ecf20Sopenharmony_ci case KDSETKEYCODE: 18828c2ecf20Sopenharmony_ci if (!perm) 18838c2ecf20Sopenharmony_ci return -EPERM; 18848c2ecf20Sopenharmony_ci kc = setkeycode(tmp.scancode, tmp.keycode); 18858c2ecf20Sopenharmony_ci break; 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci return kc; 18888c2ecf20Sopenharmony_ci} 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci#define i (tmp.kb_index) 18918c2ecf20Sopenharmony_ci#define s (tmp.kb_table) 18928c2ecf20Sopenharmony_ci#define v (tmp.kb_value) 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ciint vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, 18958c2ecf20Sopenharmony_ci int console) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 18988c2ecf20Sopenharmony_ci struct kbentry tmp; 18998c2ecf20Sopenharmony_ci ushort *key_map, *new_map, val, ov; 19008c2ecf20Sopenharmony_ci unsigned long flags; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) 19038c2ecf20Sopenharmony_ci return -EFAULT; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_TTY_CONFIG)) 19068c2ecf20Sopenharmony_ci perm = 0; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci switch (cmd) { 19098c2ecf20Sopenharmony_ci case KDGKBENT: 19108c2ecf20Sopenharmony_ci /* Ensure another thread doesn't free it under us */ 19118c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 19128c2ecf20Sopenharmony_ci key_map = key_maps[s]; 19138c2ecf20Sopenharmony_ci if (key_map) { 19148c2ecf20Sopenharmony_ci val = U(key_map[i]); 19158c2ecf20Sopenharmony_ci if (kb->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) 19168c2ecf20Sopenharmony_ci val = K_HOLE; 19178c2ecf20Sopenharmony_ci } else 19188c2ecf20Sopenharmony_ci val = (i ? K_HOLE : K_NOSUCHMAP); 19198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 19208c2ecf20Sopenharmony_ci return put_user(val, &user_kbe->kb_value); 19218c2ecf20Sopenharmony_ci case KDSKBENT: 19228c2ecf20Sopenharmony_ci if (!perm) 19238c2ecf20Sopenharmony_ci return -EPERM; 19248c2ecf20Sopenharmony_ci if (!i && v == K_NOSUCHMAP) { 19258c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 19268c2ecf20Sopenharmony_ci /* deallocate map */ 19278c2ecf20Sopenharmony_ci key_map = key_maps[s]; 19288c2ecf20Sopenharmony_ci if (s && key_map) { 19298c2ecf20Sopenharmony_ci key_maps[s] = NULL; 19308c2ecf20Sopenharmony_ci if (key_map[0] == U(K_ALLOCATED)) { 19318c2ecf20Sopenharmony_ci kfree(key_map); 19328c2ecf20Sopenharmony_ci keymap_count--; 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 19368c2ecf20Sopenharmony_ci break; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (KTYP(v) < NR_TYPES) { 19408c2ecf20Sopenharmony_ci if (KVAL(v) > max_vals[KTYP(v)]) 19418c2ecf20Sopenharmony_ci return -EINVAL; 19428c2ecf20Sopenharmony_ci } else 19438c2ecf20Sopenharmony_ci if (kb->kbdmode != VC_UNICODE) 19448c2ecf20Sopenharmony_ci return -EINVAL; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci /* ++Geert: non-PC keyboards may generate keycode zero */ 19478c2ecf20Sopenharmony_ci#if !defined(__mc68000__) && !defined(__powerpc__) 19488c2ecf20Sopenharmony_ci /* assignment to entry 0 only tests validity of args */ 19498c2ecf20Sopenharmony_ci if (!i) 19508c2ecf20Sopenharmony_ci break; 19518c2ecf20Sopenharmony_ci#endif 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); 19548c2ecf20Sopenharmony_ci if (!new_map) 19558c2ecf20Sopenharmony_ci return -ENOMEM; 19568c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 19578c2ecf20Sopenharmony_ci key_map = key_maps[s]; 19588c2ecf20Sopenharmony_ci if (key_map == NULL) { 19598c2ecf20Sopenharmony_ci int j; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && 19628c2ecf20Sopenharmony_ci !capable(CAP_SYS_RESOURCE)) { 19638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 19648c2ecf20Sopenharmony_ci kfree(new_map); 19658c2ecf20Sopenharmony_ci return -EPERM; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci key_maps[s] = new_map; 19688c2ecf20Sopenharmony_ci key_map = new_map; 19698c2ecf20Sopenharmony_ci key_map[0] = U(K_ALLOCATED); 19708c2ecf20Sopenharmony_ci for (j = 1; j < NR_KEYS; j++) 19718c2ecf20Sopenharmony_ci key_map[j] = U(K_HOLE); 19728c2ecf20Sopenharmony_ci keymap_count++; 19738c2ecf20Sopenharmony_ci } else 19748c2ecf20Sopenharmony_ci kfree(new_map); 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci ov = U(key_map[i]); 19778c2ecf20Sopenharmony_ci if (v == ov) 19788c2ecf20Sopenharmony_ci goto out; 19798c2ecf20Sopenharmony_ci /* 19808c2ecf20Sopenharmony_ci * Attention Key. 19818c2ecf20Sopenharmony_ci */ 19828c2ecf20Sopenharmony_ci if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { 19838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 19848c2ecf20Sopenharmony_ci return -EPERM; 19858c2ecf20Sopenharmony_ci } 19868c2ecf20Sopenharmony_ci key_map[i] = U(v); 19878c2ecf20Sopenharmony_ci if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) 19888c2ecf20Sopenharmony_ci do_compute_shiftstate(); 19898c2ecf20Sopenharmony_ciout: 19908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 19918c2ecf20Sopenharmony_ci break; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci return 0; 19948c2ecf20Sopenharmony_ci} 19958c2ecf20Sopenharmony_ci#undef i 19968c2ecf20Sopenharmony_ci#undef s 19978c2ecf20Sopenharmony_ci#undef v 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci/* FIXME: This one needs untangling */ 20008c2ecf20Sopenharmony_ciint vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci struct kbsentry *kbs; 20038c2ecf20Sopenharmony_ci u_char *q; 20048c2ecf20Sopenharmony_ci int sz, fnw_sz; 20058c2ecf20Sopenharmony_ci int delta; 20068c2ecf20Sopenharmony_ci char *first_free, *fj, *fnw; 20078c2ecf20Sopenharmony_ci int i, j, k; 20088c2ecf20Sopenharmony_ci int ret; 20098c2ecf20Sopenharmony_ci unsigned long flags; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_TTY_CONFIG)) 20128c2ecf20Sopenharmony_ci perm = 0; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); 20158c2ecf20Sopenharmony_ci if (!kbs) { 20168c2ecf20Sopenharmony_ci ret = -ENOMEM; 20178c2ecf20Sopenharmony_ci goto reterr; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* we mostly copy too much here (512bytes), but who cares ;) */ 20218c2ecf20Sopenharmony_ci if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { 20228c2ecf20Sopenharmony_ci ret = -EFAULT; 20238c2ecf20Sopenharmony_ci goto reterr; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; 20268c2ecf20Sopenharmony_ci i = array_index_nospec(kbs->kb_func, MAX_NR_FUNC); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci switch (cmd) { 20298c2ecf20Sopenharmony_ci case KDGKBSENT: { 20308c2ecf20Sopenharmony_ci /* size should have been a struct member */ 20318c2ecf20Sopenharmony_ci ssize_t len = sizeof(user_kdgkb->kb_string); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci spin_lock_irqsave(&func_buf_lock, flags); 20348c2ecf20Sopenharmony_ci len = strlcpy(kbs->kb_string, func_table[i] ? : "", len); 20358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&func_buf_lock, flags); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci ret = copy_to_user(user_kdgkb->kb_string, kbs->kb_string, 20388c2ecf20Sopenharmony_ci len + 1) ? -EFAULT : 0; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci goto reterr; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci case KDSKBSENT: 20438c2ecf20Sopenharmony_ci if (!perm) { 20448c2ecf20Sopenharmony_ci ret = -EPERM; 20458c2ecf20Sopenharmony_ci goto reterr; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci fnw = NULL; 20498c2ecf20Sopenharmony_ci fnw_sz = 0; 20508c2ecf20Sopenharmony_ci /* race aginst other writers */ 20518c2ecf20Sopenharmony_ci again: 20528c2ecf20Sopenharmony_ci spin_lock_irqsave(&func_buf_lock, flags); 20538c2ecf20Sopenharmony_ci q = func_table[i]; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /* fj pointer to next entry after 'q' */ 20568c2ecf20Sopenharmony_ci first_free = funcbufptr + (funcbufsize - funcbufleft); 20578c2ecf20Sopenharmony_ci for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 20588c2ecf20Sopenharmony_ci ; 20598c2ecf20Sopenharmony_ci if (j < MAX_NR_FUNC) 20608c2ecf20Sopenharmony_ci fj = func_table[j]; 20618c2ecf20Sopenharmony_ci else 20628c2ecf20Sopenharmony_ci fj = first_free; 20638c2ecf20Sopenharmony_ci /* buffer usage increase by new entry */ 20648c2ecf20Sopenharmony_ci delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (delta <= funcbufleft) { /* it fits in current buf */ 20678c2ecf20Sopenharmony_ci if (j < MAX_NR_FUNC) { 20688c2ecf20Sopenharmony_ci /* make enough space for new entry at 'fj' */ 20698c2ecf20Sopenharmony_ci memmove(fj + delta, fj, first_free - fj); 20708c2ecf20Sopenharmony_ci for (k = j; k < MAX_NR_FUNC; k++) 20718c2ecf20Sopenharmony_ci if (func_table[k]) 20728c2ecf20Sopenharmony_ci func_table[k] += delta; 20738c2ecf20Sopenharmony_ci } 20748c2ecf20Sopenharmony_ci if (!q) 20758c2ecf20Sopenharmony_ci func_table[i] = fj; 20768c2ecf20Sopenharmony_ci funcbufleft -= delta; 20778c2ecf20Sopenharmony_ci } else { /* allocate a larger buffer */ 20788c2ecf20Sopenharmony_ci sz = 256; 20798c2ecf20Sopenharmony_ci while (sz < funcbufsize - funcbufleft + delta) 20808c2ecf20Sopenharmony_ci sz <<= 1; 20818c2ecf20Sopenharmony_ci if (fnw_sz != sz) { 20828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&func_buf_lock, flags); 20838c2ecf20Sopenharmony_ci kfree(fnw); 20848c2ecf20Sopenharmony_ci fnw = kmalloc(sz, GFP_KERNEL); 20858c2ecf20Sopenharmony_ci fnw_sz = sz; 20868c2ecf20Sopenharmony_ci if (!fnw) { 20878c2ecf20Sopenharmony_ci ret = -ENOMEM; 20888c2ecf20Sopenharmony_ci goto reterr; 20898c2ecf20Sopenharmony_ci } 20908c2ecf20Sopenharmony_ci goto again; 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci if (!q) 20948c2ecf20Sopenharmony_ci func_table[i] = fj; 20958c2ecf20Sopenharmony_ci /* copy data before insertion point to new location */ 20968c2ecf20Sopenharmony_ci if (fj > funcbufptr) 20978c2ecf20Sopenharmony_ci memmove(fnw, funcbufptr, fj - funcbufptr); 20988c2ecf20Sopenharmony_ci for (k = 0; k < j; k++) 20998c2ecf20Sopenharmony_ci if (func_table[k]) 21008c2ecf20Sopenharmony_ci func_table[k] = fnw + (func_table[k] - funcbufptr); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* copy data after insertion point to new location */ 21038c2ecf20Sopenharmony_ci if (first_free > fj) { 21048c2ecf20Sopenharmony_ci memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); 21058c2ecf20Sopenharmony_ci for (k = j; k < MAX_NR_FUNC; k++) 21068c2ecf20Sopenharmony_ci if (func_table[k]) 21078c2ecf20Sopenharmony_ci func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci if (funcbufptr != func_buf) 21108c2ecf20Sopenharmony_ci kfree(funcbufptr); 21118c2ecf20Sopenharmony_ci funcbufptr = fnw; 21128c2ecf20Sopenharmony_ci funcbufleft = funcbufleft - delta + sz - funcbufsize; 21138c2ecf20Sopenharmony_ci funcbufsize = sz; 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci /* finally insert item itself */ 21168c2ecf20Sopenharmony_ci strcpy(func_table[i], kbs->kb_string); 21178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&func_buf_lock, flags); 21188c2ecf20Sopenharmony_ci break; 21198c2ecf20Sopenharmony_ci } 21208c2ecf20Sopenharmony_ci ret = 0; 21218c2ecf20Sopenharmony_cireterr: 21228c2ecf20Sopenharmony_ci kfree(kbs); 21238c2ecf20Sopenharmony_ci return ret; 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ciint vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) 21278c2ecf20Sopenharmony_ci{ 21288c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 21298c2ecf20Sopenharmony_ci unsigned long flags; 21308c2ecf20Sopenharmony_ci unsigned char ucval; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci switch(cmd) { 21338c2ecf20Sopenharmony_ci /* the ioctls below read/set the flags usually shown in the leds */ 21348c2ecf20Sopenharmony_ci /* don't use them - they will go away without warning */ 21358c2ecf20Sopenharmony_ci case KDGKBLED: 21368c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 21378c2ecf20Sopenharmony_ci ucval = kb->ledflagstate | (kb->default_ledflagstate << 4); 21388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 21398c2ecf20Sopenharmony_ci return put_user(ucval, (char __user *)arg); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci case KDSKBLED: 21428c2ecf20Sopenharmony_ci if (!perm) 21438c2ecf20Sopenharmony_ci return -EPERM; 21448c2ecf20Sopenharmony_ci if (arg & ~0x77) 21458c2ecf20Sopenharmony_ci return -EINVAL; 21468c2ecf20Sopenharmony_ci spin_lock_irqsave(&led_lock, flags); 21478c2ecf20Sopenharmony_ci kb->ledflagstate = (arg & 7); 21488c2ecf20Sopenharmony_ci kb->default_ledflagstate = ((arg >> 4) & 7); 21498c2ecf20Sopenharmony_ci set_leds(); 21508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&led_lock, flags); 21518c2ecf20Sopenharmony_ci return 0; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci /* the ioctls below only set the lights, not the functions */ 21548c2ecf20Sopenharmony_ci /* for those, see KDGKBLED and KDSKBLED above */ 21558c2ecf20Sopenharmony_ci case KDGETLED: 21568c2ecf20Sopenharmony_ci ucval = getledstate(); 21578c2ecf20Sopenharmony_ci return put_user(ucval, (char __user *)arg); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci case KDSETLED: 21608c2ecf20Sopenharmony_ci if (!perm) 21618c2ecf20Sopenharmony_ci return -EPERM; 21628c2ecf20Sopenharmony_ci setledstate(kb, arg); 21638c2ecf20Sopenharmony_ci return 0; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 21668c2ecf20Sopenharmony_ci} 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ciint vt_do_kdgkbmode(int console) 21698c2ecf20Sopenharmony_ci{ 21708c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 21718c2ecf20Sopenharmony_ci /* This is a spot read so needs no locking */ 21728c2ecf20Sopenharmony_ci switch (kb->kbdmode) { 21738c2ecf20Sopenharmony_ci case VC_RAW: 21748c2ecf20Sopenharmony_ci return K_RAW; 21758c2ecf20Sopenharmony_ci case VC_MEDIUMRAW: 21768c2ecf20Sopenharmony_ci return K_MEDIUMRAW; 21778c2ecf20Sopenharmony_ci case VC_UNICODE: 21788c2ecf20Sopenharmony_ci return K_UNICODE; 21798c2ecf20Sopenharmony_ci case VC_OFF: 21808c2ecf20Sopenharmony_ci return K_OFF; 21818c2ecf20Sopenharmony_ci default: 21828c2ecf20Sopenharmony_ci return K_XLATE; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci} 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci/** 21878c2ecf20Sopenharmony_ci * vt_do_kdgkbmeta - report meta status 21888c2ecf20Sopenharmony_ci * @console: console to report 21898c2ecf20Sopenharmony_ci * 21908c2ecf20Sopenharmony_ci * Report the meta flag status of this console 21918c2ecf20Sopenharmony_ci */ 21928c2ecf20Sopenharmony_ciint vt_do_kdgkbmeta(int console) 21938c2ecf20Sopenharmony_ci{ 21948c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 21958c2ecf20Sopenharmony_ci /* Again a spot read so no locking */ 21968c2ecf20Sopenharmony_ci return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT; 21978c2ecf20Sopenharmony_ci} 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci/** 22008c2ecf20Sopenharmony_ci * vt_reset_unicode - reset the unicode status 22018c2ecf20Sopenharmony_ci * @console: console being reset 22028c2ecf20Sopenharmony_ci * 22038c2ecf20Sopenharmony_ci * Restore the unicode console state to its default 22048c2ecf20Sopenharmony_ci */ 22058c2ecf20Sopenharmony_civoid vt_reset_unicode(int console) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci unsigned long flags; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 22108c2ecf20Sopenharmony_ci kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; 22118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci/** 22158c2ecf20Sopenharmony_ci * vt_get_shiftstate - shift bit state 22168c2ecf20Sopenharmony_ci * 22178c2ecf20Sopenharmony_ci * Report the shift bits from the keyboard state. We have to export 22188c2ecf20Sopenharmony_ci * this to support some oddities in the vt layer. 22198c2ecf20Sopenharmony_ci */ 22208c2ecf20Sopenharmony_ciint vt_get_shift_state(void) 22218c2ecf20Sopenharmony_ci{ 22228c2ecf20Sopenharmony_ci /* Don't lock as this is a transient report */ 22238c2ecf20Sopenharmony_ci return shift_state; 22248c2ecf20Sopenharmony_ci} 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci/** 22278c2ecf20Sopenharmony_ci * vt_reset_keyboard - reset keyboard state 22288c2ecf20Sopenharmony_ci * @console: console to reset 22298c2ecf20Sopenharmony_ci * 22308c2ecf20Sopenharmony_ci * Reset the keyboard bits for a console as part of a general console 22318c2ecf20Sopenharmony_ci * reset event 22328c2ecf20Sopenharmony_ci */ 22338c2ecf20Sopenharmony_civoid vt_reset_keyboard(int console) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 22368c2ecf20Sopenharmony_ci unsigned long flags; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 22398c2ecf20Sopenharmony_ci set_vc_kbd_mode(kb, VC_REPEAT); 22408c2ecf20Sopenharmony_ci clr_vc_kbd_mode(kb, VC_CKMODE); 22418c2ecf20Sopenharmony_ci clr_vc_kbd_mode(kb, VC_APPLIC); 22428c2ecf20Sopenharmony_ci clr_vc_kbd_mode(kb, VC_CRLF); 22438c2ecf20Sopenharmony_ci kb->lockstate = 0; 22448c2ecf20Sopenharmony_ci kb->slockstate = 0; 22458c2ecf20Sopenharmony_ci spin_lock(&led_lock); 22468c2ecf20Sopenharmony_ci kb->ledmode = LED_SHOW_FLAGS; 22478c2ecf20Sopenharmony_ci kb->ledflagstate = kb->default_ledflagstate; 22488c2ecf20Sopenharmony_ci spin_unlock(&led_lock); 22498c2ecf20Sopenharmony_ci /* do not do set_leds here because this causes an endless tasklet loop 22508c2ecf20Sopenharmony_ci when the keyboard hasn't been initialized yet */ 22518c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 22528c2ecf20Sopenharmony_ci} 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci/** 22558c2ecf20Sopenharmony_ci * vt_get_kbd_mode_bit - read keyboard status bits 22568c2ecf20Sopenharmony_ci * @console: console to read from 22578c2ecf20Sopenharmony_ci * @bit: mode bit to read 22588c2ecf20Sopenharmony_ci * 22598c2ecf20Sopenharmony_ci * Report back a vt mode bit. We do this without locking so the 22608c2ecf20Sopenharmony_ci * caller must be sure that there are no synchronization needs 22618c2ecf20Sopenharmony_ci */ 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ciint vt_get_kbd_mode_bit(int console, int bit) 22648c2ecf20Sopenharmony_ci{ 22658c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 22668c2ecf20Sopenharmony_ci return vc_kbd_mode(kb, bit); 22678c2ecf20Sopenharmony_ci} 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci/** 22708c2ecf20Sopenharmony_ci * vt_set_kbd_mode_bit - read keyboard status bits 22718c2ecf20Sopenharmony_ci * @console: console to read from 22728c2ecf20Sopenharmony_ci * @bit: mode bit to read 22738c2ecf20Sopenharmony_ci * 22748c2ecf20Sopenharmony_ci * Set a vt mode bit. We do this without locking so the 22758c2ecf20Sopenharmony_ci * caller must be sure that there are no synchronization needs 22768c2ecf20Sopenharmony_ci */ 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_civoid vt_set_kbd_mode_bit(int console, int bit) 22798c2ecf20Sopenharmony_ci{ 22808c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 22818c2ecf20Sopenharmony_ci unsigned long flags; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 22848c2ecf20Sopenharmony_ci set_vc_kbd_mode(kb, bit); 22858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 22868c2ecf20Sopenharmony_ci} 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci/** 22898c2ecf20Sopenharmony_ci * vt_clr_kbd_mode_bit - read keyboard status bits 22908c2ecf20Sopenharmony_ci * @console: console to read from 22918c2ecf20Sopenharmony_ci * @bit: mode bit to read 22928c2ecf20Sopenharmony_ci * 22938c2ecf20Sopenharmony_ci * Report back a vt mode bit. We do this without locking so the 22948c2ecf20Sopenharmony_ci * caller must be sure that there are no synchronization needs 22958c2ecf20Sopenharmony_ci */ 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_civoid vt_clr_kbd_mode_bit(int console, int bit) 22988c2ecf20Sopenharmony_ci{ 22998c2ecf20Sopenharmony_ci struct kbd_struct *kb = kbd_table + console; 23008c2ecf20Sopenharmony_ci unsigned long flags; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci spin_lock_irqsave(&kbd_event_lock, flags); 23038c2ecf20Sopenharmony_ci clr_vc_kbd_mode(kb, bit); 23048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&kbd_event_lock, flags); 23058c2ecf20Sopenharmony_ci} 2306