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; 52777a5510093a6d6443351160c6969a0e66f3ba8aJulia Lawall int i; 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]) { 62939e379e9e183ae6291ac7caa4a5e1dfadae4cccJulia Lawall kbd->key_maps[i] = kmemdup(key_maps[i], 63939e379e9e183ae6291ac7caa4a5e1dfadae4cccJulia Lawall sizeof(u_short) * NR_KEYS, 64939e379e9e183ae6291ac7caa4a5e1dfadae4cccJulia Lawall GFP_KERNEL); 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->key_maps[i]) 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_maps; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6988abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->func_table) 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_maps; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(func_table); i++) { 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (func_table[i]) { 74777a5510093a6d6443351160c6969a0e66f3ba8aJulia Lawall kbd->func_table[i] = kstrdup(func_table[i], 75777a5510093a6d6443351160c6969a0e66f3ba8aJulia Lawall GFP_KERNEL); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->func_table[i]) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_func; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->fn_handler = 8188abaab4f9b08381e30e737980a1c49d6b524dfcEric Sesterhenn kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->fn_handler) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_func; 84939e379e9e183ae6291ac7caa4a5e1dfadae4cccJulia Lawall kbd->accent_table = kmemdup(accent_table, 85939e379e9e183ae6291ac7caa4a5e1dfadae4cccJulia Lawall sizeof(struct kbdiacruc) * MAX_DIACR, 86939e379e9e183ae6291ac7caa4a5e1dfadae4cccJulia Lawall GFP_KERNEL); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd->accent_table) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_fn_handler; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table_size = accent_table_size; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return kbd; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_fn_handler: 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->fn_handler); 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_func: 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(func_table); i++) 9617fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->func_table[i]); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->func_table); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_maps: 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) 10017fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->key_maps[i]); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->key_maps); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_kbd: 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 105d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens return NULL; 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_free(struct kbd_data *kbd) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->accent_table); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->fn_handler); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(func_table); i++) 11617fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->func_table[i]); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->func_table); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) 11917fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->key_maps[i]); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd->key_maps); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(kbd); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generate ascii -> ebcdic translation table from kbd_data. 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short *keymap, keysym; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, k; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(ascebc, 0x40, 256); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keymap = kbd->key_maps[i]; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!keymap) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < NR_KEYS; j++) { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = ((i & 1) << 7) + j; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = keymap[j]; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(keysym) == (KT_LATIN | 0xf0) || 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KTYP(keysym) == (KT_LETTER | 0xf0)) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ascebc[KVAL(keysym)] = k; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (KTYP(keysym) == (KT_DEAD | 0xf0)) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ascebc[ret_diacr[KVAL(keysym)]] = k; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1502b67fc46061b2171fb8fbb55d1ac717abd533569Heiko Carstens#if 0 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Generate ebcdic -> ascii translation table from kbd_data. 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short *keymap, keysym; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, j, k; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(ebcasc, ' ', 256); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(key_maps); i++) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keymap = kbd->key_maps[i]; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!keymap) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < NR_KEYS; j++) { 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = keymap[j]; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds k = ((i & 1) << 7) + j; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(keysym) == (KT_LATIN | 0xf0) || 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds KTYP(keysym) == (KT_LETTER | 0xf0)) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ebcasc[k] = KVAL(keysym); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (KTYP(keysym) == (KT_DEAD | 0xf0)) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ebcasc[k] = ret_diacr[KVAL(keysym)]; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1762b67fc46061b2171fb8fbb55d1ac717abd533569Heiko Carstens#endif 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have a combining character DIACR here, followed by the character CH. 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the combination occurs in the table, return the corresponding value. 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, if CH is a space or equals DIACR, return DIACR. 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, conclude that DIACR was not combining after all, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * queue it and return CH. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibaultstatic unsigned int 18604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibaulthandle_diacr(struct kbd_data *kbd, unsigned int ch) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, d; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d = kbd->diacr; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->diacr = 0; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < kbd->accent_table_size; i++) { 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->accent_table[i].diacr == d && 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table[i].base == ch) 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return kbd->accent_table[i].result; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ch == ' ' || ch == d) 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return d; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(kbd->tty, d); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ch; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle dead key. 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_dead(struct kbd_data *kbd, unsigned char value) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = ret_diacr[value]; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Normal character handler. 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_self(struct kbd_data *kbd, unsigned char value) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->diacr) 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = handle_diacr(kbd, value); 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(kbd->tty, value); 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Special key handlers 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_ignore(struct kbd_data *kbd, unsigned char value) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function key handler. 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_fn(struct kbd_data *kbd, unsigned char value) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->func_table[value]) 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_puts_queue(kbd->tty, kbd->func_table[value]); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsk_spec(struct kbd_data *kbd, unsigned char value) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value >= NR_FN_HANDLER) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->fn_handler[value]) 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->fn_handler[value](kbd); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put utf8 character to tty flip buffer. 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UTF-8 is defined for words of up to 31 bits, 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but we need only 16 bits here 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsto_utf8(struct tty_struct *tty, ushort c) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c < 0x80) 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0******* */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, c); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (c < 0x800) { 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 110***** 10****** */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0xc0 | (c >> 6)); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0x80 | (c & 0x3f)); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1110**** 10****** 10****** */ 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0xe0 | (c >> 12)); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f)); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd_put_queue(tty, 0x80 | (c & 0x3f)); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Process keycode. 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldskbd_keycode(struct kbd_data *kbd, unsigned int keycode) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short keysym; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char type, value; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!kbd || !kbd->tty) 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (keycode >= 384) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[5][keycode - 384]; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (keycode >= 256) 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[4][keycode - 256]; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (keycode >= 128) 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[1][keycode - 128]; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keysym = kbd->key_maps[0][keycode]; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = KTYP(keysym); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type >= 0xf0) { 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type -= 0xf0; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == KT_LETTER) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds type = KT_LATIN; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = KVAL(keysym); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->sysrq) { 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kbd->sysrq == K(KT_LATIN, '-')) { 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = 0; 308f335397d177c906256ee1bba28e8c49e8ec63817Dmitry Torokhov handle_sysrq(value); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == '-') { 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = K(KT_LATIN, '-'); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Incomplete sysrq sequence. */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*k_handler[KTYP(kbd->sysrq)])(kbd, KVAL(kbd->sysrq)); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = 0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if ((type == KT_LATIN && value == '^') || 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (type == KT_DEAD && ret_diacr[value] == '^')) { 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->sysrq = K(type, value); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*k_handler[type])(kbd, value); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to_utf8(kbd->tty, keysym); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ioctl stuff. 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe, 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd, int perm) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct kbentry tmp; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *key_map, val, ov; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if NR_KEYS < 256 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.kb_index >= NR_KEYS) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if MAX_NR_KEYMAPS < 256 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.kb_table >= MAX_NR_KEYMAPS) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBENT: 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map = kbd->key_maps[tmp.kb_table]; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_map) { 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = U(key_map[tmp.kb_index]); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(val) >= KBD_NR_TYPES) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = K_HOLE; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (tmp.kb_index ? K_HOLE : K_NOSUCHMAP); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(val, &user_kbe->kb_value); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBENT: 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tmp.kb_index && tmp.kb_value == K_NOSUCHMAP) { 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disallocate map */ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map = kbd->key_maps[tmp.kb_table]; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (key_map) { 367d2c993d845781d160a7ef759a3e65c6892c4a270Heiko Carstens kbd->key_maps[tmp.kb_table] = NULL; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(key_map); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KTYP(tmp.kb_value) >= KBD_NR_TYPES) 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)]) 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(key_map = kbd->key_maps[tmp.kb_table])) { 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3815cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day key_map = kmalloc(sizeof(plain_map), 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GFP_KERNEL); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!key_map) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->key_maps[tmp.kb_table] = key_map; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (j = 0; j < NR_KEYS; j++) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[j] = U(K_HOLE); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ov = U(key_map[tmp.kb_index]); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp.kb_value == ov) 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* nothing to do */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attention Key. 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) && 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !capable(CAP_SYS_ADMIN)) 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds key_map[tmp.kb_index] = U(tmp.kb_value); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs, 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmd, int perm) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char kb_func; 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *p; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get u_kbs->kb_func. */ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(kb_func, &u_kbs->kb_func)) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if MAX_NR_FUNC < 256 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kb_func >= MAX_NR_FUNC) 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBSENT: 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = kbd->func_table[kb_func]; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p) { 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = strlen(p); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len >= sizeof(u_kbs->kb_string)) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = sizeof(u_kbs->kb_string) - 1; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(u_kbs->kb_string, p, len)) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user('\0', u_kbs->kb_string + len)) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBSENT: 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = strnlen_user(u_kbs->kb_string, 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(u_kbs->kb_string) - 1); 439172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut if (!len) 440172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut return -EFAULT; 441172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut if (len > sizeof(u_kbs->kb_string) - 1) 442172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut return -EINVAL; 443172411f10c25bbd81b19f67566af6a7f549f46a9Davi Arnaut p = kmalloc(len + 1, GFP_KERNEL); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!p) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(p, u_kbs->kb_string, len)) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(p); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p[len] = 0; 45117fd682e544556a2a829e94383239c029bb21c5eJesper Juhl kfree(kbd->func_table[kb_func]); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->func_table[kb_func] = p; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 45865c56e073e4fd10385283561b91189572e33b519Heiko Carstensint kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg) 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __user *argp; 461b652277b09d3d030cb074cc6a98ba80b34244c03Dan Carpenter unsigned int ct; 462b652277b09d3d030cb074cc6a98ba80b34244c03Dan Carpenter int perm; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds argp = (void __user *)arg; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To have permissions to do most of the vt ioctls, we either have 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBTYPE: 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return put_user(KB_101, (char __user *)argp); 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBENT: 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBENT: 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return do_kdsk_ioctl(kbd, argp, cmd, perm); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBSENT: 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBSENT: 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return do_kdgkb_ioctl(kbd, argp, cmd, perm); 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDGKBDIACR: 48104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 48204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrs __user *a = argp; 48304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacr diacr; 48404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault int i; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (put_user(kbd->accent_table_size, &a->kb_cnt)) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 48804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault for (i = 0; i < kbd->accent_table_size; i++) { 48904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault diacr.diacr = kbd->accent_table[i].diacr; 49004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault diacr.base = kbd->accent_table[i].base; 49104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault diacr.result = kbd->accent_table[i].result; 49204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) 49304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 49404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 49504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return 0; 49604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 49704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault case KDGKBDIACRUC: 49804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 49904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrsuc __user *a = argp; 50004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ct = kbd->accent_table_size; 50204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (put_user(ct, &a->kb_cnt)) 50304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 50404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_to_user(a->kbdiacruc, kbd->accent_table, 50504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault ct * sizeof(struct kbdiacruc))) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 50804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case KDSKBDIACR: 51004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 51104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrs __user *a = argp; 51204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacr diacr; 51304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault int i; 51404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!perm) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_user(ct, &a->kb_cnt)) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ct >= MAX_DIACR) 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kbd->accent_table_size = ct; 52204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault for (i = 0; i < ct; i++) { 52304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) 52404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 52504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table[i].diacr = diacr.diacr; 52604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table[i].base = diacr.base; 52704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table[i].result = diacr.result; 52804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 52904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return 0; 53004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 53104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault case KDSKBDIACRUC: 53204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault { 53304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault struct kbdiacrsuc __user *a = argp; 53404c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault 53504c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (!perm) 53604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EPERM; 53704c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (get_user(ct, &a->kb_cnt)) 53804c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EFAULT; 53904c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (ct >= MAX_DIACR) 54004c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault return -EINVAL; 54104c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault kbd->accent_table_size = ct; 54204c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault if (copy_from_user(kbd->accent_table, a->kbdiacruc, 54304c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault ct * sizeof(struct kbdiacruc))) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 54604c71976500352d02f60616d2b960267d8c5fe24Samuel Thibault } 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOIOCTLCMD; 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_ioctl); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_ascebc); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_free); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_alloc); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(kbd_keycode); 557