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