The branch main has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=e4d3f1e40ab3327e4ff6f689f54a64bd2ebc0568

commit e4d3f1e40ab3327e4ff6f689f54a64bd2ebc0568
Author:     Yuri <y...@aetern.org>
AuthorDate: 2023-02-05 15:32:08 +0000
Commit:     Vladimir Kondratyev <w...@freebsd.org>
CommitDate: 2023-02-05 15:32:08 +0000

    hv_hid: Hyper-V HID driver
    
    Hyper-V HID driver using hidbus/hms.
    
    Reviewed by:    wulf
    MFC after:      1 week
    PR:             221074
    Differential revision:  https://reviews.freebsd.org/D38140
---
 sys/amd64/conf/NOTES            |   1 +
 sys/conf/files.x86              |   1 +
 sys/dev/hid/hidbus.c            |   1 +
 sys/dev/hyperv/input/hv_hid.c   | 564 ++++++++++++++++++++++++++++++++++++++++
 sys/i386/conf/NOTES             |   1 +
 sys/modules/hyperv/Makefile     |   2 +-
 sys/modules/hyperv/hid/Makefile |  12 +
 7 files changed, 581 insertions(+), 1 deletion(-)

diff --git a/sys/amd64/conf/NOTES b/sys/amd64/conf/NOTES
index 0781d03900ca..4b107b19ac42 100644
--- a/sys/amd64/conf/NOTES
+++ b/sys/amd64/conf/NOTES
@@ -501,6 +501,7 @@ device              kvm_clock       # KVM paravirtual clock 
driver
 
 # Microsoft Hyper-V enhancement support
 device                 hyperv          # HyperV drivers
+device         hvhid           # HyperV HID device
 
 # Xen HVM Guest Optimizations
 options        XENHVM          # Xen HVM kernel infrastructure
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index 37d0534aa67a..0a32c888cdb2 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -115,6 +115,7 @@ dev/hwpmc/hwpmc_uncore.c    optional        hwpmc
 dev/hwpmc/hwpmc_tsc.c          optional        hwpmc
 dev/hwpmc/hwpmc_x86.c          optional        hwpmc
 dev/hyperv/hvsock/hv_sock.c                            optional        hyperv
+dev/hyperv/input/hv_hid.c                              optional        hyperv 
hvhid
 dev/hyperv/input/hv_kbd.c                              optional        hyperv
 dev/hyperv/input/hv_kbdc.c                             optional        hyperv
 dev/hyperv/pcib/vmbus_pcib.c                           optional        hyperv 
