This diff adds a WSKBDIO_GETENCODINGS ioctl and uses it to print a list of supported encodings like the old kvm groveling code did. The ioctl will clamp the number of entries that are returns to the number that was passed in. This means that if the number returned is the same as the number passed in, there might be more entries and you probably want to retry with a larger buffer. The new implementation does this.
Waring; this did not go through a make release yet. And that might be relevant, since this code gets included in the ramdisks. Thoughts? Index: sys/dev/wscons/wsconsio.h =================================================================== RCS file: /cvs/src/sys/dev/wscons/wsconsio.h,v retrieving revision 1.75 diff -u -p -r1.75 wsconsio.h --- sys/dev/wscons/wsconsio.h 14 Sep 2016 03:25:51 -0000 1.75 +++ sys/dev/wscons/wsconsio.h 29 Sep 2016 12:10:57 -0000 @@ -207,6 +207,12 @@ struct wskbd_backlight { #define WSKBD_TRANSLATED 0 #define WSKBD_RAW 1 +struct wskbd_encoding_data { + int nencodings; + kbd_t *encodings; +}; +#define WSKBDIO_GETENCODINGS _IOWR('W', 21, struct wskbd_encoding_data) + /* * Mouse ioctls (32 - 63) */ Index: sys/dev/wscons/wskbd.c =================================================================== RCS file: /cvs/src/sys/dev/wscons/wskbd.c,v retrieving revision 1.83 diff -u -p -r1.83 wskbd.c --- sys/dev/wscons/wskbd.c 12 Dec 2015 12:30:18 -0000 1.83 +++ sys/dev/wscons/wskbd.c 29 Sep 2016 12:10:57 -0000 @@ -1001,9 +1001,11 @@ wskbd_displayioctl(struct device *dev, u struct wskbd_bell_data *ubdp, *kbdp; struct wskbd_keyrepeat_data *ukdp, *kkdp; struct wskbd_map_data *umdp; + struct wskbd_encoding_data *uedp; kbd_t enc; void *buf; int len, error; + int count, i; switch (cmd) { case WSKBDIO_BELL: @@ -1159,6 +1161,20 @@ getkeyrepeat: wsmux_set_layout(sc->sc_base.me_parent, enc); #endif return (0); + + case WSKBDIO_GETENCODINGS: + uedp = (struct wskbd_encoding_data *)data; + for (count = 0; sc->id->t_keymap.keydesc[count].name; count++) + ; + if (uedp->nencodings > count) + uedp->nencodings = count; + for (i = 0; i < uedp->nencodings; i++) { + error = copyout(&sc->id->t_keymap.keydesc[i].name, + &uedp->encodings[i], sizeof(kbd_t)); + if (error) + return (error); + } + return(0); case WSKBDIO_GETBACKLIGHT: if (wskbd_get_backlight != NULL) Index: sbin/kbd/kbd_wscons.c =================================================================== RCS file: /cvs/src/sbin/kbd/kbd_wscons.c,v retrieving revision 1.30 diff -u -p -r1.30 kbd_wscons.c --- sbin/kbd/kbd_wscons.c 27 Sep 2016 22:03:49 -0000 1.30 +++ sbin/kbd/kbd_wscons.c 29 Sep 2016 12:10:57 -0000 @@ -34,6 +34,7 @@ #include <fcntl.h> #include <limits.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> @@ -82,31 +83,83 @@ struct nameint kbdvar_tab[] = { extern char *__progname; -void kbd_show_enc(int idx); +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(int idx) +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; kbdenc_tab[i].value; i++) - printf("%s\n", kbdenc_tab[i].name); + for (i = 0; i < encs->nencodings; i++) { + n = &kbdenc_tab[0]; + found = 0; + encoding = encs->encodings[i]; + while (n->value) { + if (n->value == KB_ENCODING(encoding)) { + printf("%s", n->name); + found++; + } + n++; + } + if (found == 0) + printf("<encoding 0x%04x>", KB_ENCODING(encoding)); + n = &kbdvar_tab[0]; + found = 0; + variant = KB_VARIANT(encoding); + while (n->value) { + if ((n->value & KB_VARIANT(encoding)) == n->value) { + printf(".%s", n->name); + variant &= ~n->value; + } + n++; + } + if (variant != 0) + printf(".<variant 0x%08x>", 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, "reallocarray"); + if (ioctl(fd, WSKBDIO_GETENCODINGS, encs) < 0) + err(1, "WSKBDIO_GETENCODINGS"); + if (encs->nencodings == nencodings) { + nencodings *= 2; + encs->nencodings = nencodings; + } + } +} + +void kbd_list(void) { int kbds[SA_MAX]; - int fd, i, kbtype; + struct wskbd_encoding_data encs[SA_MAX]; + int fd, i, kbtype, t; char device[PATH_MAX]; + int j; - bzero(kbds, sizeof(kbds)); + memset(kbds, 0, sizeof(kbds)); + memset(encs, 0, sizeof(encs)); /* Go through all keyboards. */ for (i = 0; i < NUM_KBD; i++) { @@ -120,41 +173,50 @@ kbd_list(void) switch (kbtype) { case WSKBD_TYPE_PC_XT: case WSKBD_TYPE_PC_AT: - kbds[SA_PCKBD]++; + t = SA_PCKBD; break; case WSKBD_TYPE_USB: - kbds[SA_UKBD]++; + t = SA_UKBD; break; case WSKBD_TYPE_ADB: - kbds[SA_AKBD]++; + t = SA_AKBD; break; case WSKBD_TYPE_LK201: case WSKBD_TYPE_LK401: - kbds[SA_LKKBD]++; + t = SA_LKKBD; break; case WSKBD_TYPE_SUN: - kbds[SA_SUNKBD]++; + t = SA_SUNKBD; break; case WSKBD_TYPE_SUN5: - kbds[SA_SUN5KBD]++; + t = SA_SUN5KBD; break; case WSKBD_TYPE_HIL: - kbds[SA_HILKBD]++; + t = SA_HILKBD; break; case WSKBD_TYPE_GSC: - kbds[SA_GSCKBD]++; + t = SA_GSCKBD; break; case WSKBD_TYPE_SGI: - kbds[SA_SGIKBD]++; + 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); } } for (i = 0; i < SA_MAX; i++) if (kbds[i] != 0) - kbd_show_enc(i); + kbd_show_enc(&encs[i], i); } void