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