Hi,

this is a port of NetBSD's hvkbd(4).  While Hyper-V Gen1 provides
pckbc(4) as keyboard, Gen2's no-legcay-HW approach needs us to make
use of the Synthetic Keyboard if we want to be able to type in the
framebuffer console.

One thing I'm not so sure about is if we really need another wskbd
type (WSKBD_TYPE_HYPERV).

Comments?  ok?

Patrick

diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index ecccd1323d9..85a95e11eae 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -92,6 +92,8 @@ xnf*  at xen?                 # Xen Netfront
 xbf*   at xen?                 # Xen Blkfront
 
 hyperv0        at pvbus?               # Hyper-V guest
+hvkbd* at hyperv?              # Hyper-V Keyboard
+wskbd* at hvkbd? mux 1
 hvn*   at hyperv?              # Hyper-V NetVSC
 hvs*   at hyperv?              # Hyper-V StorVSC
 
diff --git a/sys/dev/pv/files.pv b/sys/dev/pv/files.pv
index e081897d582..0c0ab1a23e0 100644
--- a/sys/dev/pv/files.pv
+++ b/sys/dev/pv/files.pv
@@ -40,6 +40,11 @@ attach       hyperv at pvbus
 file   dev/pv/hyperv.c                 hyperv  needs-flag
 file   dev/pv/hypervic.c               hyperv
 
+# Hyper-V Keyboard
+device hvkbd: wskbddev
+attach hvkbd at hyperv
+file   dev/pv/hvkbd.c                  hvkbd
+
 # Hyper-V NetVSC
 device hvn: ether, ifnet, ifmedia
 attach hvn at hyperv
