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