xref: /freebsd/sys/dev/hyperv/input/hv_hid.c (revision 315ee00f)
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, device_t child __unused, hid_intr_t intr,
477     void *ctx, 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, device_t child __unused)
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, device_t child __unused)
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, device_t child __unused)
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, device_t child __unused, void *buf,
528     hid_size_t len)
529 {
530 	hv_hid_sc	*sc;
531 
532 	sc = device_get_softc(dev);
533 	if (len < sc->hdi.rdescsize)
534 		return (EMSGSIZE);
535 	memcpy(buf, sc->rdesc, len);
536 	return (0);
537 }
538 
539 static device_method_t hv_hid_methods[] = {
540 	DEVMETHOD(device_probe,		hv_hid_probe),
541 	DEVMETHOD(device_attach,	hv_hid_attach),
542 	DEVMETHOD(device_detach,	hv_hid_detach),
543 
544 	DEVMETHOD(hid_intr_setup,	hv_hid_intr_setup),
545 	DEVMETHOD(hid_intr_unsetup,	hv_hid_intr_unsetup),
546 	DEVMETHOD(hid_intr_start,	hv_hid_intr_start),
547 	DEVMETHOD(hid_intr_stop,	hv_hid_intr_stop),
548 
549 	DEVMETHOD(hid_get_rdesc,	hv_hid_get_rdesc),
550 	DEVMETHOD_END,
551 };
552 
553 static driver_t hv_hid_driver = {
554 	.name = "hvhid",
555 	.methods = hv_hid_methods,
556 	.size = sizeof(hv_hid_sc),
557 };
558 
559 DRIVER_MODULE(hv_hid, vmbus, hv_hid_driver, NULL, NULL);
560 MODULE_VERSION(hv_hid, 1);
561 MODULE_DEPEND(hv_hid, hidbus, 1, 1, 1);
562 MODULE_DEPEND(hv_hid, hms, 1, 1, 1);
563 MODULE_DEPEND(hv_hid, vmbus, 1, 1, 1);
564 MODULE_PNP_INFO("Z:classid", vmbus, hv_hid, vmbus_hid_descs_pnp,
565     nitems(vmbus_hid_descs_pnp));
566