12088Ssos/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4228976Suqs * Copyright (c) 1994-1995 S��ren Schmidt
52088Ssos * All rights reserved.
62088Ssos *
72088Ssos * Redistribution and use in source and binary forms, with or without
82088Ssos * modification, are permitted provided that the following conditions
92088Ssos * are met:
102088Ssos * 1. Redistributions of source code must retain the above copyright
115994Ssos *    notice, this list of conditions and the following disclaimer,
125994Ssos *    in this position and unchanged.
132088Ssos * 2. Redistributions in binary form must reproduce the above copyright
142088Ssos *    notice, this list of conditions and the following disclaimer in the
152088Ssos *    documentation and/or other materials provided with the distribution.
162088Ssos * 3. The name of the author may not be used to endorse or promote products
1797748Sschweikh *    derived from this software without specific prior written permission
182088Ssos *
192088Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
202088Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
212088Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
222088Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
232088Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
242088Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
252088Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
262088Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
272088Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
282088Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
292088Ssos */
302088Ssos
31114601Sobrien#include <sys/cdefs.h>
32114601Sobrien__FBSDID("$FreeBSD: stable/11/usr.sbin/kbdcontrol/kbdcontrol.c 344124 2019-02-14 15:33:04Z se $");
3329603Scharnier
342088Ssos#include <ctype.h>
3529603Scharnier#include <err.h>
362088Ssos#include <stdio.h>
3729603Scharnier#include <stdlib.h>
383864Sswallace#include <string.h>
3929603Scharnier#include <unistd.h>
4042505Syokota#include <fcntl.h>
4166834Sphk#include <sys/kbio.h>
4266834Sphk#include <sys/consio.h>
43296926Semaste#include <sys/queue.h>
44266839Sray#include <sys/sysctl.h>
452088Ssos#include "path.h"
462088Ssos#include "lex.h"
472088Ssos
4876643Simp/*
4990394Sru * HALT, PDWN, and PASTE aren't defined in 4.x, but we need them to bridge
5090394Sru * to 5.0-current so define them here as a stop gap transition measure.
5176643Simp */
5290394Sru#ifndef	HALT
5390394Sru#define	HALT		0xa1		/* halt machine */
5490394Sru#endif
5590394Sru#ifndef PDWN
5690394Sru#define	PDWN		0xa2		/* halt machine and power down */
5790394Sru#endif
5876643Simp#ifndef PASTE
5976643Simp#define PASTE		0xa3		/* paste from cut-paste buffer */
6076643Simp#endif
6176643Simp
62196500Sed#define	SPECIAL		0x80000000
63196500Sed
64228437Sedstatic const char ctrl_names[32][4] = {
658857Srgrimes	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
662088Ssos	"bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
672088Ssos	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
6838139Syokota	"can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us "
692088Ssos	};
702088Ssos
71228437Sedstatic const char acc_names[15][5] = {
7232316Syokota	"dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot",
7332316Syokota	"duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo",
7432316Syokota	"dcar",
7532316Syokota	};
7632316Syokota
77228437Sedstatic const char acc_names_u[15][5] = {
7832316Syokota	"DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT",
7932316Syokota	"DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO",
8032316Syokota	"DCAR",
8132316Syokota	};
8232316Syokota
83228437Sedstatic const char fkey_table[96][MAXFK] = {
845994Ssos/* 01-04 */	"\033[M", "\033[N", "\033[O", "\033[P",
855994Ssos/* 05-08 */	"\033[Q", "\033[R", "\033[S", "\033[T",
865994Ssos/* 09-12 */	"\033[U", "\033[V", "\033[W", "\033[X",
875994Ssos/* 13-16 */	"\033[Y", "\033[Z", "\033[a", "\033[b",
885994Ssos/* 17-20 */	"\033[c", "\033[d", "\033[e", "\033[f",
895994Ssos/* 21-24 */	"\033[g", "\033[h", "\033[i", "\033[j",
905994Ssos/* 25-28 */	"\033[k", "\033[l", "\033[m", "\033[n",
915994Ssos/* 29-32 */	"\033[o", "\033[p", "\033[q", "\033[r",
925994Ssos/* 33-36 */	"\033[s", "\033[t", "\033[u", "\033[v",
935994Ssos/* 37-40 */	"\033[w", "\033[x", "\033[y", "\033[z",
945994Ssos/* 41-44 */	"\033[@", "\033[[", "\033[\\","\033[]",
959202Srgrimes/* 45-48 */     "\033[^", "\033[_", "\033[`", "\033[{",
965994Ssos/* 49-52 */	"\033[H", "\033[A", "\033[I", "-"     ,
975994Ssos/* 53-56 */	"\033[D", "\033[E", "\033[C", "+"     ,
985994Ssos/* 57-60 */	"\033[F", "\033[B", "\033[G", "\033[L",
999202Srgrimes/* 61-64 */     "\177",   "\033[J", "\033[~", "\033[}",
1005994Ssos/* 65-68 */	""      , ""      , ""      , ""      ,
1015994Ssos/* 69-72 */	""      , ""      , ""      , ""      ,
1025994Ssos/* 73-76 */	""      , ""      , ""      , ""      ,
1035994Ssos/* 77-80 */	""      , ""      , ""      , ""      ,
1045994Ssos/* 81-84 */	""      , ""      , ""      , ""      ,
1055994Ssos/* 85-88 */	""      , ""      , ""      , ""      ,
1065994Ssos/* 89-92 */	""      , ""      , ""      , ""      ,
1075994Ssos/* 93-96 */	""      , ""      , ""      , ""      ,
1082088Ssos	};
1092088Ssos
110228437Sedstatic const int delays[]  = {250, 500, 750, 1000};
111228437Sedstatic const int repeats[] = { 34,  38,  42,  46,  50,  55,  59,  63,
112228437Sed		      68,  76,  84,  92, 100, 110, 118, 126,
113228437Sed		     136, 152, 168, 184, 200, 220, 236, 252,
114228437Sed		     272, 304, 336, 368, 400, 440, 472, 504};
115228437Sedstatic const int ndelays = (sizeof(delays) / sizeof(int));
116228437Sedstatic const int nrepeats = (sizeof(repeats) / sizeof(int));
117228437Sedstatic int	hex = 0;
118296926Semastestatic int	paths_configured = 0;
119228437Sedstatic int	token;
1202088Ssos
121228437Sedint		number;
122228437Sedchar		letter;
1232088Ssos
124296926Semastestatic void	add_keymap_path(const char *path);
125228437Sedstatic void	dump_accent_definition(char *name, accentmap_t *accentmap);
126228437Sedstatic void	dump_entry(int value);
127228437Sedstatic void	dump_key_definition(char *name, keymap_t *keymap);
128228437Sedstatic int	get_accent_definition_line(accentmap_t *);
129228437Sedstatic int	get_entry(void);
130228437Sedstatic int	get_key_definition_line(keymap_t *);
131228437Sedstatic void	load_keymap(char *opt, int dumponly);
132228437Sedstatic void	load_default_functionkeys(void);
133228437Sedstatic char *	nextarg(int ac, char **av, int *indp, int oc);
134228437Sedstatic char *	mkfullname(const char *s1, const char *s2, const char *s3);
135228437Sedstatic void	print_accent_definition_line(FILE *fp, int accent,
136228437Sed		struct acc_t *key);
137228437Sedstatic void	print_entry(FILE *fp, int value);
138228437Sedstatic void	print_key_definition_line(FILE *fp, int scancode,
139228437Sed		struct keyent_t *key);
140228437Sedstatic void	print_keymap(void);
141228437Sedstatic void	release_keyboard(void);
142228437Sedstatic void	mux_keyboard(u_int op, char *kbd);
143228437Sedstatic void	set_bell_values(char *opt);
144228437Sedstatic void	set_functionkey(char *keynumstr, char *string);
145228437Sedstatic void	set_keyboard(char *device);
146228437Sedstatic void	set_keyrates(char *opt);
147228437Sedstatic void	show_kbd_info(void);
148228437Sedstatic void	usage(void) __dead2;
149228437Sed
150296926Semastestruct pathent {
151296926Semaste	STAILQ_ENTRY(pathent) next;
152296926Semaste	char *path;
153296926Semaste};
154296926Semastestatic STAILQ_HEAD(, pathent) pathlist = STAILQ_HEAD_INITIALIZER(pathlist);
155296926Semaste
156266839Sray/* Detect presence of vt(4). */
157266839Sraystatic int
158266839Srayis_vt4(void)
159266839Sray{
160268175Semaste	char vty_name[4] = "";
161268175Semaste	size_t len = sizeof(vty_name);
162266839Sray
163268175Semaste	if (sysctlbyname("kern.vty", vty_name, &len, NULL, 0) != 0)
164268175Semaste		return (0);
165268175Semaste	return (strcmp(vty_name, "vt") == 0);
166266839Sray}
167266839Sray
168228437Sedstatic char *
1692088Ssosnextarg(int ac, char **av, int *indp, int oc)
1702088Ssos{
1712088Ssos	if (*indp < ac)
1722088Ssos		return(av[(*indp)++]);
17329603Scharnier	warnx("option requires two arguments -- %c", oc);
1742088Ssos	usage();
1752088Ssos}
1762088Ssos
1772088Ssos
178228437Sedstatic char *
1792088Ssosmkfullname(const char *s1, const char *s2, const char *s3)
1802088Ssos{
1815536Ssos	static char	*buf = NULL;
1825536Ssos	static int	bufl = 0;
1835536Ssos	int		f;
1842088Ssos
1852088Ssos	f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
18677394Ssobomax	if (f > bufl) {
1872088Ssos		if (buf)
1882088Ssos			buf = (char *)realloc(buf, f);
1892088Ssos		else
1902088Ssos			buf = (char *)malloc(f);
19177394Ssobomax	}
1922088Ssos	if (!buf) {
1932088Ssos		bufl = 0;
1942088Ssos		return(NULL);
1952088Ssos	}
1962088Ssos
1972088Ssos	bufl = f;
1982088Ssos	strcpy(buf, s1);
1992088Ssos	strcat(buf, s2);
2002088Ssos	strcat(buf, s3);
2012088Ssos	return(buf);
2022088Ssos}
2032088Ssos
2042088Ssos
205228437Sedstatic int
20699816Salfredget_entry(void)
2072088Ssos{
20832316Syokota	switch ((token = yylex())) {
2092088Ssos	case TNOP:
210196500Sed		return NOP | SPECIAL;
2112088Ssos	case TLSH:
212196500Sed		return LSH | SPECIAL;
2132088Ssos	case TRSH:
214196500Sed		return RSH | SPECIAL;
2152088Ssos	case TCLK:
216196500Sed		return CLK | SPECIAL;
2172088Ssos	case TNLK:
218196500Sed		return NLK | SPECIAL;
2192088Ssos	case TSLK:
220196500Sed		return SLK | SPECIAL;
2212088Ssos	case TBTAB:
222196500Sed		return BTAB | SPECIAL;
2232088Ssos	case TLALT:
224196500Sed		return LALT | SPECIAL;
2252088Ssos	case TLCTR:
226196500Sed		return LCTR | SPECIAL;
2272088Ssos	case TNEXT:
228196500Sed		return NEXT | SPECIAL;
22948105Syokota	case TPREV:
230196500Sed		return PREV | SPECIAL;
2312088Ssos	case TRCTR:
232196500Sed		return RCTR | SPECIAL;
2332088Ssos	case TRALT:
234196500Sed		return RALT | SPECIAL;
2352088Ssos	case TALK:
236196500Sed		return ALK | SPECIAL;
2372088Ssos	case TASH:
238196500Sed		return ASH | SPECIAL;
2392088Ssos	case TMETA:
240196500Sed		return META | SPECIAL;
2412088Ssos	case TRBT:
242196500Sed		return RBT | SPECIAL;
2432088Ssos	case TDBG:
244196500Sed		return DBG | SPECIAL;
2455994Ssos	case TSUSP:
246196500Sed		return SUSP | SPECIAL;
24738053Syokota	case TSPSC:
248196500Sed		return SPSC | SPECIAL;
24954380Syokota	case TPANIC:
250196500Sed		return PNC | SPECIAL;
25154380Syokota	case TLSHA:
252196500Sed		return LSHA | SPECIAL;
25354380Syokota	case TRSHA:
254196500Sed		return RSHA | SPECIAL;
25554380Syokota	case TLCTRA:
256196500Sed		return LCTRA | SPECIAL;
25754380Syokota	case TRCTRA:
258196500Sed		return RCTRA | SPECIAL;
25954380Syokota	case TLALTA:
260196500Sed		return LALTA | SPECIAL;
26154380Syokota	case TRALTA:
262196500Sed		return RALTA | SPECIAL;
26365759Sdwmalone	case THALT:
264196500Sed		return HALT | SPECIAL;
26565759Sdwmalone	case TPDWN:
266196500Sed		return PDWN | SPECIAL;
26774118Sache	case TPASTE:
268196500Sed		return PASTE | SPECIAL;
26932316Syokota	case TACC:
27032316Syokota		if (ACC(number) > L_ACC)
27132316Syokota			return -1;
272196500Sed		return ACC(number) | SPECIAL;
2732088Ssos	case TFUNC:
2742088Ssos		if (F(number) > L_FN)
2752088Ssos			return -1;
276196500Sed		return F(number) | SPECIAL;
2772088Ssos	case TSCRN:
2782088Ssos		if (S(number) > L_SCR)
2792088Ssos			return -1;
280196500Sed		return S(number) | SPECIAL;
2812088Ssos	case TLET:
2822088Ssos		return (unsigned char)letter;
2832088Ssos	case TNUM:
284197330Sed		if (number < 0x000000 || number > 0x10FFFF)
2852088Ssos			return -1;
2862088Ssos		return number;
2872088Ssos	default:
2882088Ssos		return -1;
2892088Ssos	}
2902088Ssos}
2912088Ssos
29277394Ssobomaxstatic int
293296926Semasteget_definition_line(FILE *file, keymap_t *keymap, accentmap_t *accentmap)
2942088Ssos{
29532316Syokota	int c;
2962088Ssos
297296926Semaste	yyin = file;
2982088Ssos
29932316Syokota	if (token < 0)
30032316Syokota		token = yylex();
30132316Syokota	switch (token) {
30232316Syokota	case TNUM:
30332316Syokota		c = get_key_definition_line(keymap);
30432316Syokota		if (c < 0)
30532316Syokota			errx(1, "invalid key definition");
30632316Syokota		if (c > keymap->n_keys)
30732316Syokota			keymap->n_keys = c;
30832316Syokota		break;
30932316Syokota	case TACC:
31032316Syokota		c = get_accent_definition_line(accentmap);
31132316Syokota		if (c < 0)
31232316Syokota			errx(1, "invalid accent key definition");
31332316Syokota		if (c > accentmap->n_accs)
31432316Syokota			accentmap->n_accs = c;
31532316Syokota		break;
31632316Syokota	case 0:
31732316Syokota		/* EOF */
3182088Ssos		return -1;
31932316Syokota	default:
32032316Syokota		errx(1, "illegal definition line");
32132316Syokota	}
32232316Syokota	return c;
32332316Syokota}
32432316Syokota
325228437Sedstatic int
32632316Syokotaget_key_definition_line(keymap_t *map)
32732316Syokota{
32832316Syokota	int i, def, scancode;
32932316Syokota
33032316Syokota	/* check scancode number */
3312088Ssos	if (number < 0 || number >= NUM_KEYS)
3322088Ssos		return -1;
3332088Ssos	scancode = number;
3342088Ssos
3352088Ssos	/* get key definitions */
3362088Ssos	map->key[scancode].spcl = 0;
3372088Ssos	for (i=0; i<NUM_STATES; i++) {
3382088Ssos		if ((def = get_entry()) == -1)
3392088Ssos			return -1;
340196500Sed		if (def & SPECIAL)
3412088Ssos			map->key[scancode].spcl |= (0x80 >> i);
342196500Sed		map->key[scancode].map[i] = def & ~SPECIAL;
3432088Ssos	}
3442088Ssos	/* get lock state key def */
34532316Syokota	if ((token = yylex()) != TFLAG)
3462088Ssos		return -1;
3472088Ssos	map->key[scancode].flgs = number;
34832316Syokota	token = yylex();
34932316Syokota	return (scancode + 1);
3502088Ssos}
3512088Ssos
352228437Sedstatic int
35332316Syokotaget_accent_definition_line(accentmap_t *map)
35432316Syokota{
35532316Syokota	int accent;
35632316Syokota	int c1, c2;
35732316Syokota	int i;
3582088Ssos
35932316Syokota	if (ACC(number) < F_ACC || ACC(number) > L_ACC)
36032316Syokota		/* number out of range */
36132316Syokota		return -1;
36232316Syokota	accent = number;
36332316Syokota	if (map->acc[accent].accchar != 0) {
36432316Syokota		/* this entry has already been defined before! */
36532316Syokota		errx(1, "duplicated accent key definition");
36632316Syokota	}
36732316Syokota
36832316Syokota	switch ((token = yylex())) {
36932316Syokota	case TLET:
37032316Syokota		map->acc[accent].accchar = letter;
37132316Syokota		break;
37232316Syokota	case TNUM:
37332316Syokota		map->acc[accent].accchar = number;
37432316Syokota		break;
37532316Syokota	default:
37632316Syokota		return -1;
37732316Syokota	}
37832316Syokota
37932316Syokota	for (i = 0; (token = yylex()) == '(';) {
38032316Syokota		switch ((token = yylex())) {
38132316Syokota		case TLET:
38232316Syokota			c1 = letter;
38332316Syokota			break;
38432316Syokota		case TNUM:
38532316Syokota			c1 = number;
38632316Syokota			break;
38732316Syokota		default:
38832316Syokota			return -1;
38932316Syokota		}
39032316Syokota		switch ((token = yylex())) {
39132316Syokota		case TLET:
39232316Syokota			c2 = letter;
39332316Syokota			break;
39432316Syokota		case TNUM:
39532316Syokota			c2 = number;
39632316Syokota			break;
39732316Syokota		default:
39832316Syokota			return -1;
39932316Syokota		}
40032316Syokota		if ((token = yylex()) != ')')
40132316Syokota			return -1;
40232316Syokota		if (i >= NUM_ACCENTCHARS) {
40332316Syokota			warnx("too many accented characters, ignored");
40432316Syokota			continue;
40532316Syokota		}
40632316Syokota		map->acc[accent].map[i][0] = c1;
40732316Syokota		map->acc[accent].map[i][1] = c2;
40832316Syokota		++i;
40932316Syokota	}
41032316Syokota	return (accent + 1);
41132316Syokota}
41232316Syokota
413228437Sedstatic void
4142088Ssosprint_entry(FILE *fp, int value)
4152088Ssos{
416196500Sed	int val = value & ~SPECIAL;
4172088Ssos
4182088Ssos	switch (value) {
419196500Sed	case NOP | SPECIAL:
4208857Srgrimes		fprintf(fp, " nop   ");
4212088Ssos		break;
422196500Sed	case LSH | SPECIAL:
4232088Ssos		fprintf(fp, " lshift");
4242088Ssos		break;
425196500Sed	case RSH | SPECIAL:
4262088Ssos		fprintf(fp, " rshift");
4272088Ssos		break;
428196500Sed	case CLK | SPECIAL:
4292088Ssos		fprintf(fp, " clock ");
4302088Ssos		break;
431196500Sed	case NLK | SPECIAL:
4322088Ssos		fprintf(fp, " nlock ");
4332088Ssos		break;
434196500Sed	case SLK | SPECIAL:
4352088Ssos		fprintf(fp, " slock ");
4362088Ssos		break;
437196500Sed	case BTAB | SPECIAL:
4382088Ssos		fprintf(fp, " btab  ");
4392088Ssos		break;
440196500Sed	case LALT | SPECIAL:
4412088Ssos		fprintf(fp, " lalt  ");
4422088Ssos		break;
443196500Sed	case LCTR | SPECIAL:
4442088Ssos		fprintf(fp, " lctrl ");
4452088Ssos		break;
446196500Sed	case NEXT | SPECIAL:
4472088Ssos		fprintf(fp, " nscr  ");
4482088Ssos		break;
449196500Sed	case PREV | SPECIAL:
45048105Syokota		fprintf(fp, " pscr  ");
45148105Syokota		break;
452196500Sed	case RCTR | SPECIAL:
4532088Ssos		fprintf(fp, " rctrl ");
4542088Ssos		break;
455196500Sed	case RALT | SPECIAL:
4562088Ssos		fprintf(fp, " ralt  ");
4572088Ssos		break;
458196500Sed	case ALK | SPECIAL:
4592088Ssos		fprintf(fp, " alock ");
4602088Ssos		break;
461196500Sed	case ASH | SPECIAL:
4622088Ssos		fprintf(fp, " ashift");
4632088Ssos		break;
464196500Sed	case META | SPECIAL:
4652088Ssos		fprintf(fp, " meta  ");
4662088Ssos		break;
467196500Sed	case RBT | SPECIAL:
4682088Ssos		fprintf(fp, " boot  ");
4692088Ssos		break;
470196500Sed	case DBG | SPECIAL:
4712088Ssos		fprintf(fp, " debug ");
4722088Ssos		break;
473196500Sed	case SUSP | SPECIAL:
47432316Syokota		fprintf(fp, " susp  ");
47532316Syokota		break;
476196500Sed	case SPSC | SPECIAL:
47738053Syokota		fprintf(fp, " saver ");
47838053Syokota		break;
479196500Sed	case PNC | SPECIAL:
48054380Syokota		fprintf(fp, " panic ");
48154380Syokota		break;
482196500Sed	case LSHA | SPECIAL:
48354380Syokota		fprintf(fp, " lshifta");
48454380Syokota		break;
485196500Sed	case RSHA | SPECIAL:
48654380Syokota		fprintf(fp, " rshifta");
48754380Syokota		break;
488196500Sed	case LCTRA | SPECIAL:
48954380Syokota		fprintf(fp, " lctrla");
49054380Syokota		break;
491196500Sed	case RCTRA | SPECIAL:
49254380Syokota		fprintf(fp, " rctrla");
49354380Syokota		break;
494196500Sed	case LALTA | SPECIAL:
49554380Syokota		fprintf(fp, " lalta ");
49654380Syokota		break;
497196500Sed	case RALTA | SPECIAL:
49854380Syokota		fprintf(fp, " ralta ");
49954380Syokota		break;
500196500Sed	case HALT | SPECIAL:
50165759Sdwmalone		fprintf(fp, " halt  ");
50265759Sdwmalone		break;
503196500Sed	case PDWN | SPECIAL:
50465759Sdwmalone		fprintf(fp, " pdwn  ");
50565759Sdwmalone		break;
506196500Sed	case PASTE | SPECIAL:
50774118Sache		fprintf(fp, " paste ");
50874118Sache		break;
5092088Ssos	default:
510196500Sed		if (value & SPECIAL) {
5118857Srgrimes		 	if (val >= F_FN && val <= L_FN)
5122088Ssos				fprintf(fp, " fkey%02d", val - F_FN + 1);
5138857Srgrimes		 	else if (val >= F_SCR && val <= L_SCR)
5142088Ssos				fprintf(fp, " scr%02d ", val - F_SCR + 1);
51532316Syokota		 	else if (val >= F_ACC && val <= L_ACC)
51632316Syokota				fprintf(fp, " %-6s", acc_names[val - F_ACC]);
5172088Ssos			else if (hex)
5188857Srgrimes				fprintf(fp, " 0x%02x  ", val);
5192088Ssos			else
52032316Syokota				fprintf(fp, " %3d   ", val);
5212088Ssos		}
5222088Ssos		else {
5232088Ssos			if (val < ' ')
5248857Srgrimes				fprintf(fp, " %s   ", ctrl_names[val]);
5252088Ssos			else if (val == 127)
5268857Srgrimes				fprintf(fp, " del   ");
5279202Srgrimes			else if (isascii(val) && isprint(val))
5288857Srgrimes				fprintf(fp, " '%c'   ", val);
5292088Ssos			else if (hex)
5308857Srgrimes				fprintf(fp, " 0x%02x  ", val);
5312088Ssos			else
5328857Srgrimes				fprintf(fp, " %3d   ", val);
5332088Ssos		}
5342088Ssos	}
5352088Ssos}
5362088Ssos
537228437Sedstatic void
53842505Syokotaprint_key_definition_line(FILE *fp, int scancode, struct keyent_t *key)
5392088Ssos{
54029603Scharnier	int i;
5412088Ssos
5422088Ssos	/* print scancode number */
5432088Ssos	if (hex)
5442088Ssos		fprintf(fp, " 0x%02x  ", scancode);
5452088Ssos	else
5462088Ssos		fprintf(fp, "  %03d  ", scancode);
5472088Ssos
5482088Ssos	/* print key definitions */
5492088Ssos	for (i=0; i<NUM_STATES; i++) {
5502088Ssos		if (key->spcl & (0x80 >> i))
551196500Sed			print_entry(fp, key->map[i] | SPECIAL);
5522088Ssos		else
5538857Srgrimes			print_entry(fp, key->map[i]);
5542088Ssos	}
5552088Ssos
5562088Ssos	/* print lock state key def */
5572088Ssos	switch (key->flgs) {
5582088Ssos	case 0:
5592088Ssos		fprintf(fp, "  O\n");
5602088Ssos		break;
5612088Ssos	case 1:
5622088Ssos		fprintf(fp, "  C\n");
5632088Ssos		break;
5642088Ssos	case 2:
5652088Ssos		fprintf(fp, "  N\n");
5662088Ssos		break;
5676046Ssos	case 3:
5686046Ssos		fprintf(fp, "  B\n");
5696046Ssos		break;
5708857Srgrimes	}
5712088Ssos}
5722088Ssos
573228437Sedstatic void
57432316Syokotaprint_accent_definition_line(FILE *fp, int accent, struct acc_t *key)
57532316Syokota{
57632316Syokota	int c;
57732316Syokota	int i;
5782088Ssos
57932316Syokota	if (key->accchar == 0)
58032316Syokota		return;
58132316Syokota
58232316Syokota	/* print accent number */
58332316Syokota	fprintf(fp, "  %-6s", acc_names[accent]);
58432316Syokota	if (isascii(key->accchar) && isprint(key->accchar))
58532316Syokota		fprintf(fp, "'%c'  ", key->accchar);
58632316Syokota	else if (hex)
58732316Syokota		fprintf(fp, "0x%02x ", key->accchar);
58832316Syokota	else
58932316Syokota		fprintf(fp, "%03d  ", key->accchar);
59032316Syokota
59132316Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
59232316Syokota		c = key->map[i][0];
59332316Syokota		if (c == 0)
59432316Syokota			break;
59532316Syokota		if ((i > 0) && ((i % 4) == 0))
59632316Syokota			fprintf(fp, "\n             ");
59732316Syokota		if (isascii(c) && isprint(c))
59832316Syokota			fprintf(fp, "( '%c' ", c);
59932316Syokota		else if (hex)
60032316Syokota			fprintf(fp, "(0x%02x ", c);
60132316Syokota		else
60232316Syokota			fprintf(fp, "( %03d ", c);
60332316Syokota		c = key->map[i][1];
60432316Syokota		if (isascii(c) && isprint(c))
60532316Syokota			fprintf(fp, "'%c' ) ", c);
60632316Syokota		else if (hex)
60732316Syokota			fprintf(fp, "0x%02x) ", c);
60832316Syokota		else
60932316Syokota			fprintf(fp, "%03d ) ", c);
61032316Syokota	}
61132316Syokota	fprintf(fp, "\n");
61232316Syokota}
61332316Syokota
614228437Sedstatic void
61532316Syokotadump_entry(int value)
61632316Syokota{
617196500Sed	if (value & SPECIAL) {
618196500Sed		value &= ~SPECIAL;
61932316Syokota		switch (value) {
62032316Syokota		case NOP:
62132316Syokota			printf("  NOP, ");
62232316Syokota			break;
62332316Syokota		case LSH:
62432316Syokota			printf("  LSH, ");
62532316Syokota			break;
62632316Syokota		case RSH:
62732316Syokota			printf("  RSH, ");
62832316Syokota			break;
62932316Syokota		case CLK:
63032316Syokota			printf("  CLK, ");
63132316Syokota			break;
63232316Syokota		case NLK:
63332316Syokota			printf("  NLK, ");
63432316Syokota			break;
63532316Syokota		case SLK:
63632316Syokota			printf("  SLK, ");
63732316Syokota			break;
63832316Syokota		case BTAB:
63932316Syokota			printf(" BTAB, ");
64032316Syokota			break;
64132316Syokota		case LALT:
64232316Syokota			printf(" LALT, ");
64332316Syokota			break;
64432316Syokota		case LCTR:
64532316Syokota			printf(" LCTR, ");
64632316Syokota			break;
64732316Syokota		case NEXT:
64832316Syokota			printf(" NEXT, ");
64932316Syokota			break;
65048105Syokota		case PREV:
65148105Syokota			printf(" PREV, ");
65248105Syokota			break;
65332316Syokota		case RCTR:
65432316Syokota			printf(" RCTR, ");
65532316Syokota			break;
65632316Syokota		case RALT:
65732316Syokota			printf(" RALT, ");
65832316Syokota			break;
65932316Syokota		case ALK:
66032316Syokota			printf("  ALK, ");
66132316Syokota			break;
66232316Syokota		case ASH:
66332316Syokota			printf("  ASH, ");
66432316Syokota			break;
66532316Syokota		case META:
66632316Syokota			printf(" META, ");
66732316Syokota			break;
66832316Syokota		case RBT:
66932316Syokota			printf("  RBT, ");
67032316Syokota			break;
67132316Syokota		case DBG:
67232316Syokota			printf("  DBG, ");
67332316Syokota			break;
67432316Syokota		case SUSP:
67532316Syokota			printf(" SUSP, ");
67632316Syokota			break;
67738053Syokota		case SPSC:
67838053Syokota			printf(" SPSC, ");
67938053Syokota			break;
68054380Syokota		case PNC:
68154380Syokota			printf("  PNC, ");
68254380Syokota			break;
68354380Syokota		case LSHA:
68454380Syokota			printf(" LSHA, ");
68554380Syokota			break;
68654380Syokota		case RSHA:
68754380Syokota			printf(" RSHA, ");
68854380Syokota			break;
68954380Syokota		case LCTRA:
69054380Syokota			printf("LCTRA, ");
69154380Syokota			break;
69254380Syokota		case RCTRA:
69354380Syokota			printf("RCTRA, ");
69454380Syokota			break;
69554380Syokota		case LALTA:
69654380Syokota			printf("LALTA, ");
69754380Syokota			break;
69854380Syokota		case RALTA:
69954380Syokota			printf("RALTA, ");
70054380Syokota			break;
70165759Sdwmalone		case HALT:
70265759Sdwmalone			printf(" HALT, ");
70365759Sdwmalone			break;
70465759Sdwmalone		case PDWN:
70565759Sdwmalone			printf(" PDWN, ");
70665759Sdwmalone			break;
70774118Sache		case PASTE:
70874118Sache			printf("PASTE, ");
70974118Sache			break;
71032316Syokota		default:
71132316Syokota	 		if (value >= F_FN && value <= L_FN)
71232316Syokota				printf(" F(%2d),", value - F_FN + 1);
71332316Syokota	 		else if (value >= F_SCR && value <= L_SCR)
71432486Syokota				printf(" S(%2d),", value - F_SCR + 1);
71532316Syokota	 		else if (value >= F_ACC && value <= L_ACC)
71632316Syokota				printf(" %-4s, ", acc_names_u[value - F_ACC]);
71732316Syokota			else
71832316Syokota				printf(" 0x%02X, ", value);
71932316Syokota			break;
72032316Syokota		}
72132316Syokota	} else if (value == '\'') {
72232316Syokota		printf(" '\\'', ");
72332316Syokota	} else if (value == '\\') {
72432316Syokota		printf(" '\\\\', ");
72532316Syokota	} else if (isascii(value) && isprint(value)) {
72632316Syokota		printf("  '%c', ", value);
72732316Syokota	} else {
72832316Syokota		printf(" 0x%02X, ", value);
72932316Syokota	}
73032316Syokota}
73132316Syokota
732228437Sedstatic void
73332316Syokotadump_key_definition(char *name, keymap_t *keymap)
73432316Syokota{
73532316Syokota	int	i, j;
73632316Syokota
73732486Syokota	printf("static keymap_t keymap_%s = { 0x%02x, {\n",
73832316Syokota	       name, (unsigned)keymap->n_keys);
73932316Syokota	printf(
74032486Syokota"/*                                                         alt\n"
74132486Syokota" * scan                       cntrl          alt    alt   cntrl\n"
74232486Syokota" * code  base   shift  cntrl  shift   alt   shift  cntrl  shift    spcl flgs\n"
74332316Syokota" * ---------------------------------------------------------------------------\n"
74432316Syokota" */\n");
74532316Syokota	for (i = 0; i < keymap->n_keys; i++) {
74632486Syokota		printf("/*%02x*/{{", i);
74732316Syokota		for (j = 0; j < NUM_STATES; j++) {
74832316Syokota			if (keymap->key[i].spcl & (0x80 >> j))
749196500Sed				dump_entry(keymap->key[i].map[j] | SPECIAL);
75032316Syokota			else
75132316Syokota				dump_entry(keymap->key[i].map[j]);
75232316Syokota		}
75332486Syokota		printf("}, 0x%02X,0x%02X },\n",
75432316Syokota		       (unsigned)keymap->key[i].spcl,
75532316Syokota		       (unsigned)keymap->key[i].flgs);
75632316Syokota	}
75732486Syokota	printf("} };\n\n");
75832316Syokota}
75932316Syokota
760228437Sedstatic void
76132316Syokotadump_accent_definition(char *name, accentmap_t *accentmap)
76232316Syokota{
76332316Syokota	int i, j;
76432316Syokota	int c;
76532316Syokota
76632486Syokota	printf("static accentmap_t accentmap_%s = { %d",
76732316Syokota		name, accentmap->n_accs);
76832486Syokota	if (accentmap->n_accs <= 0) {
76932486Syokota		printf(" };\n\n");
77032486Syokota		return;
77132486Syokota	}
77232486Syokota	printf(", {\n");
77332316Syokota	for (i = 0; i < NUM_DEADKEYS; i++) {
77432316Syokota		printf("    /* %s=%d */\n    {", acc_names[i], i);
77532316Syokota		c = accentmap->acc[i].accchar;
77632316Syokota		if (c == '\'')
77732316Syokota			printf(" '\\'', {");
77832316Syokota		else if (c == '\\')
77932316Syokota			printf(" '\\\\', {");
78032316Syokota		else if (isascii(c) && isprint(c))
78132316Syokota			printf("  '%c', {", c);
78232316Syokota		else if (c == 0) {
78332316Syokota			printf(" 0x00 }, \n");
78432316Syokota			continue;
78532316Syokota		} else
78632316Syokota			printf(" 0x%02x, {", c);
78732316Syokota		for (j = 0; j < NUM_ACCENTCHARS; j++) {
78832316Syokota			c = accentmap->acc[i].map[j][0];
78932316Syokota			if (c == 0)
79032316Syokota				break;
79132316Syokota			if ((j > 0) && ((j % 4) == 0))
79232316Syokota				printf("\n\t     ");
79332316Syokota			if (isascii(c) && isprint(c))
79432316Syokota				printf(" {  '%c',", c);
79532316Syokota			else
79632316Syokota				printf(" { 0x%02x,", c);
79732316Syokota			printf("0x%02x },", accentmap->acc[i].map[j][1]);
79832316Syokota		}
79932316Syokota		printf(" }, },\n");
80032316Syokota	}
80132486Syokota	printf("} };\n\n");
80232316Syokota}
80332316Syokota
804228437Sedstatic void
805296926Semasteadd_keymap_path(const char *path)
806296926Semaste{
807296926Semaste	struct pathent* pe;
808296926Semaste	size_t len;
809296926Semaste
810296926Semaste	len = strlen(path);
811296926Semaste	if ((pe = malloc(sizeof(*pe))) == NULL ||
812296926Semaste	    (pe->path = malloc(len + 2)) == NULL)
813296926Semaste		err(1, "malloc");
814296926Semaste	memcpy(pe->path, path, len);
815296926Semaste	if (len > 0 && path[len - 1] != '/')
816296926Semaste		pe->path[len++] = '/';
817296926Semaste	pe->path[len] = '\0';
818296926Semaste	STAILQ_INSERT_TAIL(&pathlist, pe, next);
819296926Semaste}
820296926Semaste
821296926Semastestatic void
82219569Sjoergload_keymap(char *opt, int dumponly)
8232088Ssos{
82432316Syokota	keymap_t keymap;
82532316Syokota	accentmap_t accentmap;
826296926Semaste	struct pathent *pe;
827296926Semaste	FILE	*file;
828296926Semaste	int	j;
82919569Sjoerg	char	*name, *cp;
830266839Sray	char	blank[] = "", keymap_path[] = KEYMAP_PATH;
831266839Sray	char	vt_keymap_path[] = VT_KEYMAP_PATH, dotkbd[] = ".kbd";
83299816Salfred	char	*postfix[] = {blank, dotkbd, NULL};
8332088Ssos
834296926Semaste	if (!paths_configured) {
835296926Semaste		cp = getenv("KEYMAP_PATH");
836296926Semaste		if (cp != NULL)
837296926Semaste			add_keymap_path(cp);
838296926Semaste		add_keymap_path("");
839296926Semaste		if (is_vt4())
840296926Semaste			add_keymap_path(vt_keymap_path);
841296926Semaste		else
842296926Semaste			add_keymap_path(keymap_path);
843296926Semaste		paths_configured = 1;
844296926Semaste	}
84576502Ssobomax
846296926Semaste	file = NULL;
847296926Semaste	STAILQ_FOREACH(pe, &pathlist, next) {
848296926Semaste		for (j=0; postfix[j] && file == NULL; j++) {
849296926Semaste			name = mkfullname(pe->path, opt, postfix[j]);
850296926Semaste			file = fopen(name, "r");
851296926Semaste			if (file != NULL)
852296926Semaste				break;
85376502Ssobomax		}
85476643Simp	}
855296926Semaste	if (file == NULL) {
85679677Sobrien		warn("keymap file \"%s\" not found", opt);
8572088Ssos		return;
8582088Ssos	}
85932316Syokota	memset(&keymap, 0, sizeof(keymap));
86032316Syokota	memset(&accentmap, 0, sizeof(accentmap));
86132316Syokota	token = -1;
8622088Ssos	while (1) {
863296926Semaste		if (get_definition_line(file, &keymap, &accentmap) < 0)
8642088Ssos			break;
8652088Ssos    	}
86619569Sjoerg	if (dumponly) {
86719569Sjoerg		/* fix up the filename to make it a valid C identifier */
86819569Sjoerg		for (cp = opt; *cp; cp++)
86919569Sjoerg			if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_';
87032316Syokota		printf("/*\n"
87132316Syokota		       " * Automatically generated from %s.\n"
87232316Syokota	               " * DO NOT EDIT!\n"
87332316Syokota		       " */\n", name);
87432316Syokota		dump_key_definition(opt, &keymap);
87532316Syokota		dump_accent_definition(opt, &accentmap);
87619569Sjoerg		return;
87719569Sjoerg	}
87832316Syokota	if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) {
87929603Scharnier		warn("setting keymap");
880296926Semaste		fclose(file);
8812088Ssos		return;
8822088Ssos	}
88332316Syokota	if ((accentmap.n_accs > 0)
88432316Syokota		&& (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) {
88532316Syokota		warn("setting accentmap");
886296926Semaste		fclose(file);
88732316Syokota		return;
88832316Syokota	}
8892088Ssos}
8902088Ssos
891228437Sedstatic void
89299816Salfredprint_keymap(void)
8932088Ssos{
89432316Syokota	keymap_t keymap;
89532316Syokota	accentmap_t accentmap;
8962088Ssos	int i;
8972088Ssos
89832316Syokota	if (ioctl(0, GIO_KEYMAP, &keymap) < 0)
89929603Scharnier		err(1, "getting keymap");
90032316Syokota	if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0)
90132316Syokota		memset(&accentmap, 0, sizeof(accentmap));
9022088Ssos    	printf(
9032088Ssos"#                                                         alt\n"
9042088Ssos"# scan                       cntrl          alt    alt   cntrl lock\n"
9052088Ssos"# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
9062088Ssos"# ------------------------------------------------------------------\n"
9072088Ssos    	);
90832316Syokota	for (i=0; i<keymap.n_keys; i++)
90932316Syokota		print_key_definition_line(stdout, i, &keymap.key[i]);
91032316Syokota
91132316Syokota	printf("\n");
91232316Syokota	for (i = 0; i < NUM_DEADKEYS; i++)
91332316Syokota		print_accent_definition_line(stdout, i, &accentmap.acc[i]);
91432316Syokota
9152088Ssos}
9162088Ssos
917228437Sedstatic void
91899816Salfredload_default_functionkeys(void)
9192088Ssos{
9202088Ssos	fkeyarg_t fkey;
9212088Ssos	int i;
9222088Ssos
9232088Ssos	for (i=0; i<NUM_FKEYS; i++) {
9242088Ssos		fkey.keynum = i;
9252088Ssos		strcpy(fkey.keydef, fkey_table[i]);
9262088Ssos		fkey.flen = strlen(fkey_table[i]);
9272088Ssos		if (ioctl(0, SETFKEY, &fkey) < 0)
92829603Scharnier			warn("setting function key");
9292088Ssos	}
9302088Ssos}
9312088Ssos
932228437Sedstatic void
9332088Ssosset_functionkey(char *keynumstr, char *string)
9342088Ssos{
9352088Ssos	fkeyarg_t fkey;
9362088Ssos
9372088Ssos	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
9382088Ssos		load_default_functionkeys();
9392088Ssos		return;
9402088Ssos	}
9412088Ssos	fkey.keynum = atoi(keynumstr);
9422088Ssos	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
94329603Scharnier		warnx("function key number must be between 1 and %d",
9442088Ssos			NUM_FKEYS);
9452088Ssos		return;
9462088Ssos	}
9472088Ssos	if ((fkey.flen = strlen(string)) > MAXFK) {
94829603Scharnier		warnx("function key string too long (%d > %d)",
9492088Ssos			fkey.flen, MAXFK);
9502088Ssos		return;
9512088Ssos	}
952133353Sjmg	strncpy(fkey.keydef, string, MAXFK);
9532088Ssos	fkey.keynum -= 1;
9542088Ssos	if (ioctl(0, SETFKEY, &fkey) < 0)
95529603Scharnier		warn("setting function key");
9562088Ssos}
9572088Ssos
958228437Sedstatic void
9592088Ssosset_bell_values(char *opt)
9602088Ssos{
9615536Ssos	int bell, duration, pitch;
9622088Ssos
96338044Syokota	bell = 0;
964344124Sse	duration = 0;
965344124Sse	pitch = 0;
96638044Syokota	if (!strncmp(opt, "quiet.", 6)) {
967164333Sru		bell = CONS_QUIET_BELL;
96838044Syokota		opt += 6;
96938044Syokota	}
9708857Srgrimes	if (!strcmp(opt, "visual"))
971164333Sru		bell |= CONS_VISUAL_BELL;
9725536Ssos	else if (!strcmp(opt, "normal"))
97338044Syokota		duration = 5, pitch = 800;
97448982Syokota	else if (!strcmp(opt, "off"))
97548982Syokota		duration = 0, pitch = 0;
9762088Ssos	else {
9772088Ssos		char		*v1;
9788857Srgrimes
9795536Ssos		bell = 0;
9802088Ssos		duration = strtol(opt, &v1, 0);
9812088Ssos		if ((duration < 0) || (*v1 != '.'))
9822088Ssos			goto badopt;
9832088Ssos		opt = ++v1;
9842088Ssos		pitch = strtol(opt, &v1, 0);
9852088Ssos		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
9862088Ssosbadopt:
98777394Ssobomax			warnx("argument to -b must be duration.pitch or [quiet.]visual|normal|off");
9882088Ssos			return;
9892088Ssos		}
99038044Syokota		if (pitch != 0)
99138044Syokota			pitch = 1193182 / pitch;	/* in Hz */
99238044Syokota		duration /= 10;	/* in 10 m sec */
9932088Ssos	}
9942088Ssos
9955536Ssos	ioctl(0, CONS_BELLTYPE, &bell);
996344124Sse	if (duration > 0 && pitch > 0)
997344124Sse		fprintf(stderr, "\e[=%d;%dB", pitch, duration);
9982088Ssos}
9992088Ssos
1000228437Sedstatic void
10012088Ssosset_keyrates(char *opt)
10022088Ssos{
100344628Syokota	int arg[2];
100439047Syokota	int repeat;
100539047Syokota	int delay;
100646761Syokota	int r, d;
10072088Ssos
100846761Syokota	if (!strcmp(opt, "slow")) {
100944628Syokota		delay = 1000, repeat = 500;
101046761Syokota		d = 3, r = 31;
101146761Syokota	} else if (!strcmp(opt, "normal")) {
101244628Syokota		delay = 500, repeat = 125;
101346761Syokota		d = 1, r = 15;
101446761Syokota	} else if (!strcmp(opt, "fast")) {
101539047Syokota		delay = repeat = 0;
101646761Syokota		d = r = 0;
101746761Syokota	} else {
10182088Ssos		int		n;
10192088Ssos		char		*v1;
10202088Ssos
10212088Ssos		delay = strtol(opt, &v1, 0);
10222088Ssos		if ((delay < 0) || (*v1 != '.'))
10232088Ssos			goto badopt;
10242088Ssos		opt = ++v1;
10252088Ssos		repeat = strtol(opt, &v1, 0);
10262088Ssos		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
10272088Ssosbadopt:
102877394Ssobomax			warnx("argument to -r must be delay.repeat or slow|normal|fast");
10292088Ssos			return;
10302088Ssos		}
103146761Syokota		for (n = 0; n < ndelays - 1; n++)
103246761Syokota			if (delay <= delays[n])
103346761Syokota				break;
103446761Syokota		d = n;
103546761Syokota		for (n = 0; n < nrepeats - 1; n++)
103646761Syokota			if (repeat <= repeats[n])
103746761Syokota				break;
103846761Syokota		r = n;
10392088Ssos	}
10402088Ssos
104144628Syokota	arg[0] = delay;
104244628Syokota	arg[1] = repeat;
104346761Syokota	if (ioctl(0, KDSETREPEAT, arg)) {
104446761Syokota		if (ioctl(0, KDSETRAD, (d << 5) | r))
104546761Syokota			warn("setting keyboard rate");
104646761Syokota	}
10472088Ssos}
10482088Ssos
104999816Salfredstatic const char *
105099816Salfredget_kbd_type_name(int type)
105142505Syokota{
105242505Syokota	static struct {
105342505Syokota		int type;
105499816Salfred		const char *name;
105542505Syokota	} name_table[] = {
105642505Syokota		{ KB_84,	"AT 84" },
105742505Syokota		{ KB_101,	"AT 101/102" },
105842505Syokota		{ KB_OTHER,	"generic" },
105942505Syokota	};
106099816Salfred	unsigned int i;
10616046Ssos
106242505Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
106342505Syokota		if (type == name_table[i].type)
106442505Syokota			return name_table[i].name;
106542505Syokota	}
106642505Syokota	return "unknown";
106742505Syokota}
106842505Syokota
1069228437Sedstatic void
107042505Syokotashow_kbd_info(void)
107142505Syokota{
107242505Syokota	keyboard_info_t info;
107342505Syokota
107442505Syokota	if (ioctl(0, KDGKBINFO, &info) == -1) {
107542505Syokota		warn("unable to obtain keyboard information");
107642505Syokota		return;
107742505Syokota	}
107842505Syokota	printf("kbd%d:\n", info.kb_index);
107942505Syokota	printf("    %.*s%d, type:%s (%d)\n",
108077394Ssobomax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
108142505Syokota		get_kbd_type_name(info.kb_type), info.kb_type);
108242505Syokota}
108342505Syokota
1084228437Sedstatic void
108542505Syokotaset_keyboard(char *device)
108642505Syokota{
108742505Syokota	keyboard_info_t info;
108842505Syokota	int fd;
108942505Syokota
109042505Syokota	fd = open(device, O_RDONLY);
109142505Syokota	if (fd < 0) {
109242505Syokota		warn("cannot open %s", device);
109342505Syokota		return;
109442505Syokota	}
109542505Syokota	if (ioctl(fd, KDGKBINFO, &info) == -1) {
109642505Syokota		warn("unable to obtain keyboard information");
109742505Syokota		close(fd);
109842505Syokota		return;
109942505Syokota	}
110042505Syokota	/*
110142505Syokota	 * The keyboard device driver won't release the keyboard by
110242505Syokota	 * the following ioctl, but it automatically will, when the device
110342505Syokota	 * is closed.  So, we don't check error here.
110442505Syokota	 */
110542505Syokota	ioctl(fd, CONS_RELKBD, 0);
110642505Syokota	close(fd);
110742505Syokota#if 1
110842505Syokota	printf("kbd%d\n", info.kb_index);
110942505Syokota	printf("    %.*s%d, type:%s (%d)\n",
111077394Ssobomax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
111142505Syokota		get_kbd_type_name(info.kb_type), info.kb_type);
111242505Syokota#endif
111342505Syokota
111442505Syokota	if (ioctl(0, CONS_SETKBD, info.kb_index) == -1)
111542505Syokota		warn("unable to set keyboard");
111642505Syokota}
111742505Syokota
1118228437Sedstatic void
111942505Syokotarelease_keyboard(void)
112042505Syokota{
112142505Syokota	keyboard_info_t info;
112242505Syokota
112342505Syokota	/*
112442505Syokota	 * If stdin is not associated with a keyboard, the following ioctl
112542505Syokota	 * will fail.
112642505Syokota	 */
112742505Syokota	if (ioctl(0, KDGKBINFO, &info) == -1) {
112842505Syokota		warn("unable to obtain keyboard information");
112942505Syokota		return;
113042505Syokota	}
113142505Syokota#if 1
113242505Syokota	printf("kbd%d\n", info.kb_index);
113342505Syokota	printf("    %.*s%d, type:%s (%d)\n",
113477394Ssobomax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
113542505Syokota		get_kbd_type_name(info.kb_type), info.kb_type);
113642505Syokota#endif
113742505Syokota	if (ioctl(0, CONS_RELKBD, 0) == -1)
113842505Syokota		warn("unable to release the keyboard");
113942505Syokota}
114042505Syokota
1141228437Sedstatic void
1142162327Semaxmux_keyboard(u_int op, char *kbd)
1143148017Semax{
1144148017Semax	keyboard_info_t	info;
1145148017Semax	char		*unit, *ep;
114642505Syokota
1147148017Semax	/*
1148148017Semax	 * If stdin is not associated with a keyboard, the following ioctl
1149148017Semax	 * will fail.
1150148017Semax	 */
1151148017Semax	if (ioctl(0, KDGKBINFO, &info) == -1) {
1152148017Semax		warn("unable to obtain keyboard information");
1153148017Semax		return;
1154148017Semax	}
1155148017Semax#if 1
1156148017Semax	printf("kbd%d\n", info.kb_index);
1157148017Semax	printf("    %.*s%d, type:%s (%d)\n",
1158148017Semax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
1159148017Semax		get_kbd_type_name(info.kb_type), info.kb_type);
1160148017Semax#endif
1161148017Semax	/*
1162148017Semax	 * split kbd into name and unit. find the right most part of the
1163148017Semax	 * kbd string that consist of only digits.
1164148017Semax	 */
1165148017Semax
1166148017Semax	memset(&info, 0, sizeof(info));
1167148017Semax
1168148017Semax	info.kb_unit = -1;
1169148017Semax	ep = kbd - 1;
1170148017Semax
1171148017Semax	do {
1172148017Semax		unit = strpbrk(ep + 1, "0123456789");
1173148017Semax		if (unit != NULL) {
1174148017Semax			info.kb_unit = strtol(unit, &ep, 10);
1175148017Semax			if (*ep != '\0')
1176148017Semax				info.kb_unit = -1;
1177148017Semax		}
1178148017Semax	} while (unit != NULL && info.kb_unit == -1);
1179148017Semax
1180148017Semax	if (info.kb_unit == -1) {
1181148017Semax		warnx("unable to find keyboard driver unit in '%s'", kbd);
1182148017Semax		return;
1183148017Semax	}
1184148017Semax
1185148017Semax	if (unit == kbd) {
1186148017Semax		warnx("unable to find keyboard driver name in '%s'", kbd);
1187148017Semax		return;
1188148017Semax	}
1189148017Semax	if (unit - kbd >= (int) sizeof(info.kb_name)) {
1190148017Semax		warnx("keyboard name '%s' is too long", kbd);
1191148017Semax		return;
1192148017Semax	}
1193148017Semax
1194148017Semax	strncpy(info.kb_name, kbd, unit - kbd);
1195148017Semax
1196148017Semax	/*
1197148017Semax	 * If stdin is not associated with a kbdmux(4) keyboard, the following
1198148017Semax	 * ioctl will fail.
1199148017Semax	 */
1200148017Semax
1201148017Semax	if (ioctl(0, op, &info) == -1)
1202148017Semax		warn("unable to (un)mux the keyboard");
1203148017Semax}
1204148017Semax
1205228437Sedstatic void
1206201387Sedusage(void)
12072088Ssos{
120829603Scharnier	fprintf(stderr, "%s\n%s\n%s\n",
1209148017Semax"usage: kbdcontrol [-dFKix] [-A name] [-a name] [-b duration.pitch | [quiet.]belltype]",
121029603Scharnier"                  [-r delay.repeat | speed] [-l mapfile] [-f # string]",
1211296926Semaste"                  [-k device] [-L mapfile] [-P path]");
121229603Scharnier	exit(1);
12132088Ssos}
12142088Ssos
12152088Ssos
121651287Speterint
12172088Ssosmain(int argc, char **argv)
12182088Ssos{
1219296926Semaste	const char	*optstring = "A:a:b:df:iKk:Fl:L:P:r:x";
12202088Ssos	int		opt;
12212088Ssos
1222296926Semaste	/* Collect any -P arguments, regardless of where they appear. */
1223296926Semaste	while ((opt = getopt(argc, argv, optstring)) != -1)
1224296926Semaste		if (opt == 'P')
1225296926Semaste			add_keymap_path(optarg);
1226296926Semaste
1227296926Semaste	optind = optreset = 1;
1228296926Semaste	while ((opt = getopt(argc, argv, optstring)) != -1)
12292088Ssos		switch(opt) {
1230148017Semax		case 'A':
1231148017Semax		case 'a':
1232148017Semax			mux_keyboard((opt == 'A')? KBRELKBD : KBADDKBD, optarg);
1233148017Semax			break;
123477329Sdes		case 'b':
123577329Sdes			set_bell_values(optarg);
123677329Sdes			break;
123777329Sdes		case 'd':
123877329Sdes			print_keymap();
123977329Sdes			break;
124077329Sdes		case 'l':
124177329Sdes			load_keymap(optarg, 0);
124277329Sdes			break;
124377329Sdes		case 'L':
124477329Sdes			load_keymap(optarg, 1);
124577329Sdes			break;
1246296926Semaste		case 'P':
1247296926Semaste			break;
124877329Sdes		case 'f':
124977329Sdes			set_functionkey(optarg,
125077329Sdes			    nextarg(argc, argv, &optind, 'f'));
125177329Sdes			break;
125277329Sdes		case 'F':
125377329Sdes			load_default_functionkeys();
125477329Sdes			break;
125577329Sdes		case 'i':
125677329Sdes			show_kbd_info();
125777329Sdes			break;
125877329Sdes		case 'K':
125977329Sdes			release_keyboard();
126077329Sdes			break;
126177329Sdes		case 'k':
126277329Sdes			set_keyboard(optarg);
126377329Sdes			break;
126477329Sdes		case 'r':
126577329Sdes			set_keyrates(optarg);
126677329Sdes			break;
126777329Sdes		case 'x':
126877329Sdes			hex = 1;
126977329Sdes			break;
127077329Sdes		default:
127177329Sdes			usage();
12722088Ssos		}
127329603Scharnier	if ((optind != argc) || (argc == 1))
12742088Ssos		usage();
12752088Ssos	exit(0);
12762088Ssos}
1277