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