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 208 field_setup(struct field *ftab, int len) 209 { 210 211 field_tab = ftab; 212 field_tab_len = len; 213 } 214 215 struct field * 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 * 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 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 * 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 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 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 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 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 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 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