1 /* $OpenBSD: kbd_wscons.c,v 1.36 2022/05/05 16:12:42 bluhm 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
kbd_show_enc(struct wskbd_encoding_data * encs,int idx)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
kbd_get_encs(int fd,struct wskbd_encoding_data * encs)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
kbd_list(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, error = 0;
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 == -1) {
166 /* remember the first error number */
167 if (error == 0)
168 error = errno;
169 } else {
170 /* at least one success, do not print error */
171 error = -1;
172
173 if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) == -1)
174 err(1, "WSKBDIO_GTYPE %s", device);
175 switch (kbtype) {
176 case WSKBD_TYPE_PC_XT:
177 case WSKBD_TYPE_PC_AT:
178 t = SA_PCKBD;
179 break;
180 case WSKBD_TYPE_USB:
181 t = SA_UKBD;
182 break;
183 case WSKBD_TYPE_ADB:
184 t = SA_AKBD;
185 break;
186 case WSKBD_TYPE_LK201:
187 case WSKBD_TYPE_LK401:
188 t = SA_LKKBD;
189 break;
190 case WSKBD_TYPE_SUN:
191 t = SA_SUNKBD;
192 break;
193 case WSKBD_TYPE_SUN5:
194 t = SA_SUN5KBD;
195 break;
196 case WSKBD_TYPE_HIL:
197 t = SA_HILKBD;
198 break;
199 case WSKBD_TYPE_GSC:
200 t = SA_GSCKBD;
201 break;
202 case WSKBD_TYPE_SGI:
203 t = SA_SGIKBD;
204 break;
205 default:
206 t = SA_MAX;
207 break;
208 }
209
210 if (t != SA_MAX) {
211 kbds[t]++;
212 if (encs[t].encodings == NULL)
213 kbd_get_encs(fd, &encs[t]);
214 }
215 close(fd);
216 }
217 }
218 if (error > 0) {
219 errno = error;
220 err(1, "/dev/wskbd0");
221 }
222
223 for (i = 0; i < SA_MAX; i++)
224 if (kbds[i] != 0)
225 kbd_show_enc(&encs[i], i);
226
227 for (i = 0; i < SA_MAX; i++)
228 free(encs[i].encodings);
229 }
230
231 void
kbd_set(char * name,int verbose)232 kbd_set(char *name, int verbose)
233 {
234 char buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"];
235 int map = 0, v, i, fd, error = 0;
236 struct nameint *n;
237
238 c = name;
239 b = buf;
240 while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
241 *b++ = *c++;
242 *b = '\0';
243 n = &kbdenc_tab[0];
244 while (n->value) {
245 if (strcmp(n->name, buf) == 0)
246 map = n->value;
247 n++;
248 }
249 if (map == 0)
250 errx(1, "unknown encoding %s", buf);
251 while (*c == '.') {
252 b = buf;
253 c++;
254 while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1)
255 *b++ = *c++;
256 *b = '\0';
257 v = 0;
258 for (n = &kbdvar_tab[0]; n->value; n++) {
259 if (strcmp(n->name, buf) == 0)
260 v = n->value;
261 }
262 if (v == 0)
263 errx(1, "unknown variant %s", buf);
264 map |= v;
265 }
266
267 /* Go through all keyboards. */
268 v = 0;
269 for (i = 0; i < NUM_KBD; i++) {
270 (void) snprintf(device, sizeof device, "/dev/wskbd%d", i);
271 fd = open(device, O_WRONLY);
272 if (fd == -1)
273 fd = open(device, O_RDONLY);
274 if (fd == -1) {
275 /* remember the first error number */
276 if (error == 0)
277 error = errno;
278 } else {
279 /* at least one success, do not print error */
280 error = -1;
281
282 if (ioctl(fd, WSKBDIO_SETENCODING, &map) == -1) {
283 if (errno != EINVAL)
284 err(1, "WSKBDIO_SETENCODING %s",
285 device);
286 fprintf(stderr,
287 "%s: unsupported encoding %s on %s\n",
288 __progname, name, device);
289 } else
290 v++;
291 close(fd);
292 }
293 }
294 if (error > 0) {
295 errno = error;
296 err(1, "/dev/wskbd0");
297 }
298
299 if (verbose && v > 0)
300 fprintf(stderr, "kbd: keyboard mapping set to %s\n", name);
301 }
302