xref: /freebsd/usr.sbin/bhyve/usb_mouse.c (revision cd49c066)
12cf9911fSPeter Grehan /*-
2ce80faa4SMarcelo Araujo  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3ce80faa4SMarcelo Araujo  *
42cf9911fSPeter Grehan  * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com>
52cf9911fSPeter Grehan  * All rights reserved.
62cf9911fSPeter Grehan  *
72cf9911fSPeter Grehan  * Redistribution and use in source and binary forms, with or without
82cf9911fSPeter Grehan  * modification, are permitted provided that the following conditions
92cf9911fSPeter Grehan  * are met:
102cf9911fSPeter Grehan  * 1. Redistributions of source code must retain the above copyright
112cf9911fSPeter Grehan  *    notice, this list of conditions and the following disclaimer.
122cf9911fSPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
132cf9911fSPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
142cf9911fSPeter Grehan  *    documentation and/or other materials provided with the distribution.
152cf9911fSPeter Grehan  *
162cf9911fSPeter Grehan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172cf9911fSPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182cf9911fSPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192cf9911fSPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202cf9911fSPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212cf9911fSPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222cf9911fSPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232cf9911fSPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242cf9911fSPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252cf9911fSPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262cf9911fSPeter Grehan  * SUCH DAMAGE.
272cf9911fSPeter Grehan  */
282cf9911fSPeter Grehan 
292cf9911fSPeter Grehan #include <sys/cdefs.h>
302cf9911fSPeter Grehan __FBSDID("$FreeBSD$");
312cf9911fSPeter Grehan 
322cf9911fSPeter Grehan #include <sys/time.h>
332cf9911fSPeter Grehan 
34483d953aSJohn Baldwin #include <machine/vmm_snapshot.h>
35483d953aSJohn Baldwin 
362cf9911fSPeter Grehan #include <pthread.h>
372cf9911fSPeter Grehan #include <stdio.h>
382cf9911fSPeter Grehan #include <stdlib.h>
392cf9911fSPeter Grehan #include <string.h>
402cf9911fSPeter Grehan 
412cf9911fSPeter Grehan #include <dev/usb/usb.h>
422cf9911fSPeter Grehan #include <dev/usb/usbdi.h>
432cf9911fSPeter Grehan 
442cf9911fSPeter Grehan #include "usb_emul.h"
452cf9911fSPeter Grehan #include "console.h"
462cf9911fSPeter Grehan #include "bhyvegc.h"
47332eff95SVincenzo Maffione #include "debug.h"
482cf9911fSPeter Grehan 
492cf9911fSPeter Grehan static int umouse_debug = 0;
50332eff95SVincenzo Maffione #define	DPRINTF(params) if (umouse_debug) PRINTLN params
51332eff95SVincenzo Maffione #define	WPRINTF(params) PRINTLN params
522cf9911fSPeter Grehan 
532cf9911fSPeter Grehan /* USB endpoint context (1-15) for reporting mouse data events*/
542cf9911fSPeter Grehan #define	UMOUSE_INTR_ENDPT	1
552cf9911fSPeter Grehan 
562cf9911fSPeter Grehan #define UMOUSE_REPORT_DESC_TYPE	0x22
572cf9911fSPeter Grehan 
582cf9911fSPeter Grehan #define	UMOUSE_GET_REPORT	0x01
592cf9911fSPeter Grehan #define	UMOUSE_GET_IDLE		0x02
602cf9911fSPeter Grehan #define	UMOUSE_GET_PROTOCOL	0x03
612cf9911fSPeter Grehan #define	UMOUSE_SET_REPORT	0x09
622cf9911fSPeter Grehan #define	UMOUSE_SET_IDLE		0x0A
632cf9911fSPeter Grehan #define	UMOUSE_SET_PROTOCOL	0x0B
642cf9911fSPeter Grehan 
652cf9911fSPeter Grehan #define HSETW(ptr, val)   ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
662cf9911fSPeter Grehan 
672cf9911fSPeter Grehan enum {
682cf9911fSPeter Grehan 	UMSTR_LANG,
692cf9911fSPeter Grehan 	UMSTR_MANUFACTURER,
702cf9911fSPeter Grehan 	UMSTR_PRODUCT,
712cf9911fSPeter Grehan 	UMSTR_SERIAL,
722cf9911fSPeter Grehan 	UMSTR_CONFIG,
732cf9911fSPeter Grehan 	UMSTR_MAX
742cf9911fSPeter Grehan };
752cf9911fSPeter Grehan 
762cf9911fSPeter Grehan static const char *umouse_desc_strings[] = {
77285e35e6SPeter Grehan 	"\x09\x04",
782cf9911fSPeter Grehan 	"BHYVE",
792cf9911fSPeter Grehan 	"HID Tablet",
802cf9911fSPeter Grehan 	"01",
812cf9911fSPeter Grehan 	"HID Tablet Device",
822cf9911fSPeter Grehan };
832cf9911fSPeter Grehan 
842cf9911fSPeter Grehan struct umouse_hid_descriptor {
852cf9911fSPeter Grehan 	uint8_t	bLength;
862cf9911fSPeter Grehan 	uint8_t	bDescriptorType;
872cf9911fSPeter Grehan 	uint8_t	bcdHID[2];
882cf9911fSPeter Grehan 	uint8_t	bCountryCode;
892cf9911fSPeter Grehan 	uint8_t	bNumDescriptors;
902cf9911fSPeter Grehan 	uint8_t	bReportDescriptorType;
912cf9911fSPeter Grehan 	uint8_t	wItemLength[2];
922cf9911fSPeter Grehan } __packed;
932cf9911fSPeter Grehan 
942cf9911fSPeter Grehan struct umouse_config_desc {
952cf9911fSPeter Grehan 	struct usb_config_descriptor		confd;
962cf9911fSPeter Grehan 	struct usb_interface_descriptor		ifcd;
972cf9911fSPeter Grehan 	struct umouse_hid_descriptor		hidd;
982cf9911fSPeter Grehan 	struct usb_endpoint_descriptor		endpd;
992cf9911fSPeter Grehan 	struct usb_endpoint_ss_comp_descriptor	sscompd;
1002cf9911fSPeter Grehan } __packed;
1012cf9911fSPeter Grehan 
1022cf9911fSPeter Grehan #define MOUSE_MAX_X	0x8000
1032cf9911fSPeter Grehan #define MOUSE_MAX_Y	0x8000
1042cf9911fSPeter Grehan 
1052cf9911fSPeter Grehan static const uint8_t umouse_report_desc[] = {
1062cf9911fSPeter Grehan 	0x05, 0x01,		/* USAGE_PAGE (Generic Desktop)		*/
1072cf9911fSPeter Grehan 	0x09, 0x02,		/* USAGE (Mouse)			*/
1082cf9911fSPeter Grehan 	0xa1, 0x01,		/* COLLECTION (Application) 		*/
1092cf9911fSPeter Grehan 	0x09, 0x01,		/*   USAGE (Pointer)			*/
1102cf9911fSPeter Grehan 	0xa1, 0x00,		/*   COLLECTION (Physical)		*/
1112cf9911fSPeter Grehan 	0x05, 0x09,		/*     USAGE_PAGE (Button)		*/
1122cf9911fSPeter Grehan 	0x19, 0x01,		/*     USAGE_MINIMUM (Button 1)		*/
1132cf9911fSPeter Grehan 	0x29, 0x03,		/*     USAGE_MAXIMUM (Button 3)		*/
1142cf9911fSPeter Grehan 	0x15, 0x00,		/*     LOGICAL_MINIMUM (0)		*/
1152cf9911fSPeter Grehan 	0x25, 0x01,		/*     LOGICAL_MAXIMUM (1)		*/
1162cf9911fSPeter Grehan 	0x75, 0x01,		/*     REPORT_SIZE (1)			*/
1172cf9911fSPeter Grehan 	0x95, 0x03,		/*     REPORT_COUNT (3)			*/
1182cf9911fSPeter Grehan 	0x81, 0x02,		/*     INPUT (Data,Var,Abs); 3 buttons	*/
1192cf9911fSPeter Grehan 	0x75, 0x05,		/*     REPORT_SIZE (5)			*/
1202cf9911fSPeter Grehan 	0x95, 0x01,		/*     REPORT_COUNT (1)			*/
1212cf9911fSPeter Grehan 	0x81, 0x03,		/*     INPUT (Cnst,Var,Abs); padding	*/
1222cf9911fSPeter Grehan 	0x05, 0x01,		/*     USAGE_PAGE (Generic Desktop)	*/
1232cf9911fSPeter Grehan 	0x09, 0x30,		/*     USAGE (X)			*/
1242cf9911fSPeter Grehan 	0x09, 0x31,		/*     USAGE (Y)			*/
1252cf9911fSPeter Grehan 	0x35, 0x00,		/*     PHYSICAL_MINIMUM (0)		*/
1262cf9911fSPeter Grehan 	0x46, 0xff, 0x7f,	/*     PHYSICAL_MAXIMUM (0x7fff)	*/
1272cf9911fSPeter Grehan 	0x15, 0x00,		/*     LOGICAL_MINIMUM (0)		*/
1282cf9911fSPeter Grehan 	0x26, 0xff, 0x7f,	/*     LOGICAL_MAXIMUM (0x7fff)		*/
1292cf9911fSPeter Grehan 	0x75, 0x10,		/*     REPORT_SIZE (16)			*/
1302cf9911fSPeter Grehan 	0x95, 0x02,		/*     REPORT_COUNT (2)			*/
1312cf9911fSPeter Grehan 	0x81, 0x02,		/*     INPUT (Data,Var,Abs)		*/
1322cf9911fSPeter Grehan 	0x05, 0x01,		/*     USAGE Page (Generic Desktop)	*/
1332cf9911fSPeter Grehan 	0x09, 0x38,		/*     USAGE (Wheel)			*/
1342cf9911fSPeter Grehan 	0x35, 0x00,		/*     PHYSICAL_MINIMUM (0)		*/
1352cf9911fSPeter Grehan 	0x45, 0x00,		/*     PHYSICAL_MAXIMUM (0)		*/
1362cf9911fSPeter Grehan 	0x15, 0x81,		/*     LOGICAL_MINIMUM (-127)		*/
1372cf9911fSPeter Grehan 	0x25, 0x7f,		/*     LOGICAL_MAXIMUM (127)		*/
1382cf9911fSPeter Grehan 	0x75, 0x08,		/*     REPORT_SIZE (8)			*/
1392cf9911fSPeter Grehan 	0x95, 0x01,		/*     REPORT_COUNT (1)			*/
1402cf9911fSPeter Grehan 	0x81, 0x06,		/*     INPUT (Data,Var,Rel)		*/
1412cf9911fSPeter Grehan 	0xc0,			/*   END_COLLECTION			*/
1422cf9911fSPeter Grehan 	0xc0			/* END_COLLECTION			*/
1432cf9911fSPeter Grehan };
1442cf9911fSPeter Grehan 
1452cf9911fSPeter Grehan struct umouse_report {
1462cf9911fSPeter Grehan 	uint8_t	buttons;	/* bits: 0 left, 1 right, 2 middle */
1472cf9911fSPeter Grehan 	int16_t	x;		/* x position */
1482cf9911fSPeter Grehan 	int16_t	y;		/* y position */
1492cf9911fSPeter Grehan 	int8_t	z;		/* z wheel position */
1502cf9911fSPeter Grehan } __packed;
1512cf9911fSPeter Grehan 
1522cf9911fSPeter Grehan 
1532cf9911fSPeter Grehan #define	MSETW(ptr, val)	ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1542cf9911fSPeter Grehan 
1552cf9911fSPeter Grehan static struct usb_device_descriptor umouse_dev_desc = {
1562cf9911fSPeter Grehan 	.bLength = sizeof(umouse_dev_desc),
1572cf9911fSPeter Grehan 	.bDescriptorType = UDESC_DEVICE,
1582cf9911fSPeter Grehan 	MSETW(.bcdUSB, UD_USB_3_0),
1592cf9911fSPeter Grehan 	.bMaxPacketSize = 8,			/* max packet size */
1602cf9911fSPeter Grehan 	MSETW(.idVendor, 0xFB5D),		/* vendor */
1612cf9911fSPeter Grehan 	MSETW(.idProduct, 0x0001),		/* product */
1622cf9911fSPeter Grehan 	MSETW(.bcdDevice, 0),			/* device version */
1632cf9911fSPeter Grehan 	.iManufacturer = UMSTR_MANUFACTURER,
1642cf9911fSPeter Grehan 	.iProduct = UMSTR_PRODUCT,
1652cf9911fSPeter Grehan 	.iSerialNumber = UMSTR_SERIAL,
1662cf9911fSPeter Grehan 	.bNumConfigurations = 1,
1672cf9911fSPeter Grehan };
1682cf9911fSPeter Grehan 
1692cf9911fSPeter Grehan static struct umouse_config_desc umouse_confd = {
1702cf9911fSPeter Grehan 	.confd = {
1712cf9911fSPeter Grehan 		.bLength = sizeof(umouse_confd.confd),
1722cf9911fSPeter Grehan 		.bDescriptorType = UDESC_CONFIG,
1732cf9911fSPeter Grehan 		.wTotalLength[0] = sizeof(umouse_confd),
1742cf9911fSPeter Grehan 		.bNumInterface = 1,
1752cf9911fSPeter Grehan 		.bConfigurationValue = 1,
1762cf9911fSPeter Grehan 		.iConfiguration = UMSTR_CONFIG,
1772cf9911fSPeter Grehan 		.bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP,
1782cf9911fSPeter Grehan 		.bMaxPower = 0,
1792cf9911fSPeter Grehan 	},
1802cf9911fSPeter Grehan 	.ifcd = {
1812cf9911fSPeter Grehan 		.bLength = sizeof(umouse_confd.ifcd),
1822cf9911fSPeter Grehan 		.bDescriptorType = UDESC_INTERFACE,
1832cf9911fSPeter Grehan 		.bNumEndpoints = 1,
1842cf9911fSPeter Grehan 		.bInterfaceClass = UICLASS_HID,
1852cf9911fSPeter Grehan 		.bInterfaceSubClass = UISUBCLASS_BOOT,
1862cf9911fSPeter Grehan 		.bInterfaceProtocol = UIPROTO_MOUSE,
1872cf9911fSPeter Grehan 	},
1882cf9911fSPeter Grehan 	.hidd = {
1892cf9911fSPeter Grehan 		.bLength = sizeof(umouse_confd.hidd),
1902cf9911fSPeter Grehan 		.bDescriptorType = 0x21,
1912cf9911fSPeter Grehan 		.bcdHID = { 0x01, 0x10 },
1922cf9911fSPeter Grehan 		.bCountryCode = 0,
1932cf9911fSPeter Grehan 		.bNumDescriptors = 1,
1942cf9911fSPeter Grehan 		.bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE,
1952cf9911fSPeter Grehan 		.wItemLength = { sizeof(umouse_report_desc), 0 },
1962cf9911fSPeter Grehan 	},
1972cf9911fSPeter Grehan 	.endpd = {
1982cf9911fSPeter Grehan 		.bLength = sizeof(umouse_confd.endpd),
1992cf9911fSPeter Grehan 		.bDescriptorType = UDESC_ENDPOINT,
2002cf9911fSPeter Grehan 		.bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT,
2012cf9911fSPeter Grehan 		.bmAttributes = UE_INTERRUPT,
2022cf9911fSPeter Grehan 		.wMaxPacketSize[0] = 8,
2032cf9911fSPeter Grehan 		.bInterval = 0xA,
2042cf9911fSPeter Grehan 	},
2052cf9911fSPeter Grehan 	.sscompd = {
2062cf9911fSPeter Grehan 		.bLength = sizeof(umouse_confd.sscompd),
2072cf9911fSPeter Grehan 		.bDescriptorType = UDESC_ENDPOINT_SS_COMP,
2082cf9911fSPeter Grehan 		.bMaxBurst = 0,
2092cf9911fSPeter Grehan 		.bmAttributes = 0,
2102cf9911fSPeter Grehan 		MSETW(.wBytesPerInterval, 0),
2112cf9911fSPeter Grehan 	},
2122cf9911fSPeter Grehan };
2132cf9911fSPeter Grehan 
2142cf9911fSPeter Grehan 
2152cf9911fSPeter Grehan struct umouse_bos_desc {
2162cf9911fSPeter Grehan 	struct usb_bos_descriptor		bosd;
2172cf9911fSPeter Grehan 	struct usb_devcap_ss_descriptor		usbssd;
2182cf9911fSPeter Grehan } __packed;
2192cf9911fSPeter Grehan 
2202cf9911fSPeter Grehan 
221cd49c066SMark Johnston static struct umouse_bos_desc umouse_bosd = {
2222cf9911fSPeter Grehan 	.bosd = {
2232cf9911fSPeter Grehan 		.bLength = sizeof(umouse_bosd.bosd),
2242cf9911fSPeter Grehan 		.bDescriptorType = UDESC_BOS,
2252cf9911fSPeter Grehan 		HSETW(.wTotalLength, sizeof(umouse_bosd)),
2262cf9911fSPeter Grehan 		.bNumDeviceCaps = 1,
2272cf9911fSPeter Grehan 	},
2282cf9911fSPeter Grehan 	.usbssd = {
2292cf9911fSPeter Grehan 		.bLength = sizeof(umouse_bosd.usbssd),
2302cf9911fSPeter Grehan 		.bDescriptorType = UDESC_DEVICE_CAPABILITY,
2312cf9911fSPeter Grehan 		.bDevCapabilityType = 3,
2322cf9911fSPeter Grehan 		.bmAttributes = 0,
2332cf9911fSPeter Grehan 		HSETW(.wSpeedsSupported, 0x08),
2342cf9911fSPeter Grehan 		.bFunctionalitySupport = 3,
2352cf9911fSPeter Grehan 		.bU1DevExitLat = 0xa,   /* dummy - not used */
2362cf9911fSPeter Grehan 		.wU2DevExitLat = { 0x20, 0x00 },
2372cf9911fSPeter Grehan 	}
2382cf9911fSPeter Grehan };
2392cf9911fSPeter Grehan 
2402cf9911fSPeter Grehan 
2412cf9911fSPeter Grehan struct umouse_softc {
2422cf9911fSPeter Grehan 	struct usb_hci *hci;
2432cf9911fSPeter Grehan 
2442cf9911fSPeter Grehan 	struct umouse_report um_report;
2452cf9911fSPeter Grehan 	int	newdata;
2462cf9911fSPeter Grehan 	struct {
2472cf9911fSPeter Grehan 		uint8_t	idle;
2482cf9911fSPeter Grehan 		uint8_t	protocol;
2492cf9911fSPeter Grehan 		uint8_t	feature;
2502cf9911fSPeter Grehan 	} hid;
2512cf9911fSPeter Grehan 
2522cf9911fSPeter Grehan 	pthread_mutex_t	mtx;
2532cf9911fSPeter Grehan 	pthread_mutex_t	ev_mtx;
2542cf9911fSPeter Grehan 	int		polling;
2552cf9911fSPeter Grehan 	struct timeval	prev_evt;
2562cf9911fSPeter Grehan };
2572cf9911fSPeter Grehan 
2582cf9911fSPeter Grehan static void
2592cf9911fSPeter Grehan umouse_event(uint8_t button, int x, int y, void *arg)
2602cf9911fSPeter Grehan {
2612cf9911fSPeter Grehan 	struct umouse_softc *sc;
2622cf9911fSPeter Grehan 	struct bhyvegc_image *gc;
2632cf9911fSPeter Grehan 
2642cf9911fSPeter Grehan 	gc = console_get_image();
2652cf9911fSPeter Grehan 	if (gc == NULL) {
2662cf9911fSPeter Grehan 		/* not ready */
2672cf9911fSPeter Grehan 		return;
2682cf9911fSPeter Grehan 	}
2692cf9911fSPeter Grehan 
2702cf9911fSPeter Grehan 	sc = arg;
2712cf9911fSPeter Grehan 
2722cf9911fSPeter Grehan 	pthread_mutex_lock(&sc->mtx);
2732cf9911fSPeter Grehan 
2742cf9911fSPeter Grehan 	sc->um_report.buttons = 0;
2752cf9911fSPeter Grehan 	sc->um_report.z = 0;
2762cf9911fSPeter Grehan 
2772cf9911fSPeter Grehan 	if (button & 0x01)
2782cf9911fSPeter Grehan 		sc->um_report.buttons |= 0x01;	/* left */
2792cf9911fSPeter Grehan 	if (button & 0x02)
2802cf9911fSPeter Grehan 		sc->um_report.buttons |= 0x04;	/* middle */
2812cf9911fSPeter Grehan 	if (button & 0x04)
2822cf9911fSPeter Grehan 		sc->um_report.buttons |= 0x02;	/* right */
2832cf9911fSPeter Grehan 	if (button & 0x8)
2842cf9911fSPeter Grehan 		sc->um_report.z = 1;
2852cf9911fSPeter Grehan 	if (button & 0x10)
2862cf9911fSPeter Grehan 		sc->um_report.z = -1;
2872cf9911fSPeter Grehan 
2882cf9911fSPeter Grehan 	/* scale coords to mouse resolution */
2892cf9911fSPeter Grehan 	sc->um_report.x = MOUSE_MAX_X * x / gc->width;
290b9c1cdd1SPeter Grehan 	sc->um_report.y = MOUSE_MAX_Y * y / gc->height;
2912cf9911fSPeter Grehan 	sc->newdata = 1;
2922cf9911fSPeter Grehan 	pthread_mutex_unlock(&sc->mtx);
2932cf9911fSPeter Grehan 
2942cf9911fSPeter Grehan 	pthread_mutex_lock(&sc->ev_mtx);
2952cf9911fSPeter Grehan 	sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT);
2962cf9911fSPeter Grehan 	pthread_mutex_unlock(&sc->ev_mtx);
2972cf9911fSPeter Grehan }
2982cf9911fSPeter Grehan 
2992cf9911fSPeter Grehan static void *
30098d920d9SMark Johnston umouse_init(struct usb_hci *hci, nvlist_t *nvl __unused)
3012cf9911fSPeter Grehan {
3022cf9911fSPeter Grehan 	struct umouse_softc *sc;
3032cf9911fSPeter Grehan 
3042cf9911fSPeter Grehan 	sc = calloc(1, sizeof(struct umouse_softc));
3052cf9911fSPeter Grehan 	sc->hci = hci;
3062cf9911fSPeter Grehan 
3072cf9911fSPeter Grehan 	sc->hid.protocol = 1;	/* REPORT protocol */
3082cf9911fSPeter Grehan 	pthread_mutex_init(&sc->mtx, NULL);
3092cf9911fSPeter Grehan 	pthread_mutex_init(&sc->ev_mtx, NULL);
3102cf9911fSPeter Grehan 
3112cf9911fSPeter Grehan 	console_ptr_register(umouse_event, sc, 10);
3122cf9911fSPeter Grehan 
3132cf9911fSPeter Grehan 	return (sc);
3142cf9911fSPeter Grehan }
3152cf9911fSPeter Grehan 
3162cf9911fSPeter Grehan #define	UREQ(x,y)	((x) | ((y) << 8))
3172cf9911fSPeter Grehan 
3182cf9911fSPeter Grehan static int
3192cf9911fSPeter Grehan umouse_request(void *scarg, struct usb_data_xfer *xfer)
3202cf9911fSPeter Grehan {
3212cf9911fSPeter Grehan 	struct umouse_softc *sc;
3222cf9911fSPeter Grehan 	struct usb_data_xfer_block *data;
3232cf9911fSPeter Grehan 	const char *str;
3242cf9911fSPeter Grehan 	uint16_t value;
3252cf9911fSPeter Grehan 	uint16_t index;
3262cf9911fSPeter Grehan 	uint16_t len;
3272cf9911fSPeter Grehan 	uint16_t slen;
3282cf9911fSPeter Grehan 	uint8_t *udata;
3292cf9911fSPeter Grehan 	int	err;
3302cf9911fSPeter Grehan 	int	i, idx;
3312cf9911fSPeter Grehan 	int	eshort;
3322cf9911fSPeter Grehan 
3332cf9911fSPeter Grehan 	sc = scarg;
3342cf9911fSPeter Grehan 
3352cf9911fSPeter Grehan 	data = NULL;
3362cf9911fSPeter Grehan 	udata = NULL;
3372cf9911fSPeter Grehan 	idx = xfer->head;
3382cf9911fSPeter Grehan 	for (i = 0; i < xfer->ndata; i++) {
3392cf9911fSPeter Grehan 		xfer->data[idx].bdone = 0;
3402cf9911fSPeter Grehan 		if (data == NULL && USB_DATA_OK(xfer,i)) {
3412cf9911fSPeter Grehan 			data = &xfer->data[idx];
3422cf9911fSPeter Grehan 			udata = data->buf;
3432cf9911fSPeter Grehan 		}
3442cf9911fSPeter Grehan 
3452cf9911fSPeter Grehan 		xfer->data[idx].processed = 1;
3462cf9911fSPeter Grehan 		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
3472cf9911fSPeter Grehan 	}
3482cf9911fSPeter Grehan 
3492cf9911fSPeter Grehan 	err = USB_ERR_NORMAL_COMPLETION;
3502cf9911fSPeter Grehan 	eshort = 0;
3512cf9911fSPeter Grehan 
3522cf9911fSPeter Grehan 	if (!xfer->ureq) {
353332eff95SVincenzo Maffione 		DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
3542cf9911fSPeter Grehan 		goto done;
3552cf9911fSPeter Grehan 	}
3562cf9911fSPeter Grehan 
3572cf9911fSPeter Grehan 	value = UGETW(xfer->ureq->wValue);
3582cf9911fSPeter Grehan 	index = UGETW(xfer->ureq->wIndex);
3592cf9911fSPeter Grehan 	len = UGETW(xfer->ureq->wLength);
3602cf9911fSPeter Grehan 
3612cf9911fSPeter Grehan 	DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
362332eff95SVincenzo Maffione 	         "idx 0x%x, len %u",
3632cf9911fSPeter Grehan 	         sc->hci->hci_port, xfer->ureq->bmRequestType,
3642cf9911fSPeter Grehan 	         xfer->ureq->bRequest, value, index, len));
3652cf9911fSPeter Grehan 
3662cf9911fSPeter Grehan 	switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
3672cf9911fSPeter Grehan 	case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
368332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
3692cf9911fSPeter Grehan 		if (!data)
3702cf9911fSPeter Grehan 			break;
3712cf9911fSPeter Grehan 
3722cf9911fSPeter Grehan 		*udata = umouse_confd.confd.bConfigurationValue;
3732cf9911fSPeter Grehan 		data->blen = len > 0 ? len - 1 : 0;
3742cf9911fSPeter Grehan 		eshort = data->blen > 0;
3752cf9911fSPeter Grehan 		data->bdone += 1;
3762cf9911fSPeter Grehan 		break;
3772cf9911fSPeter Grehan 
3782cf9911fSPeter Grehan 	case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
379332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
3802cf9911fSPeter Grehan 		        value >> 8));
3812cf9911fSPeter Grehan 		if (!data)
3822cf9911fSPeter Grehan 			break;
3832cf9911fSPeter Grehan 
3842cf9911fSPeter Grehan 		switch (value >> 8) {
3852cf9911fSPeter Grehan 		case UDESC_DEVICE:
3862cf9911fSPeter Grehan 			DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
387332eff95SVincenzo Maffione 			         "sizeof(umouse_dev_desc) %lu",
3882cf9911fSPeter Grehan 			         len, sizeof(umouse_dev_desc)));
3892cf9911fSPeter Grehan 			if ((value & 0xFF) != 0) {
39071ab6f97SPeter Grehan 				err = USB_ERR_STALLED;
3912cf9911fSPeter Grehan 				goto done;
3922cf9911fSPeter Grehan 			}
3932cf9911fSPeter Grehan 			if (len > sizeof(umouse_dev_desc)) {
3942cf9911fSPeter Grehan 				data->blen = len - sizeof(umouse_dev_desc);
3952cf9911fSPeter Grehan 				len = sizeof(umouse_dev_desc);
3962cf9911fSPeter Grehan 			} else
3972cf9911fSPeter Grehan 				data->blen = 0;
3982cf9911fSPeter Grehan 			memcpy(data->buf, &umouse_dev_desc, len);
3992cf9911fSPeter Grehan 			data->bdone += len;
4002cf9911fSPeter Grehan 			break;
4012cf9911fSPeter Grehan 
4022cf9911fSPeter Grehan 		case UDESC_CONFIG:
403332eff95SVincenzo Maffione 			DPRINTF(("umouse: (->UDESC_CONFIG)"));
4042cf9911fSPeter Grehan 			if ((value & 0xFF) != 0) {
40571ab6f97SPeter Grehan 				err = USB_ERR_STALLED;
4062cf9911fSPeter Grehan 				goto done;
4072cf9911fSPeter Grehan 			}
4082cf9911fSPeter Grehan 			if (len > sizeof(umouse_confd)) {
4092cf9911fSPeter Grehan 				data->blen = len - sizeof(umouse_confd);
4102cf9911fSPeter Grehan 				len = sizeof(umouse_confd);
4112cf9911fSPeter Grehan 			} else
4122cf9911fSPeter Grehan 				data->blen = 0;
4132cf9911fSPeter Grehan 
4142cf9911fSPeter Grehan 			memcpy(data->buf, &umouse_confd, len);
4152cf9911fSPeter Grehan 			data->bdone += len;
4162cf9911fSPeter Grehan 			break;
4172cf9911fSPeter Grehan 
4182cf9911fSPeter Grehan 		case UDESC_STRING:
419332eff95SVincenzo Maffione 			DPRINTF(("umouse: (->UDESC_STRING)"));
4202cf9911fSPeter Grehan 			str = NULL;
4212cf9911fSPeter Grehan 			if ((value & 0xFF) < UMSTR_MAX)
4222cf9911fSPeter Grehan 				str = umouse_desc_strings[value & 0xFF];
4232cf9911fSPeter Grehan 			else
4242cf9911fSPeter Grehan 				goto done;
4252cf9911fSPeter Grehan 
4262cf9911fSPeter Grehan 			if ((value & 0xFF) == UMSTR_LANG) {
4272cf9911fSPeter Grehan 				udata[0] = 4;
4282cf9911fSPeter Grehan 				udata[1] = UDESC_STRING;
4292cf9911fSPeter Grehan 				data->blen = len - 2;
4302cf9911fSPeter Grehan 				len -= 2;
4312cf9911fSPeter Grehan 				data->bdone += 2;
4322cf9911fSPeter Grehan 
4332cf9911fSPeter Grehan 				if (len >= 2) {
4342cf9911fSPeter Grehan 					udata[2] = str[0];
4352cf9911fSPeter Grehan 					udata[3] = str[1];
4362cf9911fSPeter Grehan 					data->blen -= 2;
4372cf9911fSPeter Grehan 					data->bdone += 2;
4382cf9911fSPeter Grehan 				} else
4392cf9911fSPeter Grehan 					data->blen = 0;
4402cf9911fSPeter Grehan 
4412cf9911fSPeter Grehan 				goto done;
4422cf9911fSPeter Grehan 			}
4432cf9911fSPeter Grehan 
4444edc7f41SMarcelo Araujo 			slen = 2 + strlen(str) * 2;
4452cf9911fSPeter Grehan 			udata[0] = slen;
4462cf9911fSPeter Grehan 			udata[1] = UDESC_STRING;
4472cf9911fSPeter Grehan 
4482cf9911fSPeter Grehan 			if (len > slen) {
4492cf9911fSPeter Grehan 				data->blen = len - slen;
4502cf9911fSPeter Grehan 				len = slen;
4512cf9911fSPeter Grehan 			} else
4522cf9911fSPeter Grehan 				data->blen = 0;
4532cf9911fSPeter Grehan 			for (i = 2; i < len; i += 2) {
4542cf9911fSPeter Grehan 				udata[i] = *str++;
4552cf9911fSPeter Grehan 				udata[i+1] = '\0';
4562cf9911fSPeter Grehan 			}
4572cf9911fSPeter Grehan 			data->bdone += slen;
4582cf9911fSPeter Grehan 
4592cf9911fSPeter Grehan 			break;
4602cf9911fSPeter Grehan 
4612cf9911fSPeter Grehan 		case UDESC_BOS:
462332eff95SVincenzo Maffione 			DPRINTF(("umouse: USB3 BOS"));
4632cf9911fSPeter Grehan 			if (len > sizeof(umouse_bosd)) {
4642cf9911fSPeter Grehan 				data->blen = len - sizeof(umouse_bosd);
4652cf9911fSPeter Grehan 				len = sizeof(umouse_bosd);
4662cf9911fSPeter Grehan 			} else
4672cf9911fSPeter Grehan 				data->blen = 0;
4682cf9911fSPeter Grehan 			memcpy(udata, &umouse_bosd, len);
4692cf9911fSPeter Grehan 			data->bdone += len;
4702cf9911fSPeter Grehan 			break;
4712cf9911fSPeter Grehan 
4722cf9911fSPeter Grehan 		default:
473332eff95SVincenzo Maffione 			DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
47471ab6f97SPeter Grehan 			err = USB_ERR_STALLED;
4752cf9911fSPeter Grehan 			goto done;
4762cf9911fSPeter Grehan 		}
4772cf9911fSPeter Grehan 		eshort = data->blen > 0;
4782cf9911fSPeter Grehan 		break;
4792cf9911fSPeter Grehan 
4802cf9911fSPeter Grehan 	case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
4812cf9911fSPeter Grehan 		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
482332eff95SVincenzo Maffione 		         "0x%x", (value >> 8)));
4832cf9911fSPeter Grehan 		if (!data)
4842cf9911fSPeter Grehan 			break;
4852cf9911fSPeter Grehan 
4862cf9911fSPeter Grehan 		switch (value >> 8) {
4872cf9911fSPeter Grehan 		case UMOUSE_REPORT_DESC_TYPE:
4882cf9911fSPeter Grehan 			if (len > sizeof(umouse_report_desc)) {
4892cf9911fSPeter Grehan 				data->blen = len - sizeof(umouse_report_desc);
4902cf9911fSPeter Grehan 				len = sizeof(umouse_report_desc);
4912cf9911fSPeter Grehan 			} else
4922cf9911fSPeter Grehan 				data->blen = 0;
4932cf9911fSPeter Grehan 			memcpy(data->buf, umouse_report_desc, len);
4942cf9911fSPeter Grehan 			data->bdone += len;
4952cf9911fSPeter Grehan 			break;
4962cf9911fSPeter Grehan 		default:
497332eff95SVincenzo Maffione 			DPRINTF(("umouse: IO ERROR"));
49871ab6f97SPeter Grehan 			err = USB_ERR_STALLED;
4992cf9911fSPeter Grehan 			goto done;
5002cf9911fSPeter Grehan 		}
5012cf9911fSPeter Grehan 		eshort = data->blen > 0;
5022cf9911fSPeter Grehan 		break;
5032cf9911fSPeter Grehan 
5042cf9911fSPeter Grehan 	case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
505332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
5062cf9911fSPeter Grehan 		if (index != 0) {
507332eff95SVincenzo Maffione 			DPRINTF(("umouse get_interface, invalid index %d",
5082cf9911fSPeter Grehan 			        index));
50971ab6f97SPeter Grehan 			err = USB_ERR_STALLED;
5102cf9911fSPeter Grehan 			goto done;
5112cf9911fSPeter Grehan 		}
5122cf9911fSPeter Grehan 
5132cf9911fSPeter Grehan 		if (!data)
5142cf9911fSPeter Grehan 			break;
5152cf9911fSPeter Grehan 
5162cf9911fSPeter Grehan 		if (len > 0) {
5172cf9911fSPeter Grehan 			*udata = 0;
5182cf9911fSPeter Grehan 			data->blen = len - 1;
5192cf9911fSPeter Grehan 		}
5202cf9911fSPeter Grehan 		eshort = data->blen > 0;
5212cf9911fSPeter Grehan 		data->bdone += 1;
5222cf9911fSPeter Grehan 		break;
5232cf9911fSPeter Grehan 
5242cf9911fSPeter Grehan 	case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
525332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
5262cf9911fSPeter Grehan 		if (data != NULL && len > 1) {
5272cf9911fSPeter Grehan 			if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
5282cf9911fSPeter Grehan 				USETW(udata, UDS_REMOTE_WAKEUP);
5292cf9911fSPeter Grehan 			else
5302cf9911fSPeter Grehan 				USETW(udata, 0);
5312cf9911fSPeter Grehan 			data->blen = len - 2;
5322cf9911fSPeter Grehan 			data->bdone += 2;
5332cf9911fSPeter Grehan 		}
5342cf9911fSPeter Grehan 
5352cf9911fSPeter Grehan 		eshort = data->blen > 0;
5362cf9911fSPeter Grehan 		break;
5372cf9911fSPeter Grehan 
5382cf9911fSPeter Grehan 	case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
5392cf9911fSPeter Grehan 	case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
540332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
5412cf9911fSPeter Grehan 		if (data != NULL && len > 1) {
5422cf9911fSPeter Grehan 			USETW(udata, 0);
5432cf9911fSPeter Grehan 			data->blen = len - 2;
5442cf9911fSPeter Grehan 			data->bdone += 2;
5452cf9911fSPeter Grehan 		}
5462cf9911fSPeter Grehan 		eshort = data->blen > 0;
5472cf9911fSPeter Grehan 		break;
5482cf9911fSPeter Grehan 
5492cf9911fSPeter Grehan 	case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
5502cf9911fSPeter Grehan 		/* XXX Controller should've handled this */
551332eff95SVincenzo Maffione 		DPRINTF(("umouse set address %u", value));
5522cf9911fSPeter Grehan 		break;
5532cf9911fSPeter Grehan 
5542cf9911fSPeter Grehan 	case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
555332eff95SVincenzo Maffione 		DPRINTF(("umouse set config %u", value));
5562cf9911fSPeter Grehan 		break;
5572cf9911fSPeter Grehan 
5582cf9911fSPeter Grehan 	case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
559332eff95SVincenzo Maffione 		DPRINTF(("umouse set descriptor %u", value));
5602cf9911fSPeter Grehan 		break;
5612cf9911fSPeter Grehan 
5622cf9911fSPeter Grehan 
5632cf9911fSPeter Grehan 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
564332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5652cf9911fSPeter Grehan 		if (value == UF_DEVICE_REMOTE_WAKEUP)
5662cf9911fSPeter Grehan 			sc->hid.feature = 0;
5672cf9911fSPeter Grehan 		break;
5682cf9911fSPeter Grehan 
5692cf9911fSPeter Grehan 	case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
570332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5712cf9911fSPeter Grehan 		if (value == UF_DEVICE_REMOTE_WAKEUP)
5722cf9911fSPeter Grehan 			sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
5732cf9911fSPeter Grehan 		break;
5742cf9911fSPeter Grehan 
5752cf9911fSPeter Grehan 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
5762cf9911fSPeter Grehan 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
5772cf9911fSPeter Grehan 	case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
5782cf9911fSPeter Grehan 	case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
579332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
58071ab6f97SPeter Grehan 		err = USB_ERR_STALLED;
5812cf9911fSPeter Grehan 		goto done;
5822cf9911fSPeter Grehan 
5832cf9911fSPeter Grehan 	case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
584332eff95SVincenzo Maffione 		DPRINTF(("umouse set interface %u", value));
5852cf9911fSPeter Grehan 		break;
5862cf9911fSPeter Grehan 
5872cf9911fSPeter Grehan 	case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
588332eff95SVincenzo Maffione 		DPRINTF(("umouse set isoch delay %u", value));
5892cf9911fSPeter Grehan 		break;
5902cf9911fSPeter Grehan 
5912cf9911fSPeter Grehan 	case UREQ(UR_SET_SEL, 0):
592332eff95SVincenzo Maffione 		DPRINTF(("umouse set sel"));
5932cf9911fSPeter Grehan 		break;
5942cf9911fSPeter Grehan 
5952cf9911fSPeter Grehan 	case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
596332eff95SVincenzo Maffione 		DPRINTF(("umouse synch frame"));
5972cf9911fSPeter Grehan 		break;
5982cf9911fSPeter Grehan 
5992cf9911fSPeter Grehan 	/* HID device requests */
6002cf9911fSPeter Grehan 
6012cf9911fSPeter Grehan 	case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
6022cf9911fSPeter Grehan 		DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
603332eff95SVincenzo Maffione 		         "0x%x", (value >> 8)));
6042cf9911fSPeter Grehan 		if (!data)
6052cf9911fSPeter Grehan 			break;
6062cf9911fSPeter Grehan 
6072cf9911fSPeter Grehan 		if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
6082cf9911fSPeter Grehan 			/* TODO read from backend */
6092cf9911fSPeter Grehan 
6102cf9911fSPeter Grehan 			if (len > sizeof(sc->um_report)) {
6112cf9911fSPeter Grehan 				data->blen = len - sizeof(sc->um_report);
6122cf9911fSPeter Grehan 				len = sizeof(sc->um_report);
6132cf9911fSPeter Grehan 			} else
6142cf9911fSPeter Grehan 				data->blen = 0;
6152cf9911fSPeter Grehan 
6162cf9911fSPeter Grehan 			memcpy(data->buf, &sc->um_report, len);
6172cf9911fSPeter Grehan 			data->bdone += len;
6182cf9911fSPeter Grehan 		} else {
61971ab6f97SPeter Grehan 			err = USB_ERR_STALLED;
6202cf9911fSPeter Grehan 			goto done;
6212cf9911fSPeter Grehan 		}
6222cf9911fSPeter Grehan 		eshort = data->blen > 0;
6232cf9911fSPeter Grehan 		break;
6242cf9911fSPeter Grehan 
6252cf9911fSPeter Grehan 	case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
6262cf9911fSPeter Grehan 		if (data != NULL && len > 0) {
6272cf9911fSPeter Grehan 			*udata = sc->hid.idle;
6282cf9911fSPeter Grehan 			data->blen = len - 1;
6292cf9911fSPeter Grehan 			data->bdone += 1;
6302cf9911fSPeter Grehan 		}
6312cf9911fSPeter Grehan 		eshort = data->blen > 0;
6322cf9911fSPeter Grehan 		break;
6332cf9911fSPeter Grehan 
6342cf9911fSPeter Grehan 	case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
6352cf9911fSPeter Grehan 		if (data != NULL && len > 0) {
6362cf9911fSPeter Grehan 			*udata = sc->hid.protocol;
6372cf9911fSPeter Grehan 			data->blen = len - 1;
6382cf9911fSPeter Grehan 			data->bdone += 1;
6392cf9911fSPeter Grehan 		}
6402cf9911fSPeter Grehan 		eshort = data->blen > 0;
6412cf9911fSPeter Grehan 		break;
6422cf9911fSPeter Grehan 
6432cf9911fSPeter Grehan 	case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
644332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
6452cf9911fSPeter Grehan 		break;
6462cf9911fSPeter Grehan 
6472cf9911fSPeter Grehan 	case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
6482cf9911fSPeter Grehan 		sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
649332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
6502cf9911fSPeter Grehan 		        sc->hid.idle));
6512cf9911fSPeter Grehan 		break;
6522cf9911fSPeter Grehan 
6532cf9911fSPeter Grehan 	case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
6542cf9911fSPeter Grehan 		sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
655332eff95SVincenzo Maffione 		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
6562cf9911fSPeter Grehan 		        sc->hid.protocol));
6572cf9911fSPeter Grehan 		break;
6582cf9911fSPeter Grehan 
6592cf9911fSPeter Grehan 	default:
660332eff95SVincenzo Maffione 		DPRINTF(("**** umouse request unhandled"));
66171ab6f97SPeter Grehan 		err = USB_ERR_STALLED;
6622cf9911fSPeter Grehan 		break;
6632cf9911fSPeter Grehan 	}
6642cf9911fSPeter Grehan 
6652cf9911fSPeter Grehan done:
6662cf9911fSPeter Grehan 	if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
6672cf9911fSPeter Grehan 	    (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
6682cf9911fSPeter Grehan 		data->blen = 0;
6692cf9911fSPeter Grehan 	else if (eshort)
6702cf9911fSPeter Grehan 		err = USB_ERR_SHORT_XFER;
6712cf9911fSPeter Grehan 
672332eff95SVincenzo Maffione 	DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
6732cf9911fSPeter Grehan 	        err, (data ? data->blen : 0), (data ? data->bdone : 0)));
6742cf9911fSPeter Grehan 
6752cf9911fSPeter Grehan 	return (err);
6762cf9911fSPeter Grehan }
6772cf9911fSPeter Grehan 
6782cf9911fSPeter Grehan static int
6792cf9911fSPeter Grehan umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
6802cf9911fSPeter Grehan      int epctx)
6812cf9911fSPeter Grehan {
6822cf9911fSPeter Grehan 	struct umouse_softc *sc;
6832cf9911fSPeter Grehan 	struct usb_data_xfer_block *data;
6842cf9911fSPeter Grehan 	uint8_t *udata;
6852cf9911fSPeter Grehan 	int len, i, idx;
6862cf9911fSPeter Grehan 	int err;
6872cf9911fSPeter Grehan 
688332eff95SVincenzo Maffione 	DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
6892cf9911fSPeter Grehan 	        dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
6902cf9911fSPeter Grehan 
6912cf9911fSPeter Grehan 
6922cf9911fSPeter Grehan 	/* find buffer to add data */
6932cf9911fSPeter Grehan 	udata = NULL;
6942cf9911fSPeter Grehan 	err = USB_ERR_NORMAL_COMPLETION;
6952cf9911fSPeter Grehan 
6962cf9911fSPeter Grehan 	/* handle xfer at first unprocessed item with buffer */
6972cf9911fSPeter Grehan 	data = NULL;
6982cf9911fSPeter Grehan 	idx = xfer->head;
6992cf9911fSPeter Grehan 	for (i = 0; i < xfer->ndata; i++) {
7002cf9911fSPeter Grehan 		data = &xfer->data[idx];
7012cf9911fSPeter Grehan 		if (data->buf != NULL && data->blen != 0) {
7022cf9911fSPeter Grehan 			break;
7032cf9911fSPeter Grehan 		} else {
7042cf9911fSPeter Grehan 			data->processed = 1;
7052cf9911fSPeter Grehan 			data = NULL;
7062cf9911fSPeter Grehan 		}
7072cf9911fSPeter Grehan 		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
7082cf9911fSPeter Grehan 	}
7092cf9911fSPeter Grehan 	if (!data)
7102cf9911fSPeter Grehan 		goto done;
7112cf9911fSPeter Grehan 
7122cf9911fSPeter Grehan 	udata = data->buf;
7132cf9911fSPeter Grehan 	len = data->blen;
7142cf9911fSPeter Grehan 
7152cf9911fSPeter Grehan 	if (udata == NULL) {
716332eff95SVincenzo Maffione 		DPRINTF(("umouse no buffer provided for input"));
7172cf9911fSPeter Grehan 		err = USB_ERR_NOMEM;
7182cf9911fSPeter Grehan 		goto done;
7192cf9911fSPeter Grehan 	}
7202cf9911fSPeter Grehan 
7212cf9911fSPeter Grehan 	sc = scarg;
7222cf9911fSPeter Grehan 
7232cf9911fSPeter Grehan 	if (dir) {
7242cf9911fSPeter Grehan 
7252cf9911fSPeter Grehan 		pthread_mutex_lock(&sc->mtx);
7262cf9911fSPeter Grehan 
7272cf9911fSPeter Grehan 		if (!sc->newdata) {
7282cf9911fSPeter Grehan 			err = USB_ERR_CANCELLED;
7292cf9911fSPeter Grehan 			USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
7302cf9911fSPeter Grehan 			pthread_mutex_unlock(&sc->mtx);
7312cf9911fSPeter Grehan 			goto done;
7322cf9911fSPeter Grehan 		}
7332cf9911fSPeter Grehan 
7342cf9911fSPeter Grehan 		if (sc->polling) {
7352cf9911fSPeter Grehan 			err = USB_ERR_STALLED;
7362cf9911fSPeter Grehan 			USB_DATA_SET_ERRCODE(data, USB_STALL);
7372cf9911fSPeter Grehan 			pthread_mutex_unlock(&sc->mtx);
7382cf9911fSPeter Grehan 			goto done;
7392cf9911fSPeter Grehan 		}
7402cf9911fSPeter Grehan 		sc->polling = 1;
7412cf9911fSPeter Grehan 
7422cf9911fSPeter Grehan 		if (len > 0) {
7432cf9911fSPeter Grehan 			sc->newdata = 0;
7442cf9911fSPeter Grehan 
7452cf9911fSPeter Grehan 			data->processed = 1;
7462cf9911fSPeter Grehan 			data->bdone += 6;
7472cf9911fSPeter Grehan 			memcpy(udata, &sc->um_report, 6);
7482cf9911fSPeter Grehan 			data->blen = len - 6;
7492cf9911fSPeter Grehan 			if (data->blen > 0)
7502cf9911fSPeter Grehan 				err = USB_ERR_SHORT_XFER;
7512cf9911fSPeter Grehan 		}
7522cf9911fSPeter Grehan 
7532cf9911fSPeter Grehan 		sc->polling = 0;
7542cf9911fSPeter Grehan 		pthread_mutex_unlock(&sc->mtx);
7552cf9911fSPeter Grehan 	} else {
7562cf9911fSPeter Grehan 		USB_DATA_SET_ERRCODE(data, USB_STALL);
7572cf9911fSPeter Grehan 		err = USB_ERR_STALLED;
7582cf9911fSPeter Grehan 	}
7592cf9911fSPeter Grehan 
7602cf9911fSPeter Grehan done:
7612cf9911fSPeter Grehan 	return (err);
7622cf9911fSPeter Grehan }
7632cf9911fSPeter Grehan 
7642cf9911fSPeter Grehan static int
7652cf9911fSPeter Grehan umouse_reset(void *scarg)
7662cf9911fSPeter Grehan {
7672cf9911fSPeter Grehan 	struct umouse_softc *sc;
7682cf9911fSPeter Grehan 
7692cf9911fSPeter Grehan 	sc = scarg;
7702cf9911fSPeter Grehan 
7712cf9911fSPeter Grehan 	sc->newdata = 0;
7722cf9911fSPeter Grehan 
7732cf9911fSPeter Grehan 	return (0);
7742cf9911fSPeter Grehan }
7752cf9911fSPeter Grehan 
7762cf9911fSPeter Grehan static int
77798d920d9SMark Johnston umouse_remove(void *scarg __unused)
7782cf9911fSPeter Grehan {
7792cf9911fSPeter Grehan 	return (0);
7802cf9911fSPeter Grehan }
7812cf9911fSPeter Grehan 
7822cf9911fSPeter Grehan static int
78398d920d9SMark Johnston umouse_stop(void *scarg __unused)
7842cf9911fSPeter Grehan {
7852cf9911fSPeter Grehan 	return (0);
7862cf9911fSPeter Grehan }
7872cf9911fSPeter Grehan 
788483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
789483d953aSJohn Baldwin static int
790483d953aSJohn Baldwin umouse_snapshot(void *scarg, struct vm_snapshot_meta *meta)
791483d953aSJohn Baldwin {
792483d953aSJohn Baldwin 	int ret;
793483d953aSJohn Baldwin 	struct umouse_softc *sc;
794483d953aSJohn Baldwin 
795483d953aSJohn Baldwin 	sc = scarg;
796483d953aSJohn Baldwin 
797483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->um_report, meta, ret, done);
798483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->newdata, meta, ret, done);
799483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->hid.idle, meta, ret, done);
800483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->hid.protocol, meta, ret, done);
801483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->hid.feature, meta, ret, done);
802483d953aSJohn Baldwin 
803483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->polling, meta, ret, done);
804483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_sec, meta, ret, done);
805483d953aSJohn Baldwin 	SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_usec, meta, ret, done);
806483d953aSJohn Baldwin 
807483d953aSJohn Baldwin done:
808483d953aSJohn Baldwin 	return (ret);
809483d953aSJohn Baldwin }
810483d953aSJohn Baldwin #endif
8112cf9911fSPeter Grehan 
812cd49c066SMark Johnston static struct usb_devemu ue_mouse = {
8132cf9911fSPeter Grehan 	.ue_emu =	"tablet",
8142cf9911fSPeter Grehan 	.ue_usbver =	3,
8152cf9911fSPeter Grehan 	.ue_usbspeed =	USB_SPEED_HIGH,
8162cf9911fSPeter Grehan 	.ue_init =	umouse_init,
8172cf9911fSPeter Grehan 	.ue_request =	umouse_request,
8182cf9911fSPeter Grehan 	.ue_data =	umouse_data_handler,
8192cf9911fSPeter Grehan 	.ue_reset =	umouse_reset,
8202cf9911fSPeter Grehan 	.ue_remove =	umouse_remove,
821483d953aSJohn Baldwin 	.ue_stop =	umouse_stop,
822483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
823483d953aSJohn Baldwin 	.ue_snapshot =	umouse_snapshot,
824483d953aSJohn Baldwin #endif
8252cf9911fSPeter Grehan };
8262cf9911fSPeter Grehan USB_EMUL_SET(ue_mouse);
827