> Date: Thu, 29 Sep 2016 14:19:43 +0200 (CEST)
> From: Mark Kettenis <mark.kette...@xs4all.nl>
> 
> 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.

Thanks to tb@ for testing this on a ramdisk.  Here is a slightly
better diff that frees the allocated memory.

ok?


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 18:12:48 -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 18:12:48 -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 18:12:48 -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,53 @@ 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);
+
+       for (i = 0; i < SA_MAX; i++)
+               free(encs[i].encodings);
 }
 
 void

Reply via email to