keyboard.c revision 5a0e3ad6af8660be21ca98a971cd00f331318c05
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers/s390/char/keyboard.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ebcdic keycode functions for s390 console drivers 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * S390 version 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 125a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysrq.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault#include <linux/consolemap.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_kern.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kbd_diacr.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "keyboard.h" 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handler Tables. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define K_HANDLERS\ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k_self, k_fn, k_spec, k_ignore,\ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k_dead, k_ignore, k_ignore, k_ignore,\ 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k_ignore, k_ignore, k_ignore, k_ignore,\ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k_ignore, k_ignore, k_ignore, k_ignore 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef void (k_handler_fn)(struct kbd_data *, unsigned char); 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic k_handler_fn K_HANDLERS; 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic k_handler_fn *k_handler[16] = { K_HANDLERS }; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* maximum values each key_handler can handle */ 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const int kbd_max_vals[] = { 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 255, ARRAY_SIZE(func_table) - 1, NR_FN_HANDLER - 1, 0, 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NR_DEAD - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const int KBD_NR_TYPES = ARRAY_SIZE(kbd_max_vals); 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char ret_diacr[NR_DEAD] = { 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds '`', '\'', '^', '~', '"', ',' 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Alloc/free of kbd_data structures. 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct kbd_data * 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_alloc(void) { 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbd_data *kbd; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, len; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5488abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd) 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5788abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn kbd->key_maps = kzalloc(sizeof(key_maps), GFP_KERNEL); 58da074d0ac8ccae1068dc227ef9893c2510d23bd8Peter Oberparleiter if (!kbd->key_maps) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_kbd; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_maps[i]) { 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->key_maps[i] = 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kmalloc(sizeof(u_short)*NR_KEYS, GFP_KERNEL); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->key_maps[i]) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_maps; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(kbd->key_maps[i], key_maps[i], 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(u_short)*NR_KEYS); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7088abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->func_table) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_maps; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(func_table); i++) { 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func_table[i]) { 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = strlen(func_table[i]) + 1; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->func_table[i] = kmalloc(len, GFP_KERNEL); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->func_table[i]) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_func; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(kbd->func_table[i], func_table[i], len); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->fn_handler = 8388abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->fn_handler) 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_func; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table = 8704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->accent_table) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_fn_handler; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(kbd->accent_table, accent_table, 9104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault sizeof(struct kbdiacruc)*MAX_DIACR); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table_size = accent_table_size; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return kbd; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_fn_handler: 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->fn_handler); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_func: 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(func_table); i++) 9917fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->func_table[i]); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->func_table); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_maps: 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) 10317fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->key_maps[i]); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->key_maps); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_kbd: 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 108d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens return NULL; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_free(struct kbd_data *kbd) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->accent_table); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->fn_handler); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(func_table); i++) 11917fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->func_table[i]); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->func_table); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) 12217fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->key_maps[i]); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->key_maps); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generate ascii -> ebcdic translation table from kbd_data. 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short *keymap, keysym; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, k; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(ascebc, 0x40, 256); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keymap = kbd->key_maps[i]; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!keymap) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < NR_KEYS; j++) { 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = ((i & 1) << 7) + j; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = keymap[j]; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(keysym) == (KT_LATIN | 0xf0) || 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KTYP(keysym) == (KT_LETTER | 0xf0)) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ascebc[KVAL(keysym)] = k; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (KTYP(keysym) == (KT_DEAD | 0xf0)) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ascebc[ret_diacr[KVAL(keysym)]] = k; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1532b67fc46061b2171fb8fbb55d1ac717abd533569Heiko Carstens#if 0 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generate ebcdic -> ascii translation table from kbd_data. 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short *keymap, keysym; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, k; 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(ebcasc, ' ', 256); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keymap = kbd->key_maps[i]; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!keymap) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < NR_KEYS; j++) { 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = keymap[j]; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = ((i & 1) << 7) + j; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(keysym) == (KT_LATIN | 0xf0) || 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KTYP(keysym) == (KT_LETTER | 0xf0)) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ebcasc[k] = KVAL(keysym); 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (KTYP(keysym) == (KT_DEAD | 0xf0)) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ebcasc[k] = ret_diacr[KVAL(keysym)]; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1792b67fc46061b2171fb8fbb55d1ac717abd533569Heiko Carstens#endif 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have a combining character DIACR here, followed by the character CH. 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the combination occurs in the table, return the corresponding value. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, if CH is a space or equals DIACR, return DIACR. 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, conclude that DIACR was not combining after all, 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * queue it and return CH. 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibaultstatic unsigned int 18904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibaulthandle_diacr(struct kbd_data *kbd, unsigned int ch) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, d; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d = kbd->diacr; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->diacr = 0; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < kbd->accent_table_size; i++) { 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->accent_table[i].diacr == d && 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table[i].base == ch) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return kbd->accent_table[i].result; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch == ' ' || ch == d) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return d; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(kbd->tty, d); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ch; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle dead key. 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_dead(struct kbd_data *kbd, unsigned char value) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = ret_diacr[value]; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Normal character handler. 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_self(struct kbd_data *kbd, unsigned char value) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->diacr) 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = handle_diacr(kbd, value); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(kbd->tty, value); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special key handlers 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_ignore(struct kbd_data *kbd, unsigned char value) 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function key handler. 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_fn(struct kbd_data *kbd, unsigned char value) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->func_table[value]) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_puts_queue(kbd->tty, kbd->func_table[value]); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_spec(struct kbd_data *kbd, unsigned char value) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value >= NR_FN_HANDLER) 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->fn_handler[value]) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->fn_handler[value](kbd); 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put utf8 character to tty flip buffer. 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UTF-8 is defined for words of up to 31 bits, 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but we need only 16 bits here 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsto_utf8(struct tty_struct *tty, ushort c) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c < 0x80) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0******* */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, c); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (c < 0x800) { 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 110***** 10****** */ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0xc0 | (c >> 6)); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0x80 | (c & 0x3f)); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1110**** 10****** 10****** */ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0xe0 | (c >> 12)); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f)); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0x80 | (c & 0x3f)); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process keycode. 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_keycode(struct kbd_data *kbd, unsigned int keycode) 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short keysym; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char type, value; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd || !kbd->tty) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (keycode >= 384) 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[5][keycode - 384]; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (keycode >= 256) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[4][keycode - 256]; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (keycode >= 128) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[1][keycode - 128]; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[0][keycode]; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = KTYP(keysym); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type >= 0xf0) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type -= 0xf0; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == KT_LETTER) 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = KT_LATIN; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = KVAL(keysym); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->sysrq) { 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->sysrq == K(KT_LATIN, '-')) { 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = 0; 3115a489b9846f688db7e69aa7ccb23c53459a9c20eHeiko Carstens handle_sysrq(value, kbd->tty); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == '-') { 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = K(KT_LATIN, '-'); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Incomplete sysrq sequence. */ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*k_handler[KTYP(kbd->sysrq)])(kbd, KVAL(kbd->sysrq)); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = 0; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((type == KT_LATIN && value == '^') || 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (type == KT_DEAD && ret_diacr[value] == '^')) { 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = K(type, value); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*k_handler[type])(kbd, value); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_utf8(kbd->tty, keysym); 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ioctl stuff. 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe, 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd, int perm) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbentry tmp; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *key_map, val, ov; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if NR_KEYS < 256 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.kb_index >= NR_KEYS) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if MAX_NR_KEYMAPS < 256 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.kb_table >= MAX_NR_KEYMAPS) 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBENT: 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map = kbd->key_maps[tmp.kb_table]; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_map) { 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = U(key_map[tmp.kb_index]); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(val) >= KBD_NR_TYPES) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = K_HOLE; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (tmp.kb_index ? K_HOLE : K_NOSUCHMAP); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(val, &user_kbe->kb_value); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBENT: 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tmp.kb_index && tmp.kb_value == K_NOSUCHMAP) { 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disallocate map */ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map = kbd->key_maps[tmp.kb_table]; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_map) { 370d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens kbd->key_maps[tmp.kb_table] = NULL; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(key_map); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(tmp.kb_value) >= KBD_NR_TYPES) 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)]) 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(key_map = kbd->key_maps[tmp.kb_table])) { 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3845cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day key_map = kmalloc(sizeof(plain_map), 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_KERNEL); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!key_map) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->key_maps[tmp.kb_table] = key_map; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < NR_KEYS; j++) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[j] = U(K_HOLE); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ov = U(key_map[tmp.kb_index]); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.kb_value == ov) 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* nothing to do */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attention Key. 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) && 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !capable(CAP_SYS_ADMIN)) 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[tmp.kb_index] = U(tmp.kb_value); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd, int perm) 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char kb_func; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *p; 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get u_kbs->kb_func. */ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(kb_func, &u_kbs->kb_func)) 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if MAX_NR_FUNC < 256 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kb_func >= MAX_NR_FUNC) 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBSENT: 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = kbd->func_table[kb_func]; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p) { 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = strlen(p); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len >= sizeof(u_kbs->kb_string)) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = sizeof(u_kbs->kb_string) - 1; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(u_kbs->kb_string, p, len)) 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user('\0', u_kbs->kb_string + len)) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBSENT: 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = strnlen_user(u_kbs->kb_string, 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(u_kbs->kb_string) - 1); 442172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut if (!len) 443172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut return -EFAULT; 444172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut if (len > sizeof(u_kbs->kb_string) - 1) 445172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut return -EINVAL; 446172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut p = kmalloc(len + 1, GFP_KERNEL); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!p) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(p, u_kbs->kb_string, len)) { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(p); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p[len] = 0; 45417fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->func_table[kb_func]); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->func_table[kb_func] = p; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_ioctl(struct kbd_data *kbd, struct file *file, 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cmd, unsigned long arg) 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ct, perm; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds argp = (void __user *)arg; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To have permissions to do most of the vt ioctls, we either have 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBTYPE: 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(KB_101, (char __user *)argp); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBENT: 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBENT: 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return do_kdsk_ioctl(kbd, argp, cmd, perm); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBSENT: 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBSENT: 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return do_kdgkb_ioctl(kbd, argp, cmd, perm); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBDIACR: 48504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 48604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrs __user *a = argp; 48704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacr diacr; 48804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault int i; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(kbd->accent_table_size, &a->kb_cnt)) 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 49204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault for (i = 0; i < kbd->accent_table_size; i++) { 49304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault diacr.diacr = kbd->accent_table[i].diacr; 49404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault diacr.base = kbd->accent_table[i].base; 49504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault diacr.result = kbd->accent_table[i].result; 49604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) 49704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 49804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 49904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return 0; 50004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 50104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault case KDGKBDIACRUC: 50204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 50304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrsuc __user *a = argp; 50404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ct = kbd->accent_table_size; 50604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (put_user(ct, &a->kb_cnt)) 50704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 50804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_to_user(a->kbdiacruc, kbd->accent_table, 50904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault ct * sizeof(struct kbdiacruc))) 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 51204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBDIACR: 51404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 51504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrs __user *a = argp; 51604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacr diacr; 51704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault int i; 51804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(ct, &a->kb_cnt)) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ct >= MAX_DIACR) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table_size = ct; 52604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault for (i = 0; i < ct; i++) { 52704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) 52804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 52904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table[i].diacr = diacr.diacr; 53004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table[i].base = diacr.base; 53104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table[i].result = diacr.result; 53204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 53304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return 0; 53404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 53504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault case KDSKBDIACRUC: 53604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 53704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrsuc __user *a = argp; 53804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault 53904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (!perm) 54004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EPERM; 54104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (get_user(ct, &a->kb_cnt)) 54204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 54304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (ct >= MAX_DIACR) 54404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EINVAL; 54504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table_size = ct; 54604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_from_user(kbd->accent_table, a->kbdiacruc, 54704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault ct * sizeof(struct kbdiacruc))) 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 55004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_ioctl); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_ascebc); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_free); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_alloc); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_keycode); 561