kbd_wscons.c revision 1.26
1/*	$OpenBSD: kbd_wscons.c,v 1.26 2012/07/13 10:15:19 shadchin 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	"domain"
55};
56enum {	SA_PCKBD,
57	SA_UKBD,
58	SA_AKBD,
59	SA_LKKBD,
60	SA_SUNKBD,
61	SA_SUN5KBD,
62	SA_HILKBD,
63	SA_GSCKBD,
64	SA_DOMAINKBD,
65
66	SA_MAX
67};
68
69#ifndef NOKVM
70struct nlist nl[] = {
71	{ "_pckbd_keydesctab" },
72	{ "_ukbd_keydesctab" },
73	{ "_akbd_keydesctab" },
74	{ "_lkkbd_keydesctab" },
75	{ "_sunkbd_keydesctab" },
76	{ "_sunkbd5_keydesctab" },
77	{ "_hilkbd_keydesctab" },
78	{ "_gsckbd_keydesctab" },
79	{ "_dnkbd_keydesctab" },
80	{ NULL },
81};
82#endif /* NOKVM */
83
84#ifndef NOKVM
85int rebuild = 0;
86#endif
87
88struct nameint {
89	int value;
90	char *name;
91};
92
93struct nameint kbdenc_tab[] = {
94	KB_ENCTAB
95	,
96	{ 0, NULL }
97};
98
99struct nameint kbdvar_tab[] = {
100	KB_VARTAB
101	,
102	{ 0, NULL }
103};
104
105extern char *__progname;
106
107void	kbd_show_enc(kvm_t *kd, int idx);
108void	kbd_list(void);
109void	kbd_set(char *name, int verbose);
110
111void
112kbd_show_enc(kvm_t *kd, int idx)
113{
114#ifndef NOKVM
115	struct wscons_keydesc r;
116	unsigned long p;
117	int found;
118	u_int32_t variant;
119	struct nameint *n;
120#else
121	int i;
122#endif /* NOKVM */
123
124#ifndef NOKVM
125	p = nl[idx].n_value;
126	if (p == 0) {
127		printf("no tables available for %s keyboard\n\n",
128		    kbtype_tab[idx]);
129		return;
130	}
131#endif
132
133	printf("tables available for %s keyboard:\nencoding\n\n",
134	    kbtype_tab[idx]);
135
136#ifdef NOKVM
137	for (i = 0; kbdenc_tab[i].value; i++)
138		printf("%s\n", kbdenc_tab[i].name);
139#else
140	kvm_read(kd, p, &r, sizeof(r));
141	while (r.name != 0) {
142		n = &kbdenc_tab[0];
143		found = 0;
144		while (n->value) {
145			if (n->value == KB_ENCODING(r.name)) {
146				printf("%s",n->name);
147				found++;
148			}
149			n++;
150		}
151		if (found == 0) {
152			printf("<encoding 0x%04x>",KB_ENCODING(r.name));
153			rebuild++;
154		}
155		n = &kbdvar_tab[0];
156		found = 0;
157		variant = KB_VARIANT(r.name);
158		while (n->value) {
159			if ((n->value & KB_VARIANT(r.name)) == n->value) {
160				printf(".%s",n->name);
161				variant &= ~n->value;
162			}
163			n++;
164		}
165		if (variant != 0) {
166			printf(".<variant 0x%08x>",variant);
167			rebuild++;
168		}
169		printf("\n");
170		p += sizeof(r);
171		kvm_read(kd, p, &r, sizeof(r));
172	}
173#endif
174	printf("\n");
175}
176
177void
178kbd_list(void)
179{
180	int	kbds[SA_MAX];
181	int	fd, i, kbtype;
182	char	device[MAXPATHLEN];
183	kvm_t	*kd = NULL;
184#ifndef NOKVM
185	char	errbuf[LINE_MAX];
186#endif
187
188	bzero(kbds, sizeof(kbds));
189
190	/* Go through all keyboards. */
191	for (i = 0; i < NUM_KBD; i++) {
192		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
193		fd = open(device, O_WRONLY);
194		if (fd < 0)
195			fd = open(device, O_RDONLY);
196		if (fd >= 0) {
197			if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) < 0)
198				err(1, "WSKBDIO_GTYPE");
199			switch (kbtype) {
200			case WSKBD_TYPE_PC_XT:
201			case WSKBD_TYPE_PC_AT:
202				kbds[SA_PCKBD]++;
203				break;
204			case WSKBD_TYPE_USB:
205				kbds[SA_UKBD]++;
206				break;
207			case WSKBD_TYPE_ADB:
208				kbds[SA_AKBD]++;
209				break;
210			case WSKBD_TYPE_LK201:
211			case WSKBD_TYPE_LK401:
212				kbds[SA_LKKBD]++;
213				break;
214			case WSKBD_TYPE_SUN:
215				kbds[SA_SUNKBD]++;
216				break;
217			case WSKBD_TYPE_SUN5:
218				kbds[SA_SUN5KBD]++;
219				break;
220			case WSKBD_TYPE_HIL:
221				kbds[SA_HILKBD]++;
222				break;
223			case WSKBD_TYPE_GSC:
224				kbds[SA_GSCKBD]++;
225				break;
226			case WSKBD_TYPE_DOMAIN:
227				kbds[SA_DOMAINKBD]++;
228				break;
229			};
230			close(fd);
231		}
232	}
233
234#ifndef NOKVM
235	if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL)
236		errx(1, "kvm_openfiles: %s", errbuf);
237
238	if (kvm_nlist(kd, nl) == -1)
239		errx(1, "kvm_nlist: %s", kvm_geterr(kd));
240#endif
241
242	for (i = 0; i < SA_MAX; i++)
243		if (kbds[i] != 0)
244			kbd_show_enc(kd, i);
245
246#ifndef NOKVM
247	kvm_close(kd);
248	if (rebuild > 0)
249		printf("Unknown encoding or variant. kbd(8) needs to be rebuilt.\n");
250#endif
251}
252
253void
254kbd_set(char *name, int verbose)
255{
256	char	buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"];
257	int	map = 0, v, i, fd;
258	struct nameint *n;
259
260	c = name;
261	b = buf;
262	while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
263		*b++ = *c++;
264	*b = '\0';
265	n = &kbdenc_tab[0];
266	while (n->value) {
267		if (strcmp(n->name, buf) == 0)
268			map = n->value;
269		n++;
270	}
271	if (map == 0)
272		errx(1, "unknown encoding %s", buf);
273	while (*c == '.') {
274		b = buf;
275		c++;
276		while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
277			*b++ = *c++;
278		*b = '\0';
279		v = 0;
280		n = &kbdvar_tab[0];
281		while (n->value) {
282			if (strcmp(n->name, buf) == 0)
283				v = n->value;
284			n++;
285		}
286		if (v == 0)
287			errx(1, "unknown variant %s", buf);
288		map |= v;
289	}
290
291	/* Go through all keyboards. */
292	v = 0;
293	for (i = 0; i < NUM_KBD; i++) {
294		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
295		fd = open(device, O_WRONLY);
296		if (fd < 0)
297			fd = open(device, O_RDONLY);
298		if (fd >= 0) {
299			if (ioctl(fd, WSKBDIO_SETENCODING, &map) < 0) {
300				if (errno == EINVAL) {
301					fprintf(stderr,
302					    "%s: unsupported encoding %s on %s\n",
303					    __progname, name, device);
304				} else
305					err(1, "WSKBDIO_SETENCODING: %s", device);
306				v--;
307			}
308			v++;
309			close(fd);
310		}
311	}
312
313	if (verbose && v > 0)
314		fprintf(stderr, "kbd: keyboard mapping set to %s\n", name);
315}
316