12cf9911fSPeter Grehan /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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 #include <sys/time.h>
312cf9911fSPeter Grehan
32483d953aSJohn Baldwin #include <machine/vmm_snapshot.h>
33483d953aSJohn Baldwin
342cf9911fSPeter Grehan #include <pthread.h>
352cf9911fSPeter Grehan #include <stdio.h>
362cf9911fSPeter Grehan #include <stdlib.h>
372cf9911fSPeter Grehan #include <string.h>
382cf9911fSPeter Grehan
392cf9911fSPeter Grehan #include <dev/usb/usb.h>
402cf9911fSPeter Grehan #include <dev/usb/usbdi.h>
412cf9911fSPeter Grehan
422cf9911fSPeter Grehan #include "usb_emul.h"
432cf9911fSPeter Grehan #include "console.h"
442cf9911fSPeter Grehan #include "bhyvegc.h"
45332eff95SVincenzo Maffione #include "debug.h"
462cf9911fSPeter Grehan
472cf9911fSPeter Grehan static int umouse_debug = 0;
48332eff95SVincenzo Maffione #define DPRINTF(params) if (umouse_debug) PRINTLN params
49332eff95SVincenzo Maffione #define WPRINTF(params) PRINTLN params
502cf9911fSPeter Grehan
512cf9911fSPeter Grehan /* USB endpoint context (1-15) for reporting mouse data events*/
522cf9911fSPeter Grehan #define UMOUSE_INTR_ENDPT 1
532cf9911fSPeter Grehan
542cf9911fSPeter Grehan #define UMOUSE_REPORT_DESC_TYPE 0x22
552cf9911fSPeter Grehan
562cf9911fSPeter Grehan #define UMOUSE_GET_REPORT 0x01
572cf9911fSPeter Grehan #define UMOUSE_GET_IDLE 0x02
582cf9911fSPeter Grehan #define UMOUSE_GET_PROTOCOL 0x03
592cf9911fSPeter Grehan #define UMOUSE_SET_REPORT 0x09
602cf9911fSPeter Grehan #define UMOUSE_SET_IDLE 0x0A
612cf9911fSPeter Grehan #define UMOUSE_SET_PROTOCOL 0x0B
622cf9911fSPeter Grehan
632cf9911fSPeter Grehan #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
642cf9911fSPeter Grehan
652cf9911fSPeter Grehan enum {
662cf9911fSPeter Grehan UMSTR_LANG,
672cf9911fSPeter Grehan UMSTR_MANUFACTURER,
682cf9911fSPeter Grehan UMSTR_PRODUCT,
692cf9911fSPeter Grehan UMSTR_SERIAL,
702cf9911fSPeter Grehan UMSTR_CONFIG,
712cf9911fSPeter Grehan UMSTR_MAX
722cf9911fSPeter Grehan };
732cf9911fSPeter Grehan
742cf9911fSPeter Grehan static const char *umouse_desc_strings[] = {
75285e35e6SPeter Grehan "\x09\x04",
762cf9911fSPeter Grehan "BHYVE",
772cf9911fSPeter Grehan "HID Tablet",
782cf9911fSPeter Grehan "01",
792cf9911fSPeter Grehan "HID Tablet Device",
802cf9911fSPeter Grehan };
812cf9911fSPeter Grehan
822cf9911fSPeter Grehan struct umouse_hid_descriptor {
832cf9911fSPeter Grehan uint8_t bLength;
842cf9911fSPeter Grehan uint8_t bDescriptorType;
852cf9911fSPeter Grehan uint8_t bcdHID[2];
862cf9911fSPeter Grehan uint8_t bCountryCode;
872cf9911fSPeter Grehan uint8_t bNumDescriptors;
882cf9911fSPeter Grehan uint8_t bReportDescriptorType;
892cf9911fSPeter Grehan uint8_t wItemLength[2];
902cf9911fSPeter Grehan } __packed;
912cf9911fSPeter Grehan
922cf9911fSPeter Grehan struct umouse_config_desc {
932cf9911fSPeter Grehan struct usb_config_descriptor confd;
942cf9911fSPeter Grehan struct usb_interface_descriptor ifcd;
952cf9911fSPeter Grehan struct umouse_hid_descriptor hidd;
962cf9911fSPeter Grehan struct usb_endpoint_descriptor endpd;
972cf9911fSPeter Grehan struct usb_endpoint_ss_comp_descriptor sscompd;
982cf9911fSPeter Grehan } __packed;
992cf9911fSPeter Grehan
1002cf9911fSPeter Grehan #define MOUSE_MAX_X 0x8000
1012cf9911fSPeter Grehan #define MOUSE_MAX_Y 0x8000
1022cf9911fSPeter Grehan
1032cf9911fSPeter Grehan static const uint8_t umouse_report_desc[] = {
1042cf9911fSPeter Grehan 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
1052cf9911fSPeter Grehan 0x09, 0x02, /* USAGE (Mouse) */
1062cf9911fSPeter Grehan 0xa1, 0x01, /* COLLECTION (Application) */
1072cf9911fSPeter Grehan 0x09, 0x01, /* USAGE (Pointer) */
1082cf9911fSPeter Grehan 0xa1, 0x00, /* COLLECTION (Physical) */
1092cf9911fSPeter Grehan 0x05, 0x09, /* USAGE_PAGE (Button) */
1102cf9911fSPeter Grehan 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
1112cf9911fSPeter Grehan 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
1122cf9911fSPeter Grehan 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
1132cf9911fSPeter Grehan 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
1142cf9911fSPeter Grehan 0x75, 0x01, /* REPORT_SIZE (1) */
1152cf9911fSPeter Grehan 0x95, 0x03, /* REPORT_COUNT (3) */
1162cf9911fSPeter Grehan 0x81, 0x02, /* INPUT (Data,Var,Abs); 3 buttons */
1172cf9911fSPeter Grehan 0x75, 0x05, /* REPORT_SIZE (5) */
1182cf9911fSPeter Grehan 0x95, 0x01, /* REPORT_COUNT (1) */
1192cf9911fSPeter Grehan 0x81, 0x03, /* INPUT (Cnst,Var,Abs); padding */
1202cf9911fSPeter Grehan 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
1212cf9911fSPeter Grehan 0x09, 0x30, /* USAGE (X) */
1222cf9911fSPeter Grehan 0x09, 0x31, /* USAGE (Y) */
1232cf9911fSPeter Grehan 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */
1242cf9911fSPeter Grehan 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (0x7fff) */
1252cf9911fSPeter Grehan 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
1262cf9911fSPeter Grehan 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (0x7fff) */
1272cf9911fSPeter Grehan 0x75, 0x10, /* REPORT_SIZE (16) */
1282cf9911fSPeter Grehan 0x95, 0x02, /* REPORT_COUNT (2) */
1292cf9911fSPeter Grehan 0x81, 0x02, /* INPUT (Data,Var,Abs) */
1302cf9911fSPeter Grehan 0x05, 0x01, /* USAGE Page (Generic Desktop) */
1312cf9911fSPeter Grehan 0x09, 0x38, /* USAGE (Wheel) */
1322cf9911fSPeter Grehan 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */
1332cf9911fSPeter Grehan 0x45, 0x00, /* PHYSICAL_MAXIMUM (0) */
1342cf9911fSPeter Grehan 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
1352cf9911fSPeter Grehan 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
1362cf9911fSPeter Grehan 0x75, 0x08, /* REPORT_SIZE (8) */
1372cf9911fSPeter Grehan 0x95, 0x01, /* REPORT_COUNT (1) */
1382cf9911fSPeter Grehan 0x81, 0x06, /* INPUT (Data,Var,Rel) */
1392cf9911fSPeter Grehan 0xc0, /* END_COLLECTION */
1402cf9911fSPeter Grehan 0xc0 /* END_COLLECTION */
1412cf9911fSPeter Grehan };
1422cf9911fSPeter Grehan
1432cf9911fSPeter Grehan struct umouse_report {
1442cf9911fSPeter Grehan uint8_t buttons; /* bits: 0 left, 1 right, 2 middle */
1452cf9911fSPeter Grehan int16_t x; /* x position */
1462cf9911fSPeter Grehan int16_t y; /* y position */
1472cf9911fSPeter Grehan int8_t z; /* z wheel position */
1482cf9911fSPeter Grehan } __packed;
1492cf9911fSPeter Grehan
1502cf9911fSPeter Grehan
1512cf9911fSPeter Grehan #define MSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1522cf9911fSPeter Grehan
1532cf9911fSPeter Grehan static struct usb_device_descriptor umouse_dev_desc = {
1542cf9911fSPeter Grehan .bLength = sizeof(umouse_dev_desc),
1552cf9911fSPeter Grehan .bDescriptorType = UDESC_DEVICE,
1562cf9911fSPeter Grehan MSETW(.bcdUSB, UD_USB_3_0),
1570c243cd4SPeter Grehan .bMaxPacketSize = 9, /* max pkt size, 2^9 = 512 */
1582cf9911fSPeter Grehan MSETW(.idVendor, 0xFB5D), /* vendor */
1592cf9911fSPeter Grehan MSETW(.idProduct, 0x0001), /* product */
1602cf9911fSPeter Grehan MSETW(.bcdDevice, 0), /* device version */
1612cf9911fSPeter Grehan .iManufacturer = UMSTR_MANUFACTURER,
1622cf9911fSPeter Grehan .iProduct = UMSTR_PRODUCT,
1632cf9911fSPeter Grehan .iSerialNumber = UMSTR_SERIAL,
1642cf9911fSPeter Grehan .bNumConfigurations = 1,
1652cf9911fSPeter Grehan };
1662cf9911fSPeter Grehan
1672cf9911fSPeter Grehan static struct umouse_config_desc umouse_confd = {
1682cf9911fSPeter Grehan .confd = {
1692cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.confd),
1702cf9911fSPeter Grehan .bDescriptorType = UDESC_CONFIG,
1712cf9911fSPeter Grehan .wTotalLength[0] = sizeof(umouse_confd),
1722cf9911fSPeter Grehan .bNumInterface = 1,
1732cf9911fSPeter Grehan .bConfigurationValue = 1,
1742cf9911fSPeter Grehan .iConfiguration = UMSTR_CONFIG,
1752cf9911fSPeter Grehan .bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP,
1762cf9911fSPeter Grehan .bMaxPower = 0,
1772cf9911fSPeter Grehan },
1782cf9911fSPeter Grehan .ifcd = {
1792cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.ifcd),
1802cf9911fSPeter Grehan .bDescriptorType = UDESC_INTERFACE,
1812cf9911fSPeter Grehan .bNumEndpoints = 1,
1822cf9911fSPeter Grehan .bInterfaceClass = UICLASS_HID,
1832cf9911fSPeter Grehan .bInterfaceSubClass = UISUBCLASS_BOOT,
1842cf9911fSPeter Grehan .bInterfaceProtocol = UIPROTO_MOUSE,
1852cf9911fSPeter Grehan },
1862cf9911fSPeter Grehan .hidd = {
1872cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.hidd),
1882cf9911fSPeter Grehan .bDescriptorType = 0x21,
1892cf9911fSPeter Grehan .bcdHID = { 0x01, 0x10 },
1902cf9911fSPeter Grehan .bCountryCode = 0,
1912cf9911fSPeter Grehan .bNumDescriptors = 1,
1922cf9911fSPeter Grehan .bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE,
1932cf9911fSPeter Grehan .wItemLength = { sizeof(umouse_report_desc), 0 },
1942cf9911fSPeter Grehan },
1952cf9911fSPeter Grehan .endpd = {
1962cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.endpd),
1972cf9911fSPeter Grehan .bDescriptorType = UDESC_ENDPOINT,
1982cf9911fSPeter Grehan .bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT,
1992cf9911fSPeter Grehan .bmAttributes = UE_INTERRUPT,
2002cf9911fSPeter Grehan .wMaxPacketSize[0] = 8,
2012cf9911fSPeter Grehan .bInterval = 0xA,
2022cf9911fSPeter Grehan },
2032cf9911fSPeter Grehan .sscompd = {
2042cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.sscompd),
2052cf9911fSPeter Grehan .bDescriptorType = UDESC_ENDPOINT_SS_COMP,
2062cf9911fSPeter Grehan .bMaxBurst = 0,
2072cf9911fSPeter Grehan .bmAttributes = 0,
2082cf9911fSPeter Grehan MSETW(.wBytesPerInterval, 0),
2092cf9911fSPeter Grehan },
2102cf9911fSPeter Grehan };
2112cf9911fSPeter Grehan
2122cf9911fSPeter Grehan
2132cf9911fSPeter Grehan struct umouse_bos_desc {
2142cf9911fSPeter Grehan struct usb_bos_descriptor bosd;
2152cf9911fSPeter Grehan struct usb_devcap_ss_descriptor usbssd;
2162cf9911fSPeter Grehan } __packed;
2172cf9911fSPeter Grehan
2182cf9911fSPeter Grehan
219cd49c066SMark Johnston static struct umouse_bos_desc umouse_bosd = {
2202cf9911fSPeter Grehan .bosd = {
2212cf9911fSPeter Grehan .bLength = sizeof(umouse_bosd.bosd),
2222cf9911fSPeter Grehan .bDescriptorType = UDESC_BOS,
2232cf9911fSPeter Grehan HSETW(.wTotalLength, sizeof(umouse_bosd)),
2242cf9911fSPeter Grehan .bNumDeviceCaps = 1,
2252cf9911fSPeter Grehan },
2262cf9911fSPeter Grehan .usbssd = {
2272cf9911fSPeter Grehan .bLength = sizeof(umouse_bosd.usbssd),
2282cf9911fSPeter Grehan .bDescriptorType = UDESC_DEVICE_CAPABILITY,
2292cf9911fSPeter Grehan .bDevCapabilityType = 3,
2302cf9911fSPeter Grehan .bmAttributes = 0,
2312cf9911fSPeter Grehan HSETW(.wSpeedsSupported, 0x08),
2322cf9911fSPeter Grehan .bFunctionalitySupport = 3,
2332cf9911fSPeter Grehan .bU1DevExitLat = 0xa, /* dummy - not used */
2342cf9911fSPeter Grehan .wU2DevExitLat = { 0x20, 0x00 },
2352cf9911fSPeter Grehan }
2362cf9911fSPeter Grehan };
2372cf9911fSPeter Grehan
2382cf9911fSPeter Grehan
2392cf9911fSPeter Grehan struct umouse_softc {
2402cf9911fSPeter Grehan struct usb_hci *hci;
2412cf9911fSPeter Grehan
2422cf9911fSPeter Grehan struct umouse_report um_report;
2432cf9911fSPeter Grehan int newdata;
2442cf9911fSPeter Grehan struct {
2452cf9911fSPeter Grehan uint8_t idle;
2462cf9911fSPeter Grehan uint8_t protocol;
2472cf9911fSPeter Grehan uint8_t feature;
2482cf9911fSPeter Grehan } hid;
2492cf9911fSPeter Grehan
2502cf9911fSPeter Grehan pthread_mutex_t mtx;
2512cf9911fSPeter Grehan pthread_mutex_t ev_mtx;
2522cf9911fSPeter Grehan int polling;
2532cf9911fSPeter Grehan struct timeval prev_evt;
2542cf9911fSPeter Grehan };
2552cf9911fSPeter Grehan
2562cf9911fSPeter Grehan static void
umouse_event(uint8_t button,int x,int y,void * arg)2572cf9911fSPeter Grehan umouse_event(uint8_t button, int x, int y, void *arg)
2582cf9911fSPeter Grehan {
2592cf9911fSPeter Grehan struct umouse_softc *sc;
2602cf9911fSPeter Grehan struct bhyvegc_image *gc;
2612cf9911fSPeter Grehan
2622cf9911fSPeter Grehan gc = console_get_image();
2632cf9911fSPeter Grehan if (gc == NULL) {
2642cf9911fSPeter Grehan /* not ready */
2652cf9911fSPeter Grehan return;
2662cf9911fSPeter Grehan }
2672cf9911fSPeter Grehan
2682cf9911fSPeter Grehan sc = arg;
2692cf9911fSPeter Grehan
2702cf9911fSPeter Grehan pthread_mutex_lock(&sc->mtx);
2712cf9911fSPeter Grehan
2722cf9911fSPeter Grehan sc->um_report.buttons = 0;
2732cf9911fSPeter Grehan sc->um_report.z = 0;
2742cf9911fSPeter Grehan
2752cf9911fSPeter Grehan if (button & 0x01)
2762cf9911fSPeter Grehan sc->um_report.buttons |= 0x01; /* left */
2772cf9911fSPeter Grehan if (button & 0x02)
2782cf9911fSPeter Grehan sc->um_report.buttons |= 0x04; /* middle */
2792cf9911fSPeter Grehan if (button & 0x04)
2802cf9911fSPeter Grehan sc->um_report.buttons |= 0x02; /* right */
2812cf9911fSPeter Grehan if (button & 0x8)
2822cf9911fSPeter Grehan sc->um_report.z = 1;
2832cf9911fSPeter Grehan if (button & 0x10)
2842cf9911fSPeter Grehan sc->um_report.z = -1;
2852cf9911fSPeter Grehan
2862cf9911fSPeter Grehan /* scale coords to mouse resolution */
2872cf9911fSPeter Grehan sc->um_report.x = MOUSE_MAX_X * x / gc->width;
288b9c1cdd1SPeter Grehan sc->um_report.y = MOUSE_MAX_Y * y / gc->height;
2892cf9911fSPeter Grehan sc->newdata = 1;
2902cf9911fSPeter Grehan pthread_mutex_unlock(&sc->mtx);
2912cf9911fSPeter Grehan
2922cf9911fSPeter Grehan pthread_mutex_lock(&sc->ev_mtx);
2932cf9911fSPeter Grehan sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT);
2942cf9911fSPeter Grehan pthread_mutex_unlock(&sc->ev_mtx);
2952cf9911fSPeter Grehan }
2962cf9911fSPeter Grehan
2972cf9911fSPeter Grehan static void *
umouse_init(struct usb_hci * hci,nvlist_t * nvl __unused)29898d920d9SMark Johnston umouse_init(struct usb_hci *hci, nvlist_t *nvl __unused)
2992cf9911fSPeter Grehan {
3002cf9911fSPeter Grehan struct umouse_softc *sc;
3012cf9911fSPeter Grehan
3022cf9911fSPeter Grehan sc = calloc(1, sizeof(struct umouse_softc));
3032cf9911fSPeter Grehan sc->hci = hci;
3042cf9911fSPeter Grehan
3052cf9911fSPeter Grehan sc->hid.protocol = 1; /* REPORT protocol */
3062cf9911fSPeter Grehan pthread_mutex_init(&sc->mtx, NULL);
3072cf9911fSPeter Grehan pthread_mutex_init(&sc->ev_mtx, NULL);
3082cf9911fSPeter Grehan
3092cf9911fSPeter Grehan console_ptr_register(umouse_event, sc, 10);
3102cf9911fSPeter Grehan
3112cf9911fSPeter Grehan return (sc);
3122cf9911fSPeter Grehan }
3132cf9911fSPeter Grehan
3142cf9911fSPeter Grehan #define UREQ(x,y) ((x) | ((y) << 8))
3152cf9911fSPeter Grehan
3162cf9911fSPeter Grehan static int
umouse_request(void * scarg,struct usb_data_xfer * xfer)3172cf9911fSPeter Grehan umouse_request(void *scarg, struct usb_data_xfer *xfer)
3182cf9911fSPeter Grehan {
3192cf9911fSPeter Grehan struct umouse_softc *sc;
3202cf9911fSPeter Grehan struct usb_data_xfer_block *data;
3212cf9911fSPeter Grehan const char *str;
3222cf9911fSPeter Grehan uint16_t value;
3232cf9911fSPeter Grehan uint16_t index;
3242cf9911fSPeter Grehan uint16_t len;
3252cf9911fSPeter Grehan uint16_t slen;
3262cf9911fSPeter Grehan uint8_t *udata;
3272cf9911fSPeter Grehan int err;
3282cf9911fSPeter Grehan int i, idx;
3292cf9911fSPeter Grehan int eshort;
3302cf9911fSPeter Grehan
3312cf9911fSPeter Grehan sc = scarg;
3322cf9911fSPeter Grehan
3332cf9911fSPeter Grehan data = NULL;
3342cf9911fSPeter Grehan udata = NULL;
3352cf9911fSPeter Grehan idx = xfer->head;
3362cf9911fSPeter Grehan for (i = 0; i < xfer->ndata; i++) {
3372cf9911fSPeter Grehan xfer->data[idx].bdone = 0;
3382cf9911fSPeter Grehan if (data == NULL && USB_DATA_OK(xfer,i)) {
3392cf9911fSPeter Grehan data = &xfer->data[idx];
3402cf9911fSPeter Grehan udata = data->buf;
3412cf9911fSPeter Grehan }
3422cf9911fSPeter Grehan
3432cf9911fSPeter Grehan xfer->data[idx].processed = 1;
3442cf9911fSPeter Grehan idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
3452cf9911fSPeter Grehan }
3462cf9911fSPeter Grehan
3472cf9911fSPeter Grehan err = USB_ERR_NORMAL_COMPLETION;
3482cf9911fSPeter Grehan eshort = 0;
3492cf9911fSPeter Grehan
3502cf9911fSPeter Grehan if (!xfer->ureq) {
351332eff95SVincenzo Maffione DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
3522cf9911fSPeter Grehan goto done;
3532cf9911fSPeter Grehan }
3542cf9911fSPeter Grehan
3552cf9911fSPeter Grehan value = UGETW(xfer->ureq->wValue);
3562cf9911fSPeter Grehan index = UGETW(xfer->ureq->wIndex);
3572cf9911fSPeter Grehan len = UGETW(xfer->ureq->wLength);
3582cf9911fSPeter Grehan
3592cf9911fSPeter Grehan DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
360332eff95SVincenzo Maffione "idx 0x%x, len %u",
3612cf9911fSPeter Grehan sc->hci->hci_port, xfer->ureq->bmRequestType,
3622cf9911fSPeter Grehan xfer->ureq->bRequest, value, index, len));
3632cf9911fSPeter Grehan
3642cf9911fSPeter Grehan switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
3652cf9911fSPeter Grehan case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
366332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
3672cf9911fSPeter Grehan if (!data)
3682cf9911fSPeter Grehan break;
3692cf9911fSPeter Grehan
3702cf9911fSPeter Grehan *udata = umouse_confd.confd.bConfigurationValue;
3712cf9911fSPeter Grehan data->blen = len > 0 ? len - 1 : 0;
3722cf9911fSPeter Grehan eshort = data->blen > 0;
3732cf9911fSPeter Grehan data->bdone += 1;
3742cf9911fSPeter Grehan break;
3752cf9911fSPeter Grehan
3762cf9911fSPeter Grehan case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
377332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
3782cf9911fSPeter Grehan value >> 8));
3792cf9911fSPeter Grehan if (!data)
3802cf9911fSPeter Grehan break;
3812cf9911fSPeter Grehan
3822cf9911fSPeter Grehan switch (value >> 8) {
3832cf9911fSPeter Grehan case UDESC_DEVICE:
3842cf9911fSPeter Grehan DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
385332eff95SVincenzo Maffione "sizeof(umouse_dev_desc) %lu",
3862cf9911fSPeter Grehan len, sizeof(umouse_dev_desc)));
3872cf9911fSPeter Grehan if ((value & 0xFF) != 0) {
38871ab6f97SPeter Grehan err = USB_ERR_STALLED;
3892cf9911fSPeter Grehan goto done;
3902cf9911fSPeter Grehan }
3912cf9911fSPeter Grehan if (len > sizeof(umouse_dev_desc)) {
3922cf9911fSPeter Grehan data->blen = len - sizeof(umouse_dev_desc);
3932cf9911fSPeter Grehan len = sizeof(umouse_dev_desc);
3942cf9911fSPeter Grehan } else
3952cf9911fSPeter Grehan data->blen = 0;
3962cf9911fSPeter Grehan memcpy(data->buf, &umouse_dev_desc, len);
3972cf9911fSPeter Grehan data->bdone += len;
3982cf9911fSPeter Grehan break;
3992cf9911fSPeter Grehan
4002cf9911fSPeter Grehan case UDESC_CONFIG:
401332eff95SVincenzo Maffione DPRINTF(("umouse: (->UDESC_CONFIG)"));
4022cf9911fSPeter Grehan if ((value & 0xFF) != 0) {
40371ab6f97SPeter Grehan err = USB_ERR_STALLED;
4042cf9911fSPeter Grehan goto done;
4052cf9911fSPeter Grehan }
4062cf9911fSPeter Grehan if (len > sizeof(umouse_confd)) {
4072cf9911fSPeter Grehan data->blen = len - sizeof(umouse_confd);
4082cf9911fSPeter Grehan len = sizeof(umouse_confd);
4092cf9911fSPeter Grehan } else
4102cf9911fSPeter Grehan data->blen = 0;
4112cf9911fSPeter Grehan
4122cf9911fSPeter Grehan memcpy(data->buf, &umouse_confd, len);
4132cf9911fSPeter Grehan data->bdone += len;
4142cf9911fSPeter Grehan break;
4152cf9911fSPeter Grehan
4162cf9911fSPeter Grehan case UDESC_STRING:
417332eff95SVincenzo Maffione DPRINTF(("umouse: (->UDESC_STRING)"));
4182cf9911fSPeter Grehan str = NULL;
4192cf9911fSPeter Grehan if ((value & 0xFF) < UMSTR_MAX)
4202cf9911fSPeter Grehan str = umouse_desc_strings[value & 0xFF];
4212cf9911fSPeter Grehan else
4222cf9911fSPeter Grehan goto done;
4232cf9911fSPeter Grehan
4242cf9911fSPeter Grehan if ((value & 0xFF) == UMSTR_LANG) {
4252cf9911fSPeter Grehan udata[0] = 4;
4262cf9911fSPeter Grehan udata[1] = UDESC_STRING;
4272cf9911fSPeter Grehan data->blen = len - 2;
4282cf9911fSPeter Grehan len -= 2;
4292cf9911fSPeter Grehan data->bdone += 2;
4302cf9911fSPeter Grehan
4312cf9911fSPeter Grehan if (len >= 2) {
4322cf9911fSPeter Grehan udata[2] = str[0];
4332cf9911fSPeter Grehan udata[3] = str[1];
4342cf9911fSPeter Grehan data->blen -= 2;
4352cf9911fSPeter Grehan data->bdone += 2;
4362cf9911fSPeter Grehan } else
4372cf9911fSPeter Grehan data->blen = 0;
4382cf9911fSPeter Grehan
4392cf9911fSPeter Grehan goto done;
4402cf9911fSPeter Grehan }
4412cf9911fSPeter Grehan
4424edc7f41SMarcelo Araujo slen = 2 + strlen(str) * 2;
4432cf9911fSPeter Grehan udata[0] = slen;
4442cf9911fSPeter Grehan udata[1] = UDESC_STRING;
4452cf9911fSPeter Grehan
4462cf9911fSPeter Grehan if (len > slen) {
4472cf9911fSPeter Grehan data->blen = len - slen;
4482cf9911fSPeter Grehan len = slen;
4492cf9911fSPeter Grehan } else
4502cf9911fSPeter Grehan data->blen = 0;
4512cf9911fSPeter Grehan for (i = 2; i < len; i += 2) {
4522cf9911fSPeter Grehan udata[i] = *str++;
4532cf9911fSPeter Grehan udata[i+1] = '\0';
4542cf9911fSPeter Grehan }
4552cf9911fSPeter Grehan data->bdone += slen;
4562cf9911fSPeter Grehan
4572cf9911fSPeter Grehan break;
4582cf9911fSPeter Grehan
4592cf9911fSPeter Grehan case UDESC_BOS:
460332eff95SVincenzo Maffione DPRINTF(("umouse: USB3 BOS"));
4612cf9911fSPeter Grehan if (len > sizeof(umouse_bosd)) {
4622cf9911fSPeter Grehan data->blen = len - sizeof(umouse_bosd);
4632cf9911fSPeter Grehan len = sizeof(umouse_bosd);
4642cf9911fSPeter Grehan } else
4652cf9911fSPeter Grehan data->blen = 0;
4662cf9911fSPeter Grehan memcpy(udata, &umouse_bosd, len);
4672cf9911fSPeter Grehan data->bdone += len;
4682cf9911fSPeter Grehan break;
4692cf9911fSPeter Grehan
4702cf9911fSPeter Grehan default:
471332eff95SVincenzo Maffione DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
47271ab6f97SPeter Grehan err = USB_ERR_STALLED;
4732cf9911fSPeter Grehan goto done;
4742cf9911fSPeter Grehan }
4752cf9911fSPeter Grehan eshort = data->blen > 0;
4762cf9911fSPeter Grehan break;
4772cf9911fSPeter Grehan
4782cf9911fSPeter Grehan case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
4792cf9911fSPeter Grehan DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
480332eff95SVincenzo Maffione "0x%x", (value >> 8)));
4812cf9911fSPeter Grehan if (!data)
4822cf9911fSPeter Grehan break;
4832cf9911fSPeter Grehan
4842cf9911fSPeter Grehan switch (value >> 8) {
4852cf9911fSPeter Grehan case UMOUSE_REPORT_DESC_TYPE:
4862cf9911fSPeter Grehan if (len > sizeof(umouse_report_desc)) {
4872cf9911fSPeter Grehan data->blen = len - sizeof(umouse_report_desc);
4882cf9911fSPeter Grehan len = sizeof(umouse_report_desc);
4892cf9911fSPeter Grehan } else
4902cf9911fSPeter Grehan data->blen = 0;
4912cf9911fSPeter Grehan memcpy(data->buf, umouse_report_desc, len);
4922cf9911fSPeter Grehan data->bdone += len;
4932cf9911fSPeter Grehan break;
4942cf9911fSPeter Grehan default:
495332eff95SVincenzo Maffione DPRINTF(("umouse: IO ERROR"));
49671ab6f97SPeter Grehan err = USB_ERR_STALLED;
4972cf9911fSPeter Grehan goto done;
4982cf9911fSPeter Grehan }
4992cf9911fSPeter Grehan eshort = data->blen > 0;
5002cf9911fSPeter Grehan break;
5012cf9911fSPeter Grehan
5022cf9911fSPeter Grehan case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
503332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
5042cf9911fSPeter Grehan if (index != 0) {
505332eff95SVincenzo Maffione DPRINTF(("umouse get_interface, invalid index %d",
5062cf9911fSPeter Grehan index));
50771ab6f97SPeter Grehan err = USB_ERR_STALLED;
5082cf9911fSPeter Grehan goto done;
5092cf9911fSPeter Grehan }
5102cf9911fSPeter Grehan
5112cf9911fSPeter Grehan if (!data)
5122cf9911fSPeter Grehan break;
5132cf9911fSPeter Grehan
5142cf9911fSPeter Grehan if (len > 0) {
5152cf9911fSPeter Grehan *udata = 0;
5162cf9911fSPeter Grehan data->blen = len - 1;
5172cf9911fSPeter Grehan }
5182cf9911fSPeter Grehan eshort = data->blen > 0;
5192cf9911fSPeter Grehan data->bdone += 1;
5202cf9911fSPeter Grehan break;
5212cf9911fSPeter Grehan
5222cf9911fSPeter Grehan case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
523332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
5242cf9911fSPeter Grehan if (data != NULL && len > 1) {
5252cf9911fSPeter Grehan if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
5262cf9911fSPeter Grehan USETW(udata, UDS_REMOTE_WAKEUP);
5272cf9911fSPeter Grehan else
5282cf9911fSPeter Grehan USETW(udata, 0);
5292cf9911fSPeter Grehan data->blen = len - 2;
5302cf9911fSPeter Grehan data->bdone += 2;
5312cf9911fSPeter Grehan }
5322cf9911fSPeter Grehan
5332cf9911fSPeter Grehan eshort = data->blen > 0;
5342cf9911fSPeter Grehan break;
5352cf9911fSPeter Grehan
5362cf9911fSPeter Grehan case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
5372cf9911fSPeter Grehan case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
538332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
5392cf9911fSPeter Grehan if (data != NULL && len > 1) {
5402cf9911fSPeter Grehan USETW(udata, 0);
5412cf9911fSPeter Grehan data->blen = len - 2;
5422cf9911fSPeter Grehan data->bdone += 2;
5432cf9911fSPeter Grehan }
5442cf9911fSPeter Grehan eshort = data->blen > 0;
5452cf9911fSPeter Grehan break;
5462cf9911fSPeter Grehan
5472cf9911fSPeter Grehan case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
5482cf9911fSPeter Grehan /* XXX Controller should've handled this */
549332eff95SVincenzo Maffione DPRINTF(("umouse set address %u", value));
5502cf9911fSPeter Grehan break;
5512cf9911fSPeter Grehan
5522cf9911fSPeter Grehan case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
553332eff95SVincenzo Maffione DPRINTF(("umouse set config %u", value));
5542cf9911fSPeter Grehan break;
5552cf9911fSPeter Grehan
5562cf9911fSPeter Grehan case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
557332eff95SVincenzo Maffione DPRINTF(("umouse set descriptor %u", value));
5582cf9911fSPeter Grehan break;
5592cf9911fSPeter Grehan
5602cf9911fSPeter Grehan
5612cf9911fSPeter Grehan case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
562332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5632cf9911fSPeter Grehan if (value == UF_DEVICE_REMOTE_WAKEUP)
5642cf9911fSPeter Grehan sc->hid.feature = 0;
5652cf9911fSPeter Grehan break;
5662cf9911fSPeter Grehan
5672cf9911fSPeter Grehan case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
568332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5692cf9911fSPeter Grehan if (value == UF_DEVICE_REMOTE_WAKEUP)
5702cf9911fSPeter Grehan sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
5712cf9911fSPeter Grehan break;
5722cf9911fSPeter Grehan
5732cf9911fSPeter Grehan case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
5742cf9911fSPeter Grehan case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
5752cf9911fSPeter Grehan case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
5762cf9911fSPeter Grehan case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
577332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
57871ab6f97SPeter Grehan err = USB_ERR_STALLED;
5792cf9911fSPeter Grehan goto done;
5802cf9911fSPeter Grehan
5812cf9911fSPeter Grehan case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
582332eff95SVincenzo Maffione DPRINTF(("umouse set interface %u", value));
5832cf9911fSPeter Grehan break;
5842cf9911fSPeter Grehan
5852cf9911fSPeter Grehan case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
586332eff95SVincenzo Maffione DPRINTF(("umouse set isoch delay %u", value));
5872cf9911fSPeter Grehan break;
5882cf9911fSPeter Grehan
5892cf9911fSPeter Grehan case UREQ(UR_SET_SEL, 0):
590332eff95SVincenzo Maffione DPRINTF(("umouse set sel"));
5912cf9911fSPeter Grehan break;
5922cf9911fSPeter Grehan
5932cf9911fSPeter Grehan case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
594332eff95SVincenzo Maffione DPRINTF(("umouse synch frame"));
5952cf9911fSPeter Grehan break;
5962cf9911fSPeter Grehan
5972cf9911fSPeter Grehan /* HID device requests */
5982cf9911fSPeter Grehan
5992cf9911fSPeter Grehan case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
6002cf9911fSPeter Grehan DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
601332eff95SVincenzo Maffione "0x%x", (value >> 8)));
6022cf9911fSPeter Grehan if (!data)
6032cf9911fSPeter Grehan break;
6042cf9911fSPeter Grehan
6052cf9911fSPeter Grehan if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
6062cf9911fSPeter Grehan /* TODO read from backend */
6072cf9911fSPeter Grehan
6082cf9911fSPeter Grehan if (len > sizeof(sc->um_report)) {
6092cf9911fSPeter Grehan data->blen = len - sizeof(sc->um_report);
6102cf9911fSPeter Grehan len = sizeof(sc->um_report);
6112cf9911fSPeter Grehan } else
6122cf9911fSPeter Grehan data->blen = 0;
6132cf9911fSPeter Grehan
6142cf9911fSPeter Grehan memcpy(data->buf, &sc->um_report, len);
6152cf9911fSPeter Grehan data->bdone += len;
6162cf9911fSPeter Grehan } else {
61771ab6f97SPeter Grehan err = USB_ERR_STALLED;
6182cf9911fSPeter Grehan goto done;
6192cf9911fSPeter Grehan }
6202cf9911fSPeter Grehan eshort = data->blen > 0;
6212cf9911fSPeter Grehan break;
6222cf9911fSPeter Grehan
6232cf9911fSPeter Grehan case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
6242cf9911fSPeter Grehan if (data != NULL && len > 0) {
6252cf9911fSPeter Grehan *udata = sc->hid.idle;
6262cf9911fSPeter Grehan data->blen = len - 1;
6272cf9911fSPeter Grehan data->bdone += 1;
6282cf9911fSPeter Grehan }
6292cf9911fSPeter Grehan eshort = data->blen > 0;
6302cf9911fSPeter Grehan break;
6312cf9911fSPeter Grehan
6322cf9911fSPeter Grehan case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
6332cf9911fSPeter Grehan if (data != NULL && len > 0) {
6342cf9911fSPeter Grehan *udata = sc->hid.protocol;
6352cf9911fSPeter Grehan data->blen = len - 1;
6362cf9911fSPeter Grehan data->bdone += 1;
6372cf9911fSPeter Grehan }
6382cf9911fSPeter Grehan eshort = data->blen > 0;
6392cf9911fSPeter Grehan break;
6402cf9911fSPeter Grehan
6412cf9911fSPeter Grehan case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
642332eff95SVincenzo Maffione DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
6432cf9911fSPeter Grehan break;
6442cf9911fSPeter Grehan
6452cf9911fSPeter Grehan case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
6462cf9911fSPeter Grehan sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
647332eff95SVincenzo Maffione DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
6482cf9911fSPeter Grehan sc->hid.idle));
6492cf9911fSPeter Grehan break;
6502cf9911fSPeter Grehan
6512cf9911fSPeter Grehan case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
6522cf9911fSPeter Grehan sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
653332eff95SVincenzo Maffione DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
6542cf9911fSPeter Grehan sc->hid.protocol));
6552cf9911fSPeter Grehan break;
6562cf9911fSPeter Grehan
6572cf9911fSPeter Grehan default:
658332eff95SVincenzo Maffione DPRINTF(("**** umouse request unhandled"));
65971ab6f97SPeter Grehan err = USB_ERR_STALLED;
6602cf9911fSPeter Grehan break;
6612cf9911fSPeter Grehan }
6622cf9911fSPeter Grehan
6632cf9911fSPeter Grehan done:
6642cf9911fSPeter Grehan if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
6652cf9911fSPeter Grehan (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
6662cf9911fSPeter Grehan data->blen = 0;
6672cf9911fSPeter Grehan else if (eshort)
6682cf9911fSPeter Grehan err = USB_ERR_SHORT_XFER;
6692cf9911fSPeter Grehan
670332eff95SVincenzo Maffione DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
6712cf9911fSPeter Grehan err, (data ? data->blen : 0), (data ? data->bdone : 0)));
6722cf9911fSPeter Grehan
6732cf9911fSPeter Grehan return (err);
6742cf9911fSPeter Grehan }
6752cf9911fSPeter Grehan
6762cf9911fSPeter Grehan static int
umouse_data_handler(void * scarg,struct usb_data_xfer * xfer,int dir,int epctx)6772cf9911fSPeter Grehan umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
6782cf9911fSPeter Grehan int epctx)
6792cf9911fSPeter Grehan {
6802cf9911fSPeter Grehan struct umouse_softc *sc;
6812cf9911fSPeter Grehan struct usb_data_xfer_block *data;
6822cf9911fSPeter Grehan uint8_t *udata;
6832cf9911fSPeter Grehan int len, i, idx;
6842cf9911fSPeter Grehan int err;
6852cf9911fSPeter Grehan
686332eff95SVincenzo Maffione DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
6872cf9911fSPeter Grehan dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
6882cf9911fSPeter Grehan
6892cf9911fSPeter Grehan
6902cf9911fSPeter Grehan /* find buffer to add data */
6912cf9911fSPeter Grehan udata = NULL;
6922cf9911fSPeter Grehan err = USB_ERR_NORMAL_COMPLETION;
6932cf9911fSPeter Grehan
6942cf9911fSPeter Grehan /* handle xfer at first unprocessed item with buffer */
6952cf9911fSPeter Grehan data = NULL;
6962cf9911fSPeter Grehan idx = xfer->head;
6972cf9911fSPeter Grehan for (i = 0; i < xfer->ndata; i++) {
6982cf9911fSPeter Grehan data = &xfer->data[idx];
6992cf9911fSPeter Grehan if (data->buf != NULL && data->blen != 0) {
7002cf9911fSPeter Grehan break;
7012cf9911fSPeter Grehan } else {
7022cf9911fSPeter Grehan data->processed = 1;
7032cf9911fSPeter Grehan data = NULL;
7042cf9911fSPeter Grehan }
7052cf9911fSPeter Grehan idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
7062cf9911fSPeter Grehan }
7072cf9911fSPeter Grehan if (!data)
7082cf9911fSPeter Grehan goto done;
7092cf9911fSPeter Grehan
7102cf9911fSPeter Grehan udata = data->buf;
7112cf9911fSPeter Grehan len = data->blen;
7122cf9911fSPeter Grehan
7132cf9911fSPeter Grehan if (udata == NULL) {
714332eff95SVincenzo Maffione DPRINTF(("umouse no buffer provided for input"));
7152cf9911fSPeter Grehan err = USB_ERR_NOMEM;
7162cf9911fSPeter Grehan goto done;
7172cf9911fSPeter Grehan }
7182cf9911fSPeter Grehan
7192cf9911fSPeter Grehan sc = scarg;
7202cf9911fSPeter Grehan
7212cf9911fSPeter Grehan if (dir) {
7222cf9911fSPeter Grehan
7232cf9911fSPeter Grehan pthread_mutex_lock(&sc->mtx);
7242cf9911fSPeter Grehan
7252cf9911fSPeter Grehan if (!sc->newdata) {
7262cf9911fSPeter Grehan err = USB_ERR_CANCELLED;
7272cf9911fSPeter Grehan USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
7282cf9911fSPeter Grehan pthread_mutex_unlock(&sc->mtx);
7292cf9911fSPeter Grehan goto done;
7302cf9911fSPeter Grehan }
7312cf9911fSPeter Grehan
7322cf9911fSPeter Grehan if (sc->polling) {
7332cf9911fSPeter Grehan err = USB_ERR_STALLED;
7342cf9911fSPeter Grehan USB_DATA_SET_ERRCODE(data, USB_STALL);
7352cf9911fSPeter Grehan pthread_mutex_unlock(&sc->mtx);
7362cf9911fSPeter Grehan goto done;
7372cf9911fSPeter Grehan }
7382cf9911fSPeter Grehan sc->polling = 1;
7392cf9911fSPeter Grehan
7402cf9911fSPeter Grehan if (len > 0) {
7412cf9911fSPeter Grehan sc->newdata = 0;
7422cf9911fSPeter Grehan
7432cf9911fSPeter Grehan data->processed = 1;
7442cf9911fSPeter Grehan data->bdone += 6;
7452cf9911fSPeter Grehan memcpy(udata, &sc->um_report, 6);
7462cf9911fSPeter Grehan data->blen = len - 6;
7472cf9911fSPeter Grehan if (data->blen > 0)
7482cf9911fSPeter Grehan err = USB_ERR_SHORT_XFER;
7492cf9911fSPeter Grehan }
7502cf9911fSPeter Grehan
7512cf9911fSPeter Grehan sc->polling = 0;
7522cf9911fSPeter Grehan pthread_mutex_unlock(&sc->mtx);
7532cf9911fSPeter Grehan } else {
7542cf9911fSPeter Grehan USB_DATA_SET_ERRCODE(data, USB_STALL);
7552cf9911fSPeter Grehan err = USB_ERR_STALLED;
7562cf9911fSPeter Grehan }
7572cf9911fSPeter Grehan
7582cf9911fSPeter Grehan done:
7592cf9911fSPeter Grehan return (err);
7602cf9911fSPeter Grehan }
7612cf9911fSPeter Grehan
7622cf9911fSPeter Grehan static int
umouse_reset(void * scarg)7632cf9911fSPeter Grehan umouse_reset(void *scarg)
7642cf9911fSPeter Grehan {
7652cf9911fSPeter Grehan struct umouse_softc *sc;
7662cf9911fSPeter Grehan
7672cf9911fSPeter Grehan sc = scarg;
7682cf9911fSPeter Grehan
7692cf9911fSPeter Grehan sc->newdata = 0;
7702cf9911fSPeter Grehan
7712cf9911fSPeter Grehan return (0);
7722cf9911fSPeter Grehan }
7732cf9911fSPeter Grehan
7742cf9911fSPeter Grehan static int
umouse_remove(void * scarg __unused)77598d920d9SMark Johnston umouse_remove(void *scarg __unused)
7762cf9911fSPeter Grehan {
7772cf9911fSPeter Grehan return (0);
7782cf9911fSPeter Grehan }
7792cf9911fSPeter Grehan
7802cf9911fSPeter Grehan static int
umouse_stop(void * scarg __unused)78198d920d9SMark Johnston umouse_stop(void *scarg __unused)
7822cf9911fSPeter Grehan {
7832cf9911fSPeter Grehan return (0);
7842cf9911fSPeter Grehan }
7852cf9911fSPeter Grehan
786483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
787483d953aSJohn Baldwin static int
umouse_snapshot(void * scarg,struct vm_snapshot_meta * meta)788483d953aSJohn Baldwin umouse_snapshot(void *scarg, struct vm_snapshot_meta *meta)
789483d953aSJohn Baldwin {
790483d953aSJohn Baldwin int ret;
791483d953aSJohn Baldwin struct umouse_softc *sc;
792483d953aSJohn Baldwin
793483d953aSJohn Baldwin sc = scarg;
794483d953aSJohn Baldwin
795483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->um_report, meta, ret, done);
796483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->newdata, meta, ret, done);
797483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->hid.idle, meta, ret, done);
798483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->hid.protocol, meta, ret, done);
799483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->hid.feature, meta, ret, done);
800483d953aSJohn Baldwin
801483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->polling, meta, ret, done);
802483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_sec, meta, ret, done);
803483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_usec, meta, ret, done);
804483d953aSJohn Baldwin
805483d953aSJohn Baldwin done:
806483d953aSJohn Baldwin return (ret);
807483d953aSJohn Baldwin }
808483d953aSJohn Baldwin #endif
8092cf9911fSPeter Grehan
810cd49c066SMark Johnston static struct usb_devemu ue_mouse = {
8112cf9911fSPeter Grehan .ue_emu = "tablet",
8122cf9911fSPeter Grehan .ue_usbver = 3,
8132cf9911fSPeter Grehan .ue_usbspeed = USB_SPEED_HIGH,
8142cf9911fSPeter Grehan .ue_init = umouse_init,
8152cf9911fSPeter Grehan .ue_request = umouse_request,
8162cf9911fSPeter Grehan .ue_data = umouse_data_handler,
8172cf9911fSPeter Grehan .ue_reset = umouse_reset,
8182cf9911fSPeter Grehan .ue_remove = umouse_remove,
819483d953aSJohn Baldwin .ue_stop = umouse_stop,
820483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT
821483d953aSJohn Baldwin .ue_snapshot = umouse_snapshot,
822483d953aSJohn Baldwin #endif
8232cf9911fSPeter Grehan };
8242cf9911fSPeter Grehan USB_EMUL_SET(ue_mouse);
825