/* $OpenBSD: kbd_wscons.c,v 1.36 2022/05/05 16:12:42 bluhm Exp $ */ /* * Copyright (c) 2001 Mats O Jansson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #define NUM_KBD 10 char *kbtype_tab[] = { "pc-xt/pc-at", "usb", "adb", "lk201", "sun", "sun5", "hil", "gsc", "sgi" }; enum { SA_PCKBD, SA_UKBD, SA_AKBD, SA_LKKBD, SA_SUNKBD, SA_SUN5KBD, SA_HILKBD, SA_GSCKBD, SA_SGIKBD, SA_MAX }; struct nameint { int value; char *name; }; struct nameint kbdenc_tab[] = { KB_ENCTAB , { 0, NULL } }; struct nameint kbdvar_tab[] = { KB_VARTAB , { 0, NULL } }; extern char *__progname; void kbd_show_enc(struct wskbd_encoding_data *encs, int idx); void kbd_get_encs(int fd, struct wskbd_encoding_data *encs); void kbd_list(void); void kbd_set(char *name, int verbose); void kbd_show_enc(struct wskbd_encoding_data *encs, int idx) { int found; kbd_t encoding, variant; struct nameint *n; int i; printf("tables available for %s keyboard:\nencoding\n\n", kbtype_tab[idx]); for (i = 0; i < encs->nencodings; i++) { found = 0; encoding = encs->encodings[i]; for (n = &kbdenc_tab[0]; n->value; n++) { if (n->value == KB_ENCODING(encoding)) { printf("%s", n->name); found++; } } if (found == 0) printf("", KB_ENCODING(encoding)); found = 0; variant = KB_VARIANT(encoding); for (n = &kbdvar_tab[0]; n->value; n++) { if ((n->value & KB_VARIANT(encoding)) == n->value) { printf(".%s", n->name); variant &= ~n->value; } } if (variant != 0) printf(".", variant); printf("\n"); } printf("\n"); } void kbd_get_encs(int fd, struct wskbd_encoding_data *encs) { int nencodings = 64; encs->nencodings = nencodings; while (encs->nencodings == nencodings) { encs->encodings = reallocarray(encs->encodings, encs->nencodings, sizeof(kbd_t)); if (encs->encodings == NULL) err(1, NULL); if (ioctl(fd, WSKBDIO_GETENCODINGS, encs) == -1) err(1, "WSKBDIO_GETENCODINGS"); if (encs->nencodings == nencodings) { nencodings *= 2; encs->nencodings = nencodings; } } } void kbd_list(void) { int kbds[SA_MAX]; struct wskbd_encoding_data encs[SA_MAX]; int fd, i, kbtype, t, error = 0; char device[PATH_MAX]; memset(kbds, 0, sizeof(kbds)); memset(encs, 0, sizeof(encs)); /* Go through all keyboards. */ for (i = 0; i < NUM_KBD; i++) { (void) snprintf(device, sizeof device, "/dev/wskbd%d", i); fd = open(device, O_WRONLY); if (fd == -1) fd = open(device, O_RDONLY); if (fd == -1) { /* remember the first error number */ if (error == 0) error = errno; } else { /* at least one success, do not print error */ error = -1; if (ioctl(fd, WSKBDIO_GTYPE, &kbtype) == -1) err(1, "WSKBDIO_GTYPE %s", device); switch (kbtype) { case WSKBD_TYPE_PC_XT: case WSKBD_TYPE_PC_AT: t = SA_PCKBD; break; case WSKBD_TYPE_USB: t = SA_UKBD; break; case WSKBD_TYPE_ADB: t = SA_AKBD; break; case WSKBD_TYPE_LK201: case WSKBD_TYPE_LK401: t = SA_LKKBD; break; case WSKBD_TYPE_SUN: t = SA_SUNKBD; break; case WSKBD_TYPE_SUN5: t = SA_SUN5KBD; break; case WSKBD_TYPE_HIL: t = SA_HILKBD; break; case WSKBD_TYPE_GSC: t = SA_GSCKBD; break; case WSKBD_TYPE_SGI: t = SA_SGIKBD; break; default: t = SA_MAX; break; } if (t != SA_MAX) { kbds[t]++; if (encs[t].encodings == NULL) kbd_get_encs(fd, &encs[t]); } close(fd); } } if (error > 0) { errno = error; err(1, "/dev/wskbd0"); } for (i = 0; i < SA_MAX; i++) if (kbds[i] != 0) kbd_show_enc(&encs[i], i); for (i = 0; i < SA_MAX; i++) free(encs[i].encodings); } void kbd_set(char *name, int verbose) { char buf[LINE_MAX], *c, *b, device[sizeof "/dev/wskbd00"]; int map = 0, v, i, fd, error = 0; struct nameint *n; c = name; b = buf; while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1) *b++ = *c++; *b = '\0'; n = &kbdenc_tab[0]; while (n->value) { if (strcmp(n->name, buf) == 0) map = n->value; n++; } if (map == 0) errx(1, "unknown encoding %s", buf); while (*c == '.') { b = buf; c++; while (*c != '.' && *c != '\0' && b < buf + sizeof(buf) - 1) *b++ = *c++; *b = '\0'; v = 0; for (n = &kbdvar_tab[0]; n->value; n++) { if (strcmp(n->name, buf) == 0) v = n->value; } if (v == 0) errx(1, "unknown variant %s", buf); map |= v; } /* Go through all keyboards. */ v = 0; for (i = 0; i < NUM_KBD; i++) { (void) snprintf(device, sizeof device, "/dev/wskbd%d", i); fd = open(device, O_WRONLY); if (fd == -1) fd = open(device, O_RDONLY); if (fd == -1) { /* remember the first error number */ if (error == 0) error = errno; } else { /* at least one success, do not print error */ error = -1; if (ioctl(fd, WSKBDIO_SETENCODING, &map) == -1) { if (errno != EINVAL) err(1, "WSKBDIO_SETENCODING %s", device); fprintf(stderr, "%s: unsupported encoding %s on %s\n", __progname, name, device); } else v++; close(fd); } } if (error > 0) { errno = error; err(1, "/dev/wskbd0"); } if (verbose && v > 0) fprintf(stderr, "kbd: keyboard mapping set to %s\n", name); }