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 __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