xref: /openbsd/sbin/kbd/kbd_wscons.c (revision 09467b48)
1 /*	$OpenBSD: kbd_wscons.c,v 1.34 2020/01/22 06:24:07 tedu 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/ioctl.h>
28 #include <sys/time.h>
29 #include <dev/wscons/wsconsio.h>
30 #include <dev/wscons/wsksymdef.h>
31 
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #define	NUM_KBD	10
42 
43 char *kbtype_tab[] = {
44 	"pc-xt/pc-at",
45 	"usb",
46 	"adb",
47 	"lk201",
48 	"sun",
49 	"sun5",
50 	"hil",
51 	"gsc",
52 	"sgi"
53 };
54 enum {	SA_PCKBD,
55 	SA_UKBD,
56 	SA_AKBD,
57 	SA_LKKBD,
58 	SA_SUNKBD,
59 	SA_SUN5KBD,
60 	SA_HILKBD,
61 	SA_GSCKBD,
62 	SA_SGIKBD,
63 
64 	SA_MAX
65 };
66 
67 struct nameint {
68 	int value;
69 	char *name;
70 };
71 
72 struct nameint kbdenc_tab[] = {
73 	KB_ENCTAB
74 	,
75 	{ 0, NULL }
76 };
77 
78 struct nameint kbdvar_tab[] = {
79 	KB_VARTAB
80 	,
81 	{ 0, NULL }
82 };
83 
84 extern char *__progname;
85 
86 void	kbd_show_enc(struct wskbd_encoding_data *encs, int idx);
87 void	kbd_get_encs(int fd, struct wskbd_encoding_data *encs);
88 void	kbd_list(void);
89 void	kbd_set(char *name, int verbose);
90 
91 void
92 kbd_show_enc(struct wskbd_encoding_data *encs, int idx)
93 {
94 	int found;
95 	kbd_t encoding, variant;
96 	struct nameint *n;
97 	int i;
98 
99 	printf("tables available for %s keyboard:\nencoding\n\n",
100 	    kbtype_tab[idx]);
101 
102 	for (i = 0; i < encs->nencodings; i++) {
103 		found = 0;
104 		encoding = encs->encodings[i];
105 		for (n = &kbdenc_tab[0]; n->value; n++) {
106 			if (n->value == KB_ENCODING(encoding)) {
107 				printf("%s", n->name);
108 				found++;
109 			}
110 		}
111 		if (found == 0)
112 			printf("<encoding 0x%04x>", KB_ENCODING(encoding));
113 		found = 0;
114 		variant = KB_VARIANT(encoding);
115 		for (n = &kbdvar_tab[0]; n->value; n++) {
116 			if ((n->value & KB_VARIANT(encoding)) == n->value) {
117 				printf(".%s", n->name);
118 				variant &= ~n->value;
119 			}
120 		}
121 		if (variant != 0)
122 			printf(".<variant 0x%08x>", variant);
123 		printf("\n");
124 	}
125 	printf("\n");
126 }
127 
128 void
129 kbd_get_encs(int fd, struct wskbd_encoding_data *encs)
130 {
131 	int nencodings = 64;
132 
133 	encs->nencodings = nencodings;
134 	while (encs->nencodings == nencodings) {
135 		encs->encodings = reallocarray(encs->encodings,
136 		    encs->nencodings, sizeof(kbd_t));
137 		if (encs->encodings == NULL)
138 			err(1, NULL);
139 		if (ioctl(fd, WSKBDIO_GETENCODINGS, encs) == -1)
140 			err(1, "WSKBDIO_GETENCODINGS");
141 		if (encs->nencodings == nencodings) {
142 			nencodings *= 2;
143 			encs->nencodings = nencodings;
144 		}
145 	}
146 }
147 
148 void
149 kbd_list(void)
150 {
151 	int	kbds[SA_MAX];
152 	struct wskbd_encoding_data encs[SA_MAX];
153 	int	fd, i, kbtype, t;
154 	char	device[PATH_MAX];
155 
156 	memset(kbds, 0, sizeof(kbds));
157 	memset(encs, 0, sizeof(encs));
158 
159 	/* Go through all keyboards. */
160 	for (i = 0; i < NUM_KBD; i++) {
161 		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
162 		fd = open(device, O_WRONLY);
163 		if (fd == -1)
164 			fd = open(device, O_RDONLY);
165 		if (fd >= 0) {
166 			if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) == -1)
167 				err(1, "WSKBDIO_GTYPE");
168 			switch (kbtype) {
169 			case WSKBD_TYPE_PC_XT:
170 			case WSKBD_TYPE_PC_AT:
171 				t = SA_PCKBD;
172 				break;
173 			case WSKBD_TYPE_USB:
174 				t = SA_UKBD;
175 				break;
176 			case WSKBD_TYPE_ADB:
177 				t = SA_AKBD;
178 				break;
179 			case WSKBD_TYPE_LK201:
180 			case WSKBD_TYPE_LK401:
181 				t = SA_LKKBD;
182 				break;
183 			case WSKBD_TYPE_SUN:
184 				t = SA_SUNKBD;
185 				break;
186 			case WSKBD_TYPE_SUN5:
187 				t = SA_SUN5KBD;
188 				break;
189 			case WSKBD_TYPE_HIL:
190 				t = SA_HILKBD;
191 				break;
192 			case WSKBD_TYPE_GSC:
193 				t = SA_GSCKBD;
194 				break;
195 			case WSKBD_TYPE_SGI:
196 				t = SA_SGIKBD;
197 				break;
198 			default:
199 				t = SA_MAX;
200 				break;
201 			}
202 
203 			if (t != SA_MAX) {
204 				kbds[t]++;
205 				if (encs[t].encodings == NULL)
206 					kbd_get_encs(fd, &encs[t]);
207 			}
208 			close(fd);
209 		}
210 	}
211 
212 	for (i = 0; i < SA_MAX; i++)
213 		if (kbds[i] != 0)
214 			kbd_show_enc(&encs[i], i);
215 
216 	for (i = 0; i < SA_MAX; i++)
217 		free(encs[i].encodings);
218 }
219 
220 void
221 kbd_set(char *name, int verbose)
222 {
223 	char	buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"];
224 	int	map = 0, v, i, fd;
225 	struct nameint *n;
226 
227 	c = name;
228 	b = buf;
229 	while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
230 		*b++ = *c++;
231 	*b = '\0';
232 	n = &kbdenc_tab[0];
233 	while (n->value) {
234 		if (strcmp(n->name, buf) == 0)
235 			map = n->value;
236 		n++;
237 	}
238 	if (map == 0)
239 		errx(1, "unknown encoding %s", buf);
240 	while (*c == '.') {
241 		b = buf;
242 		c++;
243 		while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
244 			*b++ = *c++;
245 		*b = '\0';
246 		v = 0;
247 		for (n = &kbdvar_tab[0]; n->value; n++) {
248 			if (strcmp(n->name, buf) == 0)
249 				v = n->value;
250 		}
251 		if (v == 0)
252 			errx(1, "unknown variant %s", buf);
253 		map |= v;
254 	}
255 
256 	/* Go through all keyboards. */
257 	v = 0;
258 	for (i = 0; i < NUM_KBD; i++) {
259 		(void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
260 		fd = open(device, O_WRONLY);
261 		if (fd == -1)
262 			fd = open(device, O_RDONLY);
263 		if (fd >= 0) {
264 			if (ioctl(fd, WSKBDIO_SETENCODING, &map) == -1) {
265 				if (errno == EINVAL) {
266 					fprintf(stderr,
267 					    "%s: unsupported encoding %s on %s\n",
268 					    __progname, name, device);
269 				} else
270 					err(1, "WSKBDIO_SETENCODING: %s", device);
271 				v--;
272 			}
273 			v++;
274 			close(fd);
275 		}
276 	}
277 
278 	if (verbose && v > 0)
279 		fprintf(stderr, "kbd: keyboard mapping set to %s\n", name);
280 }
281