xref: /freebsd/usr.sbin/bhyve/usb_mouse.c (revision ec99803ad70a757cc104334f745a2985cf60e948)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #include <sys/time.h>
31 
32 #include <machine/vmm_snapshot.h>
33 
34 #include <pthread.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include <dev/usb/usb.h>
40 #include <dev/usb/usbdi.h>
41 
42 #include "usb_emul.h"
43 #include "console.h"
44 #include "bhyvegc.h"
45 #include "debug.h"
46 
47 static int umouse_debug = 0;
48 #define	DPRINTF(params) if (umouse_debug) PRINTLN params
49 #define	WPRINTF(params) PRINTLN params
50 
51 /* USB endpoint context (1-15) for reporting mouse data events*/
52 #define	UMOUSE_INTR_ENDPT	1
53 
54 #define UMOUSE_REPORT_DESC_TYPE	0x22
55 
56 #define	UMOUSE_GET_REPORT	0x01
57 #define	UMOUSE_GET_IDLE		0x02
58 #define	UMOUSE_GET_PROTOCOL	0x03
59 #define	UMOUSE_SET_REPORT	0x09
60 #define	UMOUSE_SET_IDLE		0x0A
61 #define	UMOUSE_SET_PROTOCOL	0x0B
62 
63 #define HSETW(ptr, val)   ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
64 
65 enum {
66 	UMSTR_LANG,
67 	UMSTR_MANUFACTURER,
68 	UMSTR_PRODUCT,
69 	UMSTR_SERIAL,
70 	UMSTR_CONFIG,
71 	UMSTR_MAX
72 };
73 
74 static const char *umouse_desc_strings[] = {
75 	"\x09\x04",
76 	"BHYVE",
77 	"HID Tablet",
78 	"01",
79 	"HID Tablet Device",
80 };
81 
82 struct umouse_hid_descriptor {
83 	uint8_t	bLength;
84 	uint8_t	bDescriptorType;
85 	uint8_t	bcdHID[2];
86 	uint8_t	bCountryCode;
87 	uint8_t	bNumDescriptors;
88 	uint8_t	bReportDescriptorType;
89 	uint8_t	wItemLength[2];
90 } __packed;
91 
92 struct umouse_config_desc {
93 	struct usb_config_descriptor		confd;
94 	struct usb_interface_descriptor		ifcd;
95 	struct umouse_hid_descriptor		hidd;
96 	struct usb_endpoint_descriptor		endpd;
97 	struct usb_endpoint_ss_comp_descriptor	sscompd;
98 } __packed;
99 
100 #define MOUSE_MAX_X	0x8000
101 #define MOUSE_MAX_Y	0x8000
102 
103 static const uint8_t umouse_report_desc[] = {
104 	0x05, 0x01,		/* USAGE_PAGE (Generic Desktop)		*/
105 	0x09, 0x02,		/* USAGE (Mouse)			*/
106 	0xa1, 0x01,		/* COLLECTION (Application) 		*/
107 	0x09, 0x01,		/*   USAGE (Pointer)			*/
108 	0xa1, 0x00,		/*   COLLECTION (Physical)		*/
109 	0x05, 0x09,		/*     USAGE_PAGE (Button)		*/
110 	0x19, 0x01,		/*     USAGE_MINIMUM (Button 1)		*/
111 	0x29, 0x03,		/*     USAGE_MAXIMUM (Button 3)		*/
112 	0x15, 0x00,		/*     LOGICAL_MINIMUM (0)		*/
113 	0x25, 0x01,		/*     LOGICAL_MAXIMUM (1)		*/
114 	0x75, 0x01,		/*     REPORT_SIZE (1)			*/
115 	0x95, 0x03,		/*     REPORT_COUNT (3)			*/
116 	0x81, 0x02,		/*     INPUT (Data,Var,Abs); 3 buttons	*/
117 	0x75, 0x05,		/*     REPORT_SIZE (5)			*/
118 	0x95, 0x01,		/*     REPORT_COUNT (1)			*/
119 	0x81, 0x03,		/*     INPUT (Cnst,Var,Abs); padding	*/
120 	0x05, 0x01,		/*     USAGE_PAGE (Generic Desktop)	*/
121 	0x09, 0x30,		/*     USAGE (X)			*/
122 	0x09, 0x31,		/*     USAGE (Y)			*/
123 	0x35, 0x00,		/*     PHYSICAL_MINIMUM (0)		*/
124 	0x46, 0xff, 0x7f,	/*     PHYSICAL_MAXIMUM (0x7fff)	*/
125 	0x15, 0x00,		/*     LOGICAL_MINIMUM (0)		*/
126 	0x26, 0xff, 0x7f,	/*     LOGICAL_MAXIMUM (0x7fff)		*/
127 	0x75, 0x10,		/*     REPORT_SIZE (16)			*/
128 	0x95, 0x02,		/*     REPORT_COUNT (2)			*/
129 	0x81, 0x02,		/*     INPUT (Data,Var,Abs)		*/
130 	0x05, 0x01,		/*     USAGE Page (Generic Desktop)	*/
131 	0x09, 0x38,		/*     USAGE (Wheel)			*/
132 	0x35, 0x00,		/*     PHYSICAL_MINIMUM (0)		*/
133 	0x45, 0x00,		/*     PHYSICAL_MAXIMUM (0)		*/
134 	0x15, 0x81,		/*     LOGICAL_MINIMUM (-127)		*/
135 	0x25, 0x7f,		/*     LOGICAL_MAXIMUM (127)		*/
136 	0x75, 0x08,		/*     REPORT_SIZE (8)			*/
137 	0x95, 0x01,		/*     REPORT_COUNT (1)			*/
138 	0x81, 0x06,		/*     INPUT (Data,Var,Rel)		*/
139 	0xc0,			/*   END_COLLECTION			*/
140 	0xc0			/* END_COLLECTION			*/
141 };
142 
143 struct umouse_report {
144 	uint8_t	buttons;	/* bits: 0 left, 1 right, 2 middle */
145 	int16_t	x;		/* x position */
146 	int16_t	y;		/* y position */
147 	int8_t	z;		/* z wheel position */
148 } __packed;
149 
150 
151 #define	MSETW(ptr, val)	ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
152 
153 static struct usb_device_descriptor umouse_dev_desc = {
154 	.bLength = sizeof(umouse_dev_desc),
155 	.bDescriptorType = UDESC_DEVICE,
156 	MSETW(.bcdUSB, UD_USB_3_0),
157 	.bMaxPacketSize = 9,			/* max pkt size, 2^9 = 512 */
158 	MSETW(.idVendor, 0xFB5D),		/* vendor */
159 	MSETW(.idProduct, 0x0001),		/* product */
160 	MSETW(.bcdDevice, 0),			/* device version */
161 	.iManufacturer = UMSTR_MANUFACTURER,
162 	.iProduct = UMSTR_PRODUCT,
163 	.iSerialNumber = UMSTR_SERIAL,
164 	.bNumConfigurations = 1,
165 };
166 
167 static struct umouse_config_desc umouse_confd = {
168 	.confd = {
169 		.bLength = sizeof(umouse_confd.confd),
170 		.bDescriptorType = UDESC_CONFIG,
171 		.wTotalLength[0] = sizeof(umouse_confd),
172 		.bNumInterface = 1,
173 		.bConfigurationValue = 1,
174 		.iConfiguration = UMSTR_CONFIG,
175 		.bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP,
176 		.bMaxPower = 0,
177 	},
178 	.ifcd = {
179 		.bLength = sizeof(umouse_confd.ifcd),
180 		.bDescriptorType = UDESC_INTERFACE,
181 		.bNumEndpoints = 1,
182 		.bInterfaceClass = UICLASS_HID,
183 		.bInterfaceSubClass = UISUBCLASS_BOOT,
184 		.bInterfaceProtocol = UIPROTO_MOUSE,
185 	},
186 	.hidd = {
187 		.bLength = sizeof(umouse_confd.hidd),
188 		.bDescriptorType = 0x21,
189 		.bcdHID = { 0x01, 0x10 },
190 		.bCountryCode = 0,
191 		.bNumDescriptors = 1,
192 		.bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE,
193 		.wItemLength = { sizeof(umouse_report_desc), 0 },
194 	},
195 	.endpd = {
196 		.bLength = sizeof(umouse_confd.endpd),
197 		.bDescriptorType = UDESC_ENDPOINT,
198 		.bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT,
199 		.bmAttributes = UE_INTERRUPT,
200 		.wMaxPacketSize[0] = 8,
201 		.bInterval = 0xA,
202 	},
203 	.sscompd = {
204 		.bLength = sizeof(umouse_confd.sscompd),
205 		.bDescriptorType = UDESC_ENDPOINT_SS_COMP,
206 		.bMaxBurst = 0,
207 		.bmAttributes = 0,
208 		MSETW(.wBytesPerInterval, 0),
209 	},
210 };
211 
212 
213 struct umouse_bos_desc {
214 	struct usb_bos_descriptor		bosd;
215 	struct usb_devcap_ss_descriptor		usbssd;
216 } __packed;
217 
218 
219 static struct umouse_bos_desc umouse_bosd = {
220 	.bosd = {
221 		.bLength = sizeof(umouse_bosd.bosd),
222 		.bDescriptorType = UDESC_BOS,
223 		HSETW(.wTotalLength, sizeof(umouse_bosd)),
224 		.bNumDeviceCaps = 1,
225 	},
226 	.usbssd = {
227 		.bLength = sizeof(umouse_bosd.usbssd),
228 		.bDescriptorType = UDESC_DEVICE_CAPABILITY,
229 		.bDevCapabilityType = 3,
230 		.bmAttributes = 0,
231 		HSETW(.wSpeedsSupported, 0x08),
232 		.bFunctionalitySupport = 3,
233 		.bU1DevExitLat = 0xa,   /* dummy - not used */
234 		.wU2DevExitLat = { 0x20, 0x00 },
235 	}
236 };
237 
238 
239 struct umouse_softc {
240 	struct usb_hci *hci;
241 
242 	struct umouse_report um_report;
243 	int	newdata;
244 	struct {
245 		uint8_t	idle;
246 		uint8_t	protocol;
247 		uint8_t	feature;
248 	} hid;
249 
250 	pthread_mutex_t	mtx;
251 	pthread_mutex_t	ev_mtx;
252 	int		polling;
253 	struct timeval	prev_evt;
254 };
255 
256 static void
umouse_event(uint8_t button,int x,int y,void * arg)257 umouse_event(uint8_t button, int x, int y, void *arg)
258 {
259 	struct umouse_softc *sc;
260 	struct bhyvegc_image *gc;
261 
262 	gc = console_get_image();
263 	if (gc == NULL) {
264 		/* not ready */
265 		return;
266 	}
267 
268 	sc = arg;
269 
270 	pthread_mutex_lock(&sc->mtx);
271 
272 	sc->um_report.buttons = 0;
273 	sc->um_report.z = 0;
274 
275 	if (button & 0x01)
276 		sc->um_report.buttons |= 0x01;	/* left */
277 	if (button & 0x02)
278 		sc->um_report.buttons |= 0x04;	/* middle */
279 	if (button & 0x04)
280 		sc->um_report.buttons |= 0x02;	/* right */
281 	if (button & 0x8)
282 		sc->um_report.z = 1;
283 	if (button & 0x10)
284 		sc->um_report.z = -1;
285 
286 	/* scale coords to mouse resolution */
287 	sc->um_report.x = MOUSE_MAX_X * x / gc->width;
288 	sc->um_report.y = MOUSE_MAX_Y * y / gc->height;
289 	sc->newdata = 1;
290 	pthread_mutex_unlock(&sc->mtx);
291 
292 	pthread_mutex_lock(&sc->ev_mtx);
293 	sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT);
294 	pthread_mutex_unlock(&sc->ev_mtx);
295 }
296 
297 static void *
umouse_probe(struct usb_hci * hci,nvlist_t * nvl __unused)298 umouse_probe(struct usb_hci *hci, nvlist_t *nvl __unused)
299 {
300 	struct umouse_softc *sc;
301 
302 	sc = calloc(1, sizeof(struct umouse_softc));
303 	sc->hci = hci;
304 
305 	return (sc);
306 }
307 
308 static int
umouse_init(void * scarg)309 umouse_init(void *scarg)
310 {
311 	struct umouse_softc *sc = (struct umouse_softc *)scarg;
312 
313 	sc->hid.protocol = 1;	/* REPORT protocol */
314 	pthread_mutex_init(&sc->mtx, NULL);
315 	pthread_mutex_init(&sc->ev_mtx, NULL);
316 
317 	console_ptr_register(umouse_event, sc, 10);
318 
319 	return (0);
320 }
321 
322 #define	UREQ(x,y)	((x) | ((y) << 8))
323 
324 static int
umouse_request(void * scarg,struct usb_data_xfer * xfer)325 umouse_request(void *scarg, struct usb_data_xfer *xfer)
326 {
327 	struct umouse_softc *sc;
328 	struct usb_data_xfer_block *data;
329 	const char *str;
330 	uint16_t value;
331 	uint16_t index;
332 	uint16_t len;
333 	uint16_t slen;
334 	uint8_t *udata;
335 	int	err;
336 	int	i, idx;
337 	int	eshort;
338 
339 	sc = scarg;
340 
341 	data = NULL;
342 	udata = NULL;
343 	idx = xfer->head;
344 	for (i = 0; i < xfer->ndata; i++) {
345 		xfer->data[idx].bdone = 0;
346 		if (data == NULL && USB_DATA_OK(xfer,i)) {
347 			data = &xfer->data[idx];
348 			udata = data->buf;
349 		}
350 
351 		xfer->data[idx].processed = 1;
352 		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
353 	}
354 
355 	err = USB_ERR_NORMAL_COMPLETION;
356 	eshort = 0;
357 
358 	if (!xfer->ureq) {
359 		DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
360 		goto done;
361 	}
362 
363 	value = UGETW(xfer->ureq->wValue);
364 	index = UGETW(xfer->ureq->wIndex);
365 	len = UGETW(xfer->ureq->wLength);
366 
367 	DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
368 	         "idx 0x%x, len %u",
369 	         sc->hci->hci_port, xfer->ureq->bmRequestType,
370 	         xfer->ureq->bRequest, value, index, len));
371 
372 	switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
373 	case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
374 		DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
375 		if (!data)
376 			break;
377 
378 		*udata = umouse_confd.confd.bConfigurationValue;
379 		data->blen = len > 0 ? len - 1 : 0;
380 		eshort = data->blen > 0;
381 		data->bdone += 1;
382 		break;
383 
384 	case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
385 		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
386 		        value >> 8));
387 		if (!data)
388 			break;
389 
390 		switch (value >> 8) {
391 		case UDESC_DEVICE:
392 			DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
393 			         "sizeof(umouse_dev_desc) %lu",
394 			         len, sizeof(umouse_dev_desc)));
395 			if ((value & 0xFF) != 0) {
396 				err = USB_ERR_STALLED;
397 				goto done;
398 			}
399 			if (len > sizeof(umouse_dev_desc)) {
400 				data->blen = len - sizeof(umouse_dev_desc);
401 				len = sizeof(umouse_dev_desc);
402 			} else
403 				data->blen = 0;
404 			memcpy(data->buf, &umouse_dev_desc, len);
405 			data->bdone += len;
406 			break;
407 
408 		case UDESC_CONFIG:
409 			DPRINTF(("umouse: (->UDESC_CONFIG)"));
410 			if ((value & 0xFF) != 0) {
411 				err = USB_ERR_STALLED;
412 				goto done;
413 			}
414 			if (len > sizeof(umouse_confd)) {
415 				data->blen = len - sizeof(umouse_confd);
416 				len = sizeof(umouse_confd);
417 			} else
418 				data->blen = 0;
419 
420 			memcpy(data->buf, &umouse_confd, len);
421 			data->bdone += len;
422 			break;
423 
424 		case UDESC_STRING:
425 			DPRINTF(("umouse: (->UDESC_STRING)"));
426 			str = NULL;
427 			if ((value & 0xFF) < UMSTR_MAX)
428 				str = umouse_desc_strings[value & 0xFF];
429 			else
430 				goto done;
431 
432 			if ((value & 0xFF) == UMSTR_LANG) {
433 				udata[0] = 4;
434 				udata[1] = UDESC_STRING;
435 				data->blen = len - 2;
436 				len -= 2;
437 				data->bdone += 2;
438 
439 				if (len >= 2) {
440 					udata[2] = str[0];
441 					udata[3] = str[1];
442 					data->blen -= 2;
443 					data->bdone += 2;
444 				} else
445 					data->blen = 0;
446 
447 				goto done;
448 			}
449 
450 			slen = 2 + strlen(str) * 2;
451 			udata[0] = slen;
452 			udata[1] = UDESC_STRING;
453 
454 			if (len > slen) {
455 				data->blen = len - slen;
456 				len = slen;
457 			} else
458 				data->blen = 0;
459 			for (i = 2; i < len; i += 2) {
460 				udata[i] = *str++;
461 				udata[i+1] = '\0';
462 			}
463 			data->bdone += slen;
464 
465 			break;
466 
467 		case UDESC_BOS:
468 			DPRINTF(("umouse: USB3 BOS"));
469 			if (len > sizeof(umouse_bosd)) {
470 				data->blen = len - sizeof(umouse_bosd);
471 				len = sizeof(umouse_bosd);
472 			} else
473 				data->blen = 0;
474 			memcpy(udata, &umouse_bosd, len);
475 			data->bdone += len;
476 			break;
477 
478 		default:
479 			DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
480 			err = USB_ERR_STALLED;
481 			goto done;
482 		}
483 		eshort = data->blen > 0;
484 		break;
485 
486 	case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
487 		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
488 		         "0x%x", (value >> 8)));
489 		if (!data)
490 			break;
491 
492 		switch (value >> 8) {
493 		case UMOUSE_REPORT_DESC_TYPE:
494 			if (len > sizeof(umouse_report_desc)) {
495 				data->blen = len - sizeof(umouse_report_desc);
496 				len = sizeof(umouse_report_desc);
497 			} else
498 				data->blen = 0;
499 			memcpy(data->buf, umouse_report_desc, len);
500 			data->bdone += len;
501 			break;
502 		default:
503 			DPRINTF(("umouse: IO ERROR"));
504 			err = USB_ERR_STALLED;
505 			goto done;
506 		}
507 		eshort = data->blen > 0;
508 		break;
509 
510 	case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
511 		DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
512 		if (index != 0) {
513 			DPRINTF(("umouse get_interface, invalid index %d",
514 			        index));
515 			err = USB_ERR_STALLED;
516 			goto done;
517 		}
518 
519 		if (!data)
520 			break;
521 
522 		if (len > 0) {
523 			*udata = 0;
524 			data->blen = len - 1;
525 		}
526 		eshort = data->blen > 0;
527 		data->bdone += 1;
528 		break;
529 
530 	case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
531 		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
532 		if (data != NULL && len > 1) {
533 			if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
534 				USETW(udata, UDS_REMOTE_WAKEUP);
535 			else
536 				USETW(udata, 0);
537 			data->blen = len - 2;
538 			data->bdone += 2;
539 		}
540 
541 		eshort = data->blen > 0;
542 		break;
543 
544 	case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
545 	case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
546 		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
547 		if (data != NULL && len > 1) {
548 			USETW(udata, 0);
549 			data->blen = len - 2;
550 			data->bdone += 2;
551 		}
552 		eshort = data->blen > 0;
553 		break;
554 
555 	case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
556 		/* XXX Controller should've handled this */
557 		DPRINTF(("umouse set address %u", value));
558 		break;
559 
560 	case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
561 		DPRINTF(("umouse set config %u", value));
562 		break;
563 
564 	case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
565 		DPRINTF(("umouse set descriptor %u", value));
566 		break;
567 
568 
569 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
570 		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
571 		if (value == UF_DEVICE_REMOTE_WAKEUP)
572 			sc->hid.feature = 0;
573 		break;
574 
575 	case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
576 		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
577 		if (value == UF_DEVICE_REMOTE_WAKEUP)
578 			sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
579 		break;
580 
581 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
582 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
583 	case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
584 	case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
585 		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
586 		err = USB_ERR_STALLED;
587 		goto done;
588 
589 	case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
590 		DPRINTF(("umouse set interface %u", value));
591 		break;
592 
593 	case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
594 		DPRINTF(("umouse set isoch delay %u", value));
595 		break;
596 
597 	case UREQ(UR_SET_SEL, 0):
598 		DPRINTF(("umouse set sel"));
599 		break;
600 
601 	case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
602 		DPRINTF(("umouse synch frame"));
603 		break;
604 
605 	/* HID device requests */
606 
607 	case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
608 		DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
609 		         "0x%x", (value >> 8)));
610 		if (!data)
611 			break;
612 
613 		if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
614 			/* TODO read from backend */
615 
616 			if (len > sizeof(sc->um_report)) {
617 				data->blen = len - sizeof(sc->um_report);
618 				len = sizeof(sc->um_report);
619 			} else
620 				data->blen = 0;
621 
622 			memcpy(data->buf, &sc->um_report, len);
623 			data->bdone += len;
624 		} else {
625 			err = USB_ERR_STALLED;
626 			goto done;
627 		}
628 		eshort = data->blen > 0;
629 		break;
630 
631 	case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
632 		if (data != NULL && len > 0) {
633 			*udata = sc->hid.idle;
634 			data->blen = len - 1;
635 			data->bdone += 1;
636 		}
637 		eshort = data->blen > 0;
638 		break;
639 
640 	case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
641 		if (data != NULL && len > 0) {
642 			*udata = sc->hid.protocol;
643 			data->blen = len - 1;
644 			data->bdone += 1;
645 		}
646 		eshort = data->blen > 0;
647 		break;
648 
649 	case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
650 		DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
651 		break;
652 
653 	case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
654 		sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
655 		DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
656 		        sc->hid.idle));
657 		break;
658 
659 	case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
660 		sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
661 		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
662 		        sc->hid.protocol));
663 		break;
664 
665 	default:
666 		DPRINTF(("**** umouse request unhandled"));
667 		err = USB_ERR_STALLED;
668 		break;
669 	}
670 
671 done:
672 	if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
673 	    (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
674 		data->blen = 0;
675 	else if (eshort)
676 		err = USB_ERR_SHORT_XFER;
677 
678 	DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
679 	        err, (data ? data->blen : 0), (data ? data->bdone : 0)));
680 
681 	return (err);
682 }
683 
684 static int
umouse_data_handler(void * scarg,struct usb_data_xfer * xfer,int dir,int epctx)685 umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
686      int epctx)
687 {
688 	struct umouse_softc *sc;
689 	struct usb_data_xfer_block *data;
690 	uint8_t *udata;
691 	int len, i, idx;
692 	int err;
693 
694 	DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
695 	        dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
696 
697 
698 	/* find buffer to add data */
699 	udata = NULL;
700 	err = USB_ERR_NORMAL_COMPLETION;
701 
702 	/* handle xfer at first unprocessed item with buffer */
703 	data = NULL;
704 	idx = xfer->head;
705 	for (i = 0; i < xfer->ndata; i++) {
706 		data = &xfer->data[idx];
707 		if (data->buf != NULL && data->blen != 0) {
708 			break;
709 		} else {
710 			data->processed = 1;
711 			data = NULL;
712 		}
713 		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
714 	}
715 	if (!data)
716 		goto done;
717 
718 	udata = data->buf;
719 	len = data->blen;
720 
721 	if (udata == NULL) {
722 		DPRINTF(("umouse no buffer provided for input"));
723 		err = USB_ERR_NOMEM;
724 		goto done;
725 	}
726 
727 	sc = scarg;
728 
729 	if (dir) {
730 
731 		pthread_mutex_lock(&sc->mtx);
732 
733 		if (!sc->newdata) {
734 			err = USB_ERR_CANCELLED;
735 			USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
736 			pthread_mutex_unlock(&sc->mtx);
737 			goto done;
738 		}
739 
740 		if (sc->polling) {
741 			err = USB_ERR_STALLED;
742 			USB_DATA_SET_ERRCODE(data, USB_STALL);
743 			pthread_mutex_unlock(&sc->mtx);
744 			goto done;
745 		}
746 		sc->polling = 1;
747 
748 		if (len > 0) {
749 			sc->newdata = 0;
750 
751 			data->processed = 1;
752 			data->bdone += 6;
753 			memcpy(udata, &sc->um_report, 6);
754 			data->blen = len - 6;
755 			if (data->blen > 0)
756 				err = USB_ERR_SHORT_XFER;
757 		}
758 
759 		sc->polling = 0;
760 		pthread_mutex_unlock(&sc->mtx);
761 	} else {
762 		USB_DATA_SET_ERRCODE(data, USB_STALL);
763 		err = USB_ERR_STALLED;
764 	}
765 
766 done:
767 	return (err);
768 }
769 
770 static int
umouse_reset(void * scarg)771 umouse_reset(void *scarg)
772 {
773 	struct umouse_softc *sc;
774 
775 	sc = scarg;
776 
777 	sc->newdata = 0;
778 
779 	return (0);
780 }
781 
782 static int
umouse_remove(void * scarg __unused)783 umouse_remove(void *scarg __unused)
784 {
785 	return (0);
786 }
787 
788 static int
umouse_stop(void * scarg __unused)789 umouse_stop(void *scarg __unused)
790 {
791 	return (0);
792 }
793 
794 #ifdef BHYVE_SNAPSHOT
795 static int
umouse_snapshot(void * scarg,struct vm_snapshot_meta * meta)796 umouse_snapshot(void *scarg, struct vm_snapshot_meta *meta)
797 {
798 	int ret;
799 	struct umouse_softc *sc;
800 
801 	sc = scarg;
802 
803 	SNAPSHOT_VAR_OR_LEAVE(sc->um_report, meta, ret, done);
804 	SNAPSHOT_VAR_OR_LEAVE(sc->newdata, meta, ret, done);
805 	SNAPSHOT_VAR_OR_LEAVE(sc->hid.idle, meta, ret, done);
806 	SNAPSHOT_VAR_OR_LEAVE(sc->hid.protocol, meta, ret, done);
807 	SNAPSHOT_VAR_OR_LEAVE(sc->hid.feature, meta, ret, done);
808 
809 	SNAPSHOT_VAR_OR_LEAVE(sc->polling, meta, ret, done);
810 	SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_sec, meta, ret, done);
811 	SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_usec, meta, ret, done);
812 
813 done:
814 	return (ret);
815 }
816 #endif
817 
818 static struct usb_devemu ue_mouse = {
819 	.ue_emu =	"tablet",
820 	.ue_usbver =	3,
821 	.ue_usbspeed =	USB_SPEED_HIGH,
822 	.ue_probe =	umouse_probe,
823 	.ue_init =	umouse_init,
824 	.ue_request =	umouse_request,
825 	.ue_data =	umouse_data_handler,
826 	.ue_reset =	umouse_reset,
827 	.ue_remove =	umouse_remove,
828 	.ue_stop =	umouse_stop,
829 #ifdef BHYVE_SNAPSHOT
830 	.ue_snapshot =	umouse_snapshot,
831 #endif
832 };
833 USB_EMUL_SET(ue_mouse);
834