| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/drivers/char/keyboard.c | |||
| 3 | * | |||
| 4 | * Written for linux by Johan Myreen as a translation from | |||
| 5 | * the assembly version by Linus (with diacriticals added) | |||
| 6 | * | |||
| 7 | * Some additional features added by Christoph Niemann (ChN), March 1993 | |||
| 8 | * | |||
| 9 | * Loadable keymaps by Risto Kankkunen, May 1993 | |||
| 10 | * | |||
| 11 | * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993 | |||
| 12 | * Added decr/incr_console, dynamic keymaps, Unicode support, | |||
| 13 | * dynamic function/string keys, led setting, Sept 1994 | |||
| 14 | * `Sticky' modifier keys, 951006. | |||
| 15 | * | |||
| 16 | * 11-11-96: SAK should now work in the raw mode (Martin Mares) | |||
| 17 | * | |||
| 18 | * Modified to provide 'generic' keyboard support by Hamish Macdonald | |||
| 19 | * Merge with the m68k keyboard driver and split-off of the PC low-level | |||
| 20 | * parts by Geert Uytterhoeven, May 1997 | |||
| 21 | * | |||
| 22 | * 27-05-97: Added support for the Magic SysRq Key (Martin Mares) | |||
| 23 | * 30-07-98: Dead keys redone, aeb@cwi.nl. | |||
| 24 | * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) | |||
| 25 | */ | |||
| 26 | ||||
| 27 | #include <linux/config.h> | |||
| 28 | #include <linux/module.h> | |||
| 29 | #include <linux/sched.h> | |||
| 30 | #include <linux/tty.h> | |||
| 31 | #include <linux/tty_flip.h> | |||
| 32 | #include <linux/mm.h> | |||
| 33 | #include <linux/string.h> | |||
| 34 | #include <linux/init.h> | |||
| 35 | #include <linux/slab.h> | |||
| 36 | ||||
| 37 | #include <linux/kbd_kern.h> | |||
| 38 | #include <linux/kbd_diacr.h> | |||
| 39 | #include <linux/vt_kern.h> | |||
| 40 | #include <linux/sysrq.h> | |||
| 41 | #include <linux/input.h> | |||
| 42 | ||||
| 43 | static void kbd_disconnect(struct input_handle *handle); | |||
| 44 | extern void ctrl_alt_del(void); | |||
| 45 | ||||
| 46 | /* | |||
| 47 | * Exported functions/variables | |||
| 48 | */ | |||
| 49 | ||||
| 50 | #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) | |||
| 51 | ||||
| 52 | /* | |||
| 53 | * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. | |||
| 54 | * This seems a good reason to start with NumLock off. On HIL keyboards | |||
| 55 | * of PARISC machines however there is no NumLock key and everyone expects the keypad | |||
| 56 | * to be used for numbers. | |||
| 57 | */ | |||
| 58 | ||||
| 59 | #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) | |||
| 60 | #define KBD_DEFLEDS (1 << VC_NUMLOCK) | |||
| 61 | #else | |||
| 62 | #define KBD_DEFLEDS 0 | |||
| 63 | #endif | |||
| 64 | ||||
| 65 | #define KBD_DEFLOCK 0 | |||
| 66 | ||||
| 67 | void compute_shiftstate(void); | |||
| 68 | ||||
| 69 | /* | |||
| 70 | * Handler Tables. | |||
| 71 | */ | |||
| 72 | ||||
| 73 | #define K_HANDLERS\ | |||
| 74 | k_self, k_fn, k_spec, k_pad,\ | |||
| 75 | k_dead, k_cons, k_cur, k_shift,\ | |||
| 76 | k_meta, k_ascii, k_lock, k_lowercase,\ | |||
| 77 | k_slock, k_dead2, k_ignore, k_ignore | |||
| 78 | ||||
| 79 | typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, | |||
| 80 | char up_flag, struct pt_regs *regs); | |||
| 81 | static k_handler_fn K_HANDLERS; | |||
| 82 | static k_handler_fn *k_handler[16] = { K_HANDLERS }; | |||
| 83 | ||||
| 84 | #define FN_HANDLERS\ | |||
| 85 | fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\ | |||
| 86 | fn_show_state, fn_send_intr, fn_lastcons, fn_caps_toggle,\ | |||
| 87 | fn_num, fn_hold, fn_scroll_forw, fn_scroll_back,\ | |||
| 88 | fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\ | |||
| 89 | fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num | |||
| 90 | ||||
| 91 | typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs); | |||
| 92 | static fn_handler_fn FN_HANDLERS; | |||
| 93 | static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; | |||
| 94 | ||||
| 95 | /* | |||
| 96 | * Variables exported for vt_ioctl.c | |||
| 97 | */ | |||
| 98 | ||||
| 99 | /* maximum values each key_handler can handle */ | |||
| 100 | const int max_vals[] = { | |||
| 101 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | |||
| 102 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | |||
| 103 | 255, NR_LOCK - 1, 255 | |||
| 104 | }; | |||
| 105 | ||||
| 106 | const int NR_TYPES = ARRAY_SIZE(max_vals); | |||
| 107 | ||||
| 108 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | |||
| 109 | static struct kbd_struct *kbd = kbd_table; | |||
| 110 | static struct kbd_struct kbd0; | |||
| 111 | ||||
| 112 | int spawnpid, spawnsig; | |||
| 113 | ||||
| 114 | /* | |||
| 115 | * Variables exported for vt.c | |||
| 116 | */ | |||
| 117 | ||||
| 118 | int shift_state = 0; | |||
| 119 | ||||
| 120 | /* | |||
| 121 | * Internal Data. | |||
| 122 | */ | |||
| 123 | ||||
| 124 | static struct input_handler kbd_handler; | |||
| 125 | static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ | |||
| 126 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | |||
| 127 | static int dead_key_next; | |||
| 128 | static int npadch = -1; /* -1 or number assembled on pad */ | |||
| 129 | static unsigned char diacr; | |||
| 130 | static char rep; /* flag telling character repeat */ | |||
| 131 | ||||
| 132 | static unsigned char ledstate = 0xff; /* undefined */ | |||
| 133 | static unsigned char ledioctl; | |||
| 134 | ||||
| 135 | static struct ledptr { | |||
| 136 | unsigned int *addr; | |||
| 137 | unsigned int mask; | |||
| 138 | unsigned char valid:1; | |||
| 139 | } ledptrs[3]; | |||
| 140 | ||||
| 141 | /* Simple translation table for the SysRq keys */ | |||
| 142 | ||||
| 143 | #ifdef CONFIG_MAGIC_SYSRQ | |||
| 144 | unsigned char kbd_sysrq_xlate[KEY_MAX + 1] = | |||
| 145 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ | |||
| 146 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ | |||
| 147 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ | |||
| 148 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ | |||
| 149 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ | |||
| 150 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | |||
| 151 | "\r\000/"; /* 0x60 - 0x6f */ | |||
| 152 | static int sysrq_down; | |||
| 153 | #endif | |||
| 154 | static int sysrq_alt; | |||
| 155 | ||||
| 156 | /* | |||
| 157 | * Translation of scancodes to keycodes. We set them on only the first attached | |||
| 158 | * keyboard - for per-keyboard setting, /dev/input/event is more useful. | |||
| 159 | */ | |||
| 0 | 0 | - | 160 | int getkeycode(unsigned int scancode) |
| 161 | { | |||
| 162 | struct list_head *node; | |||
| 163 | struct input_dev *dev = NULL; | |||
| 164 | ||||
| 0 | 0 | - | 165 | list_for_each(node, &kbd_handler.h_list) { |
| 166 | struct input_handle *handle = to_handle_h(node); | |||
| 0 | 0 | - | 167 | if (handle->dev->keycodesize) { |
| 168 | dev = handle->dev; | |||
| 0 | - | 169 | break; | |
| 170 | } | |||
| 171 | } | |||
| 172 | ||||
| 0 | 0 | - | 173 | if (!dev) |
| 0 | - | 174 | return -ENODEV; | |
| 175 | ||||
| 0 | 0 | - | 176 | if (scancode >= dev->keycodemax) |
| 0 | - | 177 | return -EINVAL; | |
| 178 | ||||
| 179 | return INPUT_KEYCODE(dev, scancode); | |||
| 0 | 0 | - | 179 | ternary-?: ( dev -> keycodesize == 1 ) |
| 0 | 0 | - | 179 | ternary-?: ( dev -> keycodesize == 2 ) |
| 0 | - | 179 | return ( ( dev -> keycodesize == 1 ) ? ( ( u8 .. | |
| 180 | } | |||
| 181 | ||||
| 30 | 0 | 182 | int setkeycode(unsigned int scancode, unsigned int keycode) | |
| 183 | { | |||
| 184 | struct list_head *node; | |||
| 185 | struct input_dev *dev = NULL; | |||
| 186 | unsigned int i, oldkey; | |||
| 187 | ||||
| 30 | 0 | - | 188 | list_for_each(node, &kbd_handler.h_list) { |
| 189 | struct input_handle *handle = to_handle_h(node); | |||
| 30 | 0 | - | 190 | if (handle->dev->keycodesize) { |
| 191 | dev = handle->dev; | |||
| 30 | 192 | break; | ||
| 193 | } | |||
| 194 | } | |||
| 195 | ||||
| 0 | 30 | - | 196 | if (!dev) |
| 0 | - | 197 | return -ENODEV; | |
| 198 | ||||
| 0 | 30 | - | 199 | if (scancode >= dev->keycodemax) |
| 0 | - | 200 | return -EINVAL; | |
| 0 | 30 | - | 201 | if (keycode < 0 || keycode > KEY_MAX) |
| 0 | - | 201 | T || _ | |
| 0 | - | 201 | F || T | |
| 30 | 201 | F || F | ||
| 0 | - | 202 | return -EINVAL; | |
| 0 | 30 | - | 203 | if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) |
| 0 | - | 203 | T && (T) | |
| 30 | 203 | T && (F) | ||
| 0 | - | 203 | F && (_) | |
| 0 | - | 204 | return -EINVAL; | |
| 205 | ||||
| 206 | oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode); | |||
| 207 | ||||
| 208 | clear_bit(oldkey, dev->keybit); | |||
| 209 | set_bit(keycode, dev->keybit); | |||
| 210 | ||||
| 15360 | 30 | 211 | for (i = 0; i < dev->keycodemax; i++) | |
| 10860 | 4500 | 212 | if (INPUT_KEYCODE(dev,i) == oldkey) | |
| 15360 | 0 | - | 212 | ternary-?: ( dev -> keycodesize == 1 ) |
| 0 | 0 | - | 212 | ternary-?: ( dev -> keycodesize == 2 ) |
| 213 | set_bit(oldkey, dev->keybit); | |||
| 214 | ||||
| 30 | 215 | return 0; | ||
| 216 | } | |||
| 217 | ||||
| 218 | /* | |||
| 219 | * Making beeps and bells. | |||
| 220 | */ | |||
| 2015 | 2015 | 221 | static void kd_nosound(unsigned long ignored) | |
| 222 | { | |||
| 223 | struct list_head *node; | |||
| 224 | ||||
| 2015 | 2015 | 225 | list_for_each(node,&kbd_handler.h_list) { | |
| 226 | struct input_handle *handle = to_handle_h(node); | |||
| 0 | 2015 | - | 227 | if (test_bit(EV_SND, handle->dev->evbit)) { |
| 2015 | 0 | - | 227 | ternary-?: __builtin_constant_p ( 0x12 ) |
| 0 | 0 | - | 228 | if (test_bit(SND_TONE, handle->dev->sndbit)) |
| 0 | 0 | - | 228 | ternary-?: __builtin_constant_p ( 0x02 ) |
| 229 | input_event(handle->dev, EV_SND, SND_TONE, 0); | |||
| 0 | 0 | - | 230 | if (test_bit(SND_BELL, handle->dev->sndbit)) |
| 0 | 0 | - | 230 | ternary-?: __builtin_constant_p ( 0x01 ) |
| 231 | input_event(handle->dev, EV_SND, SND_BELL, 0); | |||
| 232 | } | |||
| 233 | } | |||
| 234 | } | |||
| 235 | ||||
| 236 | static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0); | |||
| 237 | ||||
| 2049 | 2049 | 238 | void kd_mksound(unsigned int hz, unsigned int ticks) | |
| 239 | { | |||
| 240 | struct list_head *node; | |||
| 241 | ||||
| 242 | del_timer(&kd_mksound_timer); | |||
| 243 | ||||
| 2049 | 0 | - | 244 | if (hz) { |
| 2049 | 2049 | 245 | list_for_each_prev(node, &kbd_handler.h_list) { | |
| 246 | struct input_handle *handle = to_handle_h(node); | |||
| 0 | 2049 | - | 247 | if (test_bit(EV_SND, handle->dev->evbit)) { |
| 2049 | 0 | - | 247 | ternary-?: __builtin_constant_p ( 0x12 ) |
| 0 | 0 | - | 248 | if (test_bit(SND_TONE, handle->dev->sndbit)) { |
| 0 | 0 | - | 248 | ternary-?: __builtin_constant_p ( 0x02 ) |
| 249 | input_event(handle->dev, EV_SND, SND_TONE, hz); | |||
| 0 | - | 250 | break; | |
| 251 | } | |||
| 0 | 0 | - | 252 | if (test_bit(SND_BELL, handle->dev->sndbit)) { |
| 0 | 0 | - | 252 | ternary-?: __builtin_constant_p ( 0x01 ) |
| 253 | input_event(handle->dev, EV_SND, SND_BELL, 1); | |||
| 0 | - | 254 | break; | |
| 255 | } | |||
| 256 | } | |||
| 257 | } | |||
| 2049 | 0 | - | 258 | if (ticks) |
| 259 | mod_timer(&kd_mksound_timer, jiffies + ticks); | |||
| 260 | } else | |||
| 261 | kd_nosound(0); | |||
| 262 | } | |||
| 263 | ||||
| 264 | /* | |||
| 265 | * Setting the keyboard rate. | |||
| 266 | */ | |||
| 267 | ||||
| 12 | 0 | 268 | int kbd_rate(struct kbd_repeat *rep) | |
| 269 | { | |||
| 270 | struct list_head *node; | |||
| 271 | unsigned int d = 0; | |||
| 272 | unsigned int p = 0; | |||
| 273 | ||||
| 12 | 12 | 274 | list_for_each(node,&kbd_handler.h_list) { | |
| 275 | struct input_handle *handle = to_handle_h(node); | |||
| 276 | struct input_dev *dev = handle->dev; | |||
| 277 | ||||
| 12 | 0 | - | 278 | if (test_bit(EV_REP, dev->evbit)) { |
| 12 | 0 | - | 278 | ternary-?: __builtin_constant_p ( 0x14 ) |
| 6 | 6 | 279 | if (rep->delay > 0) | |
| 280 | input_event(dev, EV_REP, REP_DELAY, rep->delay); | |||
| 6 | 6 | 281 | if (rep->period > 0) | |
| 282 | input_event(dev, EV_REP, REP_PERIOD, rep->period); | |||
| 283 | d = dev->rep[REP_DELAY]; | |||
| 284 | p = dev->rep[REP_PERIOD]; | |||
| 285 | } | |||
| 286 | } | |||
| 287 | rep->delay = d; | |||
| 288 | rep->period = p; | |||
| 12 | 289 | return 0; | ||
| 290 | } | |||
| 291 | ||||
| 292 | /* | |||
| 293 | * Helper Functions. | |||
| 294 | */ | |||
| 249213 | 249213 | 295 | static void put_queue(struct vc_data *vc, int ch) | |
| 296 | { | |||
| 297 | struct tty_struct *tty = vc->vc_tty; | |||
| 298 | ||||
| 249213 | 0 | - | 299 | if (tty) { |
| 300 | tty_insert_flip_char(tty, ch, 0); | |||
| 301 | con_schedule_flip(tty); | |||
| 302 | } | |||
| 303 | } | |||
| 304 | ||||
| 4 | 4 | 305 | static void puts_queue(struct vc_data *vc, char *cp) | |
| 306 | { | |||
| 307 | struct tty_struct *tty = vc->vc_tty; | |||
| 308 | ||||
| 0 | 4 | - | 309 | if (!tty) |
| 0 | - | 310 | return; | |
| 311 | ||||
| 12 | 4 | 312 | while (*cp) { | |
| 313 | tty_insert_flip_char(tty, *cp, 0); | |||
| 314 | cp++; | |||
| 315 | } | |||
| 316 | con_schedule_flip(tty); | |||
| 317 | } | |||
| 318 | ||||
| 4 | 4 | 319 | static void applkey(struct vc_data *vc, int key, char mode) | |
| 320 | { | |||
| 321 | static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; | |||
| 322 | ||||
| 323 | buf[1] = (mode ? 'O' : '['); | |||
| 0 | 4 | - | 323 | ternary-?: mode |
| 324 | buf[2] = key; | |||
| 325 | puts_queue(vc, buf); | |||
| 326 | } | |||
| 327 | ||||
| 328 | /* | |||
| 329 | * Many other routines do put_queue, but I think either | |||
| 330 | * they produce ASCII, or they produce some user-assigned | |||
| 331 | * string, and in both cases we might assume that it is | |||
| 332 | * in utf-8 already. UTF-8 is defined for words of up to 31 bits, | |||
| 333 | * but we need only 16 bits here | |||
| 334 | */ | |||
| 0 | 0 | - | 335 | static void to_utf8(struct vc_data *vc, ushort c) |
| 336 | { | |||
| 0 | 0 | - | 337 | if (c < 0x80) |
| 338 | /* 0******* */ | |||
| 339 | put_queue(vc, c); | |||
| 0 | 0 | - | 340 | else if (c < 0x800) { |
| 341 | /* 110***** 10****** */ | |||
| 342 | put_queue(vc, 0xc0 | (c >> 6)); | |||
| 343 | put_queue(vc, 0x80 | (c & 0x3f)); | |||
| 344 | } else { | |||
| 345 | /* 1110**** 10****** 10****** */ | |||
| 346 | put_queue(vc, 0xe0 | (c >> 12)); | |||
| 347 | put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); | |||
| 348 | put_queue(vc, 0x80 | (c & 0x3f)); | |||
| 349 | } | |||
| 350 | } | |||
| 351 | ||||
| 352 | /* | |||
| 353 | * Called after returning from RAW mode or when changing consoles - recompute | |||
| 354 | * shift_down[] and shift_state from key_down[] maybe called when keymap is | |||
| 355 | * undefined, so that shiftkey release is seen | |||
| 356 | */ | |||
| 52 | 52 | 357 | void compute_shiftstate(void) | |
| 358 | { | |||
| 359 | unsigned int i, j, k, sym, val; | |||
| 360 | ||||
| 361 | shift_state = 0; | |||
| 362 | memset(shift_down, 0, sizeof(shift_down)); | |||
| 363 | ||||
| 416 | 52 | 364 | for (i = 0; i < ARRAY_SIZE(key_down); i++) { | |
| 365 | ||||
| 390 | 26 | 366 | if (!key_down[i]) | |
| 390 | 367 | continue; | ||
| 368 | ||||
| 369 | k = i * BITS_PER_LONG; | |||
| 370 | ||||
| 1664 | 26 | 371 | for (j = 0; j < BITS_PER_LONG; j++, k++) { | |
| 372 | ||||
| 1624 | 40 | 373 | if (!test_bit(k, key_down)) | |
| 0 | 1664 | - | 373 | ternary-?: __builtin_constant_p ( k ) |
| 1624 | 374 | continue; | ||
| 375 | ||||
| 376 | sym = U(key_maps[0][k]); | |||
| 14 | 26 | 377 | if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK) | |
| 14 | 377 | T && T | ||
| 0 | - | 377 | T && F | |
| 26 | 377 | F && _ | ||
| 14 | 378 | continue; | ||
| 379 | ||||
| 380 | val = KVAL(sym); | |||
| 0 | 26 | - | 381 | if (val == KVAL(K_CAPSSHIFT)) |
| 382 | val = KVAL(K_SHIFT); | |||
| 383 | ||||
| 384 | shift_down[val]++; | |||
| 385 | shift_state |= (1 << val); | |||
| 386 | } | |||
| 387 | } | |||
| 388 | } | |||
| 389 | ||||
| 390 | /* | |||
| 391 | * We have a combining character DIACR here, followed by the character CH. | |||
| 392 | * If the combination occurs in the table, return the corresponding value. | |||
| 393 | * Otherwise, if CH is a space or equals DIACR, return DIACR. | |||
| 394 | * Otherwise, conclude that DIACR was not combining after all, | |||
| 395 | * queue it and return CH. | |||
| 396 | */ | |||
| 0 | 0 | - | 397 | static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) |
| 398 | { | |||
| 399 | int d = diacr; | |||
| 400 | unsigned int i; | |||
| 401 | ||||
| 402 | diacr = 0; | |||
| 403 | ||||
| 0 | 0 | - | 404 | for (i = 0; i < accent_table_size; i++) { |
| 0 | 0 | - | 405 | if (accent_table[i].diacr == d && accent_table[i].base == ch) |
| 0 | - | 405 | T && T | |
| 0 | - | 405 | T && F | |
| 0 | - | 405 | F && _ | |
| 0 | - | 406 | return accent_table[i].result; | |
| 407 | } | |||
| 408 | ||||
| 0 | 0 | - | 409 | if (ch == ' ' || ch == d) |
| 0 | - | 409 | T || _ | |
| 0 | - | 409 | F || T | |
| 0 | - | 409 | F || F | |
| 0 | - | 410 | return d; | |
| 411 | ||||
| 412 | put_queue(vc, d); | |||
| 0 | - | 413 | return ch; | |
| 414 | } | |||
| 415 | ||||
| 416 | /* | |||
| 417 | * Special function handlers | |||
| 418 | */ | |||
| 51 | 51 | 419 | static void fn_enter(struct vc_data *vc, struct pt_regs *regs) | |
| 420 | { | |||
| 0 | 51 | - | 421 | if (diacr) { |
| 422 | put_queue(vc, diacr); | |||
| 423 | diacr = 0; | |||
| 424 | } | |||
| 425 | put_queue(vc, 13); | |||
| 0 | 51 | - | 426 | if (vc_kbd_mode(kbd, VC_CRLF)) |
| 427 | put_queue(vc, 10); | |||
| 428 | } | |||
| 429 | ||||
| 0 | 0 | - | 430 | static void fn_caps_toggle(struct vc_data *vc, struct pt_regs *regs) |
| 431 | { | |||
| 0 | 0 | - | 432 | if (rep) |
| 0 | - | 433 | return; | |
| 434 | chg_vc_kbd_led(kbd, VC_CAPSLOCK); | |||
| 435 | } | |||
| 436 | ||||
| 0 | 0 | - | 437 | static void fn_caps_on(struct vc_data *vc, struct pt_regs *regs) |
| 438 | { | |||
| 0 | 0 | - | 439 | if (rep) |
| 0 | - | 440 | return; | |
| 441 | set_vc_kbd_led(kbd, VC_CAPSLOCK); | |||
| 442 | } | |||
| 443 | ||||
| 0 | 0 | - | 444 | static void fn_show_ptregs(struct vc_data *vc, struct pt_regs *regs) |
| 445 | { | |||
| 0 | 0 | - | 446 | if (regs) |
| 447 | show_regs(regs); | |||
| 448 | } | |||
| 449 | ||||
| 0 | 0 | - | 450 | static void fn_hold(struct vc_data *vc, struct pt_regs *regs) |
| 451 | { | |||
| 452 | struct tty_struct *tty = vc->vc_tty; | |||
| 453 | ||||
| 0 | 0 | - | 454 | if (rep || !tty) |
| 0 | - | 454 | T || _ | |
| 0 | - | 454 | F || T | |
| 0 | - | 454 | F || F | |
| 0 | - | 455 | return; | |
| 456 | ||||
| 457 | /* | |||
| 458 | * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty); | |||
| 459 | * these routines are also activated by ^S/^Q. | |||
| 460 | * (And SCROLLOCK can also be set by the ioctl KDSKBLED.) | |||
| 461 | */ | |||
| 0 | 0 | - | 462 | if (tty->stopped) |
| 463 | start_tty(tty); | |||
| 464 | else | |||
| 465 | stop_tty(tty); | |||
| 466 | } | |||
| 467 | ||||
| 0 | 0 | - | 468 | static void fn_num(struct vc_data *vc, struct pt_regs *regs) |
| 469 | { | |||
| 0 | 0 | - | 470 | if (vc_kbd_mode(kbd,VC_APPLIC)) |
| 471 | applkey(vc, 'P', 1); | |||
| 472 | else | |||
| 473 | fn_bare_num(vc, regs); | |||
| 474 | } | |||
| 475 | ||||
| 476 | /* | |||
| 477 | * Bind this to Shift-NumLock if you work in application keypad mode | |||
| 478 | * but want to be able to change the NumLock flag. | |||
| 479 | * Bind this to NumLock if you prefer that the NumLock key always | |||
| 480 | * changes the NumLock flag. | |||
| 481 | */ | |||
| 0 | 0 | - | 482 | static void fn_bare_num(struct vc_data *vc, struct pt_regs *regs) |
| 483 | { | |||
| 0 | 0 | - | 484 | if (!rep) |
| 485 | chg_vc_kbd_led(kbd, VC_NUMLOCK); | |||
| 486 | } | |||
| 487 | ||||
| 0 | 0 | - | 488 | static void fn_lastcons(struct vc_data *vc, struct pt_regs *regs) |
| 489 | { | |||
| 490 | /* switch to the last used console, ChN */ | |||
| 491 | set_console(last_console); | |||
| 492 | } | |||
| 493 | ||||
| 0 | 0 | - | 494 | static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs) |
| 495 | { | |||
| 496 | int i, cur = fg_console; | |||
| 497 | ||||
| 498 | /* Currently switching? Queue this next switch relative to that. */ | |||
| 0 | 0 | - | 499 | if (want_console != -1) |
| 500 | cur = want_console; | |||
| 501 | ||||
| 0 | 0 | - | 502 | for (i = cur - 1; i != cur; i--) { |
| 0 | 0 | - | 503 | if (i == -1) |
| 504 | i = MAX_NR_CONSOLES - 1; | |||
| 0 | 0 | - | 505 | if (vc_cons_allocated(i)) |
| 0 | - | 506 | break; | |
| 507 | } | |||
| 508 | set_console(i); | |||
| 509 | } | |||
| 510 | ||||
| 0 | 0 | - | 511 | static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs) |
| 512 | { | |||
| 513 | int i, cur = fg_console; | |||
| 514 | ||||