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