usb_mouse.c revision 302408
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: stable/11/usr.sbin/bhyve/usb_mouse.c 302408 2016-07-08 00:04:57Z gjb $");
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
44static 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
62enum {
63	UMSTR_LANG,
64	UMSTR_MANUFACTURER,
65	UMSTR_PRODUCT,
66	UMSTR_SERIAL,
67	UMSTR_CONFIG,
68	UMSTR_MAX
69};
70
71static const char *umouse_desc_strings[] = {
72	"\x04\x09",
73	"BHYVE",
74	"HID Tablet",
75	"01",
76	"HID Tablet Device",
77};
78
79struct 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
89struct 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
100static 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
140struct 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
150static 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
164static 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
210struct umouse_bos_desc {
211	struct usb_bos_descriptor		bosd;
212	struct usb_devcap_ss_descriptor		usbssd;
213} __packed;
214
215
216struct 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
236struct 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
255static void
256umouse_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
296static void *
297umouse_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
316static int
317umouse_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
663done:
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
676static int
677umouse_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
758done:
759	return (err);
760}
761
762static int
763umouse_reset(void *scarg)
764{
765	struct umouse_softc *sc;
766
767	sc = scarg;
768
769	sc->newdata = 0;
770
771	return (0);
772}
773
774static int
775umouse_remove(void *scarg)
776{
777
778	return (0);
779}
780
781static int
782umouse_stop(void *scarg)
783{
784
785	return (0);
786}
787
788
789struct 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};
800USB_EMUL_SET(ue_mouse);
801