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