0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/module.h>
0011 #include <linux/sched/signal.h>
0012 #include <linux/slab.h>
0013 #include <linux/sysrq.h>
0014
0015 #include <linux/consolemap.h>
0016 #include <linux/kbd_kern.h>
0017 #include <linux/kbd_diacr.h>
0018 #include <linux/uaccess.h>
0019
0020 #include "keyboard.h"
0021
0022
0023
0024
0025 #define K_HANDLERS\
0026 k_self, k_fn, k_spec, k_ignore,\
0027 k_dead, k_ignore, k_ignore, k_ignore,\
0028 k_ignore, k_ignore, k_ignore, k_ignore,\
0029 k_ignore, k_ignore, k_ignore, k_ignore
0030
0031 typedef void (k_handler_fn)(struct kbd_data *, unsigned char);
0032 static k_handler_fn K_HANDLERS;
0033 static k_handler_fn *k_handler[16] = { K_HANDLERS };
0034
0035
0036 static const int kbd_max_vals[] = {
0037 255, ARRAY_SIZE(func_table) - 1, NR_FN_HANDLER - 1, 0,
0038 NR_DEAD - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0
0039 };
0040 static const int KBD_NR_TYPES = ARRAY_SIZE(kbd_max_vals);
0041
0042 static const unsigned char ret_diacr[NR_DEAD] = {
0043 '`',
0044 '\'',
0045 '^',
0046 '~',
0047 '"',
0048 ',',
0049 '_',
0050 'U',
0051 '.',
0052 '*',
0053 '=',
0054 'c',
0055 'k',
0056 'i',
0057 '#',
0058 'o',
0059 '!',
0060 '?',
0061 '+',
0062 '-',
0063 ')',
0064 '(',
0065 ':',
0066 'n',
0067 ';',
0068 '$',
0069 '@',
0070 };
0071
0072
0073
0074
0075 struct kbd_data *
0076 kbd_alloc(void) {
0077 struct kbd_data *kbd;
0078 int i;
0079
0080 kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL);
0081 if (!kbd)
0082 goto out;
0083 kbd->key_maps = kzalloc(sizeof(ebc_key_maps), GFP_KERNEL);
0084 if (!kbd->key_maps)
0085 goto out_kbd;
0086 for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) {
0087 if (ebc_key_maps[i]) {
0088 kbd->key_maps[i] = kmemdup(ebc_key_maps[i],
0089 sizeof(u_short) * NR_KEYS,
0090 GFP_KERNEL);
0091 if (!kbd->key_maps[i])
0092 goto out_maps;
0093 }
0094 }
0095 kbd->func_table = kzalloc(sizeof(ebc_func_table), GFP_KERNEL);
0096 if (!kbd->func_table)
0097 goto out_maps;
0098 for (i = 0; i < ARRAY_SIZE(ebc_func_table); i++) {
0099 if (ebc_func_table[i]) {
0100 kbd->func_table[i] = kstrdup(ebc_func_table[i],
0101 GFP_KERNEL);
0102 if (!kbd->func_table[i])
0103 goto out_func;
0104 }
0105 }
0106 kbd->fn_handler =
0107 kcalloc(NR_FN_HANDLER, sizeof(fn_handler_fn *), GFP_KERNEL);
0108 if (!kbd->fn_handler)
0109 goto out_func;
0110 kbd->accent_table = kmemdup(ebc_accent_table,
0111 sizeof(struct kbdiacruc) * MAX_DIACR,
0112 GFP_KERNEL);
0113 if (!kbd->accent_table)
0114 goto out_fn_handler;
0115 kbd->accent_table_size = ebc_accent_table_size;
0116 return kbd;
0117
0118 out_fn_handler:
0119 kfree(kbd->fn_handler);
0120 out_func:
0121 for (i = 0; i < ARRAY_SIZE(ebc_func_table); i++)
0122 kfree(kbd->func_table[i]);
0123 kfree(kbd->func_table);
0124 out_maps:
0125 for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++)
0126 kfree(kbd->key_maps[i]);
0127 kfree(kbd->key_maps);
0128 out_kbd:
0129 kfree(kbd);
0130 out:
0131 return NULL;
0132 }
0133
0134 void
0135 kbd_free(struct kbd_data *kbd)
0136 {
0137 int i;
0138
0139 kfree(kbd->accent_table);
0140 kfree(kbd->fn_handler);
0141 for (i = 0; i < ARRAY_SIZE(ebc_func_table); i++)
0142 kfree(kbd->func_table[i]);
0143 kfree(kbd->func_table);
0144 for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++)
0145 kfree(kbd->key_maps[i]);
0146 kfree(kbd->key_maps);
0147 kfree(kbd);
0148 }
0149
0150
0151
0152
0153 void
0154 kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
0155 {
0156 unsigned short *keymap, keysym;
0157 int i, j, k;
0158
0159 memset(ascebc, 0x40, 256);
0160 for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) {
0161 keymap = kbd->key_maps[i];
0162 if (!keymap)
0163 continue;
0164 for (j = 0; j < NR_KEYS; j++) {
0165 k = ((i & 1) << 7) + j;
0166 keysym = keymap[j];
0167 if (KTYP(keysym) == (KT_LATIN | 0xf0) ||
0168 KTYP(keysym) == (KT_LETTER | 0xf0))
0169 ascebc[KVAL(keysym)] = k;
0170 else if (KTYP(keysym) == (KT_DEAD | 0xf0))
0171 ascebc[ret_diacr[KVAL(keysym)]] = k;
0172 }
0173 }
0174 }
0175
0176 #if 0
0177
0178
0179
0180 void
0181 kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
0182 {
0183 unsigned short *keymap, keysym;
0184 int i, j, k;
0185
0186 memset(ebcasc, ' ', 256);
0187 for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) {
0188 keymap = kbd->key_maps[i];
0189 if (!keymap)
0190 continue;
0191 for (j = 0; j < NR_KEYS; j++) {
0192 keysym = keymap[j];
0193 k = ((i & 1) << 7) + j;
0194 if (KTYP(keysym) == (KT_LATIN | 0xf0) ||
0195 KTYP(keysym) == (KT_LETTER | 0xf0))
0196 ebcasc[k] = KVAL(keysym);
0197 else if (KTYP(keysym) == (KT_DEAD | 0xf0))
0198 ebcasc[k] = ret_diacr[KVAL(keysym)];
0199 }
0200 }
0201 }
0202 #endif
0203
0204
0205
0206
0207
0208
0209
0210
0211 static unsigned int
0212 handle_diacr(struct kbd_data *kbd, unsigned int ch)
0213 {
0214 int i, d;
0215
0216 d = kbd->diacr;
0217 kbd->diacr = 0;
0218
0219 for (i = 0; i < kbd->accent_table_size; i++) {
0220 if (kbd->accent_table[i].diacr == d &&
0221 kbd->accent_table[i].base == ch)
0222 return kbd->accent_table[i].result;
0223 }
0224
0225 if (ch == ' ' || ch == d)
0226 return d;
0227
0228 kbd_put_queue(kbd->port, d);
0229 return ch;
0230 }
0231
0232
0233
0234
0235 static void
0236 k_dead(struct kbd_data *kbd, unsigned char value)
0237 {
0238 value = ret_diacr[value];
0239 kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
0240 }
0241
0242
0243
0244
0245 static void
0246 k_self(struct kbd_data *kbd, unsigned char value)
0247 {
0248 if (kbd->diacr)
0249 value = handle_diacr(kbd, value);
0250 kbd_put_queue(kbd->port, value);
0251 }
0252
0253
0254
0255
0256 static void
0257 k_ignore(struct kbd_data *kbd, unsigned char value)
0258 {
0259 }
0260
0261
0262
0263
0264 static void
0265 k_fn(struct kbd_data *kbd, unsigned char value)
0266 {
0267 if (kbd->func_table[value])
0268 kbd_puts_queue(kbd->port, kbd->func_table[value]);
0269 }
0270
0271 static void
0272 k_spec(struct kbd_data *kbd, unsigned char value)
0273 {
0274 if (value >= NR_FN_HANDLER)
0275 return;
0276 if (kbd->fn_handler[value])
0277 kbd->fn_handler[value](kbd);
0278 }
0279
0280
0281
0282
0283
0284
0285 static void
0286 to_utf8(struct tty_port *port, ushort c)
0287 {
0288 if (c < 0x80)
0289
0290 kbd_put_queue(port, c);
0291 else if (c < 0x800) {
0292
0293 kbd_put_queue(port, 0xc0 | (c >> 6));
0294 kbd_put_queue(port, 0x80 | (c & 0x3f));
0295 } else {
0296
0297 kbd_put_queue(port, 0xe0 | (c >> 12));
0298 kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
0299 kbd_put_queue(port, 0x80 | (c & 0x3f));
0300 }
0301 }
0302
0303
0304
0305
0306 void
0307 kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
0308 {
0309 unsigned short keysym;
0310 unsigned char type, value;
0311
0312 if (!kbd)
0313 return;
0314
0315 if (keycode >= 384)
0316 keysym = kbd->key_maps[5][keycode - 384];
0317 else if (keycode >= 256)
0318 keysym = kbd->key_maps[4][keycode - 256];
0319 else if (keycode >= 128)
0320 keysym = kbd->key_maps[1][keycode - 128];
0321 else
0322 keysym = kbd->key_maps[0][keycode];
0323
0324 type = KTYP(keysym);
0325 if (type >= 0xf0) {
0326 type -= 0xf0;
0327 if (type == KT_LETTER)
0328 type = KT_LATIN;
0329 value = KVAL(keysym);
0330 #ifdef CONFIG_MAGIC_SYSRQ
0331 if (kbd->sysrq) {
0332 if (kbd->sysrq == K(KT_LATIN, '-')) {
0333 kbd->sysrq = 0;
0334 handle_sysrq(value);
0335 return;
0336 }
0337 if (value == '-') {
0338 kbd->sysrq = K(KT_LATIN, '-');
0339 return;
0340 }
0341
0342 (*k_handler[KTYP(kbd->sysrq)])(kbd, KVAL(kbd->sysrq));
0343 kbd->sysrq = 0;
0344 } else if ((type == KT_LATIN && value == '^') ||
0345 (type == KT_DEAD && ret_diacr[value] == '^')) {
0346 kbd->sysrq = K(type, value);
0347 return;
0348 }
0349 #endif
0350 (*k_handler[type])(kbd, value);
0351 } else
0352 to_utf8(kbd->port, keysym);
0353 }
0354
0355
0356
0357
0358 static int
0359 do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
0360 int cmd, int perm)
0361 {
0362 struct kbentry tmp;
0363 unsigned long kb_index, kb_table;
0364 ushort *key_map, val, ov;
0365
0366 if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
0367 return -EFAULT;
0368 kb_index = (unsigned long) tmp.kb_index;
0369 #if NR_KEYS < 256
0370 if (kb_index >= NR_KEYS)
0371 return -EINVAL;
0372 #endif
0373 kb_table = (unsigned long) tmp.kb_table;
0374 #if MAX_NR_KEYMAPS < 256
0375 if (kb_table >= MAX_NR_KEYMAPS)
0376 return -EINVAL;
0377 kb_table = array_index_nospec(kb_table , MAX_NR_KEYMAPS);
0378 #endif
0379
0380 switch (cmd) {
0381 case KDGKBENT:
0382 key_map = kbd->key_maps[kb_table];
0383 if (key_map) {
0384 val = U(key_map[kb_index]);
0385 if (KTYP(val) >= KBD_NR_TYPES)
0386 val = K_HOLE;
0387 } else
0388 val = (kb_index ? K_HOLE : K_NOSUCHMAP);
0389 return put_user(val, &user_kbe->kb_value);
0390 case KDSKBENT:
0391 if (!perm)
0392 return -EPERM;
0393 if (!kb_index && tmp.kb_value == K_NOSUCHMAP) {
0394
0395 key_map = kbd->key_maps[kb_table];
0396 if (key_map) {
0397 kbd->key_maps[kb_table] = NULL;
0398 kfree(key_map);
0399 }
0400 break;
0401 }
0402
0403 if (KTYP(tmp.kb_value) >= KBD_NR_TYPES)
0404 return -EINVAL;
0405 if (KVAL(tmp.kb_value) > kbd_max_vals[KTYP(tmp.kb_value)])
0406 return -EINVAL;
0407
0408 if (!(key_map = kbd->key_maps[kb_table])) {
0409 int j;
0410
0411 key_map = kmalloc(sizeof(plain_map),
0412 GFP_KERNEL);
0413 if (!key_map)
0414 return -ENOMEM;
0415 kbd->key_maps[kb_table] = key_map;
0416 for (j = 0; j < NR_KEYS; j++)
0417 key_map[j] = U(K_HOLE);
0418 }
0419 ov = U(key_map[kb_index]);
0420 if (tmp.kb_value == ov)
0421 break;
0422
0423
0424
0425 if (((ov == K_SAK) || (tmp.kb_value == K_SAK)) &&
0426 !capable(CAP_SYS_ADMIN))
0427 return -EPERM;
0428 key_map[kb_index] = U(tmp.kb_value);
0429 break;
0430 }
0431 return 0;
0432 }
0433
0434 static int
0435 do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
0436 int cmd, int perm)
0437 {
0438 unsigned char kb_func;
0439 char *p;
0440 int len;
0441
0442
0443 if (get_user(kb_func, &u_kbs->kb_func))
0444 return -EFAULT;
0445 #if MAX_NR_FUNC < 256
0446 if (kb_func >= MAX_NR_FUNC)
0447 return -EINVAL;
0448 #endif
0449
0450 switch (cmd) {
0451 case KDGKBSENT:
0452 p = kbd->func_table[kb_func];
0453 if (p) {
0454 len = strlen(p);
0455 if (len >= sizeof(u_kbs->kb_string))
0456 len = sizeof(u_kbs->kb_string) - 1;
0457 if (copy_to_user(u_kbs->kb_string, p, len))
0458 return -EFAULT;
0459 } else
0460 len = 0;
0461 if (put_user('\0', u_kbs->kb_string + len))
0462 return -EFAULT;
0463 break;
0464 case KDSKBSENT:
0465 if (!perm)
0466 return -EPERM;
0467 p = strndup_user(u_kbs->kb_string, sizeof(u_kbs->kb_string));
0468 if (IS_ERR(p))
0469 return PTR_ERR(p);
0470 kfree(kbd->func_table[kb_func]);
0471 kbd->func_table[kb_func] = p;
0472 break;
0473 }
0474 return 0;
0475 }
0476
0477 int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
0478 {
0479 struct tty_struct *tty;
0480 void __user *argp;
0481 unsigned int ct;
0482 int perm;
0483
0484 argp = (void __user *)arg;
0485
0486
0487
0488
0489
0490 tty = tty_port_tty_get(kbd->port);
0491
0492 perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
0493 tty_kref_put(tty);
0494 switch (cmd) {
0495 case KDGKBTYPE:
0496 return put_user(KB_101, (char __user *)argp);
0497 case KDGKBENT:
0498 case KDSKBENT:
0499 return do_kdsk_ioctl(kbd, argp, cmd, perm);
0500 case KDGKBSENT:
0501 case KDSKBSENT:
0502 return do_kdgkb_ioctl(kbd, argp, cmd, perm);
0503 case KDGKBDIACR:
0504 {
0505 struct kbdiacrs __user *a = argp;
0506 struct kbdiacr diacr;
0507 int i;
0508
0509 if (put_user(kbd->accent_table_size, &a->kb_cnt))
0510 return -EFAULT;
0511 for (i = 0; i < kbd->accent_table_size; i++) {
0512 diacr.diacr = kbd->accent_table[i].diacr;
0513 diacr.base = kbd->accent_table[i].base;
0514 diacr.result = kbd->accent_table[i].result;
0515 if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
0516 return -EFAULT;
0517 }
0518 return 0;
0519 }
0520 case KDGKBDIACRUC:
0521 {
0522 struct kbdiacrsuc __user *a = argp;
0523
0524 ct = kbd->accent_table_size;
0525 if (put_user(ct, &a->kb_cnt))
0526 return -EFAULT;
0527 if (copy_to_user(a->kbdiacruc, kbd->accent_table,
0528 ct * sizeof(struct kbdiacruc)))
0529 return -EFAULT;
0530 return 0;
0531 }
0532 case KDSKBDIACR:
0533 {
0534 struct kbdiacrs __user *a = argp;
0535 struct kbdiacr diacr;
0536 int i;
0537
0538 if (!perm)
0539 return -EPERM;
0540 if (get_user(ct, &a->kb_cnt))
0541 return -EFAULT;
0542 if (ct >= MAX_DIACR)
0543 return -EINVAL;
0544 kbd->accent_table_size = ct;
0545 for (i = 0; i < ct; i++) {
0546 if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
0547 return -EFAULT;
0548 kbd->accent_table[i].diacr = diacr.diacr;
0549 kbd->accent_table[i].base = diacr.base;
0550 kbd->accent_table[i].result = diacr.result;
0551 }
0552 return 0;
0553 }
0554 case KDSKBDIACRUC:
0555 {
0556 struct kbdiacrsuc __user *a = argp;
0557
0558 if (!perm)
0559 return -EPERM;
0560 if (get_user(ct, &a->kb_cnt))
0561 return -EFAULT;
0562 if (ct >= MAX_DIACR)
0563 return -EINVAL;
0564 kbd->accent_table_size = ct;
0565 if (copy_from_user(kbd->accent_table, a->kbdiacruc,
0566 ct * sizeof(struct kbdiacruc)))
0567 return -EFAULT;
0568 return 0;
0569 }
0570 default:
0571 return -ENOIOCTLCMD;
0572 }
0573 }
0574
0575 EXPORT_SYMBOL(kbd_ioctl);
0576 EXPORT_SYMBOL(kbd_ascebc);
0577 EXPORT_SYMBOL(kbd_free);
0578 EXPORT_SYMBOL(kbd_alloc);
0579 EXPORT_SYMBOL(kbd_keycode);