keyboard.c revision 5cbded585d129d0226cb48ac4202b253c781be26
1/* 2 * drivers/s390/char/keyboard.c 3 * ebcdic keycode functions for s390 console drivers 4 * 5 * S390 version 6 * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation 7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), 8 */ 9 10#include <linux/module.h> 11#include <linux/sched.h> 12#include <linux/sysrq.h> 13 14#include <linux/kbd_kern.h> 15#include <linux/kbd_diacr.h> 16#include <asm/uaccess.h> 17 18#include "keyboard.h" 19 20/* 21 * Handler Tables. 22 */ 23#define K_HANDLERS\ 24 k_self, k_fn, k_spec, k_ignore,\ 25 k_dead, k_ignore, k_ignore, k_ignore,\ 26 k_ignore, k_ignore, k_ignore, k_ignore,\ 27 k_ignore, k_ignore, k_ignore, k_ignore 28 29typedef void (k_handler_fn)(struct kbd_data *, unsigned char); 30static k_handler_fn K_HANDLERS; 31static k_handler_fn *k_handler[16] = { K_HANDLERS }; 32 33/* maximum values each key_handler can handle */ 34static const int kbd_max_vals[] = { 35 255, ARRAY_SIZE(func_table) - 1, NR_FN_HANDLER - 1, 0, 36 NR_DEAD - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 37}; 38static const int KBD_NR_TYPES = ARRAY_SIZE(kbd_max_vals); 39 40static unsigned char ret_diacr[NR_DEAD] = { 41 '`', '\'', '^', '~', '"', ',' 42}; 43 44/* 45 * Alloc/free of kbd_data structures. 46 */ 47struct kbd_data * 48kbd_alloc(void) { 49 struct kbd_data *kbd; 50 int i, len; 51 52 kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); 53 if (!kbd) 54 goto out; 55 kbd->key_maps = kzalloc(sizeof(key_maps), GFP_KERNEL); 56 if (!kbd->key_maps) 57 goto out_kbd; 58 for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 59 if (key_maps[i]) { 60 kbd->key_maps[i] = 61 kmalloc(sizeof(u_short)*NR_KEYS, GFP_KERNEL); 62 if (!kbd->key_maps[i]) 63 goto out_maps; 64 memcpy(kbd->key_maps[i], key_maps[i], 65 sizeof(u_short)*NR_KEYS); 66 } 67 } 68 kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); 69 if (!kbd->func_table) 70 goto out_maps; 71 for (i = 0; i < ARRAY_SIZE(func_table); i++) { 72 if (func_table[i]) { 73 len = strlen(func_table[i]) + 1; 74 kbd->func_table[i] = kmalloc(len, GFP_KERNEL); 75 if (!kbd->func_table[i]) 76 goto out_func; 77 memcpy(kbd->func_table[i], func_table[i], len); 78 } 79 } 80 kbd->fn_handler = 81 kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); 82 if (!kbd->fn_handler) 83 goto out_func; 84 kbd->accent_table = 85 kmalloc(sizeof(struct kbdiacr)*MAX_DIACR, GFP_KERNEL); 86 if (!kbd->accent_table) 87 goto out_fn_handler; 88 memcpy(kbd->accent_table, accent_table, 89 sizeof(struct kbdiacr)*MAX_DIACR); 90 kbd->accent_table_size = accent_table_size; 91 return kbd; 92 93out_fn_handler: 94 kfree(kbd->fn_handler); 95out_func: 96 for (i = 0; i < ARRAY_SIZE(func_table); i++) 97 kfree(kbd->func_table[i]); 98 kfree(kbd->func_table); 99out_maps: 100 for (i = 0; i < ARRAY_SIZE(key_maps); i++) 101 kfree(kbd->key_maps[i]); 102 kfree(kbd->key_maps); 103out_kbd: 104 kfree(kbd); 105out: 106 return NULL; 107} 108 109void 110kbd_free(struct kbd_data *kbd) 111{ 112 int i; 113 114 kfree(kbd->accent_table); 115 kfree(kbd->fn_handler); 116 for (i = 0; i < ARRAY_SIZE(func_table); i++) 117 kfree(kbd->func_table[i]); 118 kfree(kbd->func_table); 119 for (i = 0; i < ARRAY_SIZE(key_maps); i++) 120 kfree(kbd->key_maps[i]); 121 kfree(kbd->key_maps); 122 kfree(kbd); 123} 124 125/* 126 * Generate ascii -> ebcdic translation table from kbd_data. 127 */ 128void 129kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) 130{ 131 unsigned short *keymap, keysym; 132 int i, j, k; 133 134 memset(ascebc, 0x40, 256); 135 for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 136 keymap = kbd->key_maps[i]; 137 if (!keymap) 138 continue; 139 for (j = 0; j < NR_KEYS; j++) { 140 k = ((i & 1) << 7) + j; 141 keysym = keymap[j]; 142 if (KTYP(keysym) == (KT_LATIN | 0xf0) || 143 KTYP(keysym) == (KT_LETTER | 0xf0)) 144 ascebc[KVAL(keysym)] = k; 145 else if (KTYP(keysym) == (KT_DEAD | 0xf0)) 146 ascebc[ret_diacr[KVAL(keysym)]] = k; 147 } 148 } 149} 150 151/* 152 * Generate ebcdic -> ascii translation table from kbd_data. 153 */ 154void 155kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) 156{ 157 unsigned short *keymap, keysym; 158 int i, j, k; 159 160 memset(ebcasc, ' ', 256); 161 for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 162 keymap = kbd->key_maps[i]; 163 if (!keymap) 164 continue; 165 for (j = 0; j < NR_KEYS; j++) { 166 keysym = keymap[j]; 167 k = ((i & 1) << 7) + j; 168 if (KTYP(keysym) == (KT_LATIN | 0xf0) || 169 KTYP(keysym) == (KT_LETTER | 0xf0)) 170 ebcasc[k] = KVAL(keysym); 171 else if (KTYP(keysym) == (KT_DEAD | 0xf0)) 172 ebcasc[k] = ret_diacr[KVAL(keysym)]; 173 } 174 } 175} 176 177/* 178 * We have a combining character DIACR here, followed by the character CH. 179 * If the combination occurs in the table, return the corresponding value. 180 * Otherwise, if CH is a space or equals DIACR, return DIACR. 181 * Otherwise, conclude that DIACR was not combining after all, 182 * queue it and return CH. 183 */ 184static unsigned char 185handle_diacr(struct kbd_data *kbd, unsigned char ch) 186{ 187 int i, d; 188 189 d = kbd->diacr; 190 kbd->diacr = 0; 191 192 for (i = 0; i < kbd->accent_table_size; i++) { 193 if (kbd->accent_table[i].diacr == d && 194 kbd->accent_table[i].base == ch) 195 return kbd->accent_table[i].result; 196 } 197 198 if (ch == ' ' || ch == d) 199 return d; 200 201 kbd_put_queue(kbd->tty, d); 202 return ch; 203} 204 205/* 206 * Handle dead key. 207 */ 208static void 209k_dead(struct kbd_data *kbd, unsigned char value) 210{ 211 value = ret_diacr[value]; 212 kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value); 213} 214 215/* 216 * Normal character handler. 217 */ 218static void 219k_self(struct kbd_data *kbd, unsigned char value) 220{ 221 if (kbd->diacr) 222 value = handle_diacr(kbd, value); 223 kbd_put_queue(kbd->tty, value); 224} 225 226/* 227 * Special key handlers 228 */ 229static void 230k_ignore(struct kbd_data *kbd, unsigned char value) 231{ 232} 233 234/* 235 * Function key handler. 236 */ 237static void 238k_fn(struct kbd_data *kbd, unsigned char value) 239{ 240 if (kbd->func_table[value]) 241 kbd_puts_queue(kbd->tty, kbd->func_table[value]); 242} 243 244static void 245k_spec(struct kbd_data *kbd, unsigned char value) 246{ 247 if (value >= NR_FN_HANDLER) 248 return; 249 if (kbd->fn_handler[value]) 250 kbd->fn_handler[value](kbd); 251} 252 253/* 254 * Put utf8 character to tty flip buffer. 255 * UTF-8 is defined for words of up to 31 bits, 256 * but we need only 16 bits here 257 */ 258static void 259to_utf8(struct tty_struct *tty, ushort c) 260{ 261 if (c < 0x80) 262 /* 0******* */ 263 kbd_put_queue(tty, c); 264 else if (c < 0x800) { 265 /* 110***** 10****** */ 266 kbd_put_queue(tty, 0xc0 | (c >> 6)); 267 kbd_put_queue(tty, 0x80 | (c & 0x3f)); 268 } else { 269 /* 1110**** 10****** 10****** */ 270 kbd_put_queue(tty, 0xe0 | (c >> 12)); 271 kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f)); 272 kbd_put_queue(tty, 0x80 | (c & 0x3f)); 273 } 274} 275 276/* 277 * Process keycode. 278 */ 279void 280kbd_keycode(struct kbd_data *kbd, unsigned int keycode) 281{ 282 unsigned short keysym; 283 unsigned char type, value; 284 285 if (!kbd || !kbd->tty) 286 return; 287 288 if (keycode >= 384) 289 keysym = kbd->key_maps[5][keycode - 384]; 290 else if (keycode >= 256) 291 keysym = kbd->key_maps[4][keycode - 256]; 292 else if (keycode >= 128) 293 keysym = kbd->key_maps[1][keycode - 128]; 294 else 295 keysym = kbd->key_maps[0][keycode]; 296 297 type = KTYP(keysym); 298 if (type >= 0xf0) { 299 type -= 0xf0; 300 if (type == KT_LETTER) 301 type = KT_LATIN; 302 value = KVAL(keysym); 303#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ 304 if (kbd->sysrq) { 305 if (kbd->sysrq == K(KT_LATIN, '-')) { 306 kbd->sysrq = 0; 307 handle_sysrq(value, kbd->tty); 308 return; 309 } 310 if (value == '-') { 311 kbd->sysrq = K(KT_LATIN, '-'); 312 return; 313 } 314 /* Incomplete sysrq sequence. */ 315 (*k_handler[KTYP(kbd->sysrq)])(kbd, KVAL(kbd->sysrq)); 316 kbd->sysrq = 0; 317 } else if ((type == KT_LATIN && value == '^') || 318 (type == KT_DEAD && ret_diacr[value] == '^')) { 319 kbd->sysrq = K(type, value); 320 return; 321 } 322#endif 323 (*k_handler[type])(kbd, value); 324 } else 325 to_utf8(kbd->tty, keysym); 326} 327 328/* 329 * Ioctl stuff. 330 */ 331static int 332do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe, 333 int cmd, int perm) 334{ 335 struct kbentry tmp; 336 ushort *key_map, val, ov; 337 338 if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) 339 return -EFAULT; 340#if NR_KEYS < 256 341 if (tmp.kb_index >= NR_KEYS) 342 return -EINVAL; 343#endif 344#if MAX_NR_KEYMAPS < 256 345 if (tmp.kb_table >= MAX_NR_KEYMAPS) 346 return -EINVAL; 347#endif 348 349 switch (cmd) { 350 case KDGKBENT: 351 key_map = kbd->key_maps[tmp.kb_table]; 352 if (key_map) { 353 val = U(key_map[tmp.kb_index]); 354 if (KTYP(val) >= KBD_NR_TYPES) 355 val = K_HOLE; 356 } else 357 val = (tmp.kb_index ? K_HOLE : K_NOSUCHMAP); 358 return put_user(val, &user_kbe->kb_value); 359 case KDSKBENT: 360 if (!perm) 361 return -EPERM; 362 if (!tmp.kb_index && tmp.kb_value == K_NOSUCHMAP) { 363 /* disallocate map */ 364 key_map = kbd->key_maps[tmp.kb_table]; 365 if (key_map) { 366 kbd->key_maps[tmp.kb_table] = NULL; 367 kfree(key_map); 368 } 369 break; 370 } 371 372 if (KTYP(tmp.kb_value) >= KBD_NR_TYPES) 373 return -EINVAL; 374 if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)]) 375 return -EINVAL; 376 377 if (!(key_map = kbd->key_maps[tmp.kb_table])) { 378 int j; 379 380 key_map = kmalloc(sizeof(plain_map), 381 GFP_KERNEL); 382 if (!key_map) 383 return -ENOMEM; 384 kbd->key_maps[tmp.kb_table] = key_map; 385 for (j = 0; j < NR_KEYS; j++) 386 key_map[j] = U(K_HOLE); 387 } 388 ov = U(key_map[tmp.kb_index]); 389 if (tmp.kb_value == ov) 390 break; /* nothing to do */ 391 /* 392 * Attention Key. 393 */ 394 if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) && 395 !capable(CAP_SYS_ADMIN)) 396 return -EPERM; 397 key_map[tmp.kb_index] = U(tmp.kb_value); 398 break; 399 } 400 return 0; 401} 402 403static int 404do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, 405 int cmd, int perm) 406{ 407 unsigned char kb_func; 408 char *p; 409 int len; 410 411 /* Get u_kbs->kb_func. */ 412 if (get_user(kb_func, &u_kbs->kb_func)) 413 return -EFAULT; 414#if MAX_NR_FUNC < 256 415 if (kb_func >= MAX_NR_FUNC) 416 return -EINVAL; 417#endif 418 419 switch (cmd) { 420 case KDGKBSENT: 421 p = kbd->func_table[kb_func]; 422 if (p) { 423 len = strlen(p); 424 if (len >= sizeof(u_kbs->kb_string)) 425 len = sizeof(u_kbs->kb_string) - 1; 426 if (copy_to_user(u_kbs->kb_string, p, len)) 427 return -EFAULT; 428 } else 429 len = 0; 430 if (put_user('\0', u_kbs->kb_string + len)) 431 return -EFAULT; 432 break; 433 case KDSKBSENT: 434 if (!perm) 435 return -EPERM; 436 len = strnlen_user(u_kbs->kb_string, 437 sizeof(u_kbs->kb_string) - 1); 438 if (!len) 439 return -EFAULT; 440 if (len > sizeof(u_kbs->kb_string) - 1) 441 return -EINVAL; 442 p = kmalloc(len + 1, GFP_KERNEL); 443 if (!p) 444 return -ENOMEM; 445 if (copy_from_user(p, u_kbs->kb_string, len)) { 446 kfree(p); 447 return -EFAULT; 448 } 449 p[len] = 0; 450 kfree(kbd->func_table[kb_func]); 451 kbd->func_table[kb_func] = p; 452 break; 453 } 454 return 0; 455} 456 457int 458kbd_ioctl(struct kbd_data *kbd, struct file *file, 459 unsigned int cmd, unsigned long arg) 460{ 461 struct kbdiacrs __user *a; 462 void __user *argp; 463 int ct, perm; 464 465 argp = (void __user *)arg; 466 467 /* 468 * To have permissions to do most of the vt ioctls, we either have 469 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. 470 */ 471 perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG); 472 switch (cmd) { 473 case KDGKBTYPE: 474 return put_user(KB_101, (char __user *)argp); 475 case KDGKBENT: 476 case KDSKBENT: 477 return do_kdsk_ioctl(kbd, argp, cmd, perm); 478 case KDGKBSENT: 479 case KDSKBSENT: 480 return do_kdgkb_ioctl(kbd, argp, cmd, perm); 481 case KDGKBDIACR: 482 a = argp; 483 484 if (put_user(kbd->accent_table_size, &a->kb_cnt)) 485 return -EFAULT; 486 ct = kbd->accent_table_size; 487 if (copy_to_user(a->kbdiacr, kbd->accent_table, 488 ct * sizeof(struct kbdiacr))) 489 return -EFAULT; 490 return 0; 491 case KDSKBDIACR: 492 a = argp; 493 if (!perm) 494 return -EPERM; 495 if (get_user(ct, &a->kb_cnt)) 496 return -EFAULT; 497 if (ct >= MAX_DIACR) 498 return -EINVAL; 499 kbd->accent_table_size = ct; 500 if (copy_from_user(kbd->accent_table, a->kbdiacr, 501 ct * sizeof(struct kbdiacr))) 502 return -EFAULT; 503 return 0; 504 default: 505 return -ENOIOCTLCMD; 506 } 507} 508 509EXPORT_SYMBOL(kbd_ioctl); 510EXPORT_SYMBOL(kbd_ascebc); 511EXPORT_SYMBOL(kbd_free); 512EXPORT_SYMBOL(kbd_alloc); 513EXPORT_SYMBOL(kbd_keycode); 514