kbd_wscons.c revision 1.30
1/*	$OpenBSD: kbd_wscons.c,v 1.30 2016/09/27 22:03:49 deraadt Exp $ */
2
3/*
4 * Copyright (c) 2001 Mats O Jansson.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/ioctl.h>
28#include <sys/time.h>
29#include <dev/wscons/wsconsio.h>
30#include <dev/wscons/wsksymdef.h>
31
32#include <err.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <limits.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39
40#define	NUM_KBD	10
41
42char *kbtype_tab[] = {
43	"pc-xt/pc-at",
44	"usb",
45	"adb",
46	"lk201",
47	"sun",
48	"sun5",
49	"hil",
50	"gsc",
51	"sgi"
52};
53enum {	SA_PCKBD,
54	SA_UKBD,
55	SA_AKBD,
56	SA_LKKBD,
57	SA_SUNKBD,
58	SA_SUN5KBD,
59	SA_HILKBD,
60	SA_GSCKBD,
61	SA_SGIKBD,
62
63	SA_MAX
64};
65
66struct nameint {
67	int value;
68	char *name;
69};
70
71struct nameint kbdenc_tab[] = {
72	KB_ENCTAB
73	,
74	{ 0, NULL }
75};
76
77struct nameint kbdvar_tab[] = {
78	KB_VARTAB
79	,
80	{ 0, NULL }
81};
82
83extern char *__progname;
84
85void	kbd_show_enc(int idx);
86void	kbd_list(void);
87void	kbd_set(char *name, int verbose);
88
89void
90kbd_show_enc(int idx)
91{
92	int i;
93
94	printf("tables available for %s keyboard:\nencoding\n\n",
95	    kbtype_tab[idx]);
96
97	for (i = 0; kbdenc_tab[i].value; i++)
98		printf("%s\n", kbdenc_tab[i].name);
99	printf("\n");
100}
101
102void
103kbd_list(void)
104{
105	int	kbds[SA_MAX];
106	int	fd, i, kbtype;
107	char	device[PATH_MAX];
108
109	bzero(kbds, sizeof(kbds));
110
111	/* Go through all keyboards. */
112	for (i = 0; i < NUM_KBD; i++) {
113		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
114		fd = open(device, O_WRONLY);
115		if (fd < 0)
116			fd = open(device, O_RDONLY);
117		if (fd >= 0) {
118			if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) < 0)
119				err(1, "WSKBDIO_GTYPE");
120			switch (kbtype) {
121			case WSKBD_TYPE_PC_XT:
122			case WSKBD_TYPE_PC_AT:
123				kbds[SA_PCKBD]++;
124				break;
125			case WSKBD_TYPE_USB:
126				kbds[SA_UKBD]++;
127				break;
128			case WSKBD_TYPE_ADB:
129				kbds[SA_AKBD]++;
130				break;
131			case WSKBD_TYPE_LK201:
132			case WSKBD_TYPE_LK401:
133				kbds[SA_LKKBD]++;
134				break;
135			case WSKBD_TYPE_SUN:
136				kbds[SA_SUNKBD]++;
137				break;
138			case WSKBD_TYPE_SUN5:
139				kbds[SA_SUN5KBD]++;
140				break;
141			case WSKBD_TYPE_HIL:
142				kbds[SA_HILKBD]++;
143				break;
144			case WSKBD_TYPE_GSC:
145				kbds[SA_GSCKBD]++;
146				break;
147			case WSKBD_TYPE_SGI:
148				kbds[SA_SGIKBD]++;
149				break;
150			};
151			close(fd);
152		}
153	}
154
155	for (i = 0; i < SA_MAX; i++)
156		if (kbds[i] != 0)
157			kbd_show_enc(i);
158}
159
160void
161kbd_set(char *name, int verbose)
162{
163	char	buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"];
164	int	map = 0, v, i, fd;
165	struct nameint *n;
166
167	c = name;
168	b = buf;
169	while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
170		*b++ = *c++;
171	*b = '\0';
172	n = &kbdenc_tab[0];
173	while (n->value) {
174		if (strcmp(n->name, buf) == 0)
175			map = n->value;
176		n++;
177	}
178	if (map == 0)
179		errx(1, "unknown encoding %s", buf);
180	while (*c == '.') {
181		b = buf;
182		c++;
183		while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
184			*b++ = *c++;
185		*b = '\0';
186		v = 0;
187		n = &kbdvar_tab[0];
188		while (n->value) {
189			if (strcmp(n->name, buf) == 0)
190				v = n->value;
191			n++;
192		}
193		if (v == 0)
194			errx(1, "unknown variant %s", buf);
195		map |= v;
196	}
197
198	/* Go through all keyboards. */
199	v = 0;
200	for (i = 0; i < NUM_KBD; i++) {
201		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
202		fd = open(device, O_WRONLY);
203		if (fd < 0)
204			fd = open(device, O_RDONLY);
205		if (fd >= 0) {
206			if (ioctl(fd, WSKBDIO_SETENCODING, &map) < 0) {
207				if (errno == EINVAL) {
208					fprintf(stderr,
209					    "%s: unsupported encoding %s on %s\n",
210					    __progname, name, device);
211				} else
212					err(1, "WSKBDIO_SETENCODING: %s", device);
213				v--;
214			}
215			v++;
216			close(fd);
217		}
218	}
219
220	if (verbose && v > 0)
221		fprintf(stderr, "kbd: keyboard mapping set to %s\n", name);
222}
223