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 <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
47static 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
65enum {
66	UMSTR_LANG,
67	UMSTR_MANUFACTURER,
68	UMSTR_PRODUCT,
69	UMSTR_SERIAL,
70	UMSTR_CONFIG,
71	UMSTR_MAX
72};
73
74static const char *umouse_desc_strings[] = {
75	"\x04\x09",
76	"BHYVE",
77	"HID Tablet",
78	"01",
79	"HID Tablet Device",
80};
81
82struct 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
92struct 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
103static 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
143struct 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
153static 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 = 8,			/* max packet size */
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
167static 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
213struct umouse_bos_desc {
214	struct usb_bos_descriptor		bosd;
215	struct usb_devcap_ss_descriptor		usbssd;
216} __packed;
217
218
219struct 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
239struct umouse_softc {
240	struct usb_hci *hci;
241
242	char	*opt;
243
244	struct umouse_report um_report;
245	int	newdata;
246	struct {
247		uint8_t	idle;
248		uint8_t	protocol;
249		uint8_t	feature;
250	} hid;
251
252	pthread_mutex_t	mtx;
253	pthread_mutex_t	ev_mtx;
254	int		polling;
255	struct timeval	prev_evt;
256};
257
258static void
259umouse_event(uint8_t button, int x, int y, void *arg)
260{
261	struct umouse_softc *sc;
262	struct bhyvegc_image *gc;
263
264	gc = console_get_image();
265	if (gc == NULL) {
266		/* not ready */
267		return;
268	}
269
270	sc = arg;
271
272	pthread_mutex_lock(&sc->mtx);
273
274	sc->um_report.buttons = 0;
275	sc->um_report.z = 0;
276
277	if (button & 0x01)
278		sc->um_report.buttons |= 0x01;	/* left */
279	if (button & 0x02)
280		sc->um_report.buttons |= 0x04;	/* middle */
281	if (button & 0x04)
282		sc->um_report.buttons |= 0x02;	/* right */
283	if (button & 0x8)
284		sc->um_report.z = 1;
285	if (button & 0x10)
286		sc->um_report.z = -1;
287
288	/* scale coords to mouse resolution */
289	sc->um_report.x = MOUSE_MAX_X * x / gc->width;
290	sc->um_report.y = MOUSE_MAX_Y * y / gc->height;
291	sc->newdata = 1;
292	pthread_mutex_unlock(&sc->mtx);
293
294	pthread_mutex_lock(&sc->ev_mtx);
295	sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT);
296	pthread_mutex_unlock(&sc->ev_mtx);
297}
298
299static void *
300umouse_init(struct usb_hci *hci, char *opt)
301{
302	struct umouse_softc *sc;
303
304	sc = calloc(1, sizeof(struct umouse_softc));
305	sc->hci = hci;
306
307	sc->hid.protocol = 1;	/* REPORT protocol */
308	sc->opt = strdup(opt);
309	pthread_mutex_init(&sc->mtx, NULL);
310	pthread_mutex_init(&sc->ev_mtx, NULL);
311
312	console_ptr_register(umouse_event, sc, 10);
313
314	return (sc);
315}
316
317#define	UREQ(x,y)	((x) | ((y) << 8))
318
319static int
320umouse_request(void *scarg, struct usb_data_xfer *xfer)
321{
322	struct umouse_softc *sc;
323	struct usb_data_xfer_block *data;
324	const char *str;
325	uint16_t value;
326	uint16_t index;
327	uint16_t len;
328	uint16_t slen;
329	uint8_t *udata;
330	int	err;
331	int	i, idx;
332	int	eshort;
333
334	sc = scarg;
335
336	data = NULL;
337	udata = NULL;
338	idx = xfer->head;
339	for (i = 0; i < xfer->ndata; i++) {
340		xfer->data[idx].bdone = 0;
341		if (data == NULL && USB_DATA_OK(xfer,i)) {
342			data = &xfer->data[idx];
343			udata = data->buf;
344		}
345
346		xfer->data[idx].processed = 1;
347		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
348	}
349
350	err = USB_ERR_NORMAL_COMPLETION;
351	eshort = 0;
352
353	if (!xfer->ureq) {
354		DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
355		goto done;
356	}
357
358	value = UGETW(xfer->ureq->wValue);
359	index = UGETW(xfer->ureq->wIndex);
360	len = UGETW(xfer->ureq->wLength);
361
362	DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
363	         "idx 0x%x, len %u",
364	         sc->hci->hci_port, xfer->ureq->bmRequestType,
365	         xfer->ureq->bRequest, value, index, len));
366
367	switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
368	case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
369		DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
370		if (!data)
371			break;
372
373		*udata = umouse_confd.confd.bConfigurationValue;
374		data->blen = len > 0 ? len - 1 : 0;
375		eshort = data->blen > 0;
376		data->bdone += 1;
377		break;
378
379	case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
380		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
381		        value >> 8));
382		if (!data)
383			break;
384
385		switch (value >> 8) {
386		case UDESC_DEVICE:
387			DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
388			         "sizeof(umouse_dev_desc) %lu",
389			         len, sizeof(umouse_dev_desc)));
390			if ((value & 0xFF) != 0) {
391				err = USB_ERR_IOERROR;
392				goto done;
393			}
394			if (len > sizeof(umouse_dev_desc)) {
395				data->blen = len - sizeof(umouse_dev_desc);
396				len = sizeof(umouse_dev_desc);
397			} else
398				data->blen = 0;
399			memcpy(data->buf, &umouse_dev_desc, len);
400			data->bdone += len;
401			break;
402
403		case UDESC_CONFIG:
404			DPRINTF(("umouse: (->UDESC_CONFIG)"));
405			if ((value & 0xFF) != 0) {
406				err = USB_ERR_IOERROR;
407				goto done;
408			}
409			if (len > sizeof(umouse_confd)) {
410				data->blen = len - sizeof(umouse_confd);
411				len = sizeof(umouse_confd);
412			} else
413				data->blen = 0;
414
415			memcpy(data->buf, &umouse_confd, len);
416			data->bdone += len;
417			break;
418
419		case UDESC_STRING:
420			DPRINTF(("umouse: (->UDESC_STRING)"));
421			str = NULL;
422			if ((value & 0xFF) < UMSTR_MAX)
423				str = umouse_desc_strings[value & 0xFF];
424			else
425				goto done;
426
427			if ((value & 0xFF) == UMSTR_LANG) {
428				udata[0] = 4;
429				udata[1] = UDESC_STRING;
430				data->blen = len - 2;
431				len -= 2;
432				data->bdone += 2;
433
434				if (len >= 2) {
435					udata[2] = str[0];
436					udata[3] = str[1];
437					data->blen -= 2;
438					data->bdone += 2;
439				} else
440					data->blen = 0;
441
442				goto done;
443			}
444
445			slen = 2 + strlen(str) * 2;
446			udata[0] = slen;
447			udata[1] = UDESC_STRING;
448
449			if (len > slen) {
450				data->blen = len - slen;
451				len = slen;
452			} else
453				data->blen = 0;
454			for (i = 2; i < len; i += 2) {
455				udata[i] = *str++;
456				udata[i+1] = '\0';
457			}
458			data->bdone += slen;
459
460			break;
461
462		case UDESC_BOS:
463			DPRINTF(("umouse: USB3 BOS"));
464			if (len > sizeof(umouse_bosd)) {
465				data->blen = len - sizeof(umouse_bosd);
466				len = sizeof(umouse_bosd);
467			} else
468				data->blen = 0;
469			memcpy(udata, &umouse_bosd, len);
470			data->bdone += len;
471			break;
472
473		default:
474			DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
475			err = USB_ERR_IOERROR;
476			goto done;
477		}
478		eshort = data->blen > 0;
479		break;
480
481	case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
482		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
483		         "0x%x", (value >> 8)));
484		if (!data)
485			break;
486
487		switch (value >> 8) {
488		case UMOUSE_REPORT_DESC_TYPE:
489			if (len > sizeof(umouse_report_desc)) {
490				data->blen = len - sizeof(umouse_report_desc);
491				len = sizeof(umouse_report_desc);
492			} else
493				data->blen = 0;
494			memcpy(data->buf, umouse_report_desc, len);
495			data->bdone += len;
496			break;
497		default:
498			DPRINTF(("umouse: IO ERROR"));
499			err = USB_ERR_IOERROR;
500			goto done;
501		}
502		eshort = data->blen > 0;
503		break;
504
505	case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
506		DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
507		if (index != 0) {
508			DPRINTF(("umouse get_interface, invalid index %d",
509			        index));
510			err = USB_ERR_IOERROR;
511			goto done;
512		}
513
514		if (!data)
515			break;
516
517		if (len > 0) {
518			*udata = 0;
519			data->blen = len - 1;
520		}
521		eshort = data->blen > 0;
522		data->bdone += 1;
523		break;
524
525	case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
526		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
527		if (data != NULL && len > 1) {
528			if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
529				USETW(udata, UDS_REMOTE_WAKEUP);
530			else
531				USETW(udata, 0);
532			data->blen = len - 2;
533			data->bdone += 2;
534		}
535
536		eshort = data->blen > 0;
537		break;
538
539	case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
540	case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
541		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
542		if (data != NULL && len > 1) {
543			USETW(udata, 0);
544			data->blen = len - 2;
545			data->bdone += 2;
546		}
547		eshort = data->blen > 0;
548		break;
549
550	case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
551		/* XXX Controller should've handled this */
552		DPRINTF(("umouse set address %u", value));
553		break;
554
555	case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
556		DPRINTF(("umouse set config %u", value));
557		break;
558
559	case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
560		DPRINTF(("umouse set descriptor %u", value));
561		break;
562
563
564	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
565		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
566		if (value == UF_DEVICE_REMOTE_WAKEUP)
567			sc->hid.feature = 0;
568		break;
569
570	case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
571		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
572		if (value == UF_DEVICE_REMOTE_WAKEUP)
573			sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
574		break;
575
576	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
577	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
578	case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
579	case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
580		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
581		err = USB_ERR_IOERROR;
582		goto done;
583
584	case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
585		DPRINTF(("umouse set interface %u", value));
586		break;
587
588	case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
589		DPRINTF(("umouse set isoch delay %u", value));
590		break;
591
592	case UREQ(UR_SET_SEL, 0):
593		DPRINTF(("umouse set sel"));
594		break;
595
596	case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
597		DPRINTF(("umouse synch frame"));
598		break;
599
600	/* HID device requests */
601
602	case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
603		DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
604		         "0x%x", (value >> 8)));
605		if (!data)
606			break;
607
608		if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
609			/* TODO read from backend */
610
611			if (len > sizeof(sc->um_report)) {
612				data->blen = len - sizeof(sc->um_report);
613				len = sizeof(sc->um_report);
614			} else
615				data->blen = 0;
616
617			memcpy(data->buf, &sc->um_report, len);
618			data->bdone += len;
619		} else {
620			err = USB_ERR_IOERROR;
621			goto done;
622		}
623		eshort = data->blen > 0;
624		break;
625
626	case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
627		if (data != NULL && len > 0) {
628			*udata = sc->hid.idle;
629			data->blen = len - 1;
630			data->bdone += 1;
631		}
632		eshort = data->blen > 0;
633		break;
634
635	case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
636		if (data != NULL && len > 0) {
637			*udata = sc->hid.protocol;
638			data->blen = len - 1;
639			data->bdone += 1;
640		}
641		eshort = data->blen > 0;
642		break;
643
644	case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
645		DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
646		break;
647
648	case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
649		sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
650		DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
651		        sc->hid.idle));
652		break;
653
654	case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
655		sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
656		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
657		        sc->hid.protocol));
658		break;
659
660	default:
661		DPRINTF(("**** umouse request unhandled"));
662		err = USB_ERR_IOERROR;
663		break;
664	}
665
666done:
667/* UT_WRITE is 0, so this is condition is never true. */
668#ifdef __FreeBSD__
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#else
675	if (eshort)
676		err = USB_ERR_SHORT_XFER;
677#endif
678
679
680	DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
681	        err, (data ? data->blen : 0), (data ? data->bdone : 0)));
682
683	return (err);
684}
685
686static int
687umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
688     int epctx)
689{
690	struct umouse_softc *sc;
691	struct usb_data_xfer_block *data;
692	uint8_t *udata;
693	int len, i, idx;
694	int err;
695
696	DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
697	        dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
698
699
700	/* find buffer to add data */
701	udata = NULL;
702	err = USB_ERR_NORMAL_COMPLETION;
703
704	/* handle xfer at first unprocessed item with buffer */
705	data = NULL;
706	idx = xfer->head;
707	for (i = 0; i < xfer->ndata; i++) {
708		data = &xfer->data[idx];
709		if (data->buf != NULL && data->blen != 0) {
710			break;
711		} else {
712			data->processed = 1;
713			data = NULL;
714		}
715		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
716	}
717	if (!data)
718		goto done;
719
720	udata = data->buf;
721	len = data->blen;
722
723	if (udata == NULL) {
724		DPRINTF(("umouse no buffer provided for input"));
725		err = USB_ERR_NOMEM;
726		goto done;
727	}
728
729	sc = scarg;
730
731	if (dir) {
732
733		pthread_mutex_lock(&sc->mtx);
734
735		if (!sc->newdata) {
736			err = USB_ERR_CANCELLED;
737			USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
738			pthread_mutex_unlock(&sc->mtx);
739			goto done;
740		}
741
742		if (sc->polling) {
743			err = USB_ERR_STALLED;
744			USB_DATA_SET_ERRCODE(data, USB_STALL);
745			pthread_mutex_unlock(&sc->mtx);
746			goto done;
747		}
748		sc->polling = 1;
749
750		if (len > 0) {
751			sc->newdata = 0;
752
753			data->processed = 1;
754			data->bdone += 6;
755			memcpy(udata, &sc->um_report, 6);
756			data->blen = len - 6;
757			if (data->blen > 0)
758				err = USB_ERR_SHORT_XFER;
759		}
760
761		sc->polling = 0;
762		pthread_mutex_unlock(&sc->mtx);
763	} else {
764		USB_DATA_SET_ERRCODE(data, USB_STALL);
765		err = USB_ERR_STALLED;
766	}
767
768done:
769	return (err);
770}
771
772static int
773umouse_reset(void *scarg)
774{
775	struct umouse_softc *sc;
776
777	sc = scarg;
778
779	sc->newdata = 0;
780
781	return (0);
782}
783
784static int
785umouse_remove(void *scarg)
786{
787
788	return (0);
789}
790
791static int
792umouse_stop(void *scarg)
793{
794
795	return (0);
796}
797
798
799struct usb_devemu ue_mouse = {
800	.ue_emu =	"tablet",
801	.ue_usbver =	3,
802	.ue_usbspeed =	USB_SPEED_HIGH,
803	.ue_init =	umouse_init,
804	.ue_request =	umouse_request,
805	.ue_data =	umouse_data_handler,
806	.ue_reset =	umouse_reset,
807	.ue_remove =	umouse_remove,
808	.ue_stop =	umouse_stop
809};
810USB_EMUL_SET(ue_mouse);
811