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