kbd_wscons.c revision 1.21
1/*	$OpenBSD: kbd_wscons.c,v 1.21 2005/03/27 05:21:19 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/param.h>
28#include <sys/ioctl.h>
29#include <sys/time.h>
30#include <dev/wscons/wsconsio.h>
31#include <dev/wscons/wsksymdef.h>
32
33#include <err.h>
34#include <errno.h>
35#include <kvm.h>
36#include <fcntl.h>
37#include <limits.h>
38#include <nlist.h>
39#include <stdio.h>
40#include <string.h>
41#include <unistd.h>
42
43#define	NUM_KBD	10
44
45char *kbtype_tab[] = {
46	"pc-xt/pc-at",
47	"usb",
48	"adb",
49	"lk201",
50	"sun",
51	"sun5",
52	"hil",
53	"gsc",
54};
55#define SA_PCKBD 0
56#define SA_UKBD  1
57#define SA_AKBD	 2
58#define SA_ZSKBD 3
59#define SA_SUNKBD 4
60#define SA_SUN5KBD 5
61#define SA_HILKBD 6
62#define	SA_GSCKBD 7
63
64#ifndef NOKVM
65struct nlist nl[] = {
66	{ "_pckbd_keydesctab" },
67	{ "_ukbd_keydesctab" },
68	{ "_akbd_keydesctab" },
69	{ "_zskbd_keydesctab" },
70	{ "_sunkbd_keydesctab" },
71	{ "_sunkbd5_keydesctab" },
72	{ "_hilkbd_keydesctab" },
73	{ "_gsckbd_keydesctab" },
74	{ NULL },
75};
76#endif /* NOKVM */
77
78int rebuild = 0;
79
80struct nameint {
81	int value;
82	char *name;
83};
84
85struct nameint kbdenc_tab[] = {
86	KB_ENCTAB
87	,
88	{ 0, 0 }
89};
90
91struct nameint kbdvar_tab[] = {
92	KB_VARTAB
93	,
94	{ 0, 0 }
95};
96
97extern char *__progname;
98
99void	kbd_show_enc(kvm_t *kd, int idx);
100void	kbd_list(void);
101void	kbd_set(char *name, int verbose);
102
103void
104kbd_show_enc(kvm_t *kd, int idx)
105{
106#ifndef NOKVM
107	struct wscons_keydesc r;
108	unsigned long p;
109	int found;
110	u_int32_t variant;
111	struct nameint *n;
112#else
113	int i;
114#endif /* NOKVM */
115
116	printf("tables available for %s keyboard:\nencoding\n\n",
117	    kbtype_tab[idx]);
118
119#ifdef NOKVM
120	for (i = 0; kbdenc_tab[i].value; i++)
121		printf("%s\n", kbdenc_tab[i].name);
122#else
123	p = nl[idx].n_value;
124	kvm_read(kd, p, &r, sizeof(r));
125	while (r.name != 0) {
126		n = &kbdenc_tab[0];
127		found = 0;
128		while (n->value) {
129			if (n->value == KB_ENCODING(r.name)) {
130				printf("%s",n->name);
131				found++;
132			}
133			n++;
134		}
135		if (found == 0) {
136			printf("<encoding 0x%04x>",KB_ENCODING(r.name));
137			rebuild++;
138		}
139		n = &kbdvar_tab[0];
140		found = 0;
141		variant = KB_VARIANT(r.name);
142		while (n->value) {
143			if ((n->value & KB_VARIANT(r.name)) == n->value) {
144				printf(".%s",n->name);
145				variant &= ~n->value;
146			}
147			n++;
148		}
149		if (variant != 0) {
150			printf(".<variant 0x%08x>",variant);
151			rebuild++;
152		}
153		printf("\n");
154		p += sizeof(r);
155		kvm_read(kd, p, &r, sizeof(r));
156	}
157#endif
158	printf("\n");
159}
160
161void
162kbd_list(void)
163{
164	int	pc_kbd = 0, usb_kbd = 0, adb_kbd = 0;
165	int	zs_kbd = 0, sun_kbd = 0, sun5_kbd = 0;
166	int	hil_kbd = 0, gsc_kbd = 0, fd, i, kbtype;
167	char	device[MAXPATHLEN];
168	kvm_t	*kd = NULL;
169#ifndef NOKVM
170	char	errbuf[LINE_MAX];
171#endif
172
173	/* Go through all keyboards. */
174	for (i = 0; i < NUM_KBD; i++) {
175		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
176		fd = open(device, O_WRONLY);
177		if (fd < 0)
178			fd = open(device, O_RDONLY);
179		if (fd >= 0) {
180			if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) < 0)
181				err(1, "WSKBDIO_GTYPE");
182			if (kbtype == WSKBD_TYPE_PC_XT ||
183			    kbtype == WSKBD_TYPE_PC_AT)
184				pc_kbd++;
185			if (kbtype == WSKBD_TYPE_USB)
186				usb_kbd++;
187			if (kbtype == WSKBD_TYPE_ADB)
188				adb_kbd++;
189			if (kbtype == WSKBD_TYPE_LK201)
190				zs_kbd++;
191			if (kbtype == WSKBD_TYPE_SUN)
192				sun_kbd++;
193			if (kbtype == WSKBD_TYPE_SUN5)
194				sun5_kbd++;
195			if (kbtype == WSKBD_TYPE_HIL)
196				hil_kbd++;
197			if (kbtype == WSKBD_TYPE_GSC)
198				gsc_kbd++;
199			close(fd);
200		}
201	}
202
203#ifndef NOKVM
204	if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == 0)
205		errx(1, "kvm_openfiles: %s", errbuf);
206
207	if (kvm_nlist(kd, nl) == -1)
208		errx(1, "kvm_nlist: %s", kvm_geterr(kd));
209#endif
210
211	if (pc_kbd > 0)
212		kbd_show_enc(kd, SA_PCKBD);
213	if (usb_kbd > 0)
214		kbd_show_enc(kd, SA_UKBD);
215	if (adb_kbd > 0)
216		kbd_show_enc(kd, SA_AKBD);
217	if (zs_kbd > 0)
218		kbd_show_enc(kd, SA_ZSKBD);
219	if (sun_kbd > 0)
220		kbd_show_enc(kd, SA_SUNKBD);
221	if (sun5_kbd > 0)
222		kbd_show_enc(kd, SA_SUN5KBD);
223	if (hil_kbd > 0)
224		kbd_show_enc(kd, SA_HILKBD);
225	if (gsc_kbd > 0)
226		kbd_show_enc(kd, SA_GSCKBD);
227#ifndef NOKVM
228	kvm_close(kd);
229#endif
230	if (rebuild > 0)
231		printf("Unknown encoding or variant. kbd(8) needs to be rebuilt.\n");
232}
233
234void
235kbd_set(char *name, int verbose)
236{
237	char	buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"];
238	int	map = 0, v, i, fd;
239	struct nameint *n;
240
241	c = name;
242	b = buf;
243	while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
244		*b++ = *c++;
245	*b = '\0';
246	n = &kbdenc_tab[0];
247	while (n->value) {
248		if (strcmp(n->name, buf) == 0)
249			map = n->value;
250		n++;
251	}
252	if (map == 0)
253		errx(1, "unknown encoding %s", buf);
254	while (*c == '.') {
255		b = buf;
256		c++;
257		while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
258			*b++ = *c++;
259		*b = '\0';
260		v = 0;
261		n = &kbdvar_tab[0];
262		while (n->value) {
263			if (strcmp(n->name, buf) == 0)
264				v = n->value;
265			n++;
266		}
267		if (v == 0)
268			errx(1, "unknown variant %s", buf);
269		map |= v;
270	}
271
272	/* Go through all keyboards. */
273	v = 0;
274	for (i = 0; i < NUM_KBD; i++) {
275		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
276		fd = open(device, O_WRONLY);
277		if (fd < 0)
278			fd = open(device, O_RDONLY);
279		if (fd >= 0) {
280			if (ioctl(fd, WSKBDIO_SETENCODING, &map) < 0) {
281				if (errno == EINVAL) {
282					fprintf(stderr,
283					    "%s: unsupported encoding %s on %s\n",
284					    __progname, name, device);
285				} else
286					err(1, "WSKBDIO_SETENCODING: %s", device);
287				v--;
288			}
289			v++;
290			close(fd);
291		}
292	}
293
294	if (verbose && v > 0)
295		fprintf(stderr, "kbd: keyboard mapping set to %s\n", name);
296}
297