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