1 /*        $NetBSD: util.c,v 1.34 2024/10/20 08:46:02 mlelstv Exp $ */
2 
3 /*-
4  * Copyright (c) 1998, 2006, 2012 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Juergen Hannken-Illjes and Julio M. Merino Vidal.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/time.h>
33 
34 #include <dev/wscons/wsconsio.h>
35 #include <dev/wscons/wsksymdef.h>
36 #include <dev/videomode/videomode.h>
37 #include <dev/videomode/edidreg.h>
38 #include <dev/videomode/edidvar.h>
39 
40 #include <err.h>
41 #include <errno.h>
42 #include <limits.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 
48 #include "wsconsctl.h"
49 
50 #define TABLEN(t)             (sizeof(t)/sizeof(t[0]))
51 
52 extern struct wskbd_map_data kbmap;     /* from keyboard.c */
53 extern struct wskbd_map_data newkbmap;  /* from map_parse.y */
54 
55 struct nameint {
56           int value;
57           const char *name;
58 };
59 
60 static struct nameint kbtype_tab[] = {
61           { WSKBD_TYPE_LK201,           "lk201" },
62           { WSKBD_TYPE_LK401,           "lk401" },
63           { WSKBD_TYPE_PC_XT,           "pc-xt" },
64           { WSKBD_TYPE_PC_AT,           "pc-at" },
65           { WSKBD_TYPE_USB,             "usb" },
66           { WSKBD_TYPE_HPC_KBD,                   "hpc-kbd" },
67           { WSKBD_TYPE_HPC_BTN,                   "hpc-btn" },
68           { WSKBD_TYPE_ARCHIMEDES,      "archimedes" },
69           { WSKBD_TYPE_RISCPC,                    "riscpc" },
70           { WSKBD_TYPE_ADB,             "adb" },
71           { WSKBD_TYPE_HIL,             "hil" },
72           { WSKBD_TYPE_AMIGA,           "amiga" },
73           { WSKBD_TYPE_MAPLE,           "maple" },
74           { WSKBD_TYPE_ATARI,           "atari" },
75           { WSKBD_TYPE_SUN,             "sun" },
76           { WSKBD_TYPE_SUN5,            "sun-type5" },
77           { WSKBD_TYPE_SGI,             "sgi" },
78           { WSKBD_TYPE_MATRIXKP,                  "matrix-keypad" },
79           { WSKBD_TYPE_BLUETOOTH,                 "bluetooth" },
80 };
81 
82 static struct nameint mstype_tab[] = {
83           { WSMOUSE_TYPE_VSXXX,                   "dec-tc" },
84           { WSMOUSE_TYPE_PS2,           "ps2" },
85           { WSMOUSE_TYPE_USB,           "usb" },
86           { WSMOUSE_TYPE_LMS,           "logitech-bus" },
87           { WSMOUSE_TYPE_MMS,           "ms-inport" },
88           { WSMOUSE_TYPE_TPANEL,                  "touch-panel" },
89           { WSMOUSE_TYPE_NEXT,                    "next" },
90           { WSMOUSE_TYPE_ARCHIMEDES,    "archimedes" },
91           { WSMOUSE_TYPE_HIL,           "hil" },
92           { WSMOUSE_TYPE_AMIGA,                   "amiga" },
93           { WSMOUSE_TYPE_MAXINE,                  "dec-maxine" },
94           { WSMOUSE_TYPE_MAPLE,                   "maple" },
95           { WSMOUSE_TYPE_BLUETOOTH,     "bluetooth" },
96 };
97 
98 static struct nameint dpytype_tab[] = {
99           { WSDISPLAY_TYPE_UNKNOWN,     "unknown" },
100           { WSDISPLAY_TYPE_PM_MONO,     "dec-pm-mono" },
101           { WSDISPLAY_TYPE_PM_COLOR,    "dec-pm-color" },
102           { WSDISPLAY_TYPE_CFB,                   "dec-cfb" },
103           { WSDISPLAY_TYPE_XCFB,                  "dec-xcfb" },
104           { WSDISPLAY_TYPE_MFB,                   "dec-mfb" },
105           { WSDISPLAY_TYPE_SFB,                   "dec-sfb" },
106           { WSDISPLAY_TYPE_ISAVGA,      "vga-isa" },
107           { WSDISPLAY_TYPE_PCIVGA,      "vga-pci" },
108           { WSDISPLAY_TYPE_TGA,                   "dec-tga-pci" },
109           { WSDISPLAY_TYPE_SFBP,                  "dec-sfb+" },
110           { WSDISPLAY_TYPE_PCIMISC,     "generic-pci" },
111           { WSDISPLAY_TYPE_NEXTMONO,    "next-mono" },
112           { WSDISPLAY_TYPE_PX,                    "dec-px" },
113           { WSDISPLAY_TYPE_PXG,                   "dec-pxg" },
114           { WSDISPLAY_TYPE_TX,                    "dec-tx" },
115           { WSDISPLAY_TYPE_HPCFB,                 "generic-hpc" },
116           { WSDISPLAY_TYPE_VIDC,                  "arm-vidc" },
117           { WSDISPLAY_TYPE_SPX,                   "dec-spx" },
118           { WSDISPLAY_TYPE_GPX,                   "dec-gpx" },
119           { WSDISPLAY_TYPE_LCG,                   "dec-lcg" },
120           { WSDISPLAY_TYPE_VAX_MONO,    "dec-vax-mono" },
121           { WSDISPLAY_TYPE_SB_P9100,    "sparcbook-p9100" },
122           { WSDISPLAY_TYPE_EGA,                   "ega" },
123           { WSDISPLAY_TYPE_DCPVR,                 "dreamcast-pvr" },
124           { WSDISPLAY_TYPE_GBOX,                  "hp-gator" },
125           { WSDISPLAY_TYPE_TOPCAT,      "hp-topcat" },
126           { WSDISPLAY_TYPE_RBOX,                  "hp-renaissance" },
127           { WSDISPLAY_TYPE_CATSEYE,     "hp-catseye" },
128           { WSDISPLAY_TYPE_DVBOX,                 "hp-davinci" },
129           { WSDISPLAY_TYPE_TVRX,                  "hp-tiger" },
130           { WSDISPLAY_TYPE_HYPERION,    "hp-hyperion" },
131           { WSDISPLAY_TYPE_AMIGACC,     "amiga-cc" },
132           { WSDISPLAY_TYPE_SUN24,                 "sun24" },
133           { WSDISPLAY_TYPE_NEWPORT,     "sgi-newport" },
134           { WSDISPLAY_TYPE_GR2,                   "sgi-gr2" },
135           { WSDISPLAY_TYPE_SUNCG12,     "suncg12" },
136           { WSDISPLAY_TYPE_SUNCG14,     "suncg14" },
137           { WSDISPLAY_TYPE_SUNTCX,      "suntcx" },
138           { WSDISPLAY_TYPE_SUNFFB,      "sunffb" },
139           { WSDISPLAY_TYPE_STI,                   "hp-sti" },
140           { WSDISPLAY_TYPE_HDLCD,                 "hd44780" },
141           { WSDISPLAY_TYPE_VESA,                  "vesa" },
142           { WSDISPLAY_TYPE_XILFB,                 "xilinx" },
143           { WSDISPLAY_TYPE_LIGHT,                 "sgi-light" },
144           { WSDISPLAY_TYPE_GENFB,                 "genfb" },
145           { WSDISPLAY_TYPE_CRIME,                 "sgi-o2" },
146           { WSDISPLAY_TYPE_PXALCD,      "pxa" },
147           { WSDISPLAY_TYPE_AG10,                  "fujitsu-ag10" },
148           { WSDISPLAY_TYPE_DL,                    "displaylink" },
149           { WSDISPLAY_TYPE_XVR1000,     "sun-xvr1000" },
150           { WSDISPLAY_TYPE_LUNA,                  "omron-luna" },
151           { WSDISPLAY_TYPE_GRF,                   "grf" },
152           { WSDISPLAY_TYPE_VNC,                   "vnc" },
153           { WSDISPLAY_TYPE_VALKYRIE,    "apple-valkyrie" },
154           { WSDISPLAY_TYPE_IMXIPU,      "imx-ipu" },
155           { WSDISPLAY_TYPE_VC4,                   "videocore4" },
156           { WSDISPLAY_TYPE_OMAP3,                 "omap3530" },
157           { WSDISPLAY_TYPE_WINDERMERE,  "windermere" },
158           { WSDISPLAY_TYPE_CLPS711X,    "clps-711x" },
159           { WSDISPLAY_TYPE_ALLWINNER,   "allwinner" },
160           { WSDISPLAY_TYPE_MGX,                   "ssb-mgx" },
161           { WSDISPLAY_TYPE_MESON,                 "amlogc-meson" },
162           { WSDISPLAY_TYPE_TEGRA,                 "nvidia-tegra" },
163           { WSDISPLAY_TYPE_PLATINUM,    "platinum" },
164           { WSDISPLAY_TYPE_PLFB,                  "primcell-pl11x" },
165           { WSDISPLAY_TYPE_SSDFB,                 "ssdfb" },
166           { WSDISPLAY_TYPE_VC6,                   "videocore6" },
167 };
168 
169 static struct nameint kbdenc_tab[] = {
170           KB_ENCTAB
171 };
172 
173 static struct nameint kbdvar_tab[] = {
174           KB_VARTAB
175 };
176 
177 static struct nameint color_tab[] = {
178           { WSCOL_UNSUPPORTED,                    "unsupported" },
179           { WSCOL_BLACK,                          "black" },
180           { WSCOL_RED,                            "red" },
181           { WSCOL_GREEN,                          "green" },
182           { WSCOL_BROWN,                          "brown" },
183           { WSCOL_BLUE,                           "blue" },
184           { WSCOL_MAGENTA,              "magenta" },
185           { WSCOL_CYAN,                           "cyan" },
186           { WSCOL_WHITE,                          "white" },
187 };
188 
189 static struct nameint attr_tab[] = {
190           { WSATTR_NONE,                          "none" },
191           { WSATTR_REVERSE,             "reverse" },
192           { WSATTR_HILIT,                         "hilit" },
193           { WSATTR_BLINK,                         "blink" },
194           { WSATTR_UNDERLINE,           "underline" },
195           { WSATTR_WSCOLORS,            "color" },
196 };
197 
198 static struct field *field_tab;
199 static int field_tab_len;
200 
201 static const char *int2name(int, int, struct nameint *, int);
202 static int name2int(char *, struct nameint *, int);
203 static void print_kmap(struct wskbd_map_data *);
204 static unsigned int rd_bitfield(const char *);
205 static void pr_bitfield(unsigned int);
206 
207 void
field_setup(struct field * ftab,int len)208 field_setup(struct field *ftab, int len)
209 {
210 
211           field_tab = ftab;
212           field_tab_len = len;
213 }
214 
215 struct field *
field_by_name(char * name)216 field_by_name(char *name)
217 {
218           int i;
219 
220           for (i = 0; i < field_tab_len; i++)
221                     if (strcmp(field_tab[i].name, name) == 0)
222                               return field_tab + i;
223 
224           errx(EXIT_FAILURE, "%s: not found", name);
225 }
226 
227 struct field *
field_by_value(void * addr)228 field_by_value(void *addr)
229 {
230           int i;
231 
232           for (i = 0; i < field_tab_len; i++)
233                     if (field_tab[i].valp == addr)
234                               return field_tab + i;
235 
236           errx(EXIT_FAILURE, "internal error: field_by_value: not found");
237 }
238 
239 void
field_disable_by_value(void * addr)240 field_disable_by_value(void *addr)
241 {
242           struct field *f;
243 
244           f = field_by_value(addr);
245           f->flags |= FLG_DISABLED;
246 }
247 
248 static const char *
int2name(int val,int uflag,struct nameint * tab,int len)249 int2name(int val, int uflag, struct nameint *tab, int len)
250 {
251           static char tmp[20];
252           int i;
253 
254           for (i = 0; i < len; i++)
255                     if (tab[i].value == val)
256                               return tab[i].name;
257 
258           if (uflag) {
259                     (void)snprintf(tmp, sizeof(tmp), "unknown_%d", val);
260                     return tmp;
261           } else
262                     return NULL;
263 }
264 
265 static int
name2int(char * val,struct nameint * tab,int len)266 name2int(char *val, struct nameint *tab, int len)
267 {
268           int i;
269 
270           for (i = 0; i < len; i++)
271                     if (strcmp(tab[i].name, val) == 0)
272                               return tab[i].value;
273           return -1;
274 }
275 
276 void
pr_field(struct field * f,const char * sep)277 pr_field(struct field *f, const char *sep)
278 {
279           const char *p;
280           unsigned int flags;
281           int first, i, mask;
282           struct wsdisplayio_edid_info *info;
283           struct edid_info edid;
284 
285           if (sep)
286                     (void)printf("%s%s", f->name, sep);
287 
288           switch (f->format) {
289           case FMT_UINT:
290                     (void)printf("%u", *((unsigned int *) f->valp));
291                     break;
292           case FMT_INT:
293                     (void)printf("%d", *((int *) f->valp));
294                     break;
295           case FMT_STRING:
296                     (void)printf("\"%s\"", *((char **) f->valp));
297                     break;
298           case FMT_BITFIELD:
299                     pr_bitfield(*((unsigned int *) f->valp));
300                     break;
301           case FMT_KBDTYPE:
302                     p = int2name(*((unsigned int *) f->valp), 1,
303                         kbtype_tab, TABLEN(kbtype_tab));
304                     (void)printf("%s", p);
305                     break;
306           case FMT_MSTYPE:
307                     p = int2name(*((unsigned int *) f->valp), 1,
308                         mstype_tab, TABLEN(mstype_tab));
309                     (void)printf("%s", p);
310                     break;
311           case FMT_DPYTYPE:
312                     p = int2name(*((unsigned int *) f->valp), 1,
313                         dpytype_tab, TABLEN(dpytype_tab));
314                     (void)printf("%s", p);
315                     break;
316           case FMT_KBDENC:
317                     p = int2name(KB_ENCODING(*((unsigned int *) f->valp)), 1,
318                         kbdenc_tab, TABLEN(kbdenc_tab));
319                     (void)printf("%s", p);
320 
321                     flags = KB_VARIANT(*((unsigned int *) f->valp));
322                     for (i = 0; i < 32; i++) {
323                               if (!(flags & (1 << i)))
324                                         continue;
325                               p = int2name(flags & (1 << i), 1,
326                                   kbdvar_tab, TABLEN(kbdvar_tab));
327                               (void)printf(".%s", p);
328                     }
329                     break;
330           case FMT_KBMAP:
331                     print_kmap((struct wskbd_map_data *) f->valp);
332                     break;
333           case FMT_COLOR:
334                     p = int2name(*((unsigned int *) f->valp), 1,
335                         color_tab, TABLEN(color_tab));
336                     (void)printf("%s", p);
337                     break;
338           case FMT_ATTRS:
339                     mask = 0x10;
340                     first = 1;
341                     while (mask > 0) {
342                               if (*((unsigned int *) f->valp) & mask) {
343                                         p = int2name(*((unsigned int *) f->valp) & mask,
344                                             1, attr_tab, TABLEN(attr_tab));
345                                         (void)printf("%s%s", first ? "" : ",", p);
346                                         first = 0;
347                               }
348                               mask >>= 1;
349                     }
350                     if (first)
351                               (void)printf("none");
352                     break;
353           case FMT_EDID:
354                     info = (struct wsdisplayio_edid_info *)f->valp;
355                     if (edid_parse(info->edid_data, &edid))
356                               (void)printf("invalid");
357                     else {
358                               (void)printf("\n");
359                               edid_print(&edid);
360                     }
361                     break;
362           default:
363                     errx(EXIT_FAILURE, "internal error: pr_field: no format %d",
364                         f->format);
365                     break;
366           }
367 
368           (void)printf("\n");
369 }
370 
371 static void
pr_bitfield(unsigned int f)372 pr_bitfield(unsigned int f)
373 {
374 
375           if (f == 0)
376                     (void)printf("none");
377           else {
378                     unsigned int i;
379                     int first, mask;
380 
381                     for (i = 0, first = 1, mask = 1; i < sizeof(f) * 8; i++) {
382                               if (f & mask) {
383                                         (void)printf("%s%u", first ? "" : " ", i);
384                                         first = 0;
385                               }
386                               mask = mask << 1;
387                     }
388           }
389 }
390 
391 void
rd_field(struct field * f,char * val,int merge)392 rd_field(struct field *f, char *val, int merge)
393 {
394           int i;
395           unsigned int u;
396           char *p;
397           struct wscons_keymap *mp;
398 
399           switch (f->format) {
400           case FMT_UINT:
401                     if (sscanf(val, "%u", &u) != 1)
402                               errx(EXIT_FAILURE, "%s: not a number", val);
403                     if (merge)
404                               *((unsigned int *) f->valp) += u;
405                     else
406                               *((unsigned int *) f->valp) = u;
407                     break;
408           case FMT_INT:
409                     if (sscanf(val, "%d", &i) != 1)
410                               errx(EXIT_FAILURE, "%s: not a number", val);
411                     if (merge)
412                               *((int *) f->valp) += i;
413                     else
414                               *((int *) f->valp) = i;
415                     break;
416           case FMT_STRING:
417                     if ((*((char **) f->valp) = strdup(val)) == NULL)
418                               err(EXIT_FAILURE, "strdup");
419                     break;
420           case FMT_BITFIELD:
421                     *((unsigned int *) f->valp) = rd_bitfield(val);
422                     break;
423           case FMT_KBDENC:
424                     p = strchr(val, '.');
425                     if (p != NULL)
426                               *p++ = '\0';
427 
428                     i = name2int(val, kbdenc_tab, TABLEN(kbdenc_tab));
429                     if (i == -1)
430                               errx(EXIT_FAILURE, "%s: not a valid encoding", val);
431                     *((unsigned int *) f->valp) = i;
432 
433                     while (p) {
434                               val = p;
435                               p = strchr(p, '.');
436                               if (p != NULL)
437                                         *p++ = '\0';
438                               i = name2int(val, kbdvar_tab, TABLEN(kbdvar_tab));
439                               if (i == -1)
440                                         errx(EXIT_FAILURE, "%s: not a valid variant",
441                                             val);
442                               *((unsigned int *) f->valp) |= i;
443                     }
444                     break;
445           case FMT_KBMAP:
446                     if (! merge)
447                               kbmap.maplen = 0;
448                     map_scan_setinput(val);
449                     yyparse();
450                     if (merge) {
451                               if (newkbmap.maplen < kbmap.maplen)
452                                         newkbmap.maplen = kbmap.maplen;
453                               for (u = 0; u < kbmap.maplen; u++) {
454                                         mp = newkbmap.map + u;
455                                         if (mp->command == KS_voidSymbol &&
456                                             mp->group1[0] == KS_voidSymbol &&
457                                             mp->group1[1] == KS_voidSymbol &&
458                                             mp->group2[0] == KS_voidSymbol &&
459                                             mp->group2[1] == KS_voidSymbol)
460                                                   *mp = kbmap.map[u];
461                               }
462                     }
463                     kbmap.maplen = newkbmap.maplen;
464                     memcpy(kbmap.map, newkbmap.map,
465                         kbmap.maplen * sizeof(struct wscons_keymap));
466                     break;
467           case FMT_COLOR:
468                     i = name2int(val, color_tab, TABLEN(color_tab));
469                     if (i == -1)
470                               errx(EXIT_FAILURE, "%s: not a valid color", val);
471                     *((unsigned int *) f->valp) = i;
472                     break;
473           case FMT_ATTRS:
474                     p = val;
475                     while (p) {
476                               val = p;
477                               p = strchr(p, ',');
478                               if (p != NULL)
479                                         *p++ = '\0';
480                               i = name2int(val, attr_tab, TABLEN(attr_tab));
481                               if (i == -1)
482                                         errx(EXIT_FAILURE, "%s: not a valid attribute",
483                                             val);
484                               *((unsigned int *) f->valp) |= i;
485                     }
486                     break;
487           default:
488                     errx(EXIT_FAILURE, "internal error: rd_field: no format %d",
489                         f->format);
490                     break;
491           }
492 }
493 
494 static unsigned int
rd_bitfield(const char * str)495 rd_bitfield(const char *str)
496 {
497           const char *ptr;
498           char *ep;
499           long lval;
500           unsigned int result;
501 
502           ep = NULL;
503           ptr = str;
504           result = 0;
505           while (*ptr != '\0') {
506                     errno = 0;
507                     lval = strtol(ptr, &ep, 10);
508                     if (*ep != '\0' && *ep != ' ')
509                               errx(EXIT_FAILURE, "%s: not a valid number list", str);
510                     if (errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
511                               errx(EXIT_FAILURE, "%s: not a valid number list", str);
512                     if (lval >= (long)sizeof(result) * 8)
513                               errx(EXIT_FAILURE, "%ld: number out of range", lval);
514                     result |= (1 << lval);
515 
516                     ptr = ep;
517                     while (*ptr == ' ')
518                               ptr++;
519           }
520 
521           return result;
522 }
523 
524 static void
print_kmap(struct wskbd_map_data * map)525 print_kmap(struct wskbd_map_data *map)
526 {
527           unsigned int i;
528           struct wscons_keymap *mp;
529 
530           for (i = 0; i < map->maplen; i++) {
531                     mp = map->map + i;
532 
533                     if (mp->command == KS_voidSymbol &&
534                         mp->group1[0] == KS_voidSymbol &&
535                         mp->group1[1] == KS_voidSymbol &&
536                         mp->group2[0] == KS_voidSymbol &&
537                         mp->group2[1] == KS_voidSymbol)
538                               continue;
539                     (void)printf("\n");
540                     (void)printf("keycode %u =", i);
541                     if (mp->command != KS_voidSymbol)
542                               (void)printf(" %s", ksym2name(mp->command));
543                     (void)printf(" %s", ksym2name(mp->group1[0]));
544                     if (mp->group1[0] != mp->group1[1] ||
545                         mp->group1[0] != mp->group2[0] ||
546                         mp->group1[0] != mp->group2[1]) {
547                               (void)printf(" %s", ksym2name(mp->group1[1]));
548                               if (mp->group1[0] != mp->group2[0] ||
549                                   mp->group1[1] != mp->group2[1]) {
550                                         (void)printf(" %s", ksym2name(mp->group2[0]));
551                                         (void)printf(" %s", ksym2name(mp->group2[1]));
552                               }
553                     }
554           }
555 }
556 
557