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