Page MenuHomeFreeBSD

D38140.id115382.diff
No OneTemporary

D38140.id115382.diff

diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -117,6 +117,7 @@
dev/hyperv/hvsock/hv_sock.c optional hyperv
dev/hyperv/input/hv_kbd.c optional hyperv
dev/hyperv/input/hv_kbdc.c optional hyperv
+dev/hyperv/input/hv_ms.c optional hyperv
dev/hyperv/pcib/vmbus_pcib.c optional hyperv pci
dev/hyperv/netvsc/hn_nvs.c optional hyperv
dev/hyperv/netvsc/hn_rndis.c optional hyperv
@@ -129,8 +130,8 @@
dev/hyperv/utilities/vmbus_shutdown.c optional hyperv
dev/hyperv/utilities/vmbus_timesync.c optional hyperv
dev/hyperv/vmbus/hyperv.c optional hyperv
-dev/hyperv/vmbus/x86/hyperv_x86.c optional hyperv
-dev/hyperv/vmbus/x86/vmbus_x86.c optional hyperv
+dev/hyperv/vmbus/x86/hyperv_x86.c optional hyperv
+dev/hyperv/vmbus/x86/vmbus_x86.c optional hyperv
dev/hyperv/vmbus/hyperv_busdma.c optional hyperv
dev/hyperv/vmbus/vmbus.c optional hyperv pci
dev/hyperv/vmbus/vmbus_br.c optional hyperv
diff --git a/sys/dev/hyperv/input/hv_ms.c b/sys/dev/hyperv/input/hv_ms.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/hyperv/input/hv_ms.c
@@ -0,0 +1,402 @@
+/*-
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.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 "vmbus_if.h"
+
+#define HV_MS_DRIVER_NAME "hvms"
+
+#define HV_MS_VER_MAJOR 2
+#define HV_MS_VER_MINOR 0
+#define HV_MS_VER (HV_MS_VER_MINOR | (HV_MS_VER_MAJOR) << 16)
+
+#define HV_BUFSIZ (4 * PAGE_SIZE)
+#define HV_MS_RINGBUFF_SEND_SZ (10 * PAGE_SIZE)
+#define HV_MS_RINGBUFF_RECV_SZ (10 * PAGE_SIZE)
+
+typedef struct {
+ device_t dev;
+ struct vmbus_channel *hs_chan;
+ struct vmbus_xact_ctx *hs_xact_ctx;
+ uint8_t *buf;
+ int32_t buflen;
+} hv_ms_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; /* XXX le16toh when used */
+} __packed sh_hcdesc;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdHID; /* XXX le16toh when used */
+ uint8_t bCountryCode;
+ uint8_t bNumDescriptors;
+ sh_hcdesc hcdesc;
+} __packed sh_hdesc;
+
+typedef struct {
+ sh_msg_hdr hdr;
+ u_char rsvd;
+} __packed sh_devinfo_ack;
+
+typedef struct {
+ sh_msg_hdr hdr;
+ sh_devinfo devinfo;
+ sh_hdesc hdesc;
+} __packed sh_devinfo_resp;
+
+typedef struct {
+ sh_msg_hdr hdr;
+ char buffer[];
+} __packed sh_input_report;
+
+typedef enum {
+ HV_MS_MSG_INVALID,
+ HV_MS_MSG_DATA,
+} hv_ms_msg_type;
+
+typedef struct {
+ hv_ms_msg_type type;
+ uint32_t size;
+ char data[];
+} hv_ms_pmsg;
+
+typedef struct {
+ hv_ms_msg_type type;
+ uint32_t size;
+ union {
+ sh_msg msg;
+ sh_proto_req req;
+ sh_proto_resp resp;
+ sh_devinfo_resp devinfo;
+ sh_devinfo_ack ack;
+ sh_input_report irep;
+ };
+} hv_ms_msg;
+
+#define HV_MS_ACK_SZ (sizeof(hv_ms_pmsg) + sizeof(sh_devinfo_ack))
+#define HV_MS_DRESP_SZ (sizeof(hv_ms_pmsg) + sizeof(sh_devinfo_resp))
+#define HV_MS_REQ_SZ (sizeof(hv_ms_pmsg) + sizeof(sh_proto_req))
+#define HV_MS_PRESP_SZ (sizeof(hv_ms_pmsg) + sizeof(sh_proto_resp))
+
+static const struct vmbus_ic_desc vmbus_ms_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 Mouse"
+ },
+ VMBUS_IC_DESC_END
+};
+
+static int hv_ms_attach(device_t dev);
+static int hv_ms_detach(device_t dev);
+
+static int
+hv_ms_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_ms_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_ms_connect_vsp(hv_ms_sc *sc)
+{
+ struct vmbus_xact *xact;
+ hv_ms_msg *req;
+ const hv_ms_msg *resp;
+ size_t resplen;
+ int ret;
+
+ xact = vmbus_xact_get(sc->hs_xact_ctx, HV_MS_REQ_SZ);
+ if (xact == NULL) {
+ device_printf(sc->dev, "no xact for init");
+ return (ENODEV);
+ }
+ req = vmbus_xact_req_data(xact);
+ req->type = HV_MS_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_MS_VER;
+
+ vmbus_xact_activate(xact);
+ ret = vmbus_chan_send(sc->hs_chan,
+ VMBUS_CHANPKT_TYPE_INBAND,
+ VMBUS_CHANPKT_FLAG_RC,
+ req, HV_MS_REQ_SZ, (uint64_t)(uintptr_t)xact);
+ if (ret != 0) {
+ device_printf(sc->dev, "failed to send\n");
+ vmbus_xact_deactivate(xact);
+ return (ret);
+ }
+ resp = vmbus_chan_xact_wait(sc->hs_chan, xact, &resplen, true);
+ if (resplen != HV_MS_PRESP_SZ || !resp->resp.app) {
+ device_printf(sc->dev, "protocol request failed\n");
+ ret = ENODEV;
+ }
+
+ vmbus_xact_put(xact);
+ return (ret);
+}
+
+static void
+hv_ms_receive(hv_ms_sc *sc, struct vmbus_chanpkt_hdr *pkt)
+{
+ const hv_ms_msg *msg;
+ sh_msg_type msg_type;
+ uint32_t msg_len;
+
+ msg = VMBUS_CHANPKT_CONST_DATA(pkt);
+ msg_len = VMBUS_CHANPKT_DATALEN(pkt);
+
+ if (msg->type != HV_MS_MSG_DATA)
+ return;
+
+ if (msg_len <= sizeof(hv_ms_pmsg)) {
+ device_printf(sc->dev, "illegal packet\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;
+ hv_ms_msg ack;
+
+ /* TODO process devinfo? */
+
+ /* Send the ack */
+ ack.type = HV_MS_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_MS_ACK_SZ);
+ if (xact == NULL)
+ break;
+ vmbus_xact_activate(xact);
+ (void) vmbus_chan_send(sc->hs_chan, VMBUS_CHANPKT_TYPE_INBAND,
+ 0, &ack, HV_MS_ACK_SZ, (uint64_t)(uintptr_t)xact);
+ vmbus_xact_deactivate(xact);
+ vmbus_xact_put(xact);
+ break;
+ }
+ case SH_INPUT_REPORT:
+ device_printf(sc->dev, "report: ");
+ for (int i = 0; i < msg->irep.hdr.size; i++)
+ printf("%02d:", msg->irep.buffer[i]);
+ printf("\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+hv_ms_read_channel(struct vmbus_channel *channel, void *ctx)
+{
+ hv_ms_sc *sc;
+ uint8_t *buf;
+ uint32_t buflen;
+ int ret;
+
+ sc = ctx;
+ buf = sc->buf;
+ buflen = sc->buflen;
+ for (;;) {
+ struct vmbus_chanpkt_hdr *pkt;
+ uint32_t 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_ms_receive(sc, pkt);
+ break;
+ default:
+ device_printf(sc->dev, "unknown event: %d\n", pkt->cph_type);
+ break;
+ }
+ }
+}
+
+static int
+hv_ms_attach(device_t dev)
+{
+ hv_ms_sc *sc;
+ int ret;
+
+ sc = device_get_softc(dev);
+ sc->hs_chan = vmbus_get_channel(dev);
+ sc->dev = dev;
+ sc->hs_xact_ctx = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
+ MAX(HV_MS_ACK_SZ, HV_MS_REQ_SZ),
+ MAX(HV_MS_DRESP_SZ, HV_MS_PRESP_SZ), 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_MS_RINGBUFF_SEND_SZ,
+ HV_MS_RINGBUFF_RECV_SZ, NULL, 0, hv_ms_read_channel, sc);
+ if (ret != 0)
+ goto out;
+ ret = hv_ms_connect_vsp(sc);
+out:
+ if (ret != 0)
+ hv_ms_detach(dev);
+ return (ret);
+}
+
+static int
+hv_ms_detach(device_t dev)
+{
+ hv_ms_sc *sc;
+
+ sc = device_get_softc(dev);
+ 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);
+
+ return (0);
+}
+
+static device_method_t hv_ms_methods[] = {
+ DEVMETHOD(device_probe, hv_ms_probe),
+ DEVMETHOD(device_attach, hv_ms_attach),
+ DEVMETHOD(device_detach, hv_ms_detach),
+ { 0, 0 }
+};
+
+static driver_t hv_ms_driver =
+ { HV_MS_DRIVER_NAME, hv_ms_methods, sizeof(hv_ms_sc) };
+
+DRIVER_MODULE(hv_ms, vmbus, hv_ms_driver, NULL, NULL);
+MODULE_VERSION(hv_ms, 1);
+MODULE_DEPEND(hv_ms, vmbus, 1, 1, 1);
+//MODULE_DEPEND(hv_ms, hid, 1, 1, 1);
+//MODULE_DEPEND(hv_ms, hidbus, 1, 1, 1);
diff --git a/sys/modules/hyperv/hv_ms/Makefile b/sys/modules/hyperv/hv_ms/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/hyperv/hv_ms/Makefile
@@ -0,0 +1,9 @@
+.PATH: ${SRCTOP}/sys/dev/hyperv/input
+
+KMOD= hv_ms
+SRCS = hv_ms.c
+SRCS+= bus_if.h device_if.h vmbus_if.h
+
+CFLAGS+= -I${SRCTOP}/sys/dev/hyperv/include
+
+.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 3:21 AM (12 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28530728
Default Alt Text
D38140.id115382.diff (11 KB)

Event Timeline