1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1994-1995 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #include <ctype.h> 33 #include <err.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <sys/kbio.h> 40 #include <sys/consio.h> 41 #include <sys/param.h> 42 #include <sys/queue.h> 43 #include <sys/sysctl.h> 44 #include "path.h" 45 #include "lex.h" 46 47 #define SPECIAL 0x80000000 48 49 #ifndef BOOTSTRAP_KBDCONTROL 50 static const char ctrl_names[32][4] = { 51 "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", 52 "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ", 53 "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", 54 "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us " 55 }; 56 #endif 57 58 static const char acc_names[15][5] = { 59 "dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot", 60 "duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo", 61 "dcar", 62 }; 63 64 static const char acc_names_u[15][5] = { 65 "DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT", 66 "DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO", 67 "DCAR", 68 }; 69 70 #ifndef BOOTSTRAP_KBDCONTROL 71 static const char fkey_table[96][MAXFK] = { 72 /* 01-04 */ "\033[M", "\033[N", "\033[O", "\033[P", 73 /* 05-08 */ "\033[Q", "\033[R", "\033[S", "\033[T", 74 /* 09-12 */ "\033[U", "\033[V", "\033[W", "\033[X", 75 /* 13-16 */ "\033[Y", "\033[Z", "\033[a", "\033[b", 76 /* 17-20 */ "\033[c", "\033[d", "\033[e", "\033[f", 77 /* 21-24 */ "\033[g", "\033[h", "\033[i", "\033[j", 78 /* 25-28 */ "\033[k", "\033[l", "\033[m", "\033[n", 79 /* 29-32 */ "\033[o", "\033[p", "\033[q", "\033[r", 80 /* 33-36 */ "\033[s", "\033[t", "\033[u", "\033[v", 81 /* 37-40 */ "\033[w", "\033[x", "\033[y", "\033[z", 82 /* 41-44 */ "\033[@", "\033[[", "\033[\\","\033[]", 83 /* 45-48 */ "\033[^", "\033[_", "\033[`", "\033[{", 84 /* 49-52 */ "\033[H", "\033[A", "\033[I", "-" , 85 /* 53-56 */ "\033[D", "\033[E", "\033[C", "+" , 86 /* 57-60 */ "\033[F", "\033[B", "\033[G", "\033[L", 87 /* 61-64 */ "\177", "\033[J", "\033[~", "\033[}", 88 /* 65-68 */ "" , "" , "" , "" , 89 /* 69-72 */ "" , "" , "" , "" , 90 /* 73-76 */ "" , "" , "" , "" , 91 /* 77-80 */ "" , "" , "" , "" , 92 /* 81-84 */ "" , "" , "" , "" , 93 /* 85-88 */ "" , "" , "" , "" , 94 /* 89-92 */ "" , "" , "" , "" , 95 /* 93-96 */ "" , "" , "" , "" , 96 }; 97 #endif 98 99 #ifndef BOOTSTRAP_KBDCONTROL 100 static const int ndelays = nitems(kbdelays); 101 static const int nrepeats = nitems(kbrates); 102 static int hex = 0; 103 #endif 104 static int paths_configured = 0; 105 static int token; 106 107 int number; 108 char letter; 109 110 static void add_keymap_path(const char *path); 111 static void dump_accent_definition(char *name, accentmap_t *accentmap); 112 static void dump_entry(int value); 113 static void dump_key_definition(char *name, keymap_t *keymap); 114 static int get_accent_definition_line(accentmap_t *); 115 static int get_entry(void); 116 static int get_key_definition_line(keymap_t *); 117 static void load_keymap(char *opt, int dumponly); 118 #ifndef BOOTSTRAP_KBDCONTROL 119 static void load_default_functionkeys(void); 120 #endif 121 static char * nextarg(int ac, char **av, int *indp, int oc); 122 static char * mkfullname(const char *s1, const char *s2, const char *s3); 123 #ifndef BOOTSTRAP_KBDCONTROL 124 static void print_accent_definition_line(FILE *fp, int accent, 125 struct acc_t *key); 126 static void print_entry(FILE *fp, int value); 127 static void print_key_definition_line(FILE *fp, int scancode, 128 struct keyent_t *key); 129 static void print_keymap(void); 130 static void release_keyboard(void); 131 static void mux_keyboard(u_int op, char *kbd); 132 static void set_bell_values(char *opt); 133 static void set_functionkey(char *keynumstr, char *string); 134 static void set_keyboard(char *device); 135 static void set_keyrates(char *opt); 136 static void show_kbd_info(void); 137 #endif 138 static void usage(void) __dead2; 139 140 struct pathent { 141 STAILQ_ENTRY(pathent) next; 142 char *path; 143 }; 144 static STAILQ_HEAD(, pathent) pathlist = STAILQ_HEAD_INITIALIZER(pathlist); 145 146 #ifndef BOOTSTRAP_KBDCONTROL 147 /* Detect presence of vt(4). */ 148 static int 149 is_vt4(void) 150 { 151 char vty_name[4] = ""; 152 size_t len = sizeof(vty_name); 153 154 if (sysctlbyname("kern.vty", vty_name, &len, NULL, 0) != 0) 155 return (0); 156 return (strcmp(vty_name, "vt") == 0); 157 } 158 #endif 159 160 static char * 161 nextarg(int ac, char **av, int *indp, int oc) 162 { 163 if (*indp < ac) 164 return(av[(*indp)++]); 165 warnx("option requires two arguments -- %c", oc); 166 usage(); 167 } 168 169 170 static char * 171 mkfullname(const char *s1, const char *s2, const char *s3) 172 { 173 static char *buf = NULL; 174 static int bufl = 0; 175 int f; 176 177 f = strlen(s1) + strlen(s2) + strlen(s3) + 1; 178 if (f > bufl) { 179 if (buf) 180 buf = (char *)realloc(buf, f); 181 else 182 buf = (char *)malloc(f); 183 } 184 if (!buf) { 185 bufl = 0; 186 return(NULL); 187 } 188 189 bufl = f; 190 strcpy(buf, s1); 191 strcat(buf, s2); 192 strcat(buf, s3); 193 return(buf); 194 } 195 196 197 static int 198 get_entry(void) 199 { 200 switch ((token = yylex())) { 201 case TNOP: 202 return NOP | SPECIAL; 203 case TLSH: 204 return LSH | SPECIAL; 205 case TRSH: 206 return RSH | SPECIAL; 207 case TCLK: 208 return CLK | SPECIAL; 209 case TNLK: 210 return NLK | SPECIAL; 211 case TSLK: 212 return SLK | SPECIAL; 213 case TBTAB: 214 return BTAB | SPECIAL; 215 case TLALT: 216 return LALT | SPECIAL; 217 case TLCTR: 218 return LCTR | SPECIAL; 219 case TNEXT: 220 return NEXT | SPECIAL; 221 case TPREV: 222 return PREV | SPECIAL; 223 case TRCTR: 224 return RCTR | SPECIAL; 225 case TRALT: 226 return RALT | SPECIAL; 227 case TALK: 228 return ALK | SPECIAL; 229 case TASH: 230 return ASH | SPECIAL; 231 case TMETA: 232 return META | SPECIAL; 233 case TRBT: 234 return RBT | SPECIAL; 235 case TDBG: 236 return DBG | SPECIAL; 237 case TSUSP: 238 return SUSP | SPECIAL; 239 case TSPSC: 240 return SPSC | SPECIAL; 241 case TPANIC: 242 return PNC | SPECIAL; 243 case TLSHA: 244 return LSHA | SPECIAL; 245 case TRSHA: 246 return RSHA | SPECIAL; 247 case TLCTRA: 248 return LCTRA | SPECIAL; 249 case TRCTRA: 250 return RCTRA | SPECIAL; 251 case TLALTA: 252 return LALTA | SPECIAL; 253 case TRALTA: 254 return RALTA | SPECIAL; 255 case THALT: 256 return HALT | SPECIAL; 257 case TPDWN: 258 return PDWN | SPECIAL; 259 case TPASTE: 260 return PASTE | SPECIAL; 261 case TACC: 262 if (ACC(number) > L_ACC) 263 return -1; 264 return ACC(number) | SPECIAL; 265 case TFUNC: 266 if (F(number) > L_FN) 267 return -1; 268 return F(number) | SPECIAL; 269 case TSCRN: 270 if (S(number) > L_SCR) 271 return -1; 272 return S(number) | SPECIAL; 273 case TLET: 274 return (unsigned char)letter; 275 case TNUM: 276 if (number < 0x000000 || number > 0x10FFFF) 277 return -1; 278 return number; 279 default: 280 return -1; 281 } 282 } 283 284 static int 285 get_definition_line(FILE *file, keymap_t *keymap, accentmap_t *accentmap) 286 { 287 int c; 288 289 yyin = file; 290 291 if (token < 0) 292 token = yylex(); 293 switch (token) { 294 case TNUM: 295 c = get_key_definition_line(keymap); 296 if (c < 0) 297 errx(1, "invalid key definition"); 298 if (c > keymap->n_keys) 299 keymap->n_keys = c; 300 break; 301 case TACC: 302 c = get_accent_definition_line(accentmap); 303 if (c < 0) 304 errx(1, "invalid accent key definition"); 305 if (c > accentmap->n_accs) 306 accentmap->n_accs = c; 307 break; 308 case 0: 309 /* EOF */ 310 return -1; 311 default: 312 errx(1, "illegal definition line"); 313 } 314 return c; 315 } 316 317 static int 318 get_key_definition_line(keymap_t *map) 319 { 320 int i, def, scancode; 321 322 /* check scancode number */ 323 if (number < 0 || number >= NUM_KEYS) 324 return -1; 325 scancode = number; 326 327 /* get key definitions */ 328 map->key[scancode].spcl = 0; 329 for (i=0; i<NUM_STATES; i++) { 330 if ((def = get_entry()) == -1) 331 return -1; 332 if (def & SPECIAL) 333 map->key[scancode].spcl |= (0x80 >> i); 334 map->key[scancode].map[i] = def & ~SPECIAL; 335 } 336 /* get lock state key def */ 337 if ((token = yylex()) != TFLAG) 338 return -1; 339 map->key[scancode].flgs = number; 340 token = yylex(); 341 return (scancode + 1); 342 } 343 344 static int 345 get_accent_definition_line(accentmap_t *map) 346 { 347 int accent; 348 int c1, c2; 349 int i; 350 351 if (ACC(number) < F_ACC || ACC(number) > L_ACC) 352 /* number out of range */ 353 return -1; 354 accent = number; 355 if (map->acc[accent].accchar != 0) { 356 /* this entry has already been defined before! */ 357 errx(1, "duplicated accent key definition"); 358 } 359 360 switch ((token = yylex())) { 361 case TLET: 362 map->acc[accent].accchar = letter; 363 break; 364 case TNUM: 365 map->acc[accent].accchar = number; 366 break; 367 default: 368 return -1; 369 } 370 371 for (i = 0; (token = yylex()) == '(';) { 372 switch ((token = yylex())) { 373 case TLET: 374 c1 = letter; 375 break; 376 case TNUM: 377 c1 = number; 378 break; 379 default: 380 return -1; 381 } 382 switch ((token = yylex())) { 383 case TLET: 384 c2 = letter; 385 break; 386 case TNUM: 387 c2 = number; 388 break; 389 default: 390 return -1; 391 } 392 if ((token = yylex()) != ')') 393 return -1; 394 if (i >= NUM_ACCENTCHARS) { 395 warnx("too many accented characters, ignored"); 396 continue; 397 } 398 map->acc[accent].map[i][0] = c1; 399 map->acc[accent].map[i][1] = c2; 400 ++i; 401 } 402 return (accent + 1); 403 } 404 405 #ifndef BOOTSTRAP_KBDCONTROL 406 static void 407 print_entry(FILE *fp, int value) 408 { 409 int val = value & ~SPECIAL; 410 411 switch (value) { 412 case NOP | SPECIAL: 413 fprintf(fp, " nop "); 414 break; 415 case LSH | SPECIAL: 416 fprintf(fp, " lshift"); 417 break; 418 case RSH | SPECIAL: 419 fprintf(fp, " rshift"); 420 break; 421 case CLK | SPECIAL: 422 fprintf(fp, " clock "); 423 break; 424 case NLK | SPECIAL: 425 fprintf(fp, " nlock "); 426 break; 427 case SLK | SPECIAL: 428 fprintf(fp, " slock "); 429 break; 430 case BTAB | SPECIAL: 431 fprintf(fp, " btab "); 432 break; 433 case LALT | SPECIAL: 434 fprintf(fp, " lalt "); 435 break; 436 case LCTR | SPECIAL: 437 fprintf(fp, " lctrl "); 438 break; 439 case NEXT | SPECIAL: 440 fprintf(fp, " nscr "); 441 break; 442 case PREV | SPECIAL: 443 fprintf(fp, " pscr "); 444 break; 445 case RCTR | SPECIAL: 446 fprintf(fp, " rctrl "); 447 break; 448 case RALT | SPECIAL: 449 fprintf(fp, " ralt "); 450 break; 451 case ALK | SPECIAL: 452 fprintf(fp, " alock "); 453 break; 454 case ASH | SPECIAL: 455 fprintf(fp, " ashift"); 456 break; 457 case META | SPECIAL: 458 fprintf(fp, " meta "); 459 break; 460 case RBT | SPECIAL: 461 fprintf(fp, " boot "); 462 break; 463 case DBG | SPECIAL: 464 fprintf(fp, " debug "); 465 break; 466 case SUSP | SPECIAL: 467 fprintf(fp, " susp "); 468 break; 469 case SPSC | SPECIAL: 470 fprintf(fp, " saver "); 471 break; 472 case PNC | SPECIAL: 473 fprintf(fp, " panic "); 474 break; 475 case LSHA | SPECIAL: 476 fprintf(fp, " lshifta"); 477 break; 478 case RSHA | SPECIAL: 479 fprintf(fp, " rshifta"); 480 break; 481 case LCTRA | SPECIAL: 482 fprintf(fp, " lctrla"); 483 break; 484 case RCTRA | SPECIAL: 485 fprintf(fp, " rctrla"); 486 break; 487 case LALTA | SPECIAL: 488 fprintf(fp, " lalta "); 489 break; 490 case RALTA | SPECIAL: 491 fprintf(fp, " ralta "); 492 break; 493 case HALT | SPECIAL: 494 fprintf(fp, " halt "); 495 break; 496 case PDWN | SPECIAL: 497 fprintf(fp, " pdwn "); 498 break; 499 case PASTE | SPECIAL: 500 fprintf(fp, " paste "); 501 break; 502 default: 503 if (value & SPECIAL) { 504 if (val >= F_FN && val <= L_FN) 505 fprintf(fp, " fkey%02d", val - F_FN + 1); 506 else if (val >= F_SCR && val <= L_SCR) 507 fprintf(fp, " scr%02d ", val - F_SCR + 1); 508 else if (val >= F_ACC && val <= L_ACC) 509 fprintf(fp, " %-6s", acc_names[val - F_ACC]); 510 else if (hex) 511 fprintf(fp, " 0x%02x ", val); 512 else 513 fprintf(fp, " %3d ", val); 514 } 515 else { 516 if (val < ' ') 517 fprintf(fp, " %s ", ctrl_names[val]); 518 else if (val == 127) 519 fprintf(fp, " del "); 520 else if (isascii(val) && isprint(val)) 521 fprintf(fp, " '%c' ", val); 522 else if (hex) 523 fprintf(fp, " 0x%02x ", val); 524 else 525 fprintf(fp, " %3d ", val); 526 } 527 } 528 } 529 530 static void 531 print_key_definition_line(FILE *fp, int scancode, struct keyent_t *key) 532 { 533 int i; 534 535 /* print scancode number */ 536 if (hex) 537 fprintf(fp, " 0x%02x ", scancode); 538 else 539 fprintf(fp, " %03d ", scancode); 540 541 /* print key definitions */ 542 for (i=0; i<NUM_STATES; i++) { 543 if (key->spcl & (0x80 >> i)) 544 print_entry(fp, key->map[i] | SPECIAL); 545 else 546 print_entry(fp, key->map[i]); 547 } 548 549 /* print lock state key def */ 550 switch (key->flgs) { 551 case 0: 552 fprintf(fp, " O\n"); 553 break; 554 case 1: 555 fprintf(fp, " C\n"); 556 break; 557 case 2: 558 fprintf(fp, " N\n"); 559 break; 560 case 3: 561 fprintf(fp, " B\n"); 562 break; 563 } 564 } 565 566 static void 567 print_accent_definition_line(FILE *fp, int accent, struct acc_t *key) 568 { 569 int c; 570 int i; 571 572 if (key->accchar == 0) 573 return; 574 575 /* print accent number */ 576 fprintf(fp, " %-6s", acc_names[accent]); 577 if (isascii(key->accchar) && isprint(key->accchar)) 578 fprintf(fp, "'%c' ", key->accchar); 579 else if (hex) 580 fprintf(fp, "0x%02x ", key->accchar); 581 else 582 fprintf(fp, "%03d ", key->accchar); 583 584 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 585 c = key->map[i][0]; 586 if (c == 0) 587 break; 588 if ((i > 0) && ((i % 4) == 0)) 589 fprintf(fp, "\n "); 590 if (isascii(c) && isprint(c)) 591 fprintf(fp, "( '%c' ", c); 592 else if (hex) 593 fprintf(fp, "(0x%02x ", c); 594 else 595 fprintf(fp, "( %03d ", c); 596 c = key->map[i][1]; 597 if (isascii(c) && isprint(c)) 598 fprintf(fp, "'%c' ) ", c); 599 else if (hex) 600 fprintf(fp, "0x%02x) ", c); 601 else 602 fprintf(fp, "%03d ) ", c); 603 } 604 fprintf(fp, "\n"); 605 } 606 #endif 607 608 static void 609 dump_entry(int value) 610 { 611 if (value & SPECIAL) { 612 value &= ~SPECIAL; 613 switch (value) { 614 case NOP: 615 printf(" NOP, "); 616 break; 617 case LSH: 618 printf(" LSH, "); 619 break; 620 case RSH: 621 printf(" RSH, "); 622 break; 623 case CLK: 624 printf(" CLK, "); 625 break; 626 case NLK: 627 printf(" NLK, "); 628 break; 629 case SLK: 630 printf(" SLK, "); 631 break; 632 case BTAB: 633 printf(" BTAB, "); 634 break; 635 case LALT: 636 printf(" LALT, "); 637 break; 638 case LCTR: 639 printf(" LCTR, "); 640 break; 641 case NEXT: 642 printf(" NEXT, "); 643 break; 644 case PREV: 645 printf(" PREV, "); 646 break; 647 case RCTR: 648 printf(" RCTR, "); 649 break; 650 case RALT: 651 printf(" RALT, "); 652 break; 653 case ALK: 654 printf(" ALK, "); 655 break; 656 case ASH: 657 printf(" ASH, "); 658 break; 659 case META: 660 printf(" META, "); 661 break; 662 case RBT: 663 printf(" RBT, "); 664 break; 665 case DBG: 666 printf(" DBG, "); 667 break; 668 case SUSP: 669 printf(" SUSP, "); 670 break; 671 case SPSC: 672 printf(" SPSC, "); 673 break; 674 case PNC: 675 printf(" PNC, "); 676 break; 677 case LSHA: 678 printf(" LSHA, "); 679 break; 680 case RSHA: 681 printf(" RSHA, "); 682 break; 683 case LCTRA: 684 printf("LCTRA, "); 685 break; 686 case RCTRA: 687 printf("RCTRA, "); 688 break; 689 case LALTA: 690 printf("LALTA, "); 691 break; 692 case RALTA: 693 printf("RALTA, "); 694 break; 695 case HALT: 696 printf(" HALT, "); 697 break; 698 case PDWN: 699 printf(" PDWN, "); 700 break; 701 case PASTE: 702 printf("PASTE, "); 703 break; 704 default: 705 if (value >= F_FN && value <= L_FN) 706 printf(" F(%2d),", value - F_FN + 1); 707 else if (value >= F_SCR && value <= L_SCR) 708 printf(" S(%2d),", value - F_SCR + 1); 709 else if (value >= F_ACC && value <= L_ACC) 710 printf(" %-4s, ", acc_names_u[value - F_ACC]); 711 else 712 printf(" 0x%02X, ", value); 713 break; 714 } 715 } else if (value == '\'') { 716 printf(" '\\'', "); 717 } else if (value == '\\') { 718 printf(" '\\\\', "); 719 } else if (isascii(value) && isprint(value)) { 720 printf(" '%c', ", value); 721 } else { 722 printf(" 0x%02X, ", value); 723 } 724 } 725 726 static void 727 dump_key_definition(char *name, keymap_t *keymap) 728 { 729 int i, j; 730 731 printf("static keymap_t keymap_%s = { 0x%02x, {\n", 732 name, (unsigned)keymap->n_keys); 733 printf( 734 "/* alt\n" 735 " * scan cntrl alt alt cntrl\n" 736 " * code base shift cntrl shift alt shift cntrl shift spcl flgs\n" 737 " * ---------------------------------------------------------------------------\n" 738 " */\n"); 739 for (i = 0; i < keymap->n_keys; i++) { 740 printf("/*%02x*/{{", i); 741 for (j = 0; j < NUM_STATES; j++) { 742 if (keymap->key[i].spcl & (0x80 >> j)) 743 dump_entry(keymap->key[i].map[j] | SPECIAL); 744 else 745 dump_entry(keymap->key[i].map[j]); 746 } 747 printf("}, 0x%02X,0x%02X },\n", 748 (unsigned)keymap->key[i].spcl, 749 (unsigned)keymap->key[i].flgs); 750 } 751 printf("} };\n\n"); 752 } 753 754 static void 755 dump_accent_definition(char *name, accentmap_t *accentmap) 756 { 757 int i, j; 758 int c; 759 760 printf("static accentmap_t accentmap_%s = { %d", 761 name, accentmap->n_accs); 762 if (accentmap->n_accs <= 0) { 763 printf(" };\n\n"); 764 return; 765 } 766 printf(", {\n"); 767 for (i = 0; i < NUM_DEADKEYS; i++) { 768 printf(" /* %s=%d */\n {", acc_names[i], i); 769 c = accentmap->acc[i].accchar; 770 if (c == '\'') 771 printf(" '\\'', {"); 772 else if (c == '\\') 773 printf(" '\\\\', {"); 774 else if (isascii(c) && isprint(c)) 775 printf(" '%c', {", c); 776 else if (c == 0) { 777 printf(" 0x00 }, \n"); 778 continue; 779 } else 780 printf(" 0x%02x, {", c); 781 for (j = 0; j < NUM_ACCENTCHARS; j++) { 782 c = accentmap->acc[i].map[j][0]; 783 if (c == 0) 784 break; 785 if ((j > 0) && ((j % 4) == 0)) 786 printf("\n\t "); 787 if (isascii(c) && isprint(c)) 788 printf(" { '%c',", c); 789 else 790 printf(" { 0x%02x,", c); 791 printf("0x%02x },", accentmap->acc[i].map[j][1]); 792 } 793 printf(" }, },\n"); 794 } 795 printf("} };\n\n"); 796 } 797 798 static void 799 add_keymap_path(const char *path) 800 { 801 struct pathent* pe; 802 size_t len; 803 804 len = strlen(path); 805 if ((pe = malloc(sizeof(*pe))) == NULL || 806 (pe->path = malloc(len + 2)) == NULL) 807 err(1, "malloc"); 808 memcpy(pe->path, path, len); 809 if (len > 0 && path[len - 1] != '/') 810 pe->path[len++] = '/'; 811 pe->path[len] = '\0'; 812 STAILQ_INSERT_TAIL(&pathlist, pe, next); 813 } 814 815 #ifdef OPIO_DEADKEYMAP 816 static void 817 to_old_accentmap(accentmap_t *from, oaccentmap_t *to) 818 { 819 int i, j; 820 821 to->n_accs = from->n_accs; 822 for (i = 0; i < NUM_DEADKEYS; i++) { 823 for (j = 0; j < NUM_ACCENTCHARS; j++) { 824 to->acc[i].map[j][0] = from->acc[i].map[j][0]; 825 to->acc[i].map[j][1] = from->acc[i].map[j][1]; 826 to->acc[i].accchar = from->acc[i].accchar; 827 } 828 } 829 } 830 #endif /* OPIO_DEADKEYMAP */ 831 832 static void 833 load_keymap(char *opt, int dumponly) 834 { 835 keymap_t keymap; 836 accentmap_t accentmap; 837 #ifdef OPIO_DEADKEYMAP 838 oaccentmap_t oaccentmap; 839 #endif /* OPIO_DEADKEYMAP */ 840 struct pathent *pe; 841 FILE *file; 842 int j; 843 char *name, *cp; 844 char blank[] = "", keymap_path[] = KEYMAP_PATH; 845 char vt_keymap_path[] = VT_KEYMAP_PATH, dotkbd[] = ".kbd"; 846 char *postfix[] = {blank, dotkbd, NULL}; 847 848 if (!paths_configured) { 849 cp = getenv("KEYMAP_PATH"); 850 if (cp != NULL) 851 add_keymap_path(cp); 852 add_keymap_path(""); 853 #ifndef BOOTSTRAP_KBDCONTROL 854 if (is_vt4()) 855 add_keymap_path(vt_keymap_path); 856 else 857 add_keymap_path(keymap_path); 858 #endif 859 paths_configured = 1; 860 } 861 862 file = NULL; 863 STAILQ_FOREACH(pe, &pathlist, next) { 864 for (j=0; postfix[j] && file == NULL; j++) { 865 name = mkfullname(pe->path, opt, postfix[j]); 866 file = fopen(name, "r"); 867 if (file != NULL) 868 break; 869 } 870 } 871 if (file == NULL) { 872 warn("keymap file \"%s\" not found", opt); 873 return; 874 } 875 memset(&keymap, 0, sizeof(keymap)); 876 memset(&accentmap, 0, sizeof(accentmap)); 877 token = -1; 878 while (1) { 879 if (get_definition_line(file, &keymap, &accentmap) < 0) 880 break; 881 } 882 if (dumponly) { 883 /* fix up the filename to make it a valid C identifier */ 884 for (cp = opt; *cp; cp++) 885 if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_'; 886 printf("/*\n" 887 " * Automatically generated from %s.\n" 888 " * DO NOT EDIT!\n" 889 " */\n", name); 890 dump_key_definition(opt, &keymap); 891 dump_accent_definition(opt, &accentmap); 892 return; 893 } 894 #ifndef BOOTSTRAP_KBDCONTROL 895 if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) { 896 warn("setting keymap"); 897 fclose(file); 898 return; 899 } 900 if ((accentmap.n_accs > 0) 901 && (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) { 902 #ifdef OPIO_DEADKEYMAP 903 to_old_accentmap(&accentmap, &oaccentmap); 904 if (ioctl(0, OPIO_DEADKEYMAP, &oaccentmap) < 0) 905 #endif /* OGIO_DEADKEYMAP */ 906 { 907 warn("setting accentmap"); 908 fclose(file); 909 return; 910 } 911 } 912 #endif 913 } 914 915 #ifdef OPIO_DEADKEYMAP 916 static void 917 to_new_accentmap(oaccentmap_t *from, accentmap_t *to) 918 { 919 int i, j; 920 921 to->n_accs = from->n_accs; 922 for (i = 0; i < NUM_DEADKEYS; i++) { 923 for (j = 0; j < NUM_ACCENTCHARS; j++) { 924 to->acc[i].map[j][0] = from->acc[i].map[j][0]; 925 to->acc[i].map[j][1] = from->acc[i].map[j][1]; 926 to->acc[i].accchar = from->acc[i].accchar; 927 } 928 } 929 } 930 #endif /* OPIO_DEADKEYMAP */ 931 932 #ifndef BOOTSTRAP_KBDCONTROL 933 static void 934 print_keymap(void) 935 { 936 keymap_t keymap; 937 accentmap_t accentmap; 938 #ifdef OGIO_DEADKEYMAP 939 oaccentmap_t oaccentmap; 940 #endif /* OPIO_DEADKEYMAP */ 941 int i; 942 943 if (ioctl(0, GIO_KEYMAP, &keymap) < 0) 944 err(1, "getting keymap"); 945 if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0) { 946 #ifdef OGIO_DEADKEYMAP 947 if (ioctl(0, OGIO_DEADKEYMAP, &oaccentmap) == 0) 948 to_new_accentmap(&oaccentmap, &accentmap); 949 else 950 #endif /* OGIO_DEADKEYMAP */ 951 memset(&accentmap, 0, sizeof(accentmap)); 952 } 953 printf( 954 "# alt\n" 955 "# scan cntrl alt alt cntrl lock\n" 956 "# code base shift cntrl shift alt shift cntrl shift state\n" 957 "# ------------------------------------------------------------------\n" 958 ); 959 for (i=0; i<keymap.n_keys; i++) 960 print_key_definition_line(stdout, i, &keymap.key[i]); 961 962 printf("\n"); 963 for (i = 0; i < NUM_DEADKEYS; i++) 964 print_accent_definition_line(stdout, i, &accentmap.acc[i]); 965 966 } 967 968 static void 969 load_default_functionkeys(void) 970 { 971 fkeyarg_t fkey; 972 int i; 973 974 for (i=0; i<NUM_FKEYS; i++) { 975 fkey.keynum = i; 976 strcpy(fkey.keydef, fkey_table[i]); 977 fkey.flen = strlen(fkey_table[i]); 978 if (ioctl(0, SETFKEY, &fkey) < 0) 979 warn("setting function key"); 980 } 981 } 982 983 static void 984 set_functionkey(char *keynumstr, char *string) 985 { 986 fkeyarg_t fkey; 987 988 if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) { 989 load_default_functionkeys(); 990 return; 991 } 992 fkey.keynum = atoi(keynumstr); 993 if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) { 994 warnx("function key number must be between 1 and %d", 995 NUM_FKEYS); 996 return; 997 } 998 if ((fkey.flen = strlen(string)) > MAXFK) { 999 warnx("function key string too long (%d > %d)", 1000 fkey.flen, MAXFK); 1001 return; 1002 } 1003 strncpy(fkey.keydef, string, MAXFK); 1004 fkey.keynum -= 1; 1005 if (ioctl(0, SETFKEY, &fkey) < 0) 1006 warn("setting function key"); 1007 } 1008 1009 static void 1010 set_bell_values(char *opt) 1011 { 1012 int bell, duration, pitch; 1013 1014 bell = 0; 1015 duration = 0; 1016 pitch = 0; 1017 if (!strncmp(opt, "quiet.", 6)) { 1018 bell = CONS_QUIET_BELL; 1019 opt += 6; 1020 } 1021 if (!strcmp(opt, "visual")) 1022 bell |= CONS_VISUAL_BELL; 1023 else if (!strcmp(opt, "normal")) 1024 duration = 5, pitch = 800; 1025 else if (!strcmp(opt, "off")) 1026 duration = 0, pitch = 0; 1027 else { 1028 char *v1; 1029 1030 bell = 0; 1031 duration = strtol(opt, &v1, 0); 1032 if ((duration < 0) || (*v1 != '.')) 1033 goto badopt; 1034 opt = ++v1; 1035 pitch = strtol(opt, &v1, 0); 1036 if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) { 1037 badopt: 1038 warnx("argument to -b must be duration.pitch or [quiet.]visual|normal|off"); 1039 return; 1040 } 1041 if (pitch != 0) 1042 pitch = 1193182 / pitch; /* in Hz */ 1043 duration /= 10; /* in 10 m sec */ 1044 } 1045 1046 ioctl(0, CONS_BELLTYPE, &bell); 1047 if (duration > 0 && pitch > 0) 1048 fprintf(stderr, "\e[=%d;%dB", pitch, duration); 1049 } 1050 1051 static void 1052 set_keyrates(char *opt) 1053 { 1054 int arg[2]; 1055 int repeat; 1056 int delay; 1057 int r, d; 1058 1059 if (!strcmp(opt, "slow")) { 1060 delay = 1000; 1061 repeat = 504; 1062 d = 3; 1063 r = 31; 1064 } else if (!strcmp(opt, "normal")) { 1065 delay = 500; 1066 repeat = 126; 1067 d = 1; 1068 r = 15; 1069 } else if (!strcmp(opt, "fast")) { 1070 delay = 0; 1071 repeat = 0; 1072 d = 0; 1073 r = 0; 1074 } else { 1075 int n; 1076 char *v1; 1077 1078 delay = strtol(opt, &v1, 0); 1079 if ((delay < 0) || (*v1 != '.')) 1080 goto badopt; 1081 opt = ++v1; 1082 repeat = strtol(opt, &v1, 0); 1083 if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) { 1084 badopt: 1085 warnx("argument to -r must be delay.repeat or slow|normal|fast"); 1086 return; 1087 } 1088 for (n = 0; n < ndelays - 1; n++) 1089 if (delay <= kbdelays[n]) 1090 break; 1091 d = n; 1092 for (n = 0; n < nrepeats - 1; n++) 1093 if (repeat <= kbrates[n]) 1094 break; 1095 r = n; 1096 } 1097 1098 arg[0] = delay; 1099 arg[1] = repeat; 1100 if (ioctl(0, KDSETREPEAT, arg)) { 1101 warn("fallback, setting keyboard rate via legacy interface (KDSETRAD), will be removed soon"); 1102 if (ioctl(0, KDSETRAD, (d << 5) | r)) 1103 warn("setting keyboard rate"); 1104 } 1105 } 1106 1107 static const char * 1108 get_kbd_type_name(int type) 1109 { 1110 static struct { 1111 int type; 1112 const char *name; 1113 } name_table[] = { 1114 { KB_84, "AT 84" }, 1115 { KB_101, "AT 101/102" }, 1116 { KB_OTHER, "generic" }, 1117 }; 1118 unsigned int i; 1119 1120 for (i = 0; i < nitems(name_table); ++i) { 1121 if (type == name_table[i].type) 1122 return name_table[i].name; 1123 } 1124 return "unknown"; 1125 } 1126 1127 static void 1128 show_kbd_info(void) 1129 { 1130 keyboard_info_t info; 1131 1132 if (ioctl(0, KDGKBINFO, &info) == -1) { 1133 warn("unable to obtain keyboard information"); 1134 return; 1135 } 1136 printf("kbd%d:\n", info.kb_index); 1137 printf(" %.*s%d, type:%s (%d)\n", 1138 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1139 get_kbd_type_name(info.kb_type), info.kb_type); 1140 } 1141 1142 static void 1143 set_keyboard(char *device) 1144 { 1145 keyboard_info_t info; 1146 int fd; 1147 1148 fd = open(device, O_RDONLY); 1149 if (fd < 0) { 1150 warn("cannot open %s", device); 1151 return; 1152 } 1153 if (ioctl(fd, KDGKBINFO, &info) == -1) { 1154 warn("unable to obtain keyboard information"); 1155 close(fd); 1156 return; 1157 } 1158 /* 1159 * The keyboard device driver won't release the keyboard by 1160 * the following ioctl, but it automatically will, when the device 1161 * is closed. So, we don't check error here. 1162 */ 1163 ioctl(fd, CONS_RELKBD, 0); 1164 close(fd); 1165 #if 1 1166 printf("kbd%d\n", info.kb_index); 1167 printf(" %.*s%d, type:%s (%d)\n", 1168 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1169 get_kbd_type_name(info.kb_type), info.kb_type); 1170 #endif 1171 1172 if (ioctl(0, CONS_SETKBD, info.kb_index) == -1) 1173 warn("unable to set keyboard"); 1174 } 1175 1176 static void 1177 release_keyboard(void) 1178 { 1179 keyboard_info_t info; 1180 1181 /* 1182 * If stdin is not associated with a keyboard, the following ioctl 1183 * will fail. 1184 */ 1185 if (ioctl(0, KDGKBINFO, &info) == -1) { 1186 warn("unable to obtain keyboard information"); 1187 return; 1188 } 1189 #if 1 1190 printf("kbd%d\n", info.kb_index); 1191 printf(" %.*s%d, type:%s (%d)\n", 1192 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1193 get_kbd_type_name(info.kb_type), info.kb_type); 1194 #endif 1195 if (ioctl(0, CONS_RELKBD, 0) == -1) 1196 warn("unable to release the keyboard"); 1197 } 1198 1199 static void 1200 mux_keyboard(u_int op, char *kbd) 1201 { 1202 keyboard_info_t info; 1203 char *unit, *ep; 1204 1205 /* 1206 * If stdin is not associated with a keyboard, the following ioctl 1207 * will fail. 1208 */ 1209 if (ioctl(0, KDGKBINFO, &info) == -1) { 1210 warn("unable to obtain keyboard information"); 1211 return; 1212 } 1213 #if 1 1214 printf("kbd%d\n", info.kb_index); 1215 printf(" %.*s%d, type:%s (%d)\n", 1216 (int)sizeof(info.kb_name), info.kb_name, info.kb_unit, 1217 get_kbd_type_name(info.kb_type), info.kb_type); 1218 #endif 1219 /* 1220 * split kbd into name and unit. find the right most part of the 1221 * kbd string that consist of only digits. 1222 */ 1223 1224 memset(&info, 0, sizeof(info)); 1225 1226 info.kb_unit = -1; 1227 ep = kbd - 1; 1228 1229 do { 1230 unit = strpbrk(ep + 1, "0123456789"); 1231 if (unit != NULL) { 1232 info.kb_unit = strtol(unit, &ep, 10); 1233 if (*ep != '\0') 1234 info.kb_unit = -1; 1235 } 1236 } while (unit != NULL && info.kb_unit == -1); 1237 1238 if (info.kb_unit == -1) { 1239 warnx("unable to find keyboard driver unit in '%s'", kbd); 1240 return; 1241 } 1242 1243 if (unit == kbd) { 1244 warnx("unable to find keyboard driver name in '%s'", kbd); 1245 return; 1246 } 1247 if (unit - kbd >= (int) sizeof(info.kb_name)) { 1248 warnx("keyboard name '%s' is too long", kbd); 1249 return; 1250 } 1251 1252 strncpy(info.kb_name, kbd, unit - kbd); 1253 1254 /* 1255 * If stdin is not associated with a kbdmux(4) keyboard, the following 1256 * ioctl will fail. 1257 */ 1258 1259 if (ioctl(0, op, &info) == -1) 1260 warn("unable to (un)mux the keyboard"); 1261 } 1262 #endif 1263 1264 static void 1265 usage(void) 1266 { 1267 #ifdef BOOTSTRAP_KBDCONTROL 1268 fprintf(stderr, "%s\n", 1269 "usage: kbdcontrol [-L mapfile] [-P path]"); 1270 #else 1271 fprintf(stderr, "%s\n%s\n%s\n", 1272 "usage: kbdcontrol [-dFKix] [-A name] [-a name] [-b duration.pitch | [quiet.]belltype]", 1273 " [-r delay.repeat | speed] [-l mapfile] [-f # string]", 1274 " [-k device] [-L mapfile] [-P path]"); 1275 #endif 1276 exit(1); 1277 } 1278 1279 1280 int 1281 main(int argc, char **argv) 1282 { 1283 #ifdef BOOTSTRAP_KBDCONTROL 1284 const char *optstring = "L:P:"; 1285 #else 1286 const char *optstring = "A:a:b:df:iKk:Fl:L:P:r:x"; 1287 #endif 1288 int opt; 1289 1290 /* Collect any -P arguments, regardless of where they appear. */ 1291 while ((opt = getopt(argc, argv, optstring)) != -1) { 1292 if (opt == 'P') 1293 add_keymap_path(optarg); 1294 if (opt == '?') 1295 usage(); 1296 } 1297 1298 optind = optreset = 1; 1299 while ((opt = getopt(argc, argv, optstring)) != -1) 1300 switch(opt) { 1301 #ifndef BOOTSTRAP_KBDCONTROL 1302 case 'A': 1303 case 'a': 1304 mux_keyboard((opt == 'A')? KBRELKBD : KBADDKBD, optarg); 1305 break; 1306 case 'b': 1307 set_bell_values(optarg); 1308 break; 1309 case 'd': 1310 print_keymap(); 1311 break; 1312 case 'l': 1313 load_keymap(optarg, 0); 1314 break; 1315 #endif 1316 case 'L': 1317 load_keymap(optarg, 1); 1318 break; 1319 case 'P': 1320 break; 1321 #ifndef BOOTSTRAP_KBDCONTROL 1322 case 'f': 1323 set_functionkey(optarg, 1324 nextarg(argc, argv, &optind, 'f')); 1325 break; 1326 case 'F': 1327 load_default_functionkeys(); 1328 break; 1329 case 'i': 1330 show_kbd_info(); 1331 break; 1332 case 'K': 1333 release_keyboard(); 1334 break; 1335 case 'k': 1336 set_keyboard(optarg); 1337 break; 1338 case 'r': 1339 set_keyrates(optarg); 1340 break; 1341 case 'x': 1342 hex = 1; 1343 break; 1344 #endif 1345 default: 1346 usage(); 1347 } 1348 if ((optind != argc) || (argc == 1)) 1349 usage(); 1350 exit(0); 1351 } 1352