12088Ssos/*-
2228976Suqs * Copyright (c) 1994-1995 S��ren Schmidt
32088Ssos * All rights reserved.
42088Ssos *
52088Ssos * Redistribution and use in source and binary forms, with or without
62088Ssos * modification, are permitted provided that the following conditions
72088Ssos * are met:
82088Ssos * 1. Redistributions of source code must retain the above copyright
95994Ssos *    notice, this list of conditions and the following disclaimer,
105994Ssos *    in this position and unchanged.
112088Ssos * 2. Redistributions in binary form must reproduce the above copyright
122088Ssos *    notice, this list of conditions and the following disclaimer in the
132088Ssos *    documentation and/or other materials provided with the distribution.
142088Ssos * 3. The name of the author may not be used to endorse or promote products
1597748Sschweikh *    derived from this software without specific prior written permission
162088Ssos *
172088Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
182088Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192088Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
202088Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
212088Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
222088Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232088Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242088Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252088Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
262088Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272088Ssos */
282088Ssos
29114601Sobrien#include <sys/cdefs.h>
30114601Sobrien__FBSDID("$FreeBSD$");
3129603Scharnier
322088Ssos#include <ctype.h>
3329603Scharnier#include <err.h>
342088Ssos#include <stdio.h>
3529603Scharnier#include <stdlib.h>
363864Sswallace#include <string.h>
3729603Scharnier#include <unistd.h>
3842505Syokota#include <fcntl.h>
3966834Sphk#include <sys/kbio.h>
4066834Sphk#include <sys/consio.h>
41298297Semaste#include <sys/queue.h>
42267540Sray#include <sys/sysctl.h>
432088Ssos#include "path.h"
442088Ssos#include "lex.h"
452088Ssos
4676643Simp/*
4790394Sru * HALT, PDWN, and PASTE aren't defined in 4.x, but we need them to bridge
4890394Sru * to 5.0-current so define them here as a stop gap transition measure.
4976643Simp */
5090394Sru#ifndef	HALT
5190394Sru#define	HALT		0xa1		/* halt machine */
5290394Sru#endif
5390394Sru#ifndef PDWN
5490394Sru#define	PDWN		0xa2		/* halt machine and power down */
5590394Sru#endif
5676643Simp#ifndef PASTE
5776643Simp#define PASTE		0xa3		/* paste from cut-paste buffer */
5876643Simp#endif
5976643Simp
60196500Sed#define	SPECIAL		0x80000000
61196500Sed
62228437Sedstatic const char ctrl_names[32][4] = {
638857Srgrimes	"nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
642088Ssos	"bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
652088Ssos	"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
6638139Syokota	"can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "us "
672088Ssos	};
682088Ssos
69228437Sedstatic const char acc_names[15][5] = {
7032316Syokota	"dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot",
7132316Syokota	"duml", "dsla", "drin", "dced", "dapo", "ddac", "dogo",
7232316Syokota	"dcar",
7332316Syokota	};
7432316Syokota
75228437Sedstatic const char acc_names_u[15][5] = {
7632316Syokota	"DGRA", "DACU", "DCIR", "DTIL", "DMAC", "DBRE", "DDOT",
7732316Syokota	"DUML", "DSLA", "DRIN", "DCED", "DAPO", "DDAC", "DOGO",
7832316Syokota	"DCAR",
7932316Syokota	};
8032316Syokota
81228437Sedstatic const char fkey_table[96][MAXFK] = {
825994Ssos/* 01-04 */	"\033[M", "\033[N", "\033[O", "\033[P",
835994Ssos/* 05-08 */	"\033[Q", "\033[R", "\033[S", "\033[T",
845994Ssos/* 09-12 */	"\033[U", "\033[V", "\033[W", "\033[X",
855994Ssos/* 13-16 */	"\033[Y", "\033[Z", "\033[a", "\033[b",
865994Ssos/* 17-20 */	"\033[c", "\033[d", "\033[e", "\033[f",
875994Ssos/* 21-24 */	"\033[g", "\033[h", "\033[i", "\033[j",
885994Ssos/* 25-28 */	"\033[k", "\033[l", "\033[m", "\033[n",
895994Ssos/* 29-32 */	"\033[o", "\033[p", "\033[q", "\033[r",
905994Ssos/* 33-36 */	"\033[s", "\033[t", "\033[u", "\033[v",
915994Ssos/* 37-40 */	"\033[w", "\033[x", "\033[y", "\033[z",
925994Ssos/* 41-44 */	"\033[@", "\033[[", "\033[\\","\033[]",
939202Srgrimes/* 45-48 */     "\033[^", "\033[_", "\033[`", "\033[{",
945994Ssos/* 49-52 */	"\033[H", "\033[A", "\033[I", "-"     ,
955994Ssos/* 53-56 */	"\033[D", "\033[E", "\033[C", "+"     ,
965994Ssos/* 57-60 */	"\033[F", "\033[B", "\033[G", "\033[L",
979202Srgrimes/* 61-64 */     "\177",   "\033[J", "\033[~", "\033[}",
985994Ssos/* 65-68 */	""      , ""      , ""      , ""      ,
995994Ssos/* 69-72 */	""      , ""      , ""      , ""      ,
1005994Ssos/* 73-76 */	""      , ""      , ""      , ""      ,
1015994Ssos/* 77-80 */	""      , ""      , ""      , ""      ,
1025994Ssos/* 81-84 */	""      , ""      , ""      , ""      ,
1035994Ssos/* 85-88 */	""      , ""      , ""      , ""      ,
1045994Ssos/* 89-92 */	""      , ""      , ""      , ""      ,
1055994Ssos/* 93-96 */	""      , ""      , ""      , ""      ,
1062088Ssos	};
1072088Ssos
108228437Sedstatic const int delays[]  = {250, 500, 750, 1000};
109228437Sedstatic const int repeats[] = { 34,  38,  42,  46,  50,  55,  59,  63,
110228437Sed		      68,  76,  84,  92, 100, 110, 118, 126,
111228437Sed		     136, 152, 168, 184, 200, 220, 236, 252,
112228437Sed		     272, 304, 336, 368, 400, 440, 472, 504};
113228437Sedstatic const int ndelays = (sizeof(delays) / sizeof(int));
114228437Sedstatic const int nrepeats = (sizeof(repeats) / sizeof(int));
115228437Sedstatic int	hex = 0;
116298297Semastestatic int	paths_configured = 0;
117228437Sedstatic int	token;
1182088Ssos
119228437Sedint		number;
120228437Sedchar		letter;
1212088Ssos
122298297Semastestatic void	add_keymap_path(const char *path);
123228437Sedstatic void	dump_accent_definition(char *name, accentmap_t *accentmap);
124228437Sedstatic void	dump_entry(int value);
125228437Sedstatic void	dump_key_definition(char *name, keymap_t *keymap);
126228437Sedstatic int	get_accent_definition_line(accentmap_t *);
127228437Sedstatic int	get_entry(void);
128228437Sedstatic int	get_key_definition_line(keymap_t *);
129228437Sedstatic void	load_keymap(char *opt, int dumponly);
130228437Sedstatic void	load_default_functionkeys(void);
131228437Sedstatic char *	nextarg(int ac, char **av, int *indp, int oc);
132228437Sedstatic char *	mkfullname(const char *s1, const char *s2, const char *s3);
133228437Sedstatic void	print_accent_definition_line(FILE *fp, int accent,
134228437Sed		struct acc_t *key);
135228437Sedstatic void	print_entry(FILE *fp, int value);
136228437Sedstatic void	print_key_definition_line(FILE *fp, int scancode,
137228437Sed		struct keyent_t *key);
138228437Sedstatic void	print_keymap(void);
139228437Sedstatic void	release_keyboard(void);
140228437Sedstatic void	mux_keyboard(u_int op, char *kbd);
141228437Sedstatic void	set_bell_values(char *opt);
142228437Sedstatic void	set_functionkey(char *keynumstr, char *string);
143228437Sedstatic void	set_keyboard(char *device);
144228437Sedstatic void	set_keyrates(char *opt);
145228437Sedstatic void	show_kbd_info(void);
146228437Sedstatic void	usage(void) __dead2;
147228437Sed
148298297Semastestruct pathent {
149298297Semaste	STAILQ_ENTRY(pathent) next;
150298297Semaste	char *path;
151298297Semaste};
152298297Semastestatic STAILQ_HEAD(, pathent) pathlist = STAILQ_HEAD_INITIALIZER(pathlist);
153298297Semaste
154267540Sray/* Detect presence of vt(4). */
155267540Sraystatic int
156267540Srayis_vt4(void)
157267540Sray{
158268366Sray	char vty_name[4] = "";
159268366Sray	size_t len = sizeof(vty_name);
160267540Sray
161268366Sray	if (sysctlbyname("kern.vty", vty_name, &len, NULL, 0) != 0)
162268366Sray		return (0);
163268366Sray	return (strcmp(vty_name, "vt") == 0);
164267540Sray}
165267540Sray
166228437Sedstatic char *
1672088Ssosnextarg(int ac, char **av, int *indp, int oc)
1682088Ssos{
1692088Ssos	if (*indp < ac)
1702088Ssos		return(av[(*indp)++]);
17129603Scharnier	warnx("option requires two arguments -- %c", oc);
1722088Ssos	usage();
1732088Ssos}
1742088Ssos
1752088Ssos
176228437Sedstatic char *
1772088Ssosmkfullname(const char *s1, const char *s2, const char *s3)
1782088Ssos{
1795536Ssos	static char	*buf = NULL;
1805536Ssos	static int	bufl = 0;
1815536Ssos	int		f;
1822088Ssos
1832088Ssos	f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
18477394Ssobomax	if (f > bufl) {
1852088Ssos		if (buf)
1862088Ssos			buf = (char *)realloc(buf, f);
1872088Ssos		else
1882088Ssos			buf = (char *)malloc(f);
18977394Ssobomax	}
1902088Ssos	if (!buf) {
1912088Ssos		bufl = 0;
1922088Ssos		return(NULL);
1932088Ssos	}
1942088Ssos
1952088Ssos	bufl = f;
1962088Ssos	strcpy(buf, s1);
1972088Ssos	strcat(buf, s2);
1982088Ssos	strcat(buf, s3);
1992088Ssos	return(buf);
2002088Ssos}
2012088Ssos
2022088Ssos
203228437Sedstatic int
20499816Salfredget_entry(void)
2052088Ssos{
20632316Syokota	switch ((token = yylex())) {
2072088Ssos	case TNOP:
208196500Sed		return NOP | SPECIAL;
2092088Ssos	case TLSH:
210196500Sed		return LSH | SPECIAL;
2112088Ssos	case TRSH:
212196500Sed		return RSH | SPECIAL;
2132088Ssos	case TCLK:
214196500Sed		return CLK | SPECIAL;
2152088Ssos	case TNLK:
216196500Sed		return NLK | SPECIAL;
2172088Ssos	case TSLK:
218196500Sed		return SLK | SPECIAL;
2192088Ssos	case TBTAB:
220196500Sed		return BTAB | SPECIAL;
2212088Ssos	case TLALT:
222196500Sed		return LALT | SPECIAL;
2232088Ssos	case TLCTR:
224196500Sed		return LCTR | SPECIAL;
2252088Ssos	case TNEXT:
226196500Sed		return NEXT | SPECIAL;
22748105Syokota	case TPREV:
228196500Sed		return PREV | SPECIAL;
2292088Ssos	case TRCTR:
230196500Sed		return RCTR | SPECIAL;
2312088Ssos	case TRALT:
232196500Sed		return RALT | SPECIAL;
2332088Ssos	case TALK:
234196500Sed		return ALK | SPECIAL;
2352088Ssos	case TASH:
236196500Sed		return ASH | SPECIAL;
2372088Ssos	case TMETA:
238196500Sed		return META | SPECIAL;
2392088Ssos	case TRBT:
240196500Sed		return RBT | SPECIAL;
2412088Ssos	case TDBG:
242196500Sed		return DBG | SPECIAL;
2435994Ssos	case TSUSP:
244196500Sed		return SUSP | SPECIAL;
24538053Syokota	case TSPSC:
246196500Sed		return SPSC | SPECIAL;
24754380Syokota	case TPANIC:
248196500Sed		return PNC | SPECIAL;
24954380Syokota	case TLSHA:
250196500Sed		return LSHA | SPECIAL;
25154380Syokota	case TRSHA:
252196500Sed		return RSHA | SPECIAL;
25354380Syokota	case TLCTRA:
254196500Sed		return LCTRA | SPECIAL;
25554380Syokota	case TRCTRA:
256196500Sed		return RCTRA | SPECIAL;
25754380Syokota	case TLALTA:
258196500Sed		return LALTA | SPECIAL;
25954380Syokota	case TRALTA:
260196500Sed		return RALTA | SPECIAL;
26165759Sdwmalone	case THALT:
262196500Sed		return HALT | SPECIAL;
26365759Sdwmalone	case TPDWN:
264196500Sed		return PDWN | SPECIAL;
26574118Sache	case TPASTE:
266196500Sed		return PASTE | SPECIAL;
26732316Syokota	case TACC:
26832316Syokota		if (ACC(number) > L_ACC)
26932316Syokota			return -1;
270196500Sed		return ACC(number) | SPECIAL;
2712088Ssos	case TFUNC:
2722088Ssos		if (F(number) > L_FN)
2732088Ssos			return -1;
274196500Sed		return F(number) | SPECIAL;
2752088Ssos	case TSCRN:
2762088Ssos		if (S(number) > L_SCR)
2772088Ssos			return -1;
278196500Sed		return S(number) | SPECIAL;
2792088Ssos	case TLET:
2802088Ssos		return (unsigned char)letter;
2812088Ssos	case TNUM:
282197330Sed		if (number < 0x000000 || number > 0x10FFFF)
2832088Ssos			return -1;
2842088Ssos		return number;
2852088Ssos	default:
2862088Ssos		return -1;
2872088Ssos	}
2882088Ssos}
2892088Ssos
29077394Ssobomaxstatic int
291298297Semasteget_definition_line(FILE *file, keymap_t *keymap, accentmap_t *accentmap)
2922088Ssos{
29332316Syokota	int c;
2942088Ssos
295298297Semaste	yyin = file;
2962088Ssos
29732316Syokota	if (token < 0)
29832316Syokota		token = yylex();
29932316Syokota	switch (token) {
30032316Syokota	case TNUM:
30132316Syokota		c = get_key_definition_line(keymap);
30232316Syokota		if (c < 0)
30332316Syokota			errx(1, "invalid key definition");
30432316Syokota		if (c > keymap->n_keys)
30532316Syokota			keymap->n_keys = c;
30632316Syokota		break;
30732316Syokota	case TACC:
30832316Syokota		c = get_accent_definition_line(accentmap);
30932316Syokota		if (c < 0)
31032316Syokota			errx(1, "invalid accent key definition");
31132316Syokota		if (c > accentmap->n_accs)
31232316Syokota			accentmap->n_accs = c;
31332316Syokota		break;
31432316Syokota	case 0:
31532316Syokota		/* EOF */
3162088Ssos		return -1;
31732316Syokota	default:
31832316Syokota		errx(1, "illegal definition line");
31932316Syokota	}
32032316Syokota	return c;
32132316Syokota}
32232316Syokota
323228437Sedstatic int
32432316Syokotaget_key_definition_line(keymap_t *map)
32532316Syokota{
32632316Syokota	int i, def, scancode;
32732316Syokota
32832316Syokota	/* check scancode number */
3292088Ssos	if (number < 0 || number >= NUM_KEYS)
3302088Ssos		return -1;
3312088Ssos	scancode = number;
3322088Ssos
3332088Ssos	/* get key definitions */
3342088Ssos	map->key[scancode].spcl = 0;
3352088Ssos	for (i=0; i<NUM_STATES; i++) {
3362088Ssos		if ((def = get_entry()) == -1)
3372088Ssos			return -1;
338196500Sed		if (def & SPECIAL)
3392088Ssos			map->key[scancode].spcl |= (0x80 >> i);
340196500Sed		map->key[scancode].map[i] = def & ~SPECIAL;
3412088Ssos	}
3422088Ssos	/* get lock state key def */
34332316Syokota	if ((token = yylex()) != TFLAG)
3442088Ssos		return -1;
3452088Ssos	map->key[scancode].flgs = number;
34632316Syokota	token = yylex();
34732316Syokota	return (scancode + 1);
3482088Ssos}
3492088Ssos
350228437Sedstatic int
35132316Syokotaget_accent_definition_line(accentmap_t *map)
35232316Syokota{
35332316Syokota	int accent;
35432316Syokota	int c1, c2;
35532316Syokota	int i;
3562088Ssos
35732316Syokota	if (ACC(number) < F_ACC || ACC(number) > L_ACC)
35832316Syokota		/* number out of range */
35932316Syokota		return -1;
36032316Syokota	accent = number;
36132316Syokota	if (map->acc[accent].accchar != 0) {
36232316Syokota		/* this entry has already been defined before! */
36332316Syokota		errx(1, "duplicated accent key definition");
36432316Syokota	}
36532316Syokota
36632316Syokota	switch ((token = yylex())) {
36732316Syokota	case TLET:
36832316Syokota		map->acc[accent].accchar = letter;
36932316Syokota		break;
37032316Syokota	case TNUM:
37132316Syokota		map->acc[accent].accchar = number;
37232316Syokota		break;
37332316Syokota	default:
37432316Syokota		return -1;
37532316Syokota	}
37632316Syokota
37732316Syokota	for (i = 0; (token = yylex()) == '(';) {
37832316Syokota		switch ((token = yylex())) {
37932316Syokota		case TLET:
38032316Syokota			c1 = letter;
38132316Syokota			break;
38232316Syokota		case TNUM:
38332316Syokota			c1 = number;
38432316Syokota			break;
38532316Syokota		default:
38632316Syokota			return -1;
38732316Syokota		}
38832316Syokota		switch ((token = yylex())) {
38932316Syokota		case TLET:
39032316Syokota			c2 = letter;
39132316Syokota			break;
39232316Syokota		case TNUM:
39332316Syokota			c2 = number;
39432316Syokota			break;
39532316Syokota		default:
39632316Syokota			return -1;
39732316Syokota		}
39832316Syokota		if ((token = yylex()) != ')')
39932316Syokota			return -1;
40032316Syokota		if (i >= NUM_ACCENTCHARS) {
40132316Syokota			warnx("too many accented characters, ignored");
40232316Syokota			continue;
40332316Syokota		}
40432316Syokota		map->acc[accent].map[i][0] = c1;
40532316Syokota		map->acc[accent].map[i][1] = c2;
40632316Syokota		++i;
40732316Syokota	}
40832316Syokota	return (accent + 1);
40932316Syokota}
41032316Syokota
411228437Sedstatic void
4122088Ssosprint_entry(FILE *fp, int value)
4132088Ssos{
414196500Sed	int val = value & ~SPECIAL;
4152088Ssos
4162088Ssos	switch (value) {
417196500Sed	case NOP | SPECIAL:
4188857Srgrimes		fprintf(fp, " nop   ");
4192088Ssos		break;
420196500Sed	case LSH | SPECIAL:
4212088Ssos		fprintf(fp, " lshift");
4222088Ssos		break;
423196500Sed	case RSH | SPECIAL:
4242088Ssos		fprintf(fp, " rshift");
4252088Ssos		break;
426196500Sed	case CLK | SPECIAL:
4272088Ssos		fprintf(fp, " clock ");
4282088Ssos		break;
429196500Sed	case NLK | SPECIAL:
4302088Ssos		fprintf(fp, " nlock ");
4312088Ssos		break;
432196500Sed	case SLK | SPECIAL:
4332088Ssos		fprintf(fp, " slock ");
4342088Ssos		break;
435196500Sed	case BTAB | SPECIAL:
4362088Ssos		fprintf(fp, " btab  ");
4372088Ssos		break;
438196500Sed	case LALT | SPECIAL:
4392088Ssos		fprintf(fp, " lalt  ");
4402088Ssos		break;
441196500Sed	case LCTR | SPECIAL:
4422088Ssos		fprintf(fp, " lctrl ");
4432088Ssos		break;
444196500Sed	case NEXT | SPECIAL:
4452088Ssos		fprintf(fp, " nscr  ");
4462088Ssos		break;
447196500Sed	case PREV | SPECIAL:
44848105Syokota		fprintf(fp, " pscr  ");
44948105Syokota		break;
450196500Sed	case RCTR | SPECIAL:
4512088Ssos		fprintf(fp, " rctrl ");
4522088Ssos		break;
453196500Sed	case RALT | SPECIAL:
4542088Ssos		fprintf(fp, " ralt  ");
4552088Ssos		break;
456196500Sed	case ALK | SPECIAL:
4572088Ssos		fprintf(fp, " alock ");
4582088Ssos		break;
459196500Sed	case ASH | SPECIAL:
4602088Ssos		fprintf(fp, " ashift");
4612088Ssos		break;
462196500Sed	case META | SPECIAL:
4632088Ssos		fprintf(fp, " meta  ");
4642088Ssos		break;
465196500Sed	case RBT | SPECIAL:
4662088Ssos		fprintf(fp, " boot  ");
4672088Ssos		break;
468196500Sed	case DBG | SPECIAL:
4692088Ssos		fprintf(fp, " debug ");
4702088Ssos		break;
471196500Sed	case SUSP | SPECIAL:
47232316Syokota		fprintf(fp, " susp  ");
47332316Syokota		break;
474196500Sed	case SPSC | SPECIAL:
47538053Syokota		fprintf(fp, " saver ");
47638053Syokota		break;
477196500Sed	case PNC | SPECIAL:
47854380Syokota		fprintf(fp, " panic ");
47954380Syokota		break;
480196500Sed	case LSHA | SPECIAL:
48154380Syokota		fprintf(fp, " lshifta");
48254380Syokota		break;
483196500Sed	case RSHA | SPECIAL:
48454380Syokota		fprintf(fp, " rshifta");
48554380Syokota		break;
486196500Sed	case LCTRA | SPECIAL:
48754380Syokota		fprintf(fp, " lctrla");
48854380Syokota		break;
489196500Sed	case RCTRA | SPECIAL:
49054380Syokota		fprintf(fp, " rctrla");
49154380Syokota		break;
492196500Sed	case LALTA | SPECIAL:
49354380Syokota		fprintf(fp, " lalta ");
49454380Syokota		break;
495196500Sed	case RALTA | SPECIAL:
49654380Syokota		fprintf(fp, " ralta ");
49754380Syokota		break;
498196500Sed	case HALT | SPECIAL:
49965759Sdwmalone		fprintf(fp, " halt  ");
50065759Sdwmalone		break;
501196500Sed	case PDWN | SPECIAL:
50265759Sdwmalone		fprintf(fp, " pdwn  ");
50365759Sdwmalone		break;
504196500Sed	case PASTE | SPECIAL:
50574118Sache		fprintf(fp, " paste ");
50674118Sache		break;
5072088Ssos	default:
508196500Sed		if (value & SPECIAL) {
5098857Srgrimes		 	if (val >= F_FN && val <= L_FN)
5102088Ssos				fprintf(fp, " fkey%02d", val - F_FN + 1);
5118857Srgrimes		 	else if (val >= F_SCR && val <= L_SCR)
5122088Ssos				fprintf(fp, " scr%02d ", val - F_SCR + 1);
51332316Syokota		 	else if (val >= F_ACC && val <= L_ACC)
51432316Syokota				fprintf(fp, " %-6s", acc_names[val - F_ACC]);
5152088Ssos			else if (hex)
5168857Srgrimes				fprintf(fp, " 0x%02x  ", val);
5172088Ssos			else
51832316Syokota				fprintf(fp, " %3d   ", val);
5192088Ssos		}
5202088Ssos		else {
5212088Ssos			if (val < ' ')
5228857Srgrimes				fprintf(fp, " %s   ", ctrl_names[val]);
5232088Ssos			else if (val == 127)
5248857Srgrimes				fprintf(fp, " del   ");
5259202Srgrimes			else if (isascii(val) && isprint(val))
5268857Srgrimes				fprintf(fp, " '%c'   ", val);
5272088Ssos			else if (hex)
5288857Srgrimes				fprintf(fp, " 0x%02x  ", val);
5292088Ssos			else
5308857Srgrimes				fprintf(fp, " %3d   ", val);
5312088Ssos		}
5322088Ssos	}
5332088Ssos}
5342088Ssos
535228437Sedstatic void
53642505Syokotaprint_key_definition_line(FILE *fp, int scancode, struct keyent_t *key)
5372088Ssos{
53829603Scharnier	int i;
5392088Ssos
5402088Ssos	/* print scancode number */
5412088Ssos	if (hex)
5422088Ssos		fprintf(fp, " 0x%02x  ", scancode);
5432088Ssos	else
5442088Ssos		fprintf(fp, "  %03d  ", scancode);
5452088Ssos
5462088Ssos	/* print key definitions */
5472088Ssos	for (i=0; i<NUM_STATES; i++) {
5482088Ssos		if (key->spcl & (0x80 >> i))
549196500Sed			print_entry(fp, key->map[i] | SPECIAL);
5502088Ssos		else
5518857Srgrimes			print_entry(fp, key->map[i]);
5522088Ssos	}
5532088Ssos
5542088Ssos	/* print lock state key def */
5552088Ssos	switch (key->flgs) {
5562088Ssos	case 0:
5572088Ssos		fprintf(fp, "  O\n");
5582088Ssos		break;
5592088Ssos	case 1:
5602088Ssos		fprintf(fp, "  C\n");
5612088Ssos		break;
5622088Ssos	case 2:
5632088Ssos		fprintf(fp, "  N\n");
5642088Ssos		break;
5656046Ssos	case 3:
5666046Ssos		fprintf(fp, "  B\n");
5676046Ssos		break;
5688857Srgrimes	}
5692088Ssos}
5702088Ssos
571228437Sedstatic void
57232316Syokotaprint_accent_definition_line(FILE *fp, int accent, struct acc_t *key)
57332316Syokota{
57432316Syokota	int c;
57532316Syokota	int i;
5762088Ssos
57732316Syokota	if (key->accchar == 0)
57832316Syokota		return;
57932316Syokota
58032316Syokota	/* print accent number */
58132316Syokota	fprintf(fp, "  %-6s", acc_names[accent]);
58232316Syokota	if (isascii(key->accchar) && isprint(key->accchar))
58332316Syokota		fprintf(fp, "'%c'  ", key->accchar);
58432316Syokota	else if (hex)
58532316Syokota		fprintf(fp, "0x%02x ", key->accchar);
58632316Syokota	else
58732316Syokota		fprintf(fp, "%03d  ", key->accchar);
58832316Syokota
58932316Syokota	for (i = 0; i < NUM_ACCENTCHARS; ++i) {
59032316Syokota		c = key->map[i][0];
59132316Syokota		if (c == 0)
59232316Syokota			break;
59332316Syokota		if ((i > 0) && ((i % 4) == 0))
59432316Syokota			fprintf(fp, "\n             ");
59532316Syokota		if (isascii(c) && isprint(c))
59632316Syokota			fprintf(fp, "( '%c' ", c);
59732316Syokota		else if (hex)
59832316Syokota			fprintf(fp, "(0x%02x ", c);
59932316Syokota		else
60032316Syokota			fprintf(fp, "( %03d ", c);
60132316Syokota		c = key->map[i][1];
60232316Syokota		if (isascii(c) && isprint(c))
60332316Syokota			fprintf(fp, "'%c' ) ", c);
60432316Syokota		else if (hex)
60532316Syokota			fprintf(fp, "0x%02x) ", c);
60632316Syokota		else
60732316Syokota			fprintf(fp, "%03d ) ", c);
60832316Syokota	}
60932316Syokota	fprintf(fp, "\n");
61032316Syokota}
61132316Syokota
612228437Sedstatic void
61332316Syokotadump_entry(int value)
61432316Syokota{
615196500Sed	if (value & SPECIAL) {
616196500Sed		value &= ~SPECIAL;
61732316Syokota		switch (value) {
61832316Syokota		case NOP:
61932316Syokota			printf("  NOP, ");
62032316Syokota			break;
62132316Syokota		case LSH:
62232316Syokota			printf("  LSH, ");
62332316Syokota			break;
62432316Syokota		case RSH:
62532316Syokota			printf("  RSH, ");
62632316Syokota			break;
62732316Syokota		case CLK:
62832316Syokota			printf("  CLK, ");
62932316Syokota			break;
63032316Syokota		case NLK:
63132316Syokota			printf("  NLK, ");
63232316Syokota			break;
63332316Syokota		case SLK:
63432316Syokota			printf("  SLK, ");
63532316Syokota			break;
63632316Syokota		case BTAB:
63732316Syokota			printf(" BTAB, ");
63832316Syokota			break;
63932316Syokota		case LALT:
64032316Syokota			printf(" LALT, ");
64132316Syokota			break;
64232316Syokota		case LCTR:
64332316Syokota			printf(" LCTR, ");
64432316Syokota			break;
64532316Syokota		case NEXT:
64632316Syokota			printf(" NEXT, ");
64732316Syokota			break;
64848105Syokota		case PREV:
64948105Syokota			printf(" PREV, ");
65048105Syokota			break;
65132316Syokota		case RCTR:
65232316Syokota			printf(" RCTR, ");
65332316Syokota			break;
65432316Syokota		case RALT:
65532316Syokota			printf(" RALT, ");
65632316Syokota			break;
65732316Syokota		case ALK:
65832316Syokota			printf("  ALK, ");
65932316Syokota			break;
66032316Syokota		case ASH:
66132316Syokota			printf("  ASH, ");
66232316Syokota			break;
66332316Syokota		case META:
66432316Syokota			printf(" META, ");
66532316Syokota			break;
66632316Syokota		case RBT:
66732316Syokota			printf("  RBT, ");
66832316Syokota			break;
66932316Syokota		case DBG:
67032316Syokota			printf("  DBG, ");
67132316Syokota			break;
67232316Syokota		case SUSP:
67332316Syokota			printf(" SUSP, ");
67432316Syokota			break;
67538053Syokota		case SPSC:
67638053Syokota			printf(" SPSC, ");
67738053Syokota			break;
67854380Syokota		case PNC:
67954380Syokota			printf("  PNC, ");
68054380Syokota			break;
68154380Syokota		case LSHA:
68254380Syokota			printf(" LSHA, ");
68354380Syokota			break;
68454380Syokota		case RSHA:
68554380Syokota			printf(" RSHA, ");
68654380Syokota			break;
68754380Syokota		case LCTRA:
68854380Syokota			printf("LCTRA, ");
68954380Syokota			break;
69054380Syokota		case RCTRA:
69154380Syokota			printf("RCTRA, ");
69254380Syokota			break;
69354380Syokota		case LALTA:
69454380Syokota			printf("LALTA, ");
69554380Syokota			break;
69654380Syokota		case RALTA:
69754380Syokota			printf("RALTA, ");
69854380Syokota			break;
69965759Sdwmalone		case HALT:
70065759Sdwmalone			printf(" HALT, ");
70165759Sdwmalone			break;
70265759Sdwmalone		case PDWN:
70365759Sdwmalone			printf(" PDWN, ");
70465759Sdwmalone			break;
70574118Sache		case PASTE:
70674118Sache			printf("PASTE, ");
70774118Sache			break;
70832316Syokota		default:
70932316Syokota	 		if (value >= F_FN && value <= L_FN)
71032316Syokota				printf(" F(%2d),", value - F_FN + 1);
71132316Syokota	 		else if (value >= F_SCR && value <= L_SCR)
71232486Syokota				printf(" S(%2d),", value - F_SCR + 1);
71332316Syokota	 		else if (value >= F_ACC && value <= L_ACC)
71432316Syokota				printf(" %-4s, ", acc_names_u[value - F_ACC]);
71532316Syokota			else
71632316Syokota				printf(" 0x%02X, ", value);
71732316Syokota			break;
71832316Syokota		}
71932316Syokota	} else if (value == '\'') {
72032316Syokota		printf(" '\\'', ");
72132316Syokota	} else if (value == '\\') {
72232316Syokota		printf(" '\\\\', ");
72332316Syokota	} else if (isascii(value) && isprint(value)) {
72432316Syokota		printf("  '%c', ", value);
72532316Syokota	} else {
72632316Syokota		printf(" 0x%02X, ", value);
72732316Syokota	}
72832316Syokota}
72932316Syokota
730228437Sedstatic void
73132316Syokotadump_key_definition(char *name, keymap_t *keymap)
73232316Syokota{
73332316Syokota	int	i, j;
73432316Syokota
73532486Syokota	printf("static keymap_t keymap_%s = { 0x%02x, {\n",
73632316Syokota	       name, (unsigned)keymap->n_keys);
73732316Syokota	printf(
73832486Syokota"/*                                                         alt\n"
73932486Syokota" * scan                       cntrl          alt    alt   cntrl\n"
74032486Syokota" * code  base   shift  cntrl  shift   alt   shift  cntrl  shift    spcl flgs\n"
74132316Syokota" * ---------------------------------------------------------------------------\n"
74232316Syokota" */\n");
74332316Syokota	for (i = 0; i < keymap->n_keys; i++) {
74432486Syokota		printf("/*%02x*/{{", i);
74532316Syokota		for (j = 0; j < NUM_STATES; j++) {
74632316Syokota			if (keymap->key[i].spcl & (0x80 >> j))
747196500Sed				dump_entry(keymap->key[i].map[j] | SPECIAL);
74832316Syokota			else
74932316Syokota				dump_entry(keymap->key[i].map[j]);
75032316Syokota		}
75132486Syokota		printf("}, 0x%02X,0x%02X },\n",
75232316Syokota		       (unsigned)keymap->key[i].spcl,
75332316Syokota		       (unsigned)keymap->key[i].flgs);
75432316Syokota	}
75532486Syokota	printf("} };\n\n");
75632316Syokota}
75732316Syokota
758228437Sedstatic void
75932316Syokotadump_accent_definition(char *name, accentmap_t *accentmap)
76032316Syokota{
76132316Syokota	int i, j;
76232316Syokota	int c;
76332316Syokota
76432486Syokota	printf("static accentmap_t accentmap_%s = { %d",
76532316Syokota		name, accentmap->n_accs);
76632486Syokota	if (accentmap->n_accs <= 0) {
76732486Syokota		printf(" };\n\n");
76832486Syokota		return;
76932486Syokota	}
77032486Syokota	printf(", {\n");
77132316Syokota	for (i = 0; i < NUM_DEADKEYS; i++) {
77232316Syokota		printf("    /* %s=%d */\n    {", acc_names[i], i);
77332316Syokota		c = accentmap->acc[i].accchar;
77432316Syokota		if (c == '\'')
77532316Syokota			printf(" '\\'', {");
77632316Syokota		else if (c == '\\')
77732316Syokota			printf(" '\\\\', {");
77832316Syokota		else if (isascii(c) && isprint(c))
77932316Syokota			printf("  '%c', {", c);
78032316Syokota		else if (c == 0) {
78132316Syokota			printf(" 0x00 }, \n");
78232316Syokota			continue;
78332316Syokota		} else
78432316Syokota			printf(" 0x%02x, {", c);
78532316Syokota		for (j = 0; j < NUM_ACCENTCHARS; j++) {
78632316Syokota			c = accentmap->acc[i].map[j][0];
78732316Syokota			if (c == 0)
78832316Syokota				break;
78932316Syokota			if ((j > 0) && ((j % 4) == 0))
79032316Syokota				printf("\n\t     ");
79132316Syokota			if (isascii(c) && isprint(c))
79232316Syokota				printf(" {  '%c',", c);
79332316Syokota			else
79432316Syokota				printf(" { 0x%02x,", c);
79532316Syokota			printf("0x%02x },", accentmap->acc[i].map[j][1]);
79632316Syokota		}
79732316Syokota		printf(" }, },\n");
79832316Syokota	}
79932486Syokota	printf("} };\n\n");
80032316Syokota}
80132316Syokota
802228437Sedstatic void
803298297Semasteadd_keymap_path(const char *path)
804298297Semaste{
805298297Semaste	struct pathent* pe;
806298297Semaste	size_t len;
807298297Semaste
808298297Semaste	len = strlen(path);
809298297Semaste	if ((pe = malloc(sizeof(*pe))) == NULL ||
810298297Semaste	    (pe->path = malloc(len + 2)) == NULL)
811298297Semaste		err(1, "malloc");
812298297Semaste	memcpy(pe->path, path, len);
813298297Semaste	if (len > 0 && path[len - 1] != '/')
814298297Semaste		pe->path[len++] = '/';
815298297Semaste	pe->path[len] = '\0';
816298297Semaste	STAILQ_INSERT_TAIL(&pathlist, pe, next);
817298297Semaste}
818298297Semaste
819298297Semastestatic void
82019569Sjoergload_keymap(char *opt, int dumponly)
8212088Ssos{
82232316Syokota	keymap_t keymap;
82332316Syokota	accentmap_t accentmap;
824298297Semaste	struct pathent *pe;
825298297Semaste	FILE	*file;
826298297Semaste	int	j;
82719569Sjoerg	char	*name, *cp;
828267540Sray	char	blank[] = "", keymap_path[] = KEYMAP_PATH;
829267540Sray	char	vt_keymap_path[] = VT_KEYMAP_PATH, dotkbd[] = ".kbd";
83099816Salfred	char	*postfix[] = {blank, dotkbd, NULL};
8312088Ssos
832298297Semaste	if (!paths_configured) {
833298297Semaste		cp = getenv("KEYMAP_PATH");
834298297Semaste		if (cp != NULL)
835298297Semaste			add_keymap_path(cp);
836298297Semaste		add_keymap_path("");
837298297Semaste		if (is_vt4())
838298297Semaste			add_keymap_path(vt_keymap_path);
839298297Semaste		else
840298297Semaste			add_keymap_path(keymap_path);
841298297Semaste		paths_configured = 1;
842298297Semaste	}
84376502Ssobomax
844298297Semaste	file = NULL;
845298297Semaste	STAILQ_FOREACH(pe, &pathlist, next) {
846298297Semaste		for (j=0; postfix[j] && file == NULL; j++) {
847298297Semaste			name = mkfullname(pe->path, opt, postfix[j]);
848298297Semaste			file = fopen(name, "r");
849298297Semaste			if (file != NULL)
850298297Semaste				break;
85176502Ssobomax		}
85276643Simp	}
853298297Semaste	if (file == NULL) {
85479677Sobrien		warn("keymap file \"%s\" not found", opt);
8552088Ssos		return;
8562088Ssos	}
85732316Syokota	memset(&keymap, 0, sizeof(keymap));
85832316Syokota	memset(&accentmap, 0, sizeof(accentmap));
85932316Syokota	token = -1;
8602088Ssos	while (1) {
861298297Semaste		if (get_definition_line(file, &keymap, &accentmap) < 0)
8622088Ssos			break;
8632088Ssos    	}
86419569Sjoerg	if (dumponly) {
86519569Sjoerg		/* fix up the filename to make it a valid C identifier */
86619569Sjoerg		for (cp = opt; *cp; cp++)
86719569Sjoerg			if (!isalpha(*cp) && !isdigit(*cp)) *cp = '_';
86832316Syokota		printf("/*\n"
86932316Syokota		       " * Automatically generated from %s.\n"
87032316Syokota	               " * DO NOT EDIT!\n"
87132316Syokota		       " */\n", name);
87232316Syokota		dump_key_definition(opt, &keymap);
87332316Syokota		dump_accent_definition(opt, &accentmap);
87419569Sjoerg		return;
87519569Sjoerg	}
87632316Syokota	if ((keymap.n_keys > 0) && (ioctl(0, PIO_KEYMAP, &keymap) < 0)) {
87729603Scharnier		warn("setting keymap");
878298297Semaste		fclose(file);
8792088Ssos		return;
8802088Ssos	}
88132316Syokota	if ((accentmap.n_accs > 0)
88232316Syokota		&& (ioctl(0, PIO_DEADKEYMAP, &accentmap) < 0)) {
88332316Syokota		warn("setting accentmap");
884298297Semaste		fclose(file);
88532316Syokota		return;
88632316Syokota	}
8872088Ssos}
8882088Ssos
889228437Sedstatic void
89099816Salfredprint_keymap(void)
8912088Ssos{
89232316Syokota	keymap_t keymap;
89332316Syokota	accentmap_t accentmap;
8942088Ssos	int i;
8952088Ssos
89632316Syokota	if (ioctl(0, GIO_KEYMAP, &keymap) < 0)
89729603Scharnier		err(1, "getting keymap");
89832316Syokota	if (ioctl(0, GIO_DEADKEYMAP, &accentmap) < 0)
89932316Syokota		memset(&accentmap, 0, sizeof(accentmap));
9002088Ssos    	printf(
9012088Ssos"#                                                         alt\n"
9022088Ssos"# scan                       cntrl          alt    alt   cntrl lock\n"
9032088Ssos"# code  base   shift  cntrl  shift  alt    shift  cntrl  shift state\n"
9042088Ssos"# ------------------------------------------------------------------\n"
9052088Ssos    	);
90632316Syokota	for (i=0; i<keymap.n_keys; i++)
90732316Syokota		print_key_definition_line(stdout, i, &keymap.key[i]);
90832316Syokota
90932316Syokota	printf("\n");
91032316Syokota	for (i = 0; i < NUM_DEADKEYS; i++)
91132316Syokota		print_accent_definition_line(stdout, i, &accentmap.acc[i]);
91232316Syokota
9132088Ssos}
9142088Ssos
915228437Sedstatic void
91699816Salfredload_default_functionkeys(void)
9172088Ssos{
9182088Ssos	fkeyarg_t fkey;
9192088Ssos	int i;
9202088Ssos
9212088Ssos	for (i=0; i<NUM_FKEYS; i++) {
9222088Ssos		fkey.keynum = i;
9232088Ssos		strcpy(fkey.keydef, fkey_table[i]);
9242088Ssos		fkey.flen = strlen(fkey_table[i]);
9252088Ssos		if (ioctl(0, SETFKEY, &fkey) < 0)
92629603Scharnier			warn("setting function key");
9272088Ssos	}
9282088Ssos}
9292088Ssos
930228437Sedstatic void
9312088Ssosset_functionkey(char *keynumstr, char *string)
9322088Ssos{
9332088Ssos	fkeyarg_t fkey;
9342088Ssos
9352088Ssos	if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
9362088Ssos		load_default_functionkeys();
9372088Ssos		return;
9382088Ssos	}
9392088Ssos	fkey.keynum = atoi(keynumstr);
9402088Ssos	if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
94129603Scharnier		warnx("function key number must be between 1 and %d",
9422088Ssos			NUM_FKEYS);
9432088Ssos		return;
9442088Ssos	}
9452088Ssos	if ((fkey.flen = strlen(string)) > MAXFK) {
94629603Scharnier		warnx("function key string too long (%d > %d)",
9472088Ssos			fkey.flen, MAXFK);
9482088Ssos		return;
9492088Ssos	}
950133353Sjmg	strncpy(fkey.keydef, string, MAXFK);
9512088Ssos	fkey.keynum -= 1;
9522088Ssos	if (ioctl(0, SETFKEY, &fkey) < 0)
95329603Scharnier		warn("setting function key");
9542088Ssos}
9552088Ssos
956228437Sedstatic void
9572088Ssosset_bell_values(char *opt)
9582088Ssos{
9595536Ssos	int bell, duration, pitch;
9602088Ssos
96138044Syokota	bell = 0;
96238044Syokota	if (!strncmp(opt, "quiet.", 6)) {
963164333Sru		bell = CONS_QUIET_BELL;
96438044Syokota		opt += 6;
96538044Syokota	}
9668857Srgrimes	if (!strcmp(opt, "visual"))
967164333Sru		bell |= CONS_VISUAL_BELL;
9685536Ssos	else if (!strcmp(opt, "normal"))
96938044Syokota		duration = 5, pitch = 800;
97048982Syokota	else if (!strcmp(opt, "off"))
97148982Syokota		duration = 0, pitch = 0;
9722088Ssos	else {
9732088Ssos		char		*v1;
9748857Srgrimes
9755536Ssos		bell = 0;
9762088Ssos		duration = strtol(opt, &v1, 0);
9772088Ssos		if ((duration < 0) || (*v1 != '.'))
9782088Ssos			goto badopt;
9792088Ssos		opt = ++v1;
9802088Ssos		pitch = strtol(opt, &v1, 0);
9812088Ssos		if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
9822088Ssosbadopt:
98377394Ssobomax			warnx("argument to -b must be duration.pitch or [quiet.]visual|normal|off");
9842088Ssos			return;
9852088Ssos		}
98638044Syokota		if (pitch != 0)
98738044Syokota			pitch = 1193182 / pitch;	/* in Hz */
98838044Syokota		duration /= 10;	/* in 10 m sec */
9892088Ssos	}
9902088Ssos
9915536Ssos	ioctl(0, CONS_BELLTYPE, &bell);
992164333Sru	if (!(bell & CONS_VISUAL_BELL))
9935536Ssos		fprintf(stderr, "[=%d;%dB", pitch, duration);
9942088Ssos}
9952088Ssos
996228437Sedstatic void
9972088Ssosset_keyrates(char *opt)
9982088Ssos{
99944628Syokota	int arg[2];
100039047Syokota	int repeat;
100139047Syokota	int delay;
100246761Syokota	int r, d;
10032088Ssos
100446761Syokota	if (!strcmp(opt, "slow")) {
100544628Syokota		delay = 1000, repeat = 500;
100646761Syokota		d = 3, r = 31;
100746761Syokota	} else if (!strcmp(opt, "normal")) {
100844628Syokota		delay = 500, repeat = 125;
100946761Syokota		d = 1, r = 15;
101046761Syokota	} else if (!strcmp(opt, "fast")) {
101139047Syokota		delay = repeat = 0;
101246761Syokota		d = r = 0;
101346761Syokota	} else {
10142088Ssos		int		n;
10152088Ssos		char		*v1;
10162088Ssos
10172088Ssos		delay = strtol(opt, &v1, 0);
10182088Ssos		if ((delay < 0) || (*v1 != '.'))
10192088Ssos			goto badopt;
10202088Ssos		opt = ++v1;
10212088Ssos		repeat = strtol(opt, &v1, 0);
10222088Ssos		if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
10232088Ssosbadopt:
102477394Ssobomax			warnx("argument to -r must be delay.repeat or slow|normal|fast");
10252088Ssos			return;
10262088Ssos		}
102746761Syokota		for (n = 0; n < ndelays - 1; n++)
102846761Syokota			if (delay <= delays[n])
102946761Syokota				break;
103046761Syokota		d = n;
103146761Syokota		for (n = 0; n < nrepeats - 1; n++)
103246761Syokota			if (repeat <= repeats[n])
103346761Syokota				break;
103446761Syokota		r = n;
10352088Ssos	}
10362088Ssos
103744628Syokota	arg[0] = delay;
103844628Syokota	arg[1] = repeat;
103946761Syokota	if (ioctl(0, KDSETREPEAT, arg)) {
104046761Syokota		if (ioctl(0, KDSETRAD, (d << 5) | r))
104146761Syokota			warn("setting keyboard rate");
104246761Syokota	}
10432088Ssos}
10442088Ssos
104599816Salfredstatic const char *
104699816Salfredget_kbd_type_name(int type)
104742505Syokota{
104842505Syokota	static struct {
104942505Syokota		int type;
105099816Salfred		const char *name;
105142505Syokota	} name_table[] = {
105242505Syokota		{ KB_84,	"AT 84" },
105342505Syokota		{ KB_101,	"AT 101/102" },
105442505Syokota		{ KB_OTHER,	"generic" },
105542505Syokota	};
105699816Salfred	unsigned int i;
10576046Ssos
105842505Syokota	for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) {
105942505Syokota		if (type == name_table[i].type)
106042505Syokota			return name_table[i].name;
106142505Syokota	}
106242505Syokota	return "unknown";
106342505Syokota}
106442505Syokota
1065228437Sedstatic void
106642505Syokotashow_kbd_info(void)
106742505Syokota{
106842505Syokota	keyboard_info_t info;
106942505Syokota
107042505Syokota	if (ioctl(0, KDGKBINFO, &info) == -1) {
107142505Syokota		warn("unable to obtain keyboard information");
107242505Syokota		return;
107342505Syokota	}
107442505Syokota	printf("kbd%d:\n", info.kb_index);
107542505Syokota	printf("    %.*s%d, type:%s (%d)\n",
107677394Ssobomax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
107742505Syokota		get_kbd_type_name(info.kb_type), info.kb_type);
107842505Syokota}
107942505Syokota
1080228437Sedstatic void
108142505Syokotaset_keyboard(char *device)
108242505Syokota{
108342505Syokota	keyboard_info_t info;
108442505Syokota	int fd;
108542505Syokota
108642505Syokota	fd = open(device, O_RDONLY);
108742505Syokota	if (fd < 0) {
108842505Syokota		warn("cannot open %s", device);
108942505Syokota		return;
109042505Syokota	}
109142505Syokota	if (ioctl(fd, KDGKBINFO, &info) == -1) {
109242505Syokota		warn("unable to obtain keyboard information");
109342505Syokota		close(fd);
109442505Syokota		return;
109542505Syokota	}
109642505Syokota	/*
109742505Syokota	 * The keyboard device driver won't release the keyboard by
109842505Syokota	 * the following ioctl, but it automatically will, when the device
109942505Syokota	 * is closed.  So, we don't check error here.
110042505Syokota	 */
110142505Syokota	ioctl(fd, CONS_RELKBD, 0);
110242505Syokota	close(fd);
110342505Syokota#if 1
110442505Syokota	printf("kbd%d\n", info.kb_index);
110542505Syokota	printf("    %.*s%d, type:%s (%d)\n",
110677394Ssobomax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
110742505Syokota		get_kbd_type_name(info.kb_type), info.kb_type);
110842505Syokota#endif
110942505Syokota
111042505Syokota	if (ioctl(0, CONS_SETKBD, info.kb_index) == -1)
111142505Syokota		warn("unable to set keyboard");
111242505Syokota}
111342505Syokota
1114228437Sedstatic void
111542505Syokotarelease_keyboard(void)
111642505Syokota{
111742505Syokota	keyboard_info_t info;
111842505Syokota
111942505Syokota	/*
112042505Syokota	 * If stdin is not associated with a keyboard, the following ioctl
112142505Syokota	 * will fail.
112242505Syokota	 */
112342505Syokota	if (ioctl(0, KDGKBINFO, &info) == -1) {
112442505Syokota		warn("unable to obtain keyboard information");
112542505Syokota		return;
112642505Syokota	}
112742505Syokota#if 1
112842505Syokota	printf("kbd%d\n", info.kb_index);
112942505Syokota	printf("    %.*s%d, type:%s (%d)\n",
113077394Ssobomax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
113142505Syokota		get_kbd_type_name(info.kb_type), info.kb_type);
113242505Syokota#endif
113342505Syokota	if (ioctl(0, CONS_RELKBD, 0) == -1)
113442505Syokota		warn("unable to release the keyboard");
113542505Syokota}
113642505Syokota
1137228437Sedstatic void
1138162327Semaxmux_keyboard(u_int op, char *kbd)
1139148017Semax{
1140148017Semax	keyboard_info_t	info;
1141148017Semax	char		*unit, *ep;
114242505Syokota
1143148017Semax	/*
1144148017Semax	 * If stdin is not associated with a keyboard, the following ioctl
1145148017Semax	 * will fail.
1146148017Semax	 */
1147148017Semax	if (ioctl(0, KDGKBINFO, &info) == -1) {
1148148017Semax		warn("unable to obtain keyboard information");
1149148017Semax		return;
1150148017Semax	}
1151148017Semax#if 1
1152148017Semax	printf("kbd%d\n", info.kb_index);
1153148017Semax	printf("    %.*s%d, type:%s (%d)\n",
1154148017Semax		(int)sizeof(info.kb_name), info.kb_name, info.kb_unit,
1155148017Semax		get_kbd_type_name(info.kb_type), info.kb_type);
1156148017Semax#endif
1157148017Semax	/*
1158148017Semax	 * split kbd into name and unit. find the right most part of the
1159148017Semax	 * kbd string that consist of only digits.
1160148017Semax	 */
1161148017Semax
1162148017Semax	memset(&info, 0, sizeof(info));
1163148017Semax
1164148017Semax	info.kb_unit = -1;
1165148017Semax	ep = kbd - 1;
1166148017Semax
1167148017Semax	do {
1168148017Semax		unit = strpbrk(ep + 1, "0123456789");
1169148017Semax		if (unit != NULL) {
1170148017Semax			info.kb_unit = strtol(unit, &ep, 10);
1171148017Semax			if (*ep != '\0')
1172148017Semax				info.kb_unit = -1;
1173148017Semax		}
1174148017Semax	} while (unit != NULL && info.kb_unit == -1);
1175148017Semax
1176148017Semax	if (info.kb_unit == -1) {
1177148017Semax		warnx("unable to find keyboard driver unit in '%s'", kbd);
1178148017Semax		return;
1179148017Semax	}
1180148017Semax
1181148017Semax	if (unit == kbd) {
1182148017Semax		warnx("unable to find keyboard driver name in '%s'", kbd);
1183148017Semax		return;
1184148017Semax	}
1185148017Semax	if (unit - kbd >= (int) sizeof(info.kb_name)) {
1186148017Semax		warnx("keyboard name '%s' is too long", kbd);
1187148017Semax		return;
1188148017Semax	}
1189148017Semax
1190148017Semax	strncpy(info.kb_name, kbd, unit - kbd);
1191148017Semax
1192148017Semax	/*
1193148017Semax	 * If stdin is not associated with a kbdmux(4) keyboard, the following
1194148017Semax	 * ioctl will fail.
1195148017Semax	 */
1196148017Semax
1197148017Semax	if (ioctl(0, op, &info) == -1)
1198148017Semax		warn("unable to (un)mux the keyboard");
1199148017Semax}
1200148017Semax
1201228437Sedstatic void
1202201387Sedusage(void)
12032088Ssos{
120429603Scharnier	fprintf(stderr, "%s\n%s\n%s\n",
1205148017Semax"usage: kbdcontrol [-dFKix] [-A name] [-a name] [-b duration.pitch | [quiet.]belltype]",
120629603Scharnier"                  [-r delay.repeat | speed] [-l mapfile] [-f # string]",
1207298297Semaste"                  [-k device] [-L mapfile] [-P path]");
120829603Scharnier	exit(1);
12092088Ssos}
12102088Ssos
12112088Ssos
121251287Speterint
12132088Ssosmain(int argc, char **argv)
12142088Ssos{
1215298297Semaste	const char	*optstring = "A:a:b:df:iKk:Fl:L:P:r:x";
12162088Ssos	int		opt;
12172088Ssos
1218298297Semaste	/* Collect any -P arguments, regardless of where they appear. */
1219298297Semaste	while ((opt = getopt(argc, argv, optstring)) != -1)
1220298297Semaste		if (opt == 'P')
1221298297Semaste			add_keymap_path(optarg);
1222298297Semaste
1223298297Semaste	optind = optreset = 1;
1224298297Semaste	while ((opt = getopt(argc, argv, optstring)) != -1)
12252088Ssos		switch(opt) {
1226148017Semax		case 'A':
1227148017Semax		case 'a':
1228148017Semax			mux_keyboard((opt == 'A')? KBRELKBD : KBADDKBD, optarg);
1229148017Semax			break;
123077329Sdes		case 'b':
123177329Sdes			set_bell_values(optarg);
123277329Sdes			break;
123377329Sdes		case 'd':
123477329Sdes			print_keymap();
123577329Sdes			break;
123677329Sdes		case 'l':
123777329Sdes			load_keymap(optarg, 0);
123877329Sdes			break;
123977329Sdes		case 'L':
124077329Sdes			load_keymap(optarg, 1);
124177329Sdes			break;
1242298297Semaste		case 'P':
1243298297Semaste			break;
124477329Sdes		case 'f':
124577329Sdes			set_functionkey(optarg,
124677329Sdes			    nextarg(argc, argv, &optind, 'f'));
124777329Sdes			break;
124877329Sdes		case 'F':
124977329Sdes			load_default_functionkeys();
125077329Sdes			break;
125177329Sdes		case 'i':
125277329Sdes			show_kbd_info();
125377329Sdes			break;
125477329Sdes		case 'K':
125577329Sdes			release_keyboard();
125677329Sdes			break;
125777329Sdes		case 'k':
125877329Sdes			set_keyboard(optarg);
125977329Sdes			break;
126077329Sdes		case 'r':
126177329Sdes			set_keyrates(optarg);
126277329Sdes			break;
126377329Sdes		case 'x':
126477329Sdes			hex = 1;
126577329Sdes			break;
126677329Sdes		default:
126777329Sdes			usage();
12682088Ssos		}
126929603Scharnier	if ((optind != argc) || (argc == 1))
12702088Ssos		usage();
12712088Ssos	exit(0);
12722088Ssos}
1273