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