kbdcontrol.c revision 164333
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 164333 2006-11-16 12:27:51Z ru $");
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
58char 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
65char acc_names[15][5] = {
66	"dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot",
67	"duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo",
68	"dcar",
69	};
70
71char 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
77char 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
104const int	delays[]  = {250, 500, 750, 1000};
105const 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};
109const int	ndelays = (sizeof(delays) / sizeof(int));
110const int	nrepeats = (sizeof(repeats) / sizeof(int));
111int 		hex = 0;
112int 		number;
113char 		letter;
114int		token;
115
116void		dump_accent_definition(char *name, accentmap_t *accentmap);
117void		dump_entry(int value);
118void		dump_key_definition(char *name, keymap_t *keymap);
119int		get_accent_definition_line(accentmap_t *);
120int		get_entry(void);
121int		get_key_definition_line(keymap_t *);
122void		load_keymap(char *opt, int dumponly);
123void		load_default_functionkeys(void);
124char *		nextarg(int ac, char **av, int *indp, int oc);
125char *		mkfullname(const char *s1, const char *s2, const char *s3);
126void		print_accent_definition_line(FILE *fp, int accent,
127			struct acc_t *key);
128void		print_entry(FILE *fp, int value);
129void		print_key_definition_line(FILE *fp, int scancode,
130			struct keyent_t *key);
131void		print_keymap(void);
132void		release_keyboard(void);
133void		mux_keyboard(u_int op, char *kbd);
134void		set_bell_values(char *opt);
135void		set_functionkey(char *keynumstr, char *string);
136void		set_keyboard(char *device);
137void		set_keyrates(char *opt);
138void		show_kbd_info(void);
139void		usage(void) __dead2;
140
141char *
142nextarg(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
151char *
152mkfullname(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
178int
179get_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
265static int
266get_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
298int
299get_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
325int
326get_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
386void
387print_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
510void
511print_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
546void
547print_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
587void
588dump_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
705void
706dump_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
733void
734dump_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
777void
778load_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
836void
837print_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
862void
863load_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
877void
878set_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
903void
904set_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')) {
929badopt:
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, "[=%d;%dB", pitch, duration);
941}
942
943void
944set_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')) {
970badopt:
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
992static const char *
993get_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
1012void
1013show_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
1027void
1028set_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
1061void
1062release_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
1084void
1085mux_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
1148void
1149usage()
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
1159int
1160main(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}
1211