xref: /illumos-gate/usr/src/cmd/bhyve/usb_mouse.c (revision 2b948146)
14c87aefeSPatrick Mooney /*-
24c87aefeSPatrick Mooney  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
34c87aefeSPatrick Mooney  *
44c87aefeSPatrick Mooney  * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com>
54c87aefeSPatrick Mooney  * All rights reserved.
64c87aefeSPatrick Mooney  *
74c87aefeSPatrick Mooney  * Redistribution and use in source and binary forms, with or without
84c87aefeSPatrick Mooney  * modification, are permitted provided that the following conditions
94c87aefeSPatrick Mooney  * are met:
104c87aefeSPatrick Mooney  * 1. Redistributions of source code must retain the above copyright
114c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer.
124c87aefeSPatrick Mooney  * 2. Redistributions in binary form must reproduce the above copyright
134c87aefeSPatrick Mooney  *    notice, this list of conditions and the following disclaimer in the
144c87aefeSPatrick Mooney  *    documentation and/or other materials provided with the distribution.
154c87aefeSPatrick Mooney  *
164c87aefeSPatrick Mooney  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174c87aefeSPatrick Mooney  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184c87aefeSPatrick Mooney  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194c87aefeSPatrick Mooney  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
204c87aefeSPatrick Mooney  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214c87aefeSPatrick Mooney  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224c87aefeSPatrick Mooney  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234c87aefeSPatrick Mooney  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244c87aefeSPatrick Mooney  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254c87aefeSPatrick Mooney  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264c87aefeSPatrick Mooney  * SUCH DAMAGE.
274c87aefeSPatrick Mooney  */
284c87aefeSPatrick Mooney 
294c87aefeSPatrick Mooney #include <sys/cdefs.h>
304c87aefeSPatrick Mooney __FBSDID("$FreeBSD$");
314c87aefeSPatrick Mooney 
324c87aefeSPatrick Mooney #include <sys/time.h>
334c87aefeSPatrick Mooney 
344c87aefeSPatrick Mooney #include <pthread.h>
354c87aefeSPatrick Mooney #include <stdio.h>
364c87aefeSPatrick Mooney #include <stdlib.h>
374c87aefeSPatrick Mooney #include <string.h>
384c87aefeSPatrick Mooney 
394c87aefeSPatrick Mooney #include <dev/usb/usb.h>
404c87aefeSPatrick Mooney #include <dev/usb/usbdi.h>
414c87aefeSPatrick Mooney 
424c87aefeSPatrick Mooney #include "usb_emul.h"
434c87aefeSPatrick Mooney #include "console.h"
444c87aefeSPatrick Mooney #include "bhyvegc.h"
45154972afSPatrick Mooney #include "debug.h"
464c87aefeSPatrick Mooney 
474c87aefeSPatrick Mooney static int umouse_debug = 0;
48154972afSPatrick Mooney #define	DPRINTF(params) if (umouse_debug) PRINTLN params
49154972afSPatrick Mooney #define	WPRINTF(params) PRINTLN params
504c87aefeSPatrick Mooney 
514c87aefeSPatrick Mooney /* USB endpoint context (1-15) for reporting mouse data events*/
524c87aefeSPatrick Mooney #define	UMOUSE_INTR_ENDPT	1
534c87aefeSPatrick Mooney 
544c87aefeSPatrick Mooney #define UMOUSE_REPORT_DESC_TYPE	0x22
554c87aefeSPatrick Mooney 
564c87aefeSPatrick Mooney #define	UMOUSE_GET_REPORT	0x01
574c87aefeSPatrick Mooney #define	UMOUSE_GET_IDLE		0x02
584c87aefeSPatrick Mooney #define	UMOUSE_GET_PROTOCOL	0x03
594c87aefeSPatrick Mooney #define	UMOUSE_SET_REPORT	0x09
604c87aefeSPatrick Mooney #define	UMOUSE_SET_IDLE		0x0A
614c87aefeSPatrick Mooney #define	UMOUSE_SET_PROTOCOL	0x0B
624c87aefeSPatrick Mooney 
634c87aefeSPatrick Mooney #define HSETW(ptr, val)   ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
644c87aefeSPatrick Mooney 
654c87aefeSPatrick Mooney enum {
664c87aefeSPatrick Mooney 	UMSTR_LANG,
674c87aefeSPatrick Mooney 	UMSTR_MANUFACTURER,
684c87aefeSPatrick Mooney 	UMSTR_PRODUCT,
694c87aefeSPatrick Mooney 	UMSTR_SERIAL,
704c87aefeSPatrick Mooney 	UMSTR_CONFIG,
714c87aefeSPatrick Mooney 	UMSTR_MAX
724c87aefeSPatrick Mooney };
734c87aefeSPatrick Mooney 
744c87aefeSPatrick Mooney static const char *umouse_desc_strings[] = {
756960cd89SAndy Fiddaman 	"\x09\x04",
764c87aefeSPatrick Mooney 	"BHYVE",
774c87aefeSPatrick Mooney 	"HID Tablet",
784c87aefeSPatrick Mooney 	"01",
794c87aefeSPatrick Mooney 	"HID Tablet Device",
804c87aefeSPatrick Mooney };
814c87aefeSPatrick Mooney 
824c87aefeSPatrick Mooney struct umouse_hid_descriptor {
834c87aefeSPatrick Mooney 	uint8_t	bLength;
844c87aefeSPatrick Mooney 	uint8_t	bDescriptorType;
854c87aefeSPatrick Mooney 	uint8_t	bcdHID[2];
864c87aefeSPatrick Mooney 	uint8_t	bCountryCode;
874c87aefeSPatrick Mooney 	uint8_t	bNumDescriptors;
884c87aefeSPatrick Mooney 	uint8_t	bReportDescriptorType;
894c87aefeSPatrick Mooney 	uint8_t	wItemLength[2];
904c87aefeSPatrick Mooney } __packed;
914c87aefeSPatrick Mooney 
924c87aefeSPatrick Mooney struct umouse_config_desc {
934c87aefeSPatrick Mooney 	struct usb_config_descriptor		confd;
944c87aefeSPatrick Mooney 	struct usb_interface_descriptor		ifcd;
954c87aefeSPatrick Mooney 	struct umouse_hid_descriptor		hidd;
964c87aefeSPatrick Mooney 	struct usb_endpoint_descriptor		endpd;
974c87aefeSPatrick Mooney 	struct usb_endpoint_ss_comp_descriptor	sscompd;
984c87aefeSPatrick Mooney } __packed;
994c87aefeSPatrick Mooney 
1004c87aefeSPatrick Mooney #define MOUSE_MAX_X	0x8000
1014c87aefeSPatrick Mooney #define MOUSE_MAX_Y	0x8000
1024c87aefeSPatrick Mooney 
1034c87aefeSPatrick Mooney static const uint8_t umouse_report_desc[] = {
1044c87aefeSPatrick Mooney 	0x05, 0x01,		/* USAGE_PAGE (Generic Desktop)		*/
1054c87aefeSPatrick Mooney 	0x09, 0x02,		/* USAGE (Mouse)			*/
1064c87aefeSPatrick Mooney 	0xa1, 0x01,		/* COLLECTION (Application) 		*/
1074c87aefeSPatrick Mooney 	0x09, 0x01,		/*   USAGE (Pointer)			*/
1084c87aefeSPatrick Mooney 	0xa1, 0x00,		/*   COLLECTION (Physical)		*/
1094c87aefeSPatrick Mooney 	0x05, 0x09,		/*     USAGE_PAGE (Button)		*/
1104c87aefeSPatrick Mooney 	0x19, 0x01,		/*     USAGE_MINIMUM (Button 1)		*/
1114c87aefeSPatrick Mooney 	0x29, 0x03,		/*     USAGE_MAXIMUM (Button 3)		*/
1124c87aefeSPatrick Mooney 	0x15, 0x00,		/*     LOGICAL_MINIMUM (0)		*/
1134c87aefeSPatrick Mooney 	0x25, 0x01,		/*     LOGICAL_MAXIMUM (1)		*/
1144c87aefeSPatrick Mooney 	0x75, 0x01,		/*     REPORT_SIZE (1)			*/
1154c87aefeSPatrick Mooney 	0x95, 0x03,		/*     REPORT_COUNT (3)			*/
1164c87aefeSPatrick Mooney 	0x81, 0x02,		/*     INPUT (Data,Var,Abs); 3 buttons	*/
1174c87aefeSPatrick Mooney 	0x75, 0x05,		/*     REPORT_SIZE (5)			*/
1184c87aefeSPatrick Mooney 	0x95, 0x01,		/*     REPORT_COUNT (1)			*/
1194c87aefeSPatrick Mooney 	0x81, 0x03,		/*     INPUT (Cnst,Var,Abs); padding	*/
1204c87aefeSPatrick Mooney 	0x05, 0x01,		/*     USAGE_PAGE (Generic Desktop)	*/
1214c87aefeSPatrick Mooney 	0x09, 0x30,		/*     USAGE (X)			*/
1224c87aefeSPatrick Mooney 	0x09, 0x31,		/*     USAGE (Y)			*/
1234c87aefeSPatrick Mooney 	0x35, 0x00,		/*     PHYSICAL_MINIMUM (0)		*/
1244c87aefeSPatrick Mooney 	0x46, 0xff, 0x7f,	/*     PHYSICAL_MAXIMUM (0x7fff)	*/
1254c87aefeSPatrick Mooney 	0x15, 0x00,		/*     LOGICAL_MINIMUM (0)		*/
1264c87aefeSPatrick Mooney 	0x26, 0xff, 0x7f,	/*     LOGICAL_MAXIMUM (0x7fff)		*/
1274c87aefeSPatrick Mooney 	0x75, 0x10,		/*     REPORT_SIZE (16)			*/
1284c87aefeSPatrick Mooney 	0x95, 0x02,		/*     REPORT_COUNT (2)			*/
1294c87aefeSPatrick Mooney 	0x81, 0x02,		/*     INPUT (Data,Var,Abs)		*/
1304c87aefeSPatrick Mooney 	0x05, 0x01,		/*     USAGE Page (Generic Desktop)	*/
1314c87aefeSPatrick Mooney 	0x09, 0x38,		/*     USAGE (Wheel)			*/
1324c87aefeSPatrick Mooney 	0x35, 0x00,		/*     PHYSICAL_MINIMUM (0)		*/
1334c87aefeSPatrick Mooney 	0x45, 0x00,		/*     PHYSICAL_MAXIMUM (0)		*/
1344c87aefeSPatrick Mooney 	0x15, 0x81,		/*     LOGICAL_MINIMUM (-127)		*/
1354c87aefeSPatrick Mooney 	0x25, 0x7f,		/*     LOGICAL_MAXIMUM (127)		*/
1364c87aefeSPatrick Mooney 	0x75, 0x08,		/*     REPORT_SIZE (8)			*/
1374c87aefeSPatrick Mooney 	0x95, 0x01,		/*     REPORT_COUNT (1)			*/
1384c87aefeSPatrick Mooney 	0x81, 0x06,		/*     INPUT (Data,Var,Rel)		*/
1394c87aefeSPatrick Mooney 	0xc0,			/*   END_COLLECTION			*/
1404c87aefeSPatrick Mooney 	0xc0			/* END_COLLECTION			*/
1414c87aefeSPatrick Mooney };
1424c87aefeSPatrick Mooney 
1434c87aefeSPatrick Mooney struct umouse_report {
1444c87aefeSPatrick Mooney 	uint8_t	buttons;	/* bits: 0 left, 1 right, 2 middle */
1454c87aefeSPatrick Mooney 	int16_t	x;		/* x position */
1464c87aefeSPatrick Mooney 	int16_t	y;		/* y position */
1474c87aefeSPatrick Mooney 	int8_t	z;		/* z wheel position */
1484c87aefeSPatrick Mooney } __packed;
1494c87aefeSPatrick Mooney 
1504c87aefeSPatrick Mooney 
1514c87aefeSPatrick Mooney #define	MSETW(ptr, val)	ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1524c87aefeSPatrick Mooney 
1534c87aefeSPatrick Mooney static struct usb_device_descriptor umouse_dev_desc = {
1544c87aefeSPatrick Mooney 	.bLength = sizeof(umouse_dev_desc),
1554c87aefeSPatrick Mooney 	.bDescriptorType = UDESC_DEVICE,
1564c87aefeSPatrick Mooney 	MSETW(.bcdUSB, UD_USB_3_0),
1574c87aefeSPatrick Mooney 	.bMaxPacketSize = 8,			/* max packet size */
1584c87aefeSPatrick Mooney 	MSETW(.idVendor, 0xFB5D),		/* vendor */
1594c87aefeSPatrick Mooney 	MSETW(.idProduct, 0x0001),		/* product */
1604c87aefeSPatrick Mooney 	MSETW(.bcdDevice, 0),			/* device version */
1614c87aefeSPatrick Mooney 	.iManufacturer = UMSTR_MANUFACTURER,
1624c87aefeSPatrick Mooney 	.iProduct = UMSTR_PRODUCT,
1634c87aefeSPatrick Mooney 	.iSerialNumber = UMSTR_SERIAL,
1644c87aefeSPatrick Mooney 	.bNumConfigurations = 1,
1654c87aefeSPatrick Mooney };
1664c87aefeSPatrick Mooney 
1674c87aefeSPatrick Mooney static struct umouse_config_desc umouse_confd = {
1684c87aefeSPatrick Mooney 	.confd = {
1694c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_confd.confd),
1704c87aefeSPatrick Mooney 		.bDescriptorType = UDESC_CONFIG,
1714c87aefeSPatrick Mooney 		.wTotalLength[0] = sizeof(umouse_confd),
1724c87aefeSPatrick Mooney 		.bNumInterface = 1,
1734c87aefeSPatrick Mooney 		.bConfigurationValue = 1,
1744c87aefeSPatrick Mooney 		.iConfiguration = UMSTR_CONFIG,
1754c87aefeSPatrick Mooney 		.bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP,
1764c87aefeSPatrick Mooney 		.bMaxPower = 0,
1774c87aefeSPatrick Mooney 	},
1784c87aefeSPatrick Mooney 	.ifcd = {
1794c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_confd.ifcd),
1804c87aefeSPatrick Mooney 		.bDescriptorType = UDESC_INTERFACE,
1814c87aefeSPatrick Mooney 		.bNumEndpoints = 1,
1824c87aefeSPatrick Mooney 		.bInterfaceClass = UICLASS_HID,
1834c87aefeSPatrick Mooney 		.bInterfaceSubClass = UISUBCLASS_BOOT,
1844c87aefeSPatrick Mooney 		.bInterfaceProtocol = UIPROTO_MOUSE,
1854c87aefeSPatrick Mooney 	},
1864c87aefeSPatrick Mooney 	.hidd = {
1874c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_confd.hidd),
1884c87aefeSPatrick Mooney 		.bDescriptorType = 0x21,
1894c87aefeSPatrick Mooney 		.bcdHID = { 0x01, 0x10 },
1904c87aefeSPatrick Mooney 		.bCountryCode = 0,
1914c87aefeSPatrick Mooney 		.bNumDescriptors = 1,
1924c87aefeSPatrick Mooney 		.bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE,
1934c87aefeSPatrick Mooney 		.wItemLength = { sizeof(umouse_report_desc), 0 },
1944c87aefeSPatrick Mooney 	},
1954c87aefeSPatrick Mooney 	.endpd = {
1964c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_confd.endpd),
1974c87aefeSPatrick Mooney 		.bDescriptorType = UDESC_ENDPOINT,
1984c87aefeSPatrick Mooney 		.bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT,
1994c87aefeSPatrick Mooney 		.bmAttributes = UE_INTERRUPT,
2004c87aefeSPatrick Mooney 		.wMaxPacketSize[0] = 8,
2014c87aefeSPatrick Mooney 		.bInterval = 0xA,
2024c87aefeSPatrick Mooney 	},
2034c87aefeSPatrick Mooney 	.sscompd = {
2044c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_confd.sscompd),
2054c87aefeSPatrick Mooney 		.bDescriptorType = UDESC_ENDPOINT_SS_COMP,
2064c87aefeSPatrick Mooney 		.bMaxBurst = 0,
2074c87aefeSPatrick Mooney 		.bmAttributes = 0,
2084c87aefeSPatrick Mooney 		MSETW(.wBytesPerInterval, 0),
2094c87aefeSPatrick Mooney 	},
2104c87aefeSPatrick Mooney };
2114c87aefeSPatrick Mooney 
2124c87aefeSPatrick Mooney 
2134c87aefeSPatrick Mooney struct umouse_bos_desc {
2144c87aefeSPatrick Mooney 	struct usb_bos_descriptor		bosd;
2154c87aefeSPatrick Mooney 	struct usb_devcap_ss_descriptor		usbssd;
2164c87aefeSPatrick Mooney } __packed;
2174c87aefeSPatrick Mooney 
2184c87aefeSPatrick Mooney 
2194c87aefeSPatrick Mooney struct umouse_bos_desc umouse_bosd = {
2204c87aefeSPatrick Mooney 	.bosd = {
2214c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_bosd.bosd),
2224c87aefeSPatrick Mooney 		.bDescriptorType = UDESC_BOS,
2234c87aefeSPatrick Mooney 		HSETW(.wTotalLength, sizeof(umouse_bosd)),
2244c87aefeSPatrick Mooney 		.bNumDeviceCaps = 1,
2254c87aefeSPatrick Mooney 	},
2264c87aefeSPatrick Mooney 	.usbssd = {
2274c87aefeSPatrick Mooney 		.bLength = sizeof(umouse_bosd.usbssd),
2284c87aefeSPatrick Mooney 		.bDescriptorType = UDESC_DEVICE_CAPABILITY,
2294c87aefeSPatrick Mooney 		.bDevCapabilityType = 3,
2304c87aefeSPatrick Mooney 		.bmAttributes = 0,
2314c87aefeSPatrick Mooney 		HSETW(.wSpeedsSupported, 0x08),
2324c87aefeSPatrick Mooney 		.bFunctionalitySupport = 3,
2334c87aefeSPatrick Mooney 		.bU1DevExitLat = 0xa,   /* dummy - not used */
2344c87aefeSPatrick Mooney 		.wU2DevExitLat = { 0x20, 0x00 },
2354c87aefeSPatrick Mooney 	}
2364c87aefeSPatrick Mooney };
2374c87aefeSPatrick Mooney 
2384c87aefeSPatrick Mooney 
2394c87aefeSPatrick Mooney struct umouse_softc {
2404c87aefeSPatrick Mooney 	struct usb_hci *hci;
2414c87aefeSPatrick Mooney 
2424c87aefeSPatrick Mooney 	struct umouse_report um_report;
2434c87aefeSPatrick Mooney 	int	newdata;
2444c87aefeSPatrick Mooney 	struct {
2454c87aefeSPatrick Mooney 		uint8_t	idle;
2464c87aefeSPatrick Mooney 		uint8_t	protocol;
2474c87aefeSPatrick Mooney 		uint8_t	feature;
2484c87aefeSPatrick Mooney 	} hid;
2494c87aefeSPatrick Mooney 
2504c87aefeSPatrick Mooney 	pthread_mutex_t	mtx;
2514c87aefeSPatrick Mooney 	pthread_mutex_t	ev_mtx;
2524c87aefeSPatrick Mooney 	int		polling;
2534c87aefeSPatrick Mooney 	struct timeval	prev_evt;
2544c87aefeSPatrick Mooney };
2554c87aefeSPatrick Mooney 
2564c87aefeSPatrick Mooney static void
2574c87aefeSPatrick Mooney umouse_event(uint8_t button, int x, int y, void *arg)
2584c87aefeSPatrick Mooney {
2594c87aefeSPatrick Mooney 	struct umouse_softc *sc;
2604c87aefeSPatrick Mooney 	struct bhyvegc_image *gc;
2614c87aefeSPatrick Mooney 
2624c87aefeSPatrick Mooney 	gc = console_get_image();
2634c87aefeSPatrick Mooney 	if (gc == NULL) {
2644c87aefeSPatrick Mooney 		/* not ready */
2654c87aefeSPatrick Mooney 		return;
2664c87aefeSPatrick Mooney 	}
2674c87aefeSPatrick Mooney 
2684c87aefeSPatrick Mooney 	sc = arg;
2694c87aefeSPatrick Mooney 
2704c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->mtx);
2714c87aefeSPatrick Mooney 
2724c87aefeSPatrick Mooney 	sc->um_report.buttons = 0;
2734c87aefeSPatrick Mooney 	sc->um_report.z = 0;
2744c87aefeSPatrick Mooney 
2754c87aefeSPatrick Mooney 	if (button & 0x01)
2764c87aefeSPatrick Mooney 		sc->um_report.buttons |= 0x01;	/* left */
2774c87aefeSPatrick Mooney 	if (button & 0x02)
2784c87aefeSPatrick Mooney 		sc->um_report.buttons |= 0x04;	/* middle */
2794c87aefeSPatrick Mooney 	if (button & 0x04)
2804c87aefeSPatrick Mooney 		sc->um_report.buttons |= 0x02;	/* right */
2814c87aefeSPatrick Mooney 	if (button & 0x8)
2824c87aefeSPatrick Mooney 		sc->um_report.z = 1;
2834c87aefeSPatrick Mooney 	if (button & 0x10)
2844c87aefeSPatrick Mooney 		sc->um_report.z = -1;
2854c87aefeSPatrick Mooney 
2864c87aefeSPatrick Mooney 	/* scale coords to mouse resolution */
2874c87aefeSPatrick Mooney 	sc->um_report.x = MOUSE_MAX_X * x / gc->width;
2884c87aefeSPatrick Mooney 	sc->um_report.y = MOUSE_MAX_Y * y / gc->height;
2894c87aefeSPatrick Mooney 	sc->newdata = 1;
2904c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->mtx);
2914c87aefeSPatrick Mooney 
2924c87aefeSPatrick Mooney 	pthread_mutex_lock(&sc->ev_mtx);
2934c87aefeSPatrick Mooney 	sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT);
2944c87aefeSPatrick Mooney 	pthread_mutex_unlock(&sc->ev_mtx);
2954c87aefeSPatrick Mooney }
2964c87aefeSPatrick Mooney 
2974c87aefeSPatrick Mooney static void *
298*2b948146SAndy Fiddaman umouse_init(struct usb_hci *hci, nvlist_t *nvl)
2994c87aefeSPatrick Mooney {
3004c87aefeSPatrick Mooney 	struct umouse_softc *sc;
3014c87aefeSPatrick Mooney 
3024c87aefeSPatrick Mooney 	sc = calloc(1, sizeof(struct umouse_softc));
3034c87aefeSPatrick Mooney 	sc->hci = hci;
3044c87aefeSPatrick Mooney 
3054c87aefeSPatrick Mooney 	sc->hid.protocol = 1;	/* REPORT protocol */
3064c87aefeSPatrick Mooney 	pthread_mutex_init(&sc->mtx, NULL);
3074c87aefeSPatrick Mooney 	pthread_mutex_init(&sc->ev_mtx, NULL);
3084c87aefeSPatrick Mooney 
3094c87aefeSPatrick Mooney 	console_ptr_register(umouse_event, sc, 10);
3104c87aefeSPatrick Mooney 
3114c87aefeSPatrick Mooney 	return (sc);
3124c87aefeSPatrick Mooney }
3134c87aefeSPatrick Mooney 
3144c87aefeSPatrick Mooney #define	UREQ(x,y)	((x) | ((y) << 8))
3154c87aefeSPatrick Mooney 
3164c87aefeSPatrick Mooney static int
3174c87aefeSPatrick Mooney umouse_request(void *scarg, struct usb_data_xfer *xfer)
3184c87aefeSPatrick Mooney {
3194c87aefeSPatrick Mooney 	struct umouse_softc *sc;
3204c87aefeSPatrick Mooney 	struct usb_data_xfer_block *data;
3214c87aefeSPatrick Mooney 	const char *str;
3224c87aefeSPatrick Mooney 	uint16_t value;
3234c87aefeSPatrick Mooney 	uint16_t index;
3244c87aefeSPatrick Mooney 	uint16_t len;
3254c87aefeSPatrick Mooney 	uint16_t slen;
3264c87aefeSPatrick Mooney 	uint8_t *udata;
3274c87aefeSPatrick Mooney 	int	err;
3284c87aefeSPatrick Mooney 	int	i, idx;
3294c87aefeSPatrick Mooney 	int	eshort;
3304c87aefeSPatrick Mooney 
3314c87aefeSPatrick Mooney 	sc = scarg;
3324c87aefeSPatrick Mooney 
3334c87aefeSPatrick Mooney 	data = NULL;
3344c87aefeSPatrick Mooney 	udata = NULL;
3354c87aefeSPatrick Mooney 	idx = xfer->head;
3364c87aefeSPatrick Mooney 	for (i = 0; i < xfer->ndata; i++) {
3374c87aefeSPatrick Mooney 		xfer->data[idx].bdone = 0;
3384c87aefeSPatrick Mooney 		if (data == NULL && USB_DATA_OK(xfer,i)) {
3394c87aefeSPatrick Mooney 			data = &xfer->data[idx];
3404c87aefeSPatrick Mooney 			udata = data->buf;
3414c87aefeSPatrick Mooney 		}
3424c87aefeSPatrick Mooney 
3434c87aefeSPatrick Mooney 		xfer->data[idx].processed = 1;
3444c87aefeSPatrick Mooney 		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
3454c87aefeSPatrick Mooney 	}
3464c87aefeSPatrick Mooney 
3474c87aefeSPatrick Mooney 	err = USB_ERR_NORMAL_COMPLETION;
3484c87aefeSPatrick Mooney 	eshort = 0;
3494c87aefeSPatrick Mooney 
3504c87aefeSPatrick Mooney 	if (!xfer->ureq) {
351154972afSPatrick Mooney 		DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
3524c87aefeSPatrick Mooney 		goto done;
3534c87aefeSPatrick Mooney 	}
3544c87aefeSPatrick Mooney 
3554c87aefeSPatrick Mooney 	value = UGETW(xfer->ureq->wValue);
3564c87aefeSPatrick Mooney 	index = UGETW(xfer->ureq->wIndex);
3574c87aefeSPatrick Mooney 	len = UGETW(xfer->ureq->wLength);
3584c87aefeSPatrick Mooney 
3594c87aefeSPatrick Mooney 	DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
360154972afSPatrick Mooney 	         "idx 0x%x, len %u",
3614c87aefeSPatrick Mooney 	         sc->hci->hci_port, xfer->ureq->bmRequestType,
3624c87aefeSPatrick Mooney 	         xfer->ureq->bRequest, value, index, len));
3634c87aefeSPatrick Mooney 
3644c87aefeSPatrick Mooney 	switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
3654c87aefeSPatrick Mooney 	case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
366154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
3674c87aefeSPatrick Mooney 		if (!data)
3684c87aefeSPatrick Mooney 			break;
3694c87aefeSPatrick Mooney 
3704c87aefeSPatrick Mooney 		*udata = umouse_confd.confd.bConfigurationValue;
3714c87aefeSPatrick Mooney 		data->blen = len > 0 ? len - 1 : 0;
3724c87aefeSPatrick Mooney 		eshort = data->blen > 0;
3734c87aefeSPatrick Mooney 		data->bdone += 1;
3744c87aefeSPatrick Mooney 		break;
3754c87aefeSPatrick Mooney 
3764c87aefeSPatrick Mooney 	case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
377154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
3784c87aefeSPatrick Mooney 		        value >> 8));
3794c87aefeSPatrick Mooney 		if (!data)
3804c87aefeSPatrick Mooney 			break;
3814c87aefeSPatrick Mooney 
3824c87aefeSPatrick Mooney 		switch (value >> 8) {
3834c87aefeSPatrick Mooney 		case UDESC_DEVICE:
3844c87aefeSPatrick Mooney 			DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
385154972afSPatrick Mooney 			         "sizeof(umouse_dev_desc) %lu",
3864c87aefeSPatrick Mooney 			         len, sizeof(umouse_dev_desc)));
3874c87aefeSPatrick Mooney 			if ((value & 0xFF) != 0) {
3886960cd89SAndy Fiddaman 				err = USB_ERR_STALLED;
3894c87aefeSPatrick Mooney 				goto done;
3904c87aefeSPatrick Mooney 			}
3914c87aefeSPatrick Mooney 			if (len > sizeof(umouse_dev_desc)) {
3924c87aefeSPatrick Mooney 				data->blen = len - sizeof(umouse_dev_desc);
3934c87aefeSPatrick Mooney 				len = sizeof(umouse_dev_desc);
3944c87aefeSPatrick Mooney 			} else
3954c87aefeSPatrick Mooney 				data->blen = 0;
3964c87aefeSPatrick Mooney 			memcpy(data->buf, &umouse_dev_desc, len);
3974c87aefeSPatrick Mooney 			data->bdone += len;
3984c87aefeSPatrick Mooney 			break;
3994c87aefeSPatrick Mooney 
4004c87aefeSPatrick Mooney 		case UDESC_CONFIG:
401154972afSPatrick Mooney 			DPRINTF(("umouse: (->UDESC_CONFIG)"));
4024c87aefeSPatrick Mooney 			if ((value & 0xFF) != 0) {
4036960cd89SAndy Fiddaman 				err = USB_ERR_STALLED;
4044c87aefeSPatrick Mooney 				goto done;
4054c87aefeSPatrick Mooney 			}
4064c87aefeSPatrick Mooney 			if (len > sizeof(umouse_confd)) {
4074c87aefeSPatrick Mooney 				data->blen = len - sizeof(umouse_confd);
4084c87aefeSPatrick Mooney 				len = sizeof(umouse_confd);
4094c87aefeSPatrick Mooney 			} else
4104c87aefeSPatrick Mooney 				data->blen = 0;
4114c87aefeSPatrick Mooney 
4124c87aefeSPatrick Mooney 			memcpy(data->buf, &umouse_confd, len);
4134c87aefeSPatrick Mooney 			data->bdone += len;
4144c87aefeSPatrick Mooney 			break;
4154c87aefeSPatrick Mooney 
4164c87aefeSPatrick Mooney 		case UDESC_STRING:
417154972afSPatrick Mooney 			DPRINTF(("umouse: (->UDESC_STRING)"));
4184c87aefeSPatrick Mooney 			str = NULL;
4194c87aefeSPatrick Mooney 			if ((value & 0xFF) < UMSTR_MAX)
4204c87aefeSPatrick Mooney 				str = umouse_desc_strings[value & 0xFF];
4214c87aefeSPatrick Mooney 			else
4224c87aefeSPatrick Mooney 				goto done;
4234c87aefeSPatrick Mooney 
4244c87aefeSPatrick Mooney 			if ((value & 0xFF) == UMSTR_LANG) {
4254c87aefeSPatrick Mooney 				udata[0] = 4;
4264c87aefeSPatrick Mooney 				udata[1] = UDESC_STRING;
4274c87aefeSPatrick Mooney 				data->blen = len - 2;
4284c87aefeSPatrick Mooney 				len -= 2;
4294c87aefeSPatrick Mooney 				data->bdone += 2;
4304c87aefeSPatrick Mooney 
4314c87aefeSPatrick Mooney 				if (len >= 2) {
4324c87aefeSPatrick Mooney 					udata[2] = str[0];
4334c87aefeSPatrick Mooney 					udata[3] = str[1];
4344c87aefeSPatrick Mooney 					data->blen -= 2;
4354c87aefeSPatrick Mooney 					data->bdone += 2;
4364c87aefeSPatrick Mooney 				} else
4374c87aefeSPatrick Mooney 					data->blen = 0;
4384c87aefeSPatrick Mooney 
4394c87aefeSPatrick Mooney 				goto done;
4404c87aefeSPatrick Mooney 			}
4414c87aefeSPatrick Mooney 
4424c87aefeSPatrick Mooney 			slen = 2 + strlen(str) * 2;
4434c87aefeSPatrick Mooney 			udata[0] = slen;
4444c87aefeSPatrick Mooney 			udata[1] = UDESC_STRING;
4454c87aefeSPatrick Mooney 
4464c87aefeSPatrick Mooney 			if (len > slen) {
4474c87aefeSPatrick Mooney 				data->blen = len - slen;
4484c87aefeSPatrick Mooney 				len = slen;
4494c87aefeSPatrick Mooney 			} else
4504c87aefeSPatrick Mooney 				data->blen = 0;
4514c87aefeSPatrick Mooney 			for (i = 2; i < len; i += 2) {
4524c87aefeSPatrick Mooney 				udata[i] = *str++;
4534c87aefeSPatrick Mooney 				udata[i+1] = '\0';
4544c87aefeSPatrick Mooney 			}
4554c87aefeSPatrick Mooney 			data->bdone += slen;
4564c87aefeSPatrick Mooney 
4574c87aefeSPatrick Mooney 			break;
4584c87aefeSPatrick Mooney 
4594c87aefeSPatrick Mooney 		case UDESC_BOS:
460154972afSPatrick Mooney 			DPRINTF(("umouse: USB3 BOS"));
4614c87aefeSPatrick Mooney 			if (len > sizeof(umouse_bosd)) {
4624c87aefeSPatrick Mooney 				data->blen = len - sizeof(umouse_bosd);
4634c87aefeSPatrick Mooney 				len = sizeof(umouse_bosd);
4644c87aefeSPatrick Mooney 			} else
4654c87aefeSPatrick Mooney 				data->blen = 0;
4664c87aefeSPatrick Mooney 			memcpy(udata, &umouse_bosd, len);
4674c87aefeSPatrick Mooney 			data->bdone += len;
4684c87aefeSPatrick Mooney 			break;
4694c87aefeSPatrick Mooney 
4704c87aefeSPatrick Mooney 		default:
471154972afSPatrick Mooney 			DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
4726960cd89SAndy Fiddaman 			err = USB_ERR_STALLED;
4734c87aefeSPatrick Mooney 			goto done;
4744c87aefeSPatrick Mooney 		}
4754c87aefeSPatrick Mooney 		eshort = data->blen > 0;
4764c87aefeSPatrick Mooney 		break;
4774c87aefeSPatrick Mooney 
4784c87aefeSPatrick Mooney 	case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
4794c87aefeSPatrick Mooney 		DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
480154972afSPatrick Mooney 		         "0x%x", (value >> 8)));
4814c87aefeSPatrick Mooney 		if (!data)
4824c87aefeSPatrick Mooney 			break;
4834c87aefeSPatrick Mooney 
4844c87aefeSPatrick Mooney 		switch (value >> 8) {
4854c87aefeSPatrick Mooney 		case UMOUSE_REPORT_DESC_TYPE:
4864c87aefeSPatrick Mooney 			if (len > sizeof(umouse_report_desc)) {
4874c87aefeSPatrick Mooney 				data->blen = len - sizeof(umouse_report_desc);
4884c87aefeSPatrick Mooney 				len = sizeof(umouse_report_desc);
4894c87aefeSPatrick Mooney 			} else
4904c87aefeSPatrick Mooney 				data->blen = 0;
4914c87aefeSPatrick Mooney 			memcpy(data->buf, umouse_report_desc, len);
4924c87aefeSPatrick Mooney 			data->bdone += len;
4934c87aefeSPatrick Mooney 			break;
4944c87aefeSPatrick Mooney 		default:
495154972afSPatrick Mooney 			DPRINTF(("umouse: IO ERROR"));
4966960cd89SAndy Fiddaman 			err = USB_ERR_STALLED;
4974c87aefeSPatrick Mooney 			goto done;
4984c87aefeSPatrick Mooney 		}
4994c87aefeSPatrick Mooney 		eshort = data->blen > 0;
5004c87aefeSPatrick Mooney 		break;
5014c87aefeSPatrick Mooney 
5024c87aefeSPatrick Mooney 	case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
503154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
5044c87aefeSPatrick Mooney 		if (index != 0) {
505154972afSPatrick Mooney 			DPRINTF(("umouse get_interface, invalid index %d",
5064c87aefeSPatrick Mooney 			        index));
5076960cd89SAndy Fiddaman 			err = USB_ERR_STALLED;
5084c87aefeSPatrick Mooney 			goto done;
5094c87aefeSPatrick Mooney 		}
5104c87aefeSPatrick Mooney 
5114c87aefeSPatrick Mooney 		if (!data)
5124c87aefeSPatrick Mooney 			break;
5134c87aefeSPatrick Mooney 
5144c87aefeSPatrick Mooney 		if (len > 0) {
5154c87aefeSPatrick Mooney 			*udata = 0;
5164c87aefeSPatrick Mooney 			data->blen = len - 1;
5174c87aefeSPatrick Mooney 		}
5184c87aefeSPatrick Mooney 		eshort = data->blen > 0;
5194c87aefeSPatrick Mooney 		data->bdone += 1;
5204c87aefeSPatrick Mooney 		break;
5214c87aefeSPatrick Mooney 
5224c87aefeSPatrick Mooney 	case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
523154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
5244c87aefeSPatrick Mooney 		if (data != NULL && len > 1) {
5254c87aefeSPatrick Mooney 			if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
5264c87aefeSPatrick Mooney 				USETW(udata, UDS_REMOTE_WAKEUP);
5274c87aefeSPatrick Mooney 			else
5284c87aefeSPatrick Mooney 				USETW(udata, 0);
5294c87aefeSPatrick Mooney 			data->blen = len - 2;
5304c87aefeSPatrick Mooney 			data->bdone += 2;
5314c87aefeSPatrick Mooney 		}
5324c87aefeSPatrick Mooney 
5334c87aefeSPatrick Mooney 		eshort = data->blen > 0;
5344c87aefeSPatrick Mooney 		break;
5354c87aefeSPatrick Mooney 
5364c87aefeSPatrick Mooney 	case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
5374c87aefeSPatrick Mooney 	case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
538154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
5394c87aefeSPatrick Mooney 		if (data != NULL && len > 1) {
5404c87aefeSPatrick Mooney 			USETW(udata, 0);
5414c87aefeSPatrick Mooney 			data->blen = len - 2;
5424c87aefeSPatrick Mooney 			data->bdone += 2;
5434c87aefeSPatrick Mooney 		}
5444c87aefeSPatrick Mooney 		eshort = data->blen > 0;
5454c87aefeSPatrick Mooney 		break;
5464c87aefeSPatrick Mooney 
5474c87aefeSPatrick Mooney 	case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
5484c87aefeSPatrick Mooney 		/* XXX Controller should've handled this */
549154972afSPatrick Mooney 		DPRINTF(("umouse set address %u", value));
5504c87aefeSPatrick Mooney 		break;
5514c87aefeSPatrick Mooney 
5524c87aefeSPatrick Mooney 	case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
553154972afSPatrick Mooney 		DPRINTF(("umouse set config %u", value));
5544c87aefeSPatrick Mooney 		break;
5554c87aefeSPatrick Mooney 
5564c87aefeSPatrick Mooney 	case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
557154972afSPatrick Mooney 		DPRINTF(("umouse set descriptor %u", value));
5584c87aefeSPatrick Mooney 		break;
5594c87aefeSPatrick Mooney 
5604c87aefeSPatrick Mooney 
5614c87aefeSPatrick Mooney 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
562154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5634c87aefeSPatrick Mooney 		if (value == UF_DEVICE_REMOTE_WAKEUP)
5644c87aefeSPatrick Mooney 			sc->hid.feature = 0;
5654c87aefeSPatrick Mooney 		break;
5664c87aefeSPatrick Mooney 
5674c87aefeSPatrick Mooney 	case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
568154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5694c87aefeSPatrick Mooney 		if (value == UF_DEVICE_REMOTE_WAKEUP)
5704c87aefeSPatrick Mooney 			sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
5714c87aefeSPatrick Mooney 		break;
5724c87aefeSPatrick Mooney 
5734c87aefeSPatrick Mooney 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
5744c87aefeSPatrick Mooney 	case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
5754c87aefeSPatrick Mooney 	case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
5764c87aefeSPatrick Mooney 	case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
577154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
5786960cd89SAndy Fiddaman 		err = USB_ERR_STALLED;
5794c87aefeSPatrick Mooney 		goto done;
5804c87aefeSPatrick Mooney 
5814c87aefeSPatrick Mooney 	case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
582154972afSPatrick Mooney 		DPRINTF(("umouse set interface %u", value));
5834c87aefeSPatrick Mooney 		break;
5844c87aefeSPatrick Mooney 
5854c87aefeSPatrick Mooney 	case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
586154972afSPatrick Mooney 		DPRINTF(("umouse set isoch delay %u", value));
5874c87aefeSPatrick Mooney 		break;
5884c87aefeSPatrick Mooney 
5894c87aefeSPatrick Mooney 	case UREQ(UR_SET_SEL, 0):
590154972afSPatrick Mooney 		DPRINTF(("umouse set sel"));
5914c87aefeSPatrick Mooney 		break;
5924c87aefeSPatrick Mooney 
5934c87aefeSPatrick Mooney 	case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
594154972afSPatrick Mooney 		DPRINTF(("umouse synch frame"));
5954c87aefeSPatrick Mooney 		break;
5964c87aefeSPatrick Mooney 
5974c87aefeSPatrick Mooney 	/* HID device requests */
5984c87aefeSPatrick Mooney 
5994c87aefeSPatrick Mooney 	case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
6004c87aefeSPatrick Mooney 		DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
601154972afSPatrick Mooney 		         "0x%x", (value >> 8)));
6024c87aefeSPatrick Mooney 		if (!data)
6034c87aefeSPatrick Mooney 			break;
6044c87aefeSPatrick Mooney 
6054c87aefeSPatrick Mooney 		if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
6064c87aefeSPatrick Mooney 			/* TODO read from backend */
6074c87aefeSPatrick Mooney 
6084c87aefeSPatrick Mooney 			if (len > sizeof(sc->um_report)) {
6094c87aefeSPatrick Mooney 				data->blen = len - sizeof(sc->um_report);
6104c87aefeSPatrick Mooney 				len = sizeof(sc->um_report);
6114c87aefeSPatrick Mooney 			} else
6124c87aefeSPatrick Mooney 				data->blen = 0;
6134c87aefeSPatrick Mooney 
6144c87aefeSPatrick Mooney 			memcpy(data->buf, &sc->um_report, len);
6154c87aefeSPatrick Mooney 			data->bdone += len;
6164c87aefeSPatrick Mooney 		} else {
6176960cd89SAndy Fiddaman 			err = USB_ERR_STALLED;
6184c87aefeSPatrick Mooney 			goto done;
6194c87aefeSPatrick Mooney 		}
6204c87aefeSPatrick Mooney 		eshort = data->blen > 0;
6214c87aefeSPatrick Mooney 		break;
6224c87aefeSPatrick Mooney 
6234c87aefeSPatrick Mooney 	case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
6244c87aefeSPatrick Mooney 		if (data != NULL && len > 0) {
6254c87aefeSPatrick Mooney 			*udata = sc->hid.idle;
6264c87aefeSPatrick Mooney 			data->blen = len - 1;
6274c87aefeSPatrick Mooney 			data->bdone += 1;
6284c87aefeSPatrick Mooney 		}
6294c87aefeSPatrick Mooney 		eshort = data->blen > 0;
6304c87aefeSPatrick Mooney 		break;
6314c87aefeSPatrick Mooney 
6324c87aefeSPatrick Mooney 	case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
6334c87aefeSPatrick Mooney 		if (data != NULL && len > 0) {
6344c87aefeSPatrick Mooney 			*udata = sc->hid.protocol;
6354c87aefeSPatrick Mooney 			data->blen = len - 1;
6364c87aefeSPatrick Mooney 			data->bdone += 1;
6374c87aefeSPatrick Mooney 		}
6384c87aefeSPatrick Mooney 		eshort = data->blen > 0;
6394c87aefeSPatrick Mooney 		break;
6404c87aefeSPatrick Mooney 
6414c87aefeSPatrick Mooney 	case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
642154972afSPatrick Mooney 		DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
6434c87aefeSPatrick Mooney 		break;
6444c87aefeSPatrick Mooney 
6454c87aefeSPatrick Mooney 	case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
6464c87aefeSPatrick Mooney 		sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
647154972afSPatrick Mooney 		DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
6484c87aefeSPatrick Mooney 		        sc->hid.idle));
6494c87aefeSPatrick Mooney 		break;
6504c87aefeSPatrick Mooney 
6514c87aefeSPatrick Mooney 	case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
6524c87aefeSPatrick Mooney 		sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
653154972afSPatrick Mooney 		DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
6544c87aefeSPatrick Mooney 		        sc->hid.protocol));
6554c87aefeSPatrick Mooney 		break;
6564c87aefeSPatrick Mooney 
6574c87aefeSPatrick Mooney 	default:
658154972afSPatrick Mooney 		DPRINTF(("**** umouse request unhandled"));
6596960cd89SAndy Fiddaman 		err = USB_ERR_STALLED;
6604c87aefeSPatrick Mooney 		break;
6614c87aefeSPatrick Mooney 	}
6624c87aefeSPatrick Mooney 
6634c87aefeSPatrick Mooney done:
6644c87aefeSPatrick Mooney /* UT_WRITE is 0, so this is condition is never true. */
6654c87aefeSPatrick Mooney #ifdef __FreeBSD__
6664c87aefeSPatrick Mooney 	if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
6674c87aefeSPatrick Mooney 	    (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
6684c87aefeSPatrick Mooney 		data->blen = 0;
6694c87aefeSPatrick Mooney 	else if (eshort)
6704c87aefeSPatrick Mooney 		err = USB_ERR_SHORT_XFER;
6714c87aefeSPatrick Mooney #else
6724c87aefeSPatrick Mooney 	if (eshort)
6734c87aefeSPatrick Mooney 		err = USB_ERR_SHORT_XFER;
6744c87aefeSPatrick Mooney #endif
6754c87aefeSPatrick Mooney 
6764c87aefeSPatrick Mooney 
677154972afSPatrick Mooney 	DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
6784c87aefeSPatrick Mooney 	        err, (data ? data->blen : 0), (data ? data->bdone : 0)));
6794c87aefeSPatrick Mooney 
6804c87aefeSPatrick Mooney 	return (err);
6814c87aefeSPatrick Mooney }
6824c87aefeSPatrick Mooney 
6834c87aefeSPatrick Mooney static int
6844c87aefeSPatrick Mooney umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
6854c87aefeSPatrick Mooney      int epctx)
6864c87aefeSPatrick Mooney {
6874c87aefeSPatrick Mooney 	struct umouse_softc *sc;
6884c87aefeSPatrick Mooney 	struct usb_data_xfer_block *data;
6894c87aefeSPatrick Mooney 	uint8_t *udata;
6904c87aefeSPatrick Mooney 	int len, i, idx;
6914c87aefeSPatrick Mooney 	int err;
6924c87aefeSPatrick Mooney 
693154972afSPatrick Mooney 	DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
6944c87aefeSPatrick Mooney 	        dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
6954c87aefeSPatrick Mooney 
6964c87aefeSPatrick Mooney 
6974c87aefeSPatrick Mooney 	/* find buffer to add data */
6984c87aefeSPatrick Mooney 	udata = NULL;
6994c87aefeSPatrick Mooney 	err = USB_ERR_NORMAL_COMPLETION;
7004c87aefeSPatrick Mooney 
7014c87aefeSPatrick Mooney 	/* handle xfer at first unprocessed item with buffer */
7024c87aefeSPatrick Mooney 	data = NULL;
7034c87aefeSPatrick Mooney 	idx = xfer->head;
7044c87aefeSPatrick Mooney 	for (i = 0; i < xfer->ndata; i++) {
7054c87aefeSPatrick Mooney 		data = &xfer->data[idx];
7064c87aefeSPatrick Mooney 		if (data->buf != NULL && data->blen != 0) {
7074c87aefeSPatrick Mooney 			break;
7084c87aefeSPatrick Mooney 		} else {
7094c87aefeSPatrick Mooney 			data->processed = 1;
7104c87aefeSPatrick Mooney 			data = NULL;
7114c87aefeSPatrick Mooney 		}
7124c87aefeSPatrick Mooney 		idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
7134c87aefeSPatrick Mooney 	}
7144c87aefeSPatrick Mooney 	if (!data)
7154c87aefeSPatrick Mooney 		goto done;
7164c87aefeSPatrick Mooney 
7174c87aefeSPatrick Mooney 	udata = data->buf;
7184c87aefeSPatrick Mooney 	len = data->blen;
7194c87aefeSPatrick Mooney 
7204c87aefeSPatrick Mooney 	if (udata == NULL) {
721154972afSPatrick Mooney 		DPRINTF(("umouse no buffer provided for input"));
7224c87aefeSPatrick Mooney 		err = USB_ERR_NOMEM;
7234c87aefeSPatrick Mooney 		goto done;
7244c87aefeSPatrick Mooney 	}
7254c87aefeSPatrick Mooney 
7264c87aefeSPatrick Mooney 	sc = scarg;
7274c87aefeSPatrick Mooney 
7284c87aefeSPatrick Mooney 	if (dir) {
7294c87aefeSPatrick Mooney 
7304c87aefeSPatrick Mooney 		pthread_mutex_lock(&sc->mtx);
7314c87aefeSPatrick Mooney 
7324c87aefeSPatrick Mooney 		if (!sc->newdata) {
7334c87aefeSPatrick Mooney 			err = USB_ERR_CANCELLED;
7344c87aefeSPatrick Mooney 			USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
7354c87aefeSPatrick Mooney 			pthread_mutex_unlock(&sc->mtx);
7364c87aefeSPatrick Mooney 			goto done;
7374c87aefeSPatrick Mooney 		}
7384c87aefeSPatrick Mooney 
7394c87aefeSPatrick Mooney 		if (sc->polling) {
7404c87aefeSPatrick Mooney 			err = USB_ERR_STALLED;
7414c87aefeSPatrick Mooney 			USB_DATA_SET_ERRCODE(data, USB_STALL);
7424c87aefeSPatrick Mooney 			pthread_mutex_unlock(&sc->mtx);
7434c87aefeSPatrick Mooney 			goto done;
7444c87aefeSPatrick Mooney 		}
7454c87aefeSPatrick Mooney 		sc->polling = 1;
7464c87aefeSPatrick Mooney 
7474c87aefeSPatrick Mooney 		if (len > 0) {
7484c87aefeSPatrick Mooney 			sc->newdata = 0;
7494c87aefeSPatrick Mooney 
7504c87aefeSPatrick Mooney 			data->processed = 1;
7514c87aefeSPatrick Mooney 			data->bdone += 6;
7524c87aefeSPatrick Mooney 			memcpy(udata, &sc->um_report, 6);
7534c87aefeSPatrick Mooney 			data->blen = len - 6;
7544c87aefeSPatrick Mooney 			if (data->blen > 0)
7554c87aefeSPatrick Mooney 				err = USB_ERR_SHORT_XFER;
7564c87aefeSPatrick Mooney 		}
7574c87aefeSPatrick Mooney 
7584c87aefeSPatrick Mooney 		sc->polling = 0;
7594c87aefeSPatrick Mooney 		pthread_mutex_unlock(&sc->mtx);
7604c87aefeSPatrick Mooney 	} else {
7614c87aefeSPatrick Mooney 		USB_DATA_SET_ERRCODE(data, USB_STALL);
7624c87aefeSPatrick Mooney 		err = USB_ERR_STALLED;
7634c87aefeSPatrick Mooney 	}
7644c87aefeSPatrick Mooney 
7654c87aefeSPatrick Mooney done:
7664c87aefeSPatrick Mooney 	return (err);
7674c87aefeSPatrick Mooney }
7684c87aefeSPatrick Mooney 
7694c87aefeSPatrick Mooney static int
7704c87aefeSPatrick Mooney umouse_reset(void *scarg)
7714c87aefeSPatrick Mooney {
7724c87aefeSPatrick Mooney 	struct umouse_softc *sc;
7734c87aefeSPatrick Mooney 
7744c87aefeSPatrick Mooney 	sc = scarg;
7754c87aefeSPatrick Mooney 
7764c87aefeSPatrick Mooney 	sc->newdata = 0;
7774c87aefeSPatrick Mooney 
7784c87aefeSPatrick Mooney 	return (0);
7794c87aefeSPatrick Mooney }
7804c87aefeSPatrick Mooney 
7814c87aefeSPatrick Mooney static int
7824c87aefeSPatrick Mooney umouse_remove(void *scarg)
7834c87aefeSPatrick Mooney {
7844c87aefeSPatrick Mooney 
7854c87aefeSPatrick Mooney 	return (0);
7864c87aefeSPatrick Mooney }
7874c87aefeSPatrick Mooney 
7884c87aefeSPatrick Mooney static int
7894c87aefeSPatrick Mooney umouse_stop(void *scarg)
7904c87aefeSPatrick Mooney {
7914c87aefeSPatrick Mooney 
7924c87aefeSPatrick Mooney 	return (0);
7934c87aefeSPatrick Mooney }
7944c87aefeSPatrick Mooney 
7954c87aefeSPatrick Mooney 
7964c87aefeSPatrick Mooney struct usb_devemu ue_mouse = {
7974c87aefeSPatrick Mooney 	.ue_emu =	"tablet",
7984c87aefeSPatrick Mooney 	.ue_usbver =	3,
7994c87aefeSPatrick Mooney 	.ue_usbspeed =	USB_SPEED_HIGH,
8004c87aefeSPatrick Mooney 	.ue_init =	umouse_init,
8014c87aefeSPatrick Mooney 	.ue_request =	umouse_request,
8024c87aefeSPatrick Mooney 	.ue_data =	umouse_data_handler,
8034c87aefeSPatrick Mooney 	.ue_reset =	umouse_reset,
8044c87aefeSPatrick Mooney 	.ue_remove =	umouse_remove,
8054c87aefeSPatrick Mooney 	.ue_stop =	umouse_stop
8064c87aefeSPatrick Mooney };
8074c87aefeSPatrick Mooney USB_EMUL_SET(ue_mouse);
808