From nobody Fri Mar 31 19:55:50 2023 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Pp9yH2F9bz43BR0; Fri, 31 Mar 2023 19:55:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Pp9yH101Dz3NVd; Fri, 31 Mar 2023 19:55:51 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680292551; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=WueU7HbrVmhOKqwn58IYPPKmb34gqq/pISH3NyRJZ/E=; b=sqGukqAWbsf8FaYQXIFY5/ISaQol5OrfcJ+j8vDZmtNqISfGLsaFSKUpqZFAycvR9joRXy DWdwIrocq5uBH8NQNd4a3CgxaL3dcrWlRvn4Q1jnDodcHy80sxjNbe5T/PqKuBuOxXHlc4 eno36vqj9K0WQoSFOf45jCfY5iJG9BrLf1QLSqmPDqP6hJQsvgvEE9Jja7gVp75/rrBrCK fNgD+0T8ucyRLScJMOyk0hQequERWTkaVAKAVTw5hskRUYHxaPnKY4We2+1uQzAu4DAYht i7BnMiWbeSq6cCAhKZkypgs5Ca3+lFhTGQ/78Pdmj6HrxVK47LfQM1Vc/q6egw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1680292551; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=WueU7HbrVmhOKqwn58IYPPKmb34gqq/pISH3NyRJZ/E=; b=YjP0Uv7BU11lejAWH72hQN/z5eh6xr1KxYzouenHW4XAH+8QtqHMGwCSGxP9Be5Pk97bxS ZGGAtgpg2eTtRhvxJWlYAJ7Ztl+NE8vjbAEvr0guL4i7c9ctkQCUKYeeC5++Fm6FGV89xV 1ShzuzCZ/qAcCRq7JDFOCa6Oiat1EfBrGn70lQQv8S/jNNEsicJ7TR47yD65RK6fo44WAt y/ODFOH73BS+mU0G4efOZDTdQ6OXJVW3yyjwsp9lBvF9V2b1Wrs+vhAuADFZmEYGX7aUUT GIQ0ExrhEHC+Q5Lh5aw3u2GsPuupmhF8jb8c/PWD24rWHHNvupQK7kgY8Po3yg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1680292551; a=rsa-sha256; cv=none; b=qXgn966CTvUHT6lOAEJah86/fg/3+6Ew61FxqBb/x2K7Orz7hVU0RhbkjsdWKLR7VxIbxG z/8s5JGVYwXaTeATGUlCXGmJ/59KgYEaJdhekE3yoyL20cZ06QlTMb88ItufEgLyuFMjmh w11ZNPzV3nFiJ0FIGGMLI8W7q/v7vPlszPYCrnT1gghS9IaRvNG8ynRifgR018kxLlOhwZ UD3FtGL6l9XhIjY2fw5BCbAkbP4wUW92qnLn+DxKItLf/Vs1V6sWojTfyK79tj1OvKIpdj GsdAxcmM+by9C+3bNaWf9E0GTUTK1YhHud4DzdigSw7JKX7N88QD8DoXtvPuQw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Pp9yH01pwz16L5; Fri, 31 Mar 2023 19:55:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 32VJtoXa075716; Fri, 31 Mar 2023 19:55:50 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 32VJtoHY075715; Fri, 31 Mar 2023 19:55:50 GMT (envelope-from git) Date: Fri, 31 Mar 2023 19:55:50 GMT Message-Id: <202303311955.32VJtoHY075715@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Yuri Pankov Subject: git: 21f4e817fde7 - stable/13 - hv_hid: Hyper-V HID driver List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: yuripv X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 21f4e817fde79d5de79bfbdf180d358ca5f48bf9 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by yuripv: URL: https://cgit.FreeBSD.org/src/commit/?id=21f4e817fde79d5de79bfbdf180d358ca5f48bf9 commit 21f4e817fde79d5de79bfbdf180d358ca5f48bf9 Author: Yuri AuthorDate: 2023-02-05 15:32:08 +0000 Commit: Yuri Pankov CommitDate: 2023-03-31 18:44:04 +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 (cherry picked from commit e4d3f1e40ab3327e4ff6f689f54a64bd2ebc0568) --- 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 300a8a48bab7..a72e9f2623bb 100644 --- a/sys/amd64/conf/NOTES +++ b/sys/amd64/conf/NOTES @@ -508,6 +508,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 a5a565483fe8..07ecb9fe1e01 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -134,6 +134,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 9ff00fece820..c10f17748e8d 100644 --- a/sys/dev/hid/hidbus.c +++ b/sys/dev/hid/hidbus.c @@ -926,5 +926,6 @@ driver_t hidbus_driver = { MODULE_DEPEND(hidbus, hid, 1, 1, 1); MODULE_VERSION(hidbus, 1); +DRIVER_MODULE(hidbus, hvhid, hidbus_driver, hidbus_devclass, 0, 0); DRIVER_MODULE(hidbus, iichid, hidbus_driver, hidbus_devclass, 0, 0); DRIVER_MODULE(hidbus, usbhid, hidbus_driver, hidbus_devclass, 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#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 763ba321380a..2c069e1c52b8 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -725,6 +725,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 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