diff --git a/sys/dev/pv/hvkbd.c b/sys/dev/pv/hvkbd.c
new file mode 100644
index 00000000000..f8dc1202033
--- /dev/null
+++ b/sys/dev/pv/hvkbd.c
@@ -0,0 +1,593 @@
+/*     $OpenBSD$       */
+/*     $NetBSD: hvkbd.c,v 1.9 2021/08/07 16:19:11 thorpej Exp $        */
+
+/*-
+ * Copyright (c) 2017 Microsoft Corp.
+ * 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 unmodified, 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.
+ *
+ * $FreeBSD: head/sys/dev/hyperv/input/hv_kbd.c 317821 2017-05-05 03:28:30Z 
sephe $
+ * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.c 320490 2017-06-30 03:01:22Z 
sephe $
+ * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.h 316515 2017-04-05 05:01:23Z 
sephe $
+ */
+
+/* __KERNEL_RCSID(0, "$NetBSD: hvkbd.c,v 1.9 2021/08/07 16:19:11 thorpej Exp 
$"); */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/task.h>
+#include <sys/timeout.h>
+
+#include <machine/bus.h>
+#include <machine/biosvar.h>
+
+#include <dev/pv/hypervreg.h>
+#include <dev/pv/hypervvar.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+#include <dev/pckbc/wskbdmap_mfii.h>
+
+#define HVKBD_BUFSIZE          (4 * PAGE_SIZE)
+#define HVKBD_TX_RING_SIZE     (10 * PAGE_SIZE)
+#define HVKBD_RX_RING_SIZE     (10 * PAGE_SIZE)
+
+#define HVKBD_VER_MAJOR                (1)
+#define HVKBD_VER_MINOR                (0)
+#define HVKBD_VERSION          ((HVKBD_VER_MAJOR << 16) | HVKBD_VER_MINOR)
+
+enum hvkbd_msg_type {
+       HVKBD_PROTO_REQUEST             = 1,
+       HVKBD_PROTO_RESPONSE            = 2,
+       HVKBD_PROTO_EVENT               = 3,
+       HVKBD_PROTO_LED_INDICATORS      = 4
+};
+
+struct hvkbd_msg_hdr {
+       uint32_t                type;
+} __packed;
+
+struct hvkbd_proto_req {
+       struct hvkbd_msg_hdr    hdr;
+       uint32_t                ver;
+} __packed;
+
+struct hvkbd_proto_resp {
+       struct hvkbd_msg_hdr    hdr;
+       uint32_t                status;
+#define        RESP_STATUS_ACCEPTED    (1 << 0)
+} __packed;
+
+struct keystroke {
+       uint16_t                makecode;
+       uint16_t                pad0;
+       uint32_t                info;
+#define KS_INFO_UNICODE                (1 << 0)
+#define KS_INFO_BREAK          (1 << 1)
+#define KS_INFO_E0             (1 << 2)
+#define KS_INFO_E1             (1 << 3)
+} __packed;
+
+struct hvkbd_keystroke {
+       struct hvkbd_msg_hdr    hdr;
+       struct keystroke        ks;
+} __packed;
+
+struct hvkbd_keystroke_info {
+       LIST_ENTRY(hvkbd_keystroke_info)        link;
+       STAILQ_ENTRY(hvkbd_keystroke_info)      slink;
+       struct keystroke                        ks;
+};
+
+#define        HVKBD_KEYBUF_SIZE       16
+
+struct hvkbd_softc {
+       struct device                           sc_dev;
+
+       struct hv_channel                       *sc_chan;
+       void                                    *sc_buf;
+
+       struct mutex                            sc_ks_lock;
+       LIST_HEAD(, hvkbd_keystroke_info)       sc_ks_free;
+       STAILQ_HEAD(, hvkbd_keystroke_info)     sc_ks_queue;
+
+       int                                     sc_enabled;
+       int                                     sc_polling;
+       int                                     sc_console_keyboard;
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+       int                                     sc_rawkbd;
+#endif
+
+       int                                     sc_connected;
+       uint32_t                                sc_connect_status;
+
+       struct device *                         sc_wskbddev;
+};
+
+static int     hvkbd_match(struct device *, void *, void *);
+static void    hvkbd_attach(struct device *, struct device *, void *);
+
+struct cfdriver hvkbd_cd = {
+       NULL, "hvkbd", DV_DULL
+};
+
+const struct cfattach hvkbd_ca = {
+       sizeof(struct hvkbd_softc), hvkbd_match, hvkbd_attach
+};
+
+static int     hvkbd_alloc_keybuf(struct hvkbd_softc *);
+static void    hvkbd_free_keybuf(struct hvkbd_softc *);
+
+static int     hvkbd_enable(void *, int);
+static void    hvkbd_set_leds(void *, int);
+static int     hvkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+static const struct wskbd_accessops hvkbd_accessops = {
+       hvkbd_enable,
+       hvkbd_set_leds,
+       hvkbd_ioctl,
+};
+
+static const struct wskbd_mapdata hvkbd_keymapdata = {
+       pckbd_keydesctab,
+#if defined(PCKBD_LAYOUT)
+       PCKBD_LAYOUT,
+#else
+       KB_US,
+#endif
+};
+
+static int     hvkbd_connect(struct hvkbd_softc *);
+static void    hvkbd_intr(void *);
+
+static void    hvkbd_cngetc(void *, u_int *, int *);
+static void    hvkbd_cnpollc(void *, int);
+
+static const struct wskbd_consops hvkbd_consops = {
+       .getc =  hvkbd_cngetc,
+       .pollc = hvkbd_cnpollc,
+       .bell =  NULL,
+};
+
+static int     hvkbd_is_console;
+
+static int
+hvkbd_match(struct device *parent, void *match, void *aux)
+{
+       struct hv_attach_args *aa = aux;
+
+       if (memcmp(aa->aa_type, &hv_guid_kbd, sizeof(*aa->aa_type)) != 0)
+               return 0;
+
+       /* We use pckbd(4) in Gen.1 VM. */
+       if (bios_efiinfo == NULL)
+               return 0;
+
+       return 1;
+}
+
+static void
+hvkbd_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct hvkbd_softc *sc = (struct hvkbd_softc *)self;
+       struct hv_attach_args *aa = aux;
+       struct wskbddev_attach_args a;
+
+       sc->sc_chan = aa->aa_chan;
+
+       printf("\n");
+
+       mtx_init(&sc->sc_ks_lock, IPL_TTY);
+       LIST_INIT(&sc->sc_ks_free);
+       STAILQ_INIT(&sc->sc_ks_queue);
+       hvkbd_alloc_keybuf(sc);
+
+       sc->sc_buf = malloc(HVKBD_BUFSIZE, M_DEVBUF, M_WAITOK | M_ZERO);
+
+       sc->sc_chan->ch_flags &= ~CHF_BATCHED;
+       if (hv_channel_open(sc->sc_chan,
+           HVKBD_TX_RING_SIZE + HVKBD_RX_RING_SIZE, NULL, 0, hvkbd_intr, sc)) {
+               printf("%s: failed to open channel\n", sc->sc_dev.dv_xname);
+               goto free_buf;
+       }
+
+       if (hvkbd_connect(sc))
+               goto free_buf;
+
+       sc->sc_console_keyboard = hvkbd_is_console;
+       if (hvkbd_is_console)
+               hvkbd_is_console = 0;
+
+       if (sc->sc_console_keyboard) {
+               wskbd_cnattach(&hvkbd_consops, sc, &hvkbd_keymapdata);
+               hvkbd_enable(sc, 1);
+       }
+
+       a.console = sc->sc_console_keyboard;
+       a.keymap = &hvkbd_keymapdata;
+       a.accessops = &hvkbd_accessops;
+       a.accesscookie = sc;
+       sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
+       return;
+
+free_buf:
+       if (sc->sc_buf != NULL) {
+               free(sc->sc_buf, M_DEVBUF, HVKBD_BUFSIZE);
+               sc->sc_buf = NULL;
+       }
+       hvkbd_free_keybuf(sc);
+}
+
+static int
+hvkbd_alloc_keybuf(struct hvkbd_softc *sc)
+{
+       struct hvkbd_keystroke_info *ksi;
+       int i;
+
+       for (i = 0; i < HVKBD_KEYBUF_SIZE; i++) {
+               ksi = malloc(sizeof(*ksi), M_DEVBUF, M_WAITOK | M_ZERO);
+               LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link);
+       }
+
+       return 0;
+}
+
+static void
+hvkbd_free_keybuf(struct hvkbd_softc *sc)
+{
+       struct hvkbd_keystroke_info *ksi;
+
+       while ((ksi = STAILQ_FIRST(&sc->sc_ks_queue)) != NULL) {
+               STAILQ_REMOVE(&sc->sc_ks_queue, ksi, hvkbd_keystroke_info,
+                   slink);
+               free(ksi, M_DEVBUF, sizeof(*ksi));
+       }
+       while ((ksi = LIST_FIRST(&sc->sc_ks_free)) != NULL) {
+               LIST_REMOVE(ksi, link);
+               free(ksi, M_DEVBUF, sizeof(*ksi));
+       }
+}
+
+int
+hvkbd_enable(void *v, int on)
+{
+       struct hvkbd_softc *sc = v;
+
+       sc->sc_enabled = on;
+
+       return 0;
+}
+
+static void
+hvkbd_set_leds(void *v, int leds)
+{
+}
+
+static int
+hvkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+       struct hvkbd_softc *sc = v;
+#endif
+
+       switch (cmd) {
+       case WSKBDIO_GTYPE:
+               *(int *)data = WSKBD_TYPE_HYPERV;
+               return 0;
+
+       case WSKBDIO_SETLEDS:
+               hvkbd_set_leds(v, *(int *)data);
+               return 0;
+
+       case WSKBDIO_GETLEDS:
+               *(int *)data = 0;
+               return 0;
+
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+       case WSKBDIO_SETMODE:
+               sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
+               return 0;
+#endif
+       }
+
+       return -1;
+}
+
+static int
+hvkbd_connect(struct hvkbd_softc *sc)
+{
+       struct hvkbd_proto_req req;
+       int timo = 100;
+       int error, s;
+
+       sc->sc_connected = 0;
+
+       memset(&req, 0, sizeof(req));
+       req.hdr.type = HVKBD_PROTO_REQUEST;
+       req.ver = HVKBD_VERSION;
+       error = hv_channel_send(sc->sc_chan, &req, sizeof(req),
+           0, VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC);
+       if (error) {
+               printf("%s: failed to send connect: %d\n",
+                   sc->sc_dev.dv_xname, error);
+               return error;
+       }
+
+       do {
+               if (cold) {
+                       delay(1000);
+                       s = spltty();
+                       hvkbd_intr(sc);
+                       splx(s);
+               } else
+                       tsleep_nsec(sc, PRIBIO | PCATCH, "hvkbdcon",
+                           MSEC_TO_NSEC(1));
+       } while (--timo > 0 && sc->sc_connected == 0);
+
+       if (timo == 0 && sc->sc_connected == 0) {
+               printf("%s: connect timed out\n", sc->sc_dev.dv_xname);
+               return ETIMEDOUT;
+       }
+
+       if (!(sc->sc_connect_status & RESP_STATUS_ACCEPTED)) {
+               printf("%s: protocol request failed\n", sc->sc_dev.dv_xname);
+               return ENODEV;
+       }
+
+       return 0;
+}
+
+static int
+hvkbd_keybuf_add_keystroke(struct hvkbd_softc *sc, const struct keystroke *ks)
+{
+       struct hvkbd_keystroke_info *ksi;
+
+       mtx_enter(&sc->sc_ks_lock);
+       ksi = LIST_FIRST(&sc->sc_ks_free);
+       if (ksi != NULL) {
+               LIST_REMOVE(ksi, link);
+               ksi->ks = *ks;
+               STAILQ_INSERT_TAIL(&sc->sc_ks_queue, ksi, slink);
+       }
+       mtx_leave(&sc->sc_ks_lock);
+
+       return (ksi != NULL) ? 0 : 1;
+}
+
+static int
+hvkbd_decode(struct hvkbd_softc *sc, u_int *type, int *scancode)
+{
+       struct hvkbd_keystroke_info *ksi;
+       struct keystroke ks;
+
+       mtx_enter(&sc->sc_ks_lock);
+       ksi = STAILQ_FIRST(&sc->sc_ks_queue);
+       if (ksi != NULL) {
+               STAILQ_REMOVE(&sc->sc_ks_queue, ksi, hvkbd_keystroke_info,
+                   slink);
+               ks = ksi->ks;
+               LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link);
+       }
+       mtx_leave(&sc->sc_ks_lock);
+
+       if (ksi == NULL)
+               return 0;
+
+       /*
+        * XXX: Hyper-V host send unicode to VM through 'Type clipboard text',
+        * the mapping from unicode to scancode depends on the keymap.
+        * It is so complicated that we do not plan to support it yet.
+        */
+       if (ks.info & KS_INFO_UNICODE)
+               return 0;
+
+       *type = (ks.info & KS_INFO_BREAK) ?
+           WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
+       *scancode = ks.makecode;
+       return 1;
+}
+
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+static int
+hvkbd_encode(struct hvkbd_softc *sc, u_char *buf, int *len)
+{
+       struct hvkbd_keystroke_info *ksi;
+       struct keystroke ks;
+       int i;
+
+       mtx_enter(&sc->sc_ks_lock);
+       ksi = STAILQ_FIRST(&sc->sc_ks_queue);
+       if (ksi != NULL) {
+               STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink);
+               ks = ksi->ks;
+               LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link);
+       }
+       mtx_leave(&sc->sc_ks_lock);
+
+       if (ksi == NULL)
+               return 0;
+
+       /*
+        * XXX: Hyper-V host send unicode to VM through 'Type clipboard text',
+        * the mapping from unicode to scancode depends on the keymap.
+        * It is so complicated that we do not plan to support it yet.
+        */
+       if (ks.info & KS_INFO_UNICODE)
+               return 0;
+
+       i = 0;
+       if (ks.info & (KS_INFO_E0|KS_INFO_E1)) {
+               if (ks.info & KS_INFO_E0)
+                       buf[i++] = 0xe0;
+               else
+                       buf[i++] = 0xe1;
+       }
+       if (ks.info & KS_INFO_BREAK)
+               buf[i++] = (u_char)ks.makecode & 0x80;
+       else
+               buf[i++] = (u_char)ks.makecode;
+
+       KDASSERT(i <= *len);
+       *len = i;
+
+       return 1;
+}
+#endif
+
+static void
+hvkbd_intr(void *xsc)
+{
+       struct hvkbd_softc *sc = xsc;
+       struct vmbus_chanpkt_hdr *cph;
+       const struct hvkbd_msg_hdr *hdr;
+       const struct hvkbd_proto_resp *rsp;
+       const struct hvkbd_keystroke *ks;
+       uint64_t rid;
+       uint32_t rlen;
+       u_int type;
+       int key, error;
+
+       for (;;) {
+               error = hv_channel_recv(sc->sc_chan, sc->sc_buf,
+                   HVKBD_BUFSIZE, &rlen, &rid, 1);
+               if (error != 0 || rlen == 0) {
+                       if (error != EAGAIN)
+                               printf("%s: failed to receive a reply packet\n",
+                                   sc->sc_dev.dv_xname);
+                       return;
+               }
+
+               cph = (struct vmbus_chanpkt_hdr *)sc->sc_buf;
+               switch (cph->cph_type) {
+               case VMBUS_CHANPKT_TYPE_INBAND:
+                       hdr = VMBUS_CHANPKT_CONST_DATA(cph);
+                       if (rlen < sizeof(*hdr)) {
+                               printf("%s: Illegal packet\n",
+                                   sc->sc_dev.dv_xname);
+                               continue;
+                       }
+
+                       switch (hdr->type) {
+                       case HVKBD_PROTO_RESPONSE:
+                               if (!sc->sc_connected) {
+                                       rsp = VMBUS_CHANPKT_CONST_DATA(cph);
+                                       if (rlen < sizeof(*rsp)) {
+                                               printf(
+                                                   "%s: Illegal resp packet\n",
+                                                   sc->sc_dev.dv_xname);
+                                               break;
+                                       }
+                                       sc->sc_connect_status = rsp->status;
+                                       sc->sc_connected = 1;
+                                       wakeup(sc);
+                               }
+                               break;
+
+                       case HVKBD_PROTO_EVENT:
+                               if (sc->sc_wskbddev == NULL || !sc->sc_enabled)
+                                       break;
+
+                               ks = VMBUS_CHANPKT_CONST_DATA(cph);
+                               hvkbd_keybuf_add_keystroke(sc, &ks->ks);
+                               if (sc->sc_polling)
+                                       break;
+
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+                               if (sc->sc_rawkbd) {
+                                       u_char buf[2];
+                                       int len;
+
+                                       len = sizeof(buf);
+                                       if (hvkbd_encode(sc, buf, &len)) {
+                                               wskbd_rawinput(sc->sc_wskbddev,
+                                                   buf, len);
+                                       }
+                                       break;
+                               }
+#endif
+                               if (hvkbd_decode(sc, &type, &key)) {
+                                       KERNEL_LOCK();
+                                       wskbd_input(sc->sc_wskbddev, type, key);
+                                       KERNEL_UNLOCK();
+                               }
+                               break;
+
+                       case HVKBD_PROTO_REQUEST:
+                       case HVKBD_PROTO_LED_INDICATORS:
+                               printf("%s: unhandled message: %d\n",
+                                   sc->sc_dev.dv_xname, hdr->type);
+                               break;
+
+                       default:
+                               printf("%s: unknown message: %d\n",
+                                   sc->sc_dev.dv_xname, hdr->type);
+                               break;
+                       }
+                       break;
+
+               case VMBUS_CHANPKT_TYPE_COMP:
+               case VMBUS_CHANPKT_TYPE_RXBUF:
+                       printf("%s: unhandled event: %d\n",
+                           sc->sc_dev.dv_xname, cph->cph_type);
+                       break;
+
+               default:
+                       printf("%s: unknown event: %d\n",
+                           sc->sc_dev.dv_xname, cph->cph_type);
+                       break;
+               }
+       }
+}
+
+int
+hvkbd_cnattach(void)
+{
+       hvkbd_is_console = 1;
+
+       return 0;
+}
+
+static void
+hvkbd_cngetc(void *v, u_int *type, int *data)
+{
+       struct hvkbd_softc *sc = v;
+
+       while (!hvkbd_decode(sc, type, data))
+               hvkbd_intr(sc);
+}
+
+static void
+hvkbd_cnpollc(void *v, int on)
+{
+       struct hvkbd_softc *sc = v;
+
+       sc->sc_polling = on;
+}
diff --git a/sys/dev/pv/hyperv.c b/sys/dev/pv/hyperv.c
index dcebd3ae681..0b2260aed11 100644
--- a/sys/dev/pv/hyperv.c
+++ b/sys/dev/pv/hyperv.c
@@ -194,6 +194,11 @@ const struct hv_guid hv_guid_kvp = {
          0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x03, 0xe6 }
 };
 
