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