]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hyperv/input/hv_hid.c
hv_hid: Hyper-V HID driver
[FreeBSD/FreeBSD.git] / sys / dev / hyperv / input / hv_hid.c
1 /*-
2  * Copyright (c) 2017 Microsoft Corp.
3  * Copyright (c) 2023 Yuri <yuri@aetern.org>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/param.h>
28 #include <sys/bus.h>
29 #include <sys/cdefs.h>
30 #include <sys/conf.h>
31 #include <sys/kernel.h>
32 #include <sys/lock.h>
33 #include <sys/malloc.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36
37 #include <dev/evdev/input.h>
38
39 #include <dev/hid/hid.h>
40
41 #include <dev/hyperv/include/hyperv.h>
42 #include <dev/hyperv/include/vmbus_xact.h>
43 #include <dev/hyperv/utilities/hv_utilreg.h>
44 #include <dev/hyperv/utilities/vmbus_icreg.h>
45 #include <dev/hyperv/utilities/vmbus_icvar.h>
46
47 #include "hid_if.h"
48 #include "vmbus_if.h"
49
50 #define HV_HID_VER_MAJOR        2
51 #define HV_HID_VER_MINOR        0
52 #define HV_HID_VER              (HV_HID_VER_MINOR | (HV_HID_VER_MAJOR) << 16)
53
54 #define HV_BUFSIZ               (4 * PAGE_SIZE)
55 #define HV_HID_RINGBUFF_SEND_SZ (10 * PAGE_SIZE)
56 #define HV_HID_RINGBUFF_RECV_SZ (10 * PAGE_SIZE)
57
58 typedef struct {
59         device_t                dev;
60         struct mtx              mtx;
61         /* vmbus */
62         struct vmbus_channel    *hs_chan;
63         struct vmbus_xact_ctx   *hs_xact_ctx;
64         uint8_t                 *buf;
65         int                     buflen;
66         /* hid */
67         struct hid_device_info  hdi;
68         hid_intr_t              *intr;
69         bool                    intr_on;
70         void                    *intr_ctx;
71         uint8_t                 *rdesc;
72 } hv_hid_sc;
73
74 typedef enum {
75         SH_PROTO_REQ,
76         SH_PROTO_RESP,
77         SH_DEVINFO,
78         SH_DEVINFO_ACK,
79         SH_INPUT_REPORT,
80 } sh_msg_type;
81
82 typedef struct {
83         sh_msg_type     type;
84         uint32_t        size;
85 } __packed sh_msg_hdr;
86
87 typedef struct {
88         sh_msg_hdr      hdr;
89         char            data[];
90 } __packed sh_msg;
91
92 typedef struct {
93         sh_msg_hdr      hdr;
94         uint32_t        ver;
95 } __packed sh_proto_req;
96
97 typedef struct {
98         sh_msg_hdr      hdr;
99         uint32_t        ver;
100         uint32_t        app;
101 } __packed sh_proto_resp;
102
103 typedef struct {
104         u_int           size;
105         u_short         vendor;
106         u_short         product;
107         u_short         version;
108         u_short         reserved[11];
109 } __packed sh_devinfo;
110
111 /* Copied from linux/hid.h */
112 typedef struct {
113         uint8_t         bDescriptorType;
114         uint16_t        wDescriptorLength;
115 } __packed sh_hcdesc;
116
117 typedef struct {
118         uint8_t         bLength;
119         uint8_t         bDescriptorType;
120         uint16_t        bcdHID;
121         uint8_t         bCountryCode;
122         uint8_t         bNumDescriptors;
123         sh_hcdesc       hcdesc[1];
124 } __packed sh_hdesc;
125
126 typedef struct {
127         sh_msg_hdr      hdr;
128         sh_devinfo      devinfo;
129         sh_hdesc        hdesc;
130 } __packed sh_devinfo_resp;
131
132 typedef struct {
133         sh_msg_hdr      hdr;
134         uint8_t         rsvd;
135 } __packed sh_devinfo_ack;
136
137 typedef struct {
138         sh_msg_hdr      hdr;
139         char            buffer[];
140 } __packed sh_input_report;
141
142 typedef enum {
143         HV_HID_MSG_INVALID,
144         HV_HID_MSG_DATA,
145 } hv_hid_msg_type;
146
147 typedef struct {
148         hv_hid_msg_type type;
149         uint32_t        size;
150         char            data[];
151 } hv_hid_pmsg;
152
153 typedef struct {
154         hv_hid_msg_type type;
155         uint32_t        size;
156         union {
157                 sh_msg          msg;
158                 sh_proto_req    req;
159                 sh_proto_resp   resp;
160                 sh_devinfo_resp dresp;
161                 sh_devinfo_ack  ack;
162                 sh_input_report irep;
163         };
164 } hv_hid_msg;
165
166 #define HV_HID_REQ_SZ   (sizeof(hv_hid_pmsg) + sizeof(sh_proto_req))
167 #define HV_HID_RESP_SZ  (sizeof(hv_hid_pmsg) + sizeof(sh_proto_resp))
168 #define HV_HID_ACK_SZ   (sizeof(hv_hid_pmsg) + sizeof(sh_devinfo_ack))
169
170 /* Somewhat arbitrary, enough to get the devinfo response */
171 #define HV_HID_REQ_MAX  256
172 #define HV_HID_RESP_MAX 256
173
174 static const struct vmbus_ic_desc vmbus_hid_descs[] = {
175         {
176                 .ic_guid = { .hv_guid = {
177                     0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c,
178                     0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a} },
179                 .ic_desc = "Hyper-V HID device"
180         },
181         VMBUS_IC_DESC_END
182 };
183
184 /* TODO: add GUID support to devmatch(8) to export vmbus_hid_descs directly */
185 const struct {
186         char *guid;
187 } vmbus_hid_descs_pnp[] = {{ "cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a" }};
188
189 static int hv_hid_attach(device_t dev);
190 static int hv_hid_detach(device_t dev);
191
192 static int
193 hv_hid_connect_vsp(hv_hid_sc *sc)
194 {
195         struct vmbus_xact       *xact;
196         hv_hid_msg              *req;
197         const hv_hid_msg        *resp;
198         size_t                  resplen;
199         int                     ret;
200
201         xact = vmbus_xact_get(sc->hs_xact_ctx, HV_HID_REQ_SZ);
202         if (xact == NULL) {
203                 device_printf(sc->dev, "no xact for init");
204                 return (ENODEV);
205         }
206         req = vmbus_xact_req_data(xact);
207         req->type = HV_HID_MSG_DATA;
208         req->size = sizeof(sh_proto_req);
209         req->req.hdr.type = SH_PROTO_REQ;
210         req->req.hdr.size = sizeof(u_int);
211         req->req.ver = HV_HID_VER;
212
213         vmbus_xact_activate(xact);
214         ret = vmbus_chan_send(sc->hs_chan,
215             VMBUS_CHANPKT_TYPE_INBAND,
216             VMBUS_CHANPKT_FLAG_RC,
217             req, HV_HID_REQ_SZ, (uint64_t)(uintptr_t)xact);
218         if (ret != 0) {
219                 device_printf(sc->dev, "failed to send proto req\n");
220                 vmbus_xact_deactivate(xact);
221                 return (ret);
222         }
223         resp = vmbus_chan_xact_wait(sc->hs_chan, xact, &resplen, true);
224         if (resplen != HV_HID_RESP_SZ || !resp->resp.app) {
225                 device_printf(sc->dev, "proto req failed\n");
226                 ret = ENODEV;
227         }
228
229         vmbus_xact_put(xact);
230         return (ret);
231 }
232
233 static void
234 hv_hid_receive(hv_hid_sc *sc, struct vmbus_chanpkt_hdr *pkt)
235 {
236         const hv_hid_msg        *msg;
237         sh_msg_type             msg_type;
238         uint32_t                msg_len;
239         void                    *rdesc;
240
241         msg = VMBUS_CHANPKT_CONST_DATA(pkt);
242         msg_len = VMBUS_CHANPKT_DATALEN(pkt);
243
244         if (msg->type != HV_HID_MSG_DATA)
245                 return;
246
247         if (msg_len <= sizeof(hv_hid_pmsg)) {
248                 device_printf(sc->dev, "invalid packet length\n");
249                 return;
250         }
251         msg_type = msg->msg.hdr.type;
252         switch (msg_type) {
253         case SH_PROTO_RESP: {
254                 struct vmbus_xact_ctx *xact_ctx;
255
256                 xact_ctx = sc->hs_xact_ctx;
257                 if (xact_ctx != NULL) {
258                         vmbus_xact_ctx_wakeup(xact_ctx,
259                             VMBUS_CHANPKT_CONST_DATA(pkt),
260                             VMBUS_CHANPKT_DATALEN(pkt));
261                 }
262                 break;
263         }
264         case SH_DEVINFO: {
265                 struct vmbus_xact       *xact;
266                 struct hid_device_info  *hdi;
267                 hv_hid_msg              ack;
268                 const sh_devinfo        *devinfo;
269                 const sh_hdesc          *hdesc;
270
271                 /* Send ack */
272                 ack.type = HV_HID_MSG_DATA;
273                 ack.size = sizeof(sh_devinfo_ack);
274                 ack.ack.hdr.type = SH_DEVINFO_ACK;
275                 ack.ack.hdr.size = 1;
276                 ack.ack.rsvd = 0;
277
278                 xact = vmbus_xact_get(sc->hs_xact_ctx, HV_HID_ACK_SZ);
279                 if (xact == NULL)
280                         break;
281                 vmbus_xact_activate(xact);
282                 (void) vmbus_chan_send(sc->hs_chan, VMBUS_CHANPKT_TYPE_INBAND,
283                     0, &ack, HV_HID_ACK_SZ, (uint64_t)(uintptr_t)xact);
284                 vmbus_xact_deactivate(xact);
285                 vmbus_xact_put(xact);
286
287                 /* Check for resume from hibernation */
288                 if (sc->rdesc != NULL)
289                         break;
290
291                 /* Parse devinfo response */
292                 devinfo = &msg->dresp.devinfo;
293                 hdesc = &msg->dresp.hdesc;
294                 if (hdesc->bLength == 0)
295                         break;
296                 hdi = &sc->hdi;
297                 memset(hdi, 0, sizeof(*hdi));
298                 hdi->rdescsize = le16toh(hdesc->hcdesc[0].wDescriptorLength);
299                 if (hdi->rdescsize == 0)
300                         break;
301                 strlcpy(hdi->name, "Hyper-V", sizeof(hdi->name));
302                 hdi->idBus = BUS_VIRTUAL;
303                 hdi->idVendor = le16toh(devinfo->vendor);
304                 hdi->idProduct = le16toh(devinfo->product);
305                 hdi->idVersion = le16toh(devinfo->version);
306                 /* Save rdesc copy */
307                 rdesc = malloc(hdi->rdescsize, M_DEVBUF, M_WAITOK | M_ZERO);
308                 memcpy(rdesc, (const uint8_t *)hdesc + hdesc->bLength,
309                     hdi->rdescsize);
310                 mtx_lock(&sc->mtx);
311                 sc->rdesc = rdesc;
312                 wakeup(sc);
313                 mtx_unlock(&sc->mtx);
314                 break;
315         }
316         case SH_INPUT_REPORT: {
317                 mtx_lock(&sc->mtx);
318                 if (sc->intr != NULL && sc->intr_on)
319                         sc->intr(sc->intr_ctx,
320                             __DECONST(void *, msg->irep.buffer),
321                             msg->irep.hdr.size);
322                 mtx_unlock(&sc->mtx);
323                 break;
324         }
325         default:
326                 break;
327         }
328 }
329
330 static void
331 hv_hid_read_channel(struct vmbus_channel *channel, void *ctx)
332 {
333         hv_hid_sc       *sc;
334         uint8_t         *buf;
335         int             buflen;
336         int             ret;
337
338         sc = ctx;
339         buf = sc->buf;
340         buflen = sc->buflen;
341         for (;;) {
342                 struct vmbus_chanpkt_hdr *pkt;
343                 int rcvd;
344
345                 pkt = (struct vmbus_chanpkt_hdr *)buf;
346                 rcvd = buflen;
347                 ret = vmbus_chan_recv_pkt(channel, pkt, &rcvd);
348                 if (__predict_false(ret == ENOBUFS)) {
349                         buflen = sc->buflen * 2;
350                         while (buflen < rcvd)
351                                 buflen *= 2;
352                         buf = malloc(buflen, M_DEVBUF, M_WAITOK | M_ZERO);
353                         device_printf(sc->dev, "expand recvbuf %d -> %d\n",
354                             sc->buflen, buflen);
355                         free(sc->buf, M_DEVBUF);
356                         sc->buf = buf;
357                         sc->buflen = buflen;
358                         continue;
359                 } else if (__predict_false(ret == EAGAIN)) {
360                         /* No more channel packets; done! */
361                         break;
362                 }
363                 KASSERT(ret == 0, ("vmbus_chan_recv_pkt failed: %d", ret));
364
365                 switch (pkt->cph_type) {
366                 case VMBUS_CHANPKT_TYPE_COMP:
367                 case VMBUS_CHANPKT_TYPE_RXBUF:
368                         device_printf(sc->dev, "unhandled event: %d\n",
369                             pkt->cph_type);
370                         break;
371                 case VMBUS_CHANPKT_TYPE_INBAND:
372                         hv_hid_receive(sc, pkt);
373                         break;
374                 default:
375                         device_printf(sc->dev, "unknown event: %d\n",
376                             pkt->cph_type);
377                         break;
378                 }
379         }
380 }
381
382 static int
383 hv_hid_probe(device_t dev)
384 {
385         device_t                        bus;
386         const struct vmbus_ic_desc      *d;
387
388         if (resource_disabled(device_get_name(dev), 0))
389                 return (ENXIO);
390
391         bus = device_get_parent(dev);
392         for (d = vmbus_hid_descs; d->ic_desc != NULL; ++d) {
393                 if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) {
394                         device_set_desc(dev, d->ic_desc);
395                         return (BUS_PROBE_DEFAULT);
396                 }
397         }
398
399         return (ENXIO);
400 }
401
402 static int
403 hv_hid_attach(device_t dev)
404 {
405         device_t        child;
406         hv_hid_sc       *sc;
407         int             ret;
408
409         sc = device_get_softc(dev);
410         sc->dev = dev;
411         mtx_init(&sc->mtx, "hvhid lock", NULL, MTX_DEF);
412         sc->hs_chan = vmbus_get_channel(dev);
413         sc->hs_xact_ctx = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
414             HV_HID_REQ_MAX, HV_HID_RESP_MAX, 0);
415         if (sc->hs_xact_ctx == NULL) {
416                 ret = ENOMEM;
417                 goto out;
418         }
419         sc->buflen = HV_BUFSIZ;
420         sc->buf = malloc(sc->buflen, M_DEVBUF, M_WAITOK | M_ZERO);
421         vmbus_chan_set_readbatch(sc->hs_chan, false);
422         ret = vmbus_chan_open(sc->hs_chan, HV_HID_RINGBUFF_SEND_SZ,
423             HV_HID_RINGBUFF_RECV_SZ, NULL, 0, hv_hid_read_channel, sc);
424         if (ret != 0)
425                 goto out;
426         ret = hv_hid_connect_vsp(sc);
427         if (ret != 0)
428                 goto out;
429
430         /* Wait until we have devinfo (or arbitrary timeout of 3s) */
431         mtx_lock(&sc->mtx);
432         if (sc->rdesc == NULL)
433                 ret = mtx_sleep(sc, &sc->mtx, 0, "hvhid", hz * 3);
434         mtx_unlock(&sc->mtx);
435         if (ret != 0) {
436                 ret = ENODEV;
437                 goto out;
438         }
439         child = device_add_child(sc->dev, "hidbus", -1);
440         if (child == NULL) {
441                 device_printf(sc->dev, "failed to add hidbus\n");
442                 ret = ENOMEM;
443                 goto out;
444         }
445         device_set_ivars(child, &sc->hdi);
446         ret = bus_generic_attach(dev);
447         if (ret != 0)
448                 device_printf(sc->dev, "failed to attach hidbus\n");
449 out:
450         if (ret != 0)
451                 hv_hid_detach(dev);
452         return (ret);
453 }
454
455 static int
456 hv_hid_detach(device_t dev)
457 {
458         hv_hid_sc       *sc;
459         int             ret;
460
461         sc = device_get_softc(dev);
462         ret = device_delete_children(dev);
463         if (ret != 0)
464                 return (ret);
465         if (sc->hs_xact_ctx != NULL)
466                 vmbus_xact_ctx_destroy(sc->hs_xact_ctx);
467         vmbus_chan_close(vmbus_get_channel(dev));
468         free(sc->buf, M_DEVBUF);
469         free(sc->rdesc, M_DEVBUF);
470         mtx_destroy(&sc->mtx);
471
472         return (0);
473 }
474
475 static void
476 hv_hid_intr_setup(device_t dev, hid_intr_t intr, void *ctx,
477     struct hid_rdesc_info *rdesc)
478 {
479         hv_hid_sc       *sc;
480
481         if (intr == NULL)
482                 return;
483
484         sc = device_get_softc(dev);
485         sc->intr = intr;
486         sc->intr_on = false;
487         sc->intr_ctx = ctx;
488         rdesc->rdsize = rdesc->isize;
489 }
490
491 static void
492 hv_hid_intr_unsetup(device_t dev)
493 {
494         hv_hid_sc       *sc;
495
496         sc = device_get_softc(dev);
497         sc->intr = NULL;
498         sc->intr_on = false;
499         sc->intr_ctx = NULL;
500 }
501
502 static int
503 hv_hid_intr_start(device_t dev)
504 {
505         hv_hid_sc       *sc;
506
507         sc = device_get_softc(dev);
508         mtx_lock(&sc->mtx);
509         sc->intr_on = true;
510         mtx_unlock(&sc->mtx);
511         return (0);
512 }
513
514 static int
515 hv_hid_intr_stop(device_t dev)
516 {
517         hv_hid_sc       *sc;
518
519         sc = device_get_softc(dev);
520         mtx_lock(&sc->mtx);
521         sc->intr_on = false;
522         mtx_unlock(&sc->mtx);
523         return (0);
524 }
525
526 static int
527 hv_hid_get_rdesc(device_t dev, void *buf, hid_size_t len)
528 {
529         hv_hid_sc       *sc;
530
531         sc = device_get_softc(dev);
532         if (len < sc->hdi.rdescsize)
533                 return (EMSGSIZE);
534         memcpy(buf, sc->rdesc, len);
535         return (0);
536 }
537
538 static device_method_t hv_hid_methods[] = {
539         DEVMETHOD(device_probe,         hv_hid_probe),
540         DEVMETHOD(device_attach,        hv_hid_attach),
541         DEVMETHOD(device_detach,        hv_hid_detach),
542
543         DEVMETHOD(hid_intr_setup,       hv_hid_intr_setup),
544         DEVMETHOD(hid_intr_unsetup,     hv_hid_intr_unsetup),
545         DEVMETHOD(hid_intr_start,       hv_hid_intr_start),
546         DEVMETHOD(hid_intr_stop,        hv_hid_intr_stop),
547
548         DEVMETHOD(hid_get_rdesc,        hv_hid_get_rdesc),
549         DEVMETHOD_END,
550 };
551
552 static driver_t hv_hid_driver = {
553         .name = "hvhid",
554         .methods = hv_hid_methods,
555         .size = sizeof(hv_hid_sc),
556 };
557
558 DRIVER_MODULE(hv_hid, vmbus, hv_hid_driver, NULL, NULL);
559 MODULE_VERSION(hv_hid, 1);
560 MODULE_DEPEND(hv_hid, hidbus, 1, 1, 1);
561 MODULE_DEPEND(hv_hid, hms, 1, 1, 1);
562 MODULE_DEPEND(hv_hid, vmbus, 1, 1, 1);
563 MODULE_PNP_INFO("Z:classid", vmbus, hv_hid, vmbus_hid_descs_pnp,
564     nitems(vmbus_hid_descs_pnp));