pci
diff --git a/sys/dev/hid/hidbus.c b/sys/dev/hid/hidbus.c
index 92a96b10bdbd..b6a9e9f2192f 100644
--- a/sys/dev/hid/hidbus.c
+++ b/sys/dev/hid/hidbus.c
@@ -924,5 +924,6 @@ driver_t hidbus_driver = {
 
 MODULE_DEPEND(hidbus, hid, 1, 1, 1);
 MODULE_VERSION(hidbus, 1);
+DRIVER_MODULE(hidbus, hvhid, hidbus_driver, 0, 0);
 DRIVER_MODULE(hidbus, iichid, hidbus_driver, 0, 0);
 DRIVER_MODULE(hidbus, usbhid, hidbus_driver, 0, 0);
diff --git a/sys/dev/hyperv/input/hv_hid.c b/sys/dev/hyperv/input/hv_hid.c
new file mode 100644
index 000000000000..d576b292e12e
--- /dev/null
+++ b/sys/dev/hyperv/input/hv_hid.c
@@ -0,0 +1,564 @@
+/*-
+ * Copyright (c) 2017 Microsoft Corp.
+ * Copyright (c) 2023 Yuri <y...@aetern.org>
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/cdefs.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <dev/evdev/input.h>
+
+#include <dev/hid/hid.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/include/vmbus_xact.h>
+#include <dev/hyperv/utilities/hv_utilreg.h>
+#include <dev/hyperv/utilities/vmbus_icreg.h>
+#include <dev/hyperv/utilities/vmbus_icvar.h>
+
+#include "hid_if.h"
+#include "vmbus_if.h"
+
+#define        HV_HID_VER_MAJOR        2
+#define        HV_HID_VER_MINOR        0
+#define        HV_HID_VER              (HV_HID_VER_MINOR | (HV_HID_VER_MAJOR) 
<< 16)
+
+#define        HV_BUFSIZ               (4 * PAGE_SIZE)
+#define        HV_HID_RINGBUFF_SEND_SZ (10 * PAGE_SIZE)
+#define        HV_HID_RINGBUFF_RECV_SZ (10 * PAGE_SIZE)
+
+typedef struct {
+       device_t                dev;
+       struct mtx              mtx;
+       /* vmbus */
+       struct vmbus_channel    *hs_chan;
+       struct vmbus_xact_ctx   *hs_xact_ctx;
+       uint8_t                 *buf;
+       int                     buflen;
+       /* hid */
+       struct hid_device_info  hdi;
+       hid_intr_t              *intr;
+       bool                    intr_on;
+       void                    *intr_ctx;
+       uint8_t                 *rdesc;
+} hv_hid_sc;
+
+typedef enum {
+       SH_PROTO_REQ,
+       SH_PROTO_RESP,
+       SH_DEVINFO,
+       SH_DEVINFO_ACK,
+       SH_INPUT_REPORT,
+} sh_msg_type;
+
+typedef struct {
+       sh_msg_type     type;
+       uint32_t        size;
+} __packed sh_msg_hdr;
+
+typedef struct {
+       sh_msg_hdr      hdr;
+       char            data[];
+} __packed sh_msg;
+
+typedef struct {
+       sh_msg_hdr      hdr;
+       uint32_t        ver;
+} __packed sh_proto_req;
+
+typedef struct {
+       sh_msg_hdr      hdr;
+       uint32_t        ver;
+       uint32_t        app;
+} __packed sh_proto_resp;
+
+typedef struct {
+       u_int           size;
+       u_short         vendor;
+       u_short         product;
+       u_short         version;
+       u_short         reserved[11];
+} __packed sh_devinfo;
+
+/* Copied from linux/hid.h */
+typedef struct {
+       uint8_t         bDescriptorType;
+       uint16_t        wDescriptorLength;
+} __packed sh_hcdesc;
+
+typedef struct {
+       uint8_t         bLength;
+       uint8_t         bDescriptorType;
+       uint16_t        bcdHID;
+       uint8_t         bCountryCode;
+       uint8_t         bNumDescriptors;
+       sh_hcdesc       hcdesc[1];
+} __packed sh_hdesc;
+
+typedef struct {
+       sh_msg_hdr      hdr;
+       sh_devinfo      devinfo;
+       sh_hdesc        hdesc;
+} __packed sh_devinfo_resp;
+
+typedef struct {
+       sh_msg_hdr      hdr;
+       uint8_t         rsvd;
+} __packed sh_devinfo_ack;
+
+typedef struct {
+       sh_msg_hdr      hdr;
+       char            buffer[];
+} __packed sh_input_report;
+
+typedef enum {
+       HV_HID_MSG_INVALID,
+       HV_HID_MSG_DATA,
+} hv_hid_msg_type;
+
+typedef struct {
+       hv_hid_msg_type type;
+       uint32_t        size;
+       char            data[];
+} hv_hid_pmsg;
+
+typedef struct {
+       hv_hid_msg_type type;
+       uint32_t        size;
+       union {
+               sh_msg          msg;
+               sh_proto_req    req;
+               sh_proto_resp   resp;
+               sh_devinfo_resp dresp;
+               sh_devinfo_ack  ack;
+               sh_input_report irep;
+       };
+} hv_hid_msg;
+
+#define        HV_HID_REQ_SZ   (sizeof(hv_hid_pmsg) + sizeof(sh_proto_req))
+#define        HV_HID_RESP_SZ  (sizeof(hv_hid_pmsg) + sizeof(sh_proto_resp))
+#define        HV_HID_ACK_SZ   (sizeof(hv_hid_pmsg) + sizeof(sh_devinfo_ack))
+
+/* Somewhat arbitrary, enough to get the devinfo response */
+#define        HV_HID_REQ_MAX  256
+#define        HV_HID_RESP_MAX 256
+
+static const struct vmbus_ic_desc vmbus_hid_descs[] = {
+       {
+               .ic_guid = { .hv_guid = {
+                   0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c,
+                   0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a} },
+               .ic_desc = "Hyper-V HID device"
+       },
+       VMBUS_IC_DESC_END
+};
+
+/* TODO: add GUID support to devmatch(8) to export vmbus_hid_descs directly */
+const struct {
+       char *guid;
+} vmbus_hid_descs_pnp[] = {{ "cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a" }};
+
+static int hv_hid_attach(device_t dev);
+static int hv_hid_detach(device_t dev);
+
+static int
+hv_hid_connect_vsp(hv_hid_sc *sc)
+{
+       struct vmbus_xact       *xact;
+       hv_hid_msg              *req;
+       const hv_hid_msg        *resp;
+       size_t                  resplen;
+       int                     ret;
+
+       xact = vmbus_xact_get(sc->hs_xact_ctx, HV_HID_REQ_SZ);
+       if (xact == NULL) {
+               device_printf(sc->dev, "no xact for init");
+               return (ENODEV);
+       }
+       req = vmbus_xact_req_data(xact);
+       req->type = HV_HID_MSG_DATA;
+       req->size = sizeof(sh_proto_req);
+       req->req.hdr.type = SH_PROTO_REQ;
+       req->req.hdr.size = sizeof(u_int);
+       req->req.ver = HV_HID_VER;
+
+       vmbus_xact_activate(xact);
+       ret = vmbus_chan_send(sc->hs_chan,
+           VMBUS_CHANPKT_TYPE_INBAND,
+           VMBUS_CHANPKT_FLAG_RC,
+           req, HV_HID_REQ_SZ, (uint64_t)(uintptr_t)xact);
+       if (ret != 0) {
+               device_printf(sc->dev, "failed to send proto req\n");
+               vmbus_xact_deactivate(xact);
+               return (ret);
+       }
+       resp = vmbus_chan_xact_wait(sc->hs_chan, xact, &resplen, true);
+       if (resplen != HV_HID_RESP_SZ || !resp->resp.app) {
+               device_printf(sc->dev, "proto req failed\n");
+               ret = ENODEV;
+       }
+
+       vmbus_xact_put(xact);
+       return (ret);
+}
+
+static void
+hv_hid_receive(hv_hid_sc *sc, struct vmbus_chanpkt_hdr *pkt)
+{
+       const hv_hid_msg        *msg;
+       sh_msg_type             msg_type;
+       uint32_t                msg_len;
+       void                    *rdesc;
+
+       msg = VMBUS_CHANPKT_CONST_DATA(pkt);
+       msg_len = VMBUS_CHANPKT_DATALEN(pkt);
+
+       if (msg->type != HV_HID_MSG_DATA)
+               return;
+
+       if (msg_len <= sizeof(hv_hid_pmsg)) {
+               device_printf(sc->dev, "invalid packet length\n");
+               return;
+       }
+       msg_type = msg->msg.hdr.type;
+       switch (msg_type) {
+       case SH_PROTO_RESP: {
+               struct vmbus_xact_ctx *xact_ctx;
+
+               xact_ctx = sc->hs_xact_ctx;
+               if (xact_ctx != NULL) {
+                       vmbus_xact_ctx_wakeup(xact_ctx,
+                           VMBUS_CHANPKT_CONST_DATA(pkt),
+                           VMBUS_CHANPKT_DATALEN(pkt));
+               }
+               break;
+       }
+       case SH_DEVINFO: {
+               struct vmbus_xact       *xact;
+               struct hid_device_info  *hdi;
+               hv_hid_msg              ack;
+               const sh_devinfo        *devinfo;
+               const sh_hdesc          *hdesc;
+
+               /* Send ack */
+               ack.type = HV_HID_MSG_DATA;
+               ack.size = sizeof(sh_devinfo_ack);
+               ack.ack.hdr.type = SH_DEVINFO_ACK;
+               ack.ack.hdr.size = 1;
+               ack.ack.rsvd = 0;
+
+               xact = vmbus_xact_get(sc->hs_xact_ctx, HV_HID_ACK_SZ);
+               if (xact == NULL)
+                       break;
+               vmbus_xact_activate(xact);
+               (void) vmbus_chan_send(sc->hs_chan, VMBUS_CHANPKT_TYPE_INBAND,
+                   0, &ack, HV_HID_ACK_SZ, (uint64_t)(uintptr_t)xact);
+               vmbus_xact_deactivate(xact);
+               vmbus_xact_put(xact);
+
+               /* Check for resume from hibernation */
+               if (sc->rdesc != NULL)
+                       break;
+
+               /* Parse devinfo response */
+               devinfo = &msg->dresp.devinfo;
+               hdesc = &msg->dresp.hdesc;
+               if (hdesc->bLength == 0)
+                       break;
+               hdi = &sc->hdi;
+               memset(hdi, 0, sizeof(*hdi));
+               hdi->rdescsize = le16toh(hdesc->hcdesc[0].wDescriptorLength);
+               if (hdi->rdescsize == 0)
+                       break;
+               strlcpy(hdi->name, "Hyper-V", sizeof(hdi->name));
+               hdi->idBus = BUS_VIRTUAL;
+               hdi->idVendor = le16toh(devinfo->vendor);
+               hdi->idProduct = le16toh(devinfo->product);
+               hdi->idVersion = le16toh(devinfo->version);
+               /* Save rdesc copy */
+               rdesc = malloc(hdi->rdescsize, M_DEVBUF, M_WAITOK | M_ZERO);
+               memcpy(rdesc, (const uint8_t *)hdesc + hdesc->bLength,
+                   hdi->rdescsize);
+               mtx_lock(&sc->mtx);
+               sc->rdesc = rdesc;
+               wakeup(sc);
+               mtx_unlock(&sc->mtx);
+               break;
+       }
+       case SH_INPUT_REPORT: {
+               mtx_lock(&sc->mtx);
+               if (sc->intr != NULL && sc->intr_on)
+                       sc->intr(sc->intr_ctx,
+                           __DECONST(void *, msg->irep.buffer),
+                           msg->irep.hdr.size);
+               mtx_unlock(&sc->mtx);
+               break;
+       }
+       default:
+               break;
+       }
+}
+
+static void
+hv_hid_read_channel(struct vmbus_channel *channel, void *ctx)
+{
+       hv_hid_sc       *sc;
+       uint8_t         *buf;
+       int             buflen;
+       int             ret;
+
+       sc = ctx;
+       buf = sc->buf;
+       buflen = sc->buflen;
+       for (;;) {
+               struct vmbus_chanpkt_hdr *pkt;
+               int rcvd;
+
+               pkt = (struct vmbus_chanpkt_hdr *)buf;
+               rcvd = buflen;
+               ret = vmbus_chan_recv_pkt(channel, pkt, &rcvd);
+               if (__predict_false(ret == ENOBUFS)) {
+                       buflen = sc->buflen * 2;
+                       while (buflen < rcvd)
+                               buflen *= 2;
+                       buf = malloc(buflen, M_DEVBUF, M_WAITOK | M_ZERO);
+                       device_printf(sc->dev, "expand recvbuf %d -> %d\n",
+                           sc->buflen, buflen);
+                       free(sc->buf, M_DEVBUF);
+                       sc->buf = buf;
+                       sc->buflen = buflen;
+                       continue;
+               } else if (__predict_false(ret == EAGAIN)) {
+                       /* No more channel packets; done! */
+                       break;
+               }
+               KASSERT(ret == 0, ("vmbus_chan_recv_pkt failed: %d", ret));
+
+               switch (pkt->cph_type) {
+               case VMBUS_CHANPKT_TYPE_COMP:
+               case VMBUS_CHANPKT_TYPE_RXBUF:
+                       device_printf(sc->dev, "unhandled event: %d\n",
+                           pkt->cph_type);
+                       break;
+               case VMBUS_CHANPKT_TYPE_INBAND:
+                       hv_hid_receive(sc, pkt);
+                       break;
+               default:
+                       device_printf(sc->dev, "unknown event: %d\n",
+                           pkt->cph_type);
+                       break;
+               }
+       }
+}
+
+static int
+hv_hid_probe(device_t dev)
+{
+       device_t                        bus;
+       const struct vmbus_ic_desc      *d;
+
+       if (resource_disabled(device_get_name(dev), 0))
+               return (ENXIO);
+
+       bus = device_get_parent(dev);
+       for (d = vmbus_hid_descs; d->ic_desc != NULL; ++d) {
+               if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) {
+                       device_set_desc(dev, d->ic_desc);
+                       return (BUS_PROBE_DEFAULT);
+               }
+       }
+
+       return (ENXIO);
+}
+
+static int
+hv_hid_attach(device_t dev)
+{
+       device_t        child;
+       hv_hid_sc       *sc;
+       int             ret;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       mtx_init(&sc->mtx, "hvhid lock", NULL, MTX_DEF);
+       sc->hs_chan = vmbus_get_channel(dev);
+       sc->hs_xact_ctx = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
+           HV_HID_REQ_MAX, HV_HID_RESP_MAX, 0);
+       if (sc->hs_xact_ctx == NULL) {
+               ret = ENOMEM;
+               goto out;
+       }
+       sc->buflen = HV_BUFSIZ;
+       sc->buf = malloc(sc->buflen, M_DEVBUF, M_WAITOK | M_ZERO);
+       vmbus_chan_set_readbatch(sc->hs_chan, false);
+       ret = vmbus_chan_open(sc->hs_chan, HV_HID_RINGBUFF_SEND_SZ,
+           HV_HID_RINGBUFF_RECV_SZ, NULL, 0, hv_hid_read_channel, sc);
+       if (ret != 0)
+               goto out;
+       ret = hv_hid_connect_vsp(sc);
+       if (ret != 0)
+               goto out;
+
+       /* Wait until we have devinfo (or arbitrary timeout of 3s) */
+       mtx_lock(&sc->mtx);
+       if (sc->rdesc == NULL)
+               ret = mtx_sleep(sc, &sc->mtx, 0, "hvhid", hz * 3);
+       mtx_unlock(&sc->mtx);
+       if (ret != 0) {
+               ret = ENODEV;
+               goto out;
+       }
+       child = device_add_child(sc->dev, "hidbus", -1);
+       if (child == NULL) {
+               device_printf(sc->dev, "failed to add hidbus\n");
+               ret = ENOMEM;
+               goto out;
+       }
+       device_set_ivars(child, &sc->hdi);
+       ret = bus_generic_attach(dev);
+       if (ret != 0)
+               device_printf(sc->dev, "failed to attach hidbus\n");
+out:
+       if (ret != 0)
+               hv_hid_detach(dev);
+       return (ret);
+}
+
+static int
+hv_hid_detach(device_t dev)
+{
+       hv_hid_sc       *sc;
+       int             ret;
+
+       sc = device_get_softc(dev);
+       ret = device_delete_children(dev);
+       if (ret != 0)
+               return (ret);
+       if (sc->hs_xact_ctx != NULL)
+               vmbus_xact_ctx_destroy(sc->hs_xact_ctx);
+       vmbus_chan_close(vmbus_get_channel(dev));
+       free(sc->buf, M_DEVBUF);
+       free(sc->rdesc, M_DEVBUF);
+       mtx_destroy(&sc->mtx);
+
+       return (0);
+}
+
+static void
+hv_hid_intr_setup(device_t dev, hid_intr_t intr, void *ctx,
+    struct hid_rdesc_info *rdesc)
+{
+       hv_hid_sc       *sc;
+
+       if (intr == NULL)
+               return;
+
+       sc = device_get_softc(dev);
+       sc->intr = intr;
+       sc->intr_on = false;
+       sc->intr_ctx = ctx;
+       rdesc->rdsize = rdesc->isize;
+}
+
+static void
+hv_hid_intr_unsetup(device_t dev)
+{
+       hv_hid_sc       *sc;
+
+       sc = device_get_softc(dev);
+       sc->intr = NULL;
+       sc->intr_on = false;
+       sc->intr_ctx = NULL;
+}
+
+static int
+hv_hid_intr_start(device_t dev)
+{
+       hv_hid_sc       *sc;
+
+       sc = device_get_softc(dev);
+       mtx_lock(&sc->mtx);
+       sc->intr_on = true;
+       mtx_unlock(&sc->mtx);
+       return (0);
+}
+
+static int
+hv_hid_intr_stop(device_t dev)
+{
+       hv_hid_sc       *sc;
+
+       sc = device_get_softc(dev);
+       mtx_lock(&sc->mtx);
+       sc->intr_on = false;
+       mtx_unlock(&sc->mtx);
+       return (0);
+}
+
+static int
+hv_hid_get_rdesc(device_t dev, void *buf, hid_size_t len)
+{
+       hv_hid_sc       *sc;
+
+       sc = device_get_softc(dev);
+       if (len < sc->hdi.rdescsize)
+               return (EMSGSIZE);
+       memcpy(buf, sc->rdesc, len);
+       return (0);
+}
+
+static device_method_t hv_hid_methods[] = {
+       DEVMETHOD(device_probe,         hv_hid_probe),
+       DEVMETHOD(device_attach,        hv_hid_attach),
+       DEVMETHOD(device_detach,        hv_hid_detach),
+
+       DEVMETHOD(hid_intr_setup,       hv_hid_intr_setup),
+       DEVMETHOD(hid_intr_unsetup,     hv_hid_intr_unsetup),
+       DEVMETHOD(hid_intr_start,       hv_hid_intr_start),
+       DEVMETHOD(hid_intr_stop,        hv_hid_intr_stop),
+
+       DEVMETHOD(hid_get_rdesc,        hv_hid_get_rdesc),
+       DEVMETHOD_END,
+};
+
+static driver_t hv_hid_driver = {
+       .name = "hvhid",
+       .methods = hv_hid_methods,
+       .size = sizeof(hv_hid_sc),
+};
+
+DRIVER_MODULE(hv_hid, vmbus, hv_hid_driver, NULL, NULL);
+MODULE_VERSION(hv_hid, 1);
+MODULE_DEPEND(hv_hid, hidbus, 1, 1, 1);
+MODULE_DEPEND(hv_hid, hms, 1, 1, 1);
+MODULE_DEPEND(hv_hid, vmbus, 1, 1, 1);
+MODULE_PNP_INFO("Z:classid", vmbus, hv_hid, vmbus_hid_descs_pnp,
+    nitems(vmbus_hid_descs_pnp));
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 367af20d3a09..4e4c6193ebab 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -703,6 +703,7 @@ device              kvm_clock       # KVM paravirtual clock 
driver
 
 options        HYPERV
 device         hyperv          # HyperV drivers
+device         hvhid           # HyperV HID device
 
 #####################################################################
 
diff --git a/sys/modules/hyperv/Makefile b/sys/modules/hyperv/Makefile
index e94b441e876d..0e9ca2495ef6 100644
--- a/sys/modules/hyperv/Makefile
+++ b/sys/modules/hyperv/Makefile
@@ -1,5 +1,5 @@
 # $FreeBSD$
 
-SUBDIR = vmbus netvsc storvsc utilities hvsock
+SUBDIR = vmbus netvsc storvsc utilities hvsock hid
 
 .include <bsd.subdir.mk>
diff --git a/sys/modules/hyperv/hid/Makefile b/sys/modules/hyperv/hid/Makefile
new file mode 100644
index 000000000000..40b991065d2a
--- /dev/null
+++ b/sys/modules/hyperv/hid/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/dev/hyperv/input
+
+KMOD=  hv_hid
+SRCS=  hv_hid.c
+SRCS+= bus_if.h device_if.h hid_if.h vmbus_if.h
+
+CFLAGS+= -I${SRCTOP}/sys/dev/hyperv/include \
+        -I${SRCTOP}/sys/dev/hyperv/vmbus
+
+.include <bsd.kmod.mk>

Reply via email to