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