+const struct hv_guid hv_guid_kbd = {
+       { 0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48,
+         0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 }
+};
+
 #ifdef HYPERV_DEBUG
 const struct hv_guid hv_guid_vss = {
        { 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42,
@@ -210,11 +215,6 @@ const struct hv_guid hv_guid_mouse = {
          0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a }
 };
 
-const struct hv_guid hv_guid_kbd = {
-       { 0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48,
-         0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 }
-};
-
 const struct hv_guid hv_guid_video = {
        { 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a,
          0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 }
diff --git a/sys/dev/pv/hypervic.c b/sys/dev/pv/hypervic.c
index ad5fc9b0c0b..447d001b82b 100644
--- a/sys/dev/pv/hypervic.c
+++ b/sys/dev/pv/hypervic.c
@@ -103,6 +103,7 @@ struct hv_kvp {
 
 int    hv_heartbeat_attach(struct hv_ic_dev *);
 void   hv_heartbeat(void *);
+int    hv_kbd_attach(struct hv_ic_dev *);
 int    hv_kvp_attach(struct hv_ic_dev *);
 void   hv_kvp(void *);
 int    hv_kvop(void *, int, char *, char *, size_t);
@@ -120,6 +121,12 @@ static struct hv_ic_dev {
        uint8_t                  *dv_buf;
        void                     *dv_priv;
 } hv_ic_devs[] = {
+       {
+               "keyboard",
+               &hv_guid_kbd,
+               hv_kbd_attach,
+               NULL
+       },
        {
                "heartbeat",
                &hv_guid_heartbeat,
@@ -1178,3 +1185,22 @@ hv_kvop(void *arg, int op, char *key, char *val, size_t 
vallen)
 
        return (error);
 }
+
+int
+hv_kbd_attach(struct hv_ic_dev *dv)
+{
+       struct hv_channel *ch = dv->dv_ch;
+       struct hv_softc *sc = ch->ch_sc;
+       struct hv_attach_args aa;
+
+       aa.aa_parent = sc;
+       aa.aa_type = &ch->ch_type;
+       aa.aa_inst = &ch->ch_inst;
+       aa.aa_ident = ch->ch_ident;
+       aa.aa_chan = ch;
+       aa.aa_dmat = sc->sc_dmat;
+       config_found((struct device *)sc, &aa, NULL);
+
+       /* Return non-zero to stop it from opening a channel. */
+       return (-1);
+}
diff --git a/sys/dev/pv/hypervvar.h b/sys/dev/pv/hypervvar.h
index 9cd8036095d..34cddac6b01 100644
--- a/sys/dev/pv/hypervvar.h
+++ b/sys/dev/pv/hypervvar.h
@@ -187,11 +187,11 @@ extern const struct hv_guid hv_guid_shutdown;
 extern const struct hv_guid hv_guid_timesync;
 extern const struct hv_guid hv_guid_heartbeat;
 extern const struct hv_guid hv_guid_kvp;
+extern const struct hv_guid hv_guid_kbd;
 #ifdef HYPERV_DEBUG
 extern const struct hv_guid hv_guid_vss;
 extern const struct hv_guid hv_guid_dynmem;
 extern const struct hv_guid hv_guid_mouse;
-extern const struct hv_guid hv_guid_kbd;
 extern const struct hv_guid hv_guid_video;
 extern const struct hv_guid hv_guid_fc;
 extern const struct hv_guid hv_guid_fcopy;
diff --git a/sys/dev/wscons/wsconsio.h b/sys/dev/wscons/wsconsio.h
index 9a3fbb142dc..2d30c78318f 100644
--- a/sys/dev/wscons/wsconsio.h
+++ b/sys/dev/wscons/wsconsio.h
@@ -143,6 +143,7 @@ struct wscons_event {
 #define                WSKBD_TYPE_BLUETOOTH    18      /* Bluetooth keyboard */
 #define                WSKBD_TYPE_KPC          19      /* Palm keypad */
 #define                WSKBD_TYPE_SGI          20      /* SGI serial keyboard 
*/
+#define                WSKBD_TYPE_HYPERV       21      /* Hyper-V synthetic 
keyboard */
 
 /* Manipulate the keyboard bell. */
 struct wskbd_bell_data {

Reply via email to