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