kbd_wscons.c revision 1.7
1/*	$OpenBSD: kbd_wscons.c,v 1.7 2002/05/22 08:21:02 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 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by Mats O Jansson.
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/param.h>
33#include <sys/ioctl.h>
34#include <sys/time.h>
35#include <dev/wscons/wsconsio.h>
36#include <dev/wscons/wsksymdef.h>
37
38#include <err.h>
39#include <errno.h>
40#include <kvm.h>
41#include <fcntl.h>
42#include <limits.h>
43#include <nlist.h>
44#include <stdio.h>
45#include <unistd.h>
46
47#define	NUM_KBD	10
48
49#define SA_PCKBD 0
50#define SA_UKBD  1
51#define SA_AKBD	 2
52#define SA_ZSKBD 3
53#define SA_SUNKBD 4
54
55struct nlist nl[] = {
56	{ "_pckbd_keydesctab" },
57	{ "_ukbd_keydesctab" },
58	{ "_akbd_keydesctab" },
59	{ "_zskbd_keydesctab" },
60	{ "_sunkbd_keydesctab" },
61	{ NULL },
62};
63
64char *kbtype_tab[] = {
65	"pc-xt/pc-at",
66	"usb",
67	"adb",
68	"lk201",
69	"sun",
70};
71
72struct nameint {
73	int value;
74	char *name;
75};
76
77struct nameint kbdenc_tab[] = {
78	KB_ENCTAB
79	,
80	{ 0, 0 }
81};
82
83struct nameint kbdvar_tab[] = {
84	KB_VARTAB
85	,
86	{ 0, 0 }
87};
88
89extern char *__progname;
90int rebuild = 0;
91
92#ifndef NOKVM
93void
94kbd_show_enc(kd, idx)
95	kvm_t *kd;
96	int idx;
97{
98	struct wscons_keydesc r;
99	unsigned long p;
100	struct nameint *n;
101	int found;
102	u_int32_t variant;
103
104	printf("tables available for %s keyboard:\nencoding\n\n",
105	       kbtype_tab[idx]);
106	p = nl[idx].n_value;
107	kvm_read(kd, p, &r, sizeof(r));
108	while (r.name != 0) {
109		n = &kbdenc_tab[0];
110		found = 0;
111		while (n->value) {
112			if (n->value == KB_ENCODING(r.name)) {
113				printf("%s",n->name);
114				found++;
115			}
116			n++;
117		}
118		if (found == 0) {
119			printf("<encoding 0x%04x>",KB_ENCODING(r.name));
120			rebuild++;
121		}
122		n = &kbdvar_tab[0];
123		found = 0;
124		variant = KB_VARIANT(r.name);
125		while (n->value) {
126			if ((n->value & KB_VARIANT(r.name)) == n->value) {
127				printf(".%s",n->name);
128				variant &= ~n->value;
129			}
130			n++;
131		}
132		if (variant != 0) {
133			printf(".<variant 0x%08x>",variant);
134			rebuild++;
135		}
136		printf("\n");
137		p += sizeof(r);
138		kvm_read(kd, p, &r, sizeof(r));
139	}
140	printf("\n");
141}
142#endif
143
144void
145kbd_list()
146{
147	int	fd, i, kbtype, ret;
148	kvm_t	*kd;
149	char	device[MAXPATHLEN];
150	char	errbuf[_POSIX2_LINE_MAX];
151	int	pc_kbd = 0;
152	int	usb_kbd = 0;
153	int	adb_kbd = 0;
154	int	zs_kbd = 0;
155	int	sun_kbd = 0;
156
157	/* Go through all keyboards. */
158	for (i = 0; i < NUM_KBD; i++) {
159		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
160		fd = open(device, O_WRONLY);
161		if (fd < 0)
162			fd = open(device, O_RDONLY);
163		if (fd >= 0) {
164			if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) < 0)
165				err(1, "WDKBDIO_GTYPE");
166			if ((kbtype == WSKBD_TYPE_PC_XT) ||
167			    (kbtype == WSKBD_TYPE_PC_AT))
168				pc_kbd++;
169			if (kbtype == WSKBD_TYPE_USB)
170				usb_kbd++;
171			if (kbtype == WSKBD_TYPE_ADB)
172				adb_kbd++;
173			if (kbtype == WSKBD_TYPE_LK201)
174				zs_kbd++;
175			if (kbtype == WSKBD_TYPE_SUN)
176				sun_kbd++;
177			close(fd);
178		}
179	}
180
181#ifndef NOKVM
182	if ((kd = kvm_openfiles(NULL,NULL,NULL,O_RDONLY, errbuf)) == 0)
183		errx(1, "kvm_openfiles: %s", errbuf);
184
185	if ((ret = kvm_nlist(kd, nl)) == -1)
186		errx(1, "kvm_nlist: %s", kvm_geterr(kd));
187
188	if (pc_kbd > 0)
189		kbd_show_enc(kd, SA_PCKBD);
190
191	if (usb_kbd > 0)
192		kbd_show_enc(kd, SA_UKBD);
193
194	if (adb_kbd > 0)
195		kbd_show_enc(kd, SA_AKBD);
196
197	if (zs_kbd > 0)
198		kbd_show_enc(kd, SA_ZSKBD);
199
200	if (sun_kbd > 0)
201		kbd_show_enc(kd, SA_SUNKBD);
202
203	kvm_close(kd);
204
205	if (rebuild > 0) {
206		printf("Unknown encoding or variant. kbd(1) needs to be rebuild.\n");
207	}
208#else
209	printf("List not available, sorry.\n");
210#endif
211}
212
213void
214kbd_set(name, verbose)
215	char *name;
216	int verbose;
217{
218	char	buf[_POSIX2_LINE_MAX];
219	char	*c,*b;
220	struct nameint *n;
221	int	map = 0,v,i,fd;
222	char	device[sizeof "/dev/wskbd00"];
223
224	c = name;
225	b = buf;
226	while ((*c != '.') && (*c != '\0')) {
227		*b++ = *c++;
228	}
229	*b = '\0';
230	n = &kbdenc_tab[0];
231	while (n->value) {
232		if (strcmp(n->name,buf) == 0) {
233			map = n->value;
234		}
235		n++;
236	}
237	if (map == 0)
238		errx(1, "unknown encoding %s", buf);
239	while (*c == '.') {
240		b = buf;
241		c++;
242		while ((*c != '.') && (*c != '\0')) {
243			*b++ = *c++;
244		}
245		*b = '\0';
246		v = 0;
247		n = &kbdvar_tab[0];
248		while (n->value) {
249			if (strcmp(n->name,buf) == 0) {
250				v = n->value;
251			}
252			n++;
253		}
254		if (v == 0)
255			errx(1, "unknown variant %s", buf);
256		map |= v;
257	}
258
259	/* Go through all keyboards. */
260	v = 0;
261	for (i = 0; i < NUM_KBD; i++) {
262		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
263		fd = open(device, O_WRONLY);
264		if (fd < 0)
265			fd = open(device, O_RDONLY);
266		if (fd >= 0) {
267			if (ioctl(fd, WSKBDIO_SETENCODING, &map) < 0) {
268				if (errno == EINVAL) {
269					fprintf(stderr,
270					    "%s: unsupported encoding %s on %s\n",
271					    __progname, name, device);
272				} else {
273					err(1, "WDKBDIO_SETENCODING: %s", device);
274				}
275				v--;
276			}
277			v++;
278			close(fd);
279		}
280	}
281
282	if (verbose && v > 0)
283		fprintf(stderr, "keyboard mapping set to %s\n", name);
284}
285