12cf9911fSPeter Grehan /*- 22cf9911fSPeter Grehan * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com> 32cf9911fSPeter Grehan * All rights reserved. 42cf9911fSPeter Grehan * 52cf9911fSPeter Grehan * Redistribution and use in source and binary forms, with or without 62cf9911fSPeter Grehan * modification, are permitted provided that the following conditions 72cf9911fSPeter Grehan * are met: 82cf9911fSPeter Grehan * 1. Redistributions of source code must retain the above copyright 92cf9911fSPeter Grehan * notice, this list of conditions and the following disclaimer. 102cf9911fSPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 112cf9911fSPeter Grehan * notice, this list of conditions and the following disclaimer in the 122cf9911fSPeter Grehan * documentation and/or other materials provided with the distribution. 132cf9911fSPeter Grehan * 142cf9911fSPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 152cf9911fSPeter Grehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162cf9911fSPeter Grehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172cf9911fSPeter Grehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182cf9911fSPeter Grehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192cf9911fSPeter Grehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202cf9911fSPeter Grehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212cf9911fSPeter Grehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222cf9911fSPeter Grehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232cf9911fSPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242cf9911fSPeter Grehan * SUCH DAMAGE. 252cf9911fSPeter Grehan */ 262cf9911fSPeter Grehan 272cf9911fSPeter Grehan #include <sys/cdefs.h> 282cf9911fSPeter Grehan __FBSDID("$FreeBSD$"); 292cf9911fSPeter Grehan 302cf9911fSPeter Grehan #include <sys/time.h> 312cf9911fSPeter Grehan 322cf9911fSPeter Grehan #include <pthread.h> 332cf9911fSPeter Grehan #include <stdio.h> 342cf9911fSPeter Grehan #include <stdlib.h> 352cf9911fSPeter Grehan #include <string.h> 362cf9911fSPeter Grehan 372cf9911fSPeter Grehan #include <dev/usb/usb.h> 382cf9911fSPeter Grehan #include <dev/usb/usbdi.h> 392cf9911fSPeter Grehan 402cf9911fSPeter Grehan #include "usb_emul.h" 412cf9911fSPeter Grehan #include "console.h" 422cf9911fSPeter Grehan #include "bhyvegc.h" 432cf9911fSPeter Grehan 442cf9911fSPeter Grehan static int umouse_debug = 0; 452cf9911fSPeter Grehan #define DPRINTF(params) if (umouse_debug) printf params 462cf9911fSPeter Grehan #define WPRINTF(params) printf params 472cf9911fSPeter Grehan 482cf9911fSPeter Grehan /* USB endpoint context (1-15) for reporting mouse data events*/ 492cf9911fSPeter Grehan #define UMOUSE_INTR_ENDPT 1 502cf9911fSPeter Grehan 512cf9911fSPeter Grehan #define UMOUSE_REPORT_DESC_TYPE 0x22 522cf9911fSPeter Grehan 532cf9911fSPeter Grehan #define UMOUSE_GET_REPORT 0x01 542cf9911fSPeter Grehan #define UMOUSE_GET_IDLE 0x02 552cf9911fSPeter Grehan #define UMOUSE_GET_PROTOCOL 0x03 562cf9911fSPeter Grehan #define UMOUSE_SET_REPORT 0x09 572cf9911fSPeter Grehan #define UMOUSE_SET_IDLE 0x0A 582cf9911fSPeter Grehan #define UMOUSE_SET_PROTOCOL 0x0B 592cf9911fSPeter Grehan 602cf9911fSPeter Grehan #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 612cf9911fSPeter Grehan 622cf9911fSPeter Grehan enum { 632cf9911fSPeter Grehan UMSTR_LANG, 642cf9911fSPeter Grehan UMSTR_MANUFACTURER, 652cf9911fSPeter Grehan UMSTR_PRODUCT, 662cf9911fSPeter Grehan UMSTR_SERIAL, 672cf9911fSPeter Grehan UMSTR_CONFIG, 682cf9911fSPeter Grehan UMSTR_MAX 692cf9911fSPeter Grehan }; 702cf9911fSPeter Grehan 712cf9911fSPeter Grehan static const char *umouse_desc_strings[] = { 722cf9911fSPeter Grehan "\x04\x09", 732cf9911fSPeter Grehan "BHYVE", 742cf9911fSPeter Grehan "HID Tablet", 752cf9911fSPeter Grehan "01", 762cf9911fSPeter Grehan "HID Tablet Device", 772cf9911fSPeter Grehan }; 782cf9911fSPeter Grehan 792cf9911fSPeter Grehan struct umouse_hid_descriptor { 802cf9911fSPeter Grehan uint8_t bLength; 812cf9911fSPeter Grehan uint8_t bDescriptorType; 822cf9911fSPeter Grehan uint8_t bcdHID[2]; 832cf9911fSPeter Grehan uint8_t bCountryCode; 842cf9911fSPeter Grehan uint8_t bNumDescriptors; 852cf9911fSPeter Grehan uint8_t bReportDescriptorType; 862cf9911fSPeter Grehan uint8_t wItemLength[2]; 872cf9911fSPeter Grehan } __packed; 882cf9911fSPeter Grehan 892cf9911fSPeter Grehan struct umouse_config_desc { 902cf9911fSPeter Grehan struct usb_config_descriptor confd; 912cf9911fSPeter Grehan struct usb_interface_descriptor ifcd; 922cf9911fSPeter Grehan struct umouse_hid_descriptor hidd; 932cf9911fSPeter Grehan struct usb_endpoint_descriptor endpd; 942cf9911fSPeter Grehan struct usb_endpoint_ss_comp_descriptor sscompd; 952cf9911fSPeter Grehan } __packed; 962cf9911fSPeter Grehan 972cf9911fSPeter Grehan #define MOUSE_MAX_X 0x8000 982cf9911fSPeter Grehan #define MOUSE_MAX_Y 0x8000 992cf9911fSPeter Grehan 1002cf9911fSPeter Grehan static const uint8_t umouse_report_desc[] = { 1012cf9911fSPeter Grehan 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 1022cf9911fSPeter Grehan 0x09, 0x02, /* USAGE (Mouse) */ 1032cf9911fSPeter Grehan 0xa1, 0x01, /* COLLECTION (Application) */ 1042cf9911fSPeter Grehan 0x09, 0x01, /* USAGE (Pointer) */ 1052cf9911fSPeter Grehan 0xa1, 0x00, /* COLLECTION (Physical) */ 1062cf9911fSPeter Grehan 0x05, 0x09, /* USAGE_PAGE (Button) */ 1072cf9911fSPeter Grehan 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ 1082cf9911fSPeter Grehan 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */ 1092cf9911fSPeter Grehan 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 1102cf9911fSPeter Grehan 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 1112cf9911fSPeter Grehan 0x75, 0x01, /* REPORT_SIZE (1) */ 1122cf9911fSPeter Grehan 0x95, 0x03, /* REPORT_COUNT (3) */ 1132cf9911fSPeter Grehan 0x81, 0x02, /* INPUT (Data,Var,Abs); 3 buttons */ 1142cf9911fSPeter Grehan 0x75, 0x05, /* REPORT_SIZE (5) */ 1152cf9911fSPeter Grehan 0x95, 0x01, /* REPORT_COUNT (1) */ 1162cf9911fSPeter Grehan 0x81, 0x03, /* INPUT (Cnst,Var,Abs); padding */ 1172cf9911fSPeter Grehan 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 1182cf9911fSPeter Grehan 0x09, 0x30, /* USAGE (X) */ 1192cf9911fSPeter Grehan 0x09, 0x31, /* USAGE (Y) */ 1202cf9911fSPeter Grehan 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ 1212cf9911fSPeter Grehan 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (0x7fff) */ 1222cf9911fSPeter Grehan 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 1232cf9911fSPeter Grehan 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (0x7fff) */ 1242cf9911fSPeter Grehan 0x75, 0x10, /* REPORT_SIZE (16) */ 1252cf9911fSPeter Grehan 0x95, 0x02, /* REPORT_COUNT (2) */ 1262cf9911fSPeter Grehan 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 1272cf9911fSPeter Grehan 0x05, 0x01, /* USAGE Page (Generic Desktop) */ 1282cf9911fSPeter Grehan 0x09, 0x38, /* USAGE (Wheel) */ 1292cf9911fSPeter Grehan 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ 1302cf9911fSPeter Grehan 0x45, 0x00, /* PHYSICAL_MAXIMUM (0) */ 1312cf9911fSPeter Grehan 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ 1322cf9911fSPeter Grehan 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ 1332cf9911fSPeter Grehan 0x75, 0x08, /* REPORT_SIZE (8) */ 1342cf9911fSPeter Grehan 0x95, 0x01, /* REPORT_COUNT (1) */ 1352cf9911fSPeter Grehan 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 1362cf9911fSPeter Grehan 0xc0, /* END_COLLECTION */ 1372cf9911fSPeter Grehan 0xc0 /* END_COLLECTION */ 1382cf9911fSPeter Grehan }; 1392cf9911fSPeter Grehan 1402cf9911fSPeter Grehan struct umouse_report { 1412cf9911fSPeter Grehan uint8_t buttons; /* bits: 0 left, 1 right, 2 middle */ 1422cf9911fSPeter Grehan int16_t x; /* x position */ 1432cf9911fSPeter Grehan int16_t y; /* y position */ 1442cf9911fSPeter Grehan int8_t z; /* z wheel position */ 1452cf9911fSPeter Grehan } __packed; 1462cf9911fSPeter Grehan 1472cf9911fSPeter Grehan 1482cf9911fSPeter Grehan #define MSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 1492cf9911fSPeter Grehan 1502cf9911fSPeter Grehan static struct usb_device_descriptor umouse_dev_desc = { 1512cf9911fSPeter Grehan .bLength = sizeof(umouse_dev_desc), 1522cf9911fSPeter Grehan .bDescriptorType = UDESC_DEVICE, 1532cf9911fSPeter Grehan MSETW(.bcdUSB, UD_USB_3_0), 1542cf9911fSPeter Grehan .bMaxPacketSize = 8, /* max packet size */ 1552cf9911fSPeter Grehan MSETW(.idVendor, 0xFB5D), /* vendor */ 1562cf9911fSPeter Grehan MSETW(.idProduct, 0x0001), /* product */ 1572cf9911fSPeter Grehan MSETW(.bcdDevice, 0), /* device version */ 1582cf9911fSPeter Grehan .iManufacturer = UMSTR_MANUFACTURER, 1592cf9911fSPeter Grehan .iProduct = UMSTR_PRODUCT, 1602cf9911fSPeter Grehan .iSerialNumber = UMSTR_SERIAL, 1612cf9911fSPeter Grehan .bNumConfigurations = 1, 1622cf9911fSPeter Grehan }; 1632cf9911fSPeter Grehan 1642cf9911fSPeter Grehan static struct umouse_config_desc umouse_confd = { 1652cf9911fSPeter Grehan .confd = { 1662cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.confd), 1672cf9911fSPeter Grehan .bDescriptorType = UDESC_CONFIG, 1682cf9911fSPeter Grehan .wTotalLength[0] = sizeof(umouse_confd), 1692cf9911fSPeter Grehan .bNumInterface = 1, 1702cf9911fSPeter Grehan .bConfigurationValue = 1, 1712cf9911fSPeter Grehan .iConfiguration = UMSTR_CONFIG, 1722cf9911fSPeter Grehan .bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP, 1732cf9911fSPeter Grehan .bMaxPower = 0, 1742cf9911fSPeter Grehan }, 1752cf9911fSPeter Grehan .ifcd = { 1762cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.ifcd), 1772cf9911fSPeter Grehan .bDescriptorType = UDESC_INTERFACE, 1782cf9911fSPeter Grehan .bNumEndpoints = 1, 1792cf9911fSPeter Grehan .bInterfaceClass = UICLASS_HID, 1802cf9911fSPeter Grehan .bInterfaceSubClass = UISUBCLASS_BOOT, 1812cf9911fSPeter Grehan .bInterfaceProtocol = UIPROTO_MOUSE, 1822cf9911fSPeter Grehan }, 1832cf9911fSPeter Grehan .hidd = { 1842cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.hidd), 1852cf9911fSPeter Grehan .bDescriptorType = 0x21, 1862cf9911fSPeter Grehan .bcdHID = { 0x01, 0x10 }, 1872cf9911fSPeter Grehan .bCountryCode = 0, 1882cf9911fSPeter Grehan .bNumDescriptors = 1, 1892cf9911fSPeter Grehan .bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE, 1902cf9911fSPeter Grehan .wItemLength = { sizeof(umouse_report_desc), 0 }, 1912cf9911fSPeter Grehan }, 1922cf9911fSPeter Grehan .endpd = { 1932cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.endpd), 1942cf9911fSPeter Grehan .bDescriptorType = UDESC_ENDPOINT, 1952cf9911fSPeter Grehan .bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT, 1962cf9911fSPeter Grehan .bmAttributes = UE_INTERRUPT, 1972cf9911fSPeter Grehan .wMaxPacketSize[0] = 8, 1982cf9911fSPeter Grehan .bInterval = 0xA, 1992cf9911fSPeter Grehan }, 2002cf9911fSPeter Grehan .sscompd = { 2012cf9911fSPeter Grehan .bLength = sizeof(umouse_confd.sscompd), 2022cf9911fSPeter Grehan .bDescriptorType = UDESC_ENDPOINT_SS_COMP, 2032cf9911fSPeter Grehan .bMaxBurst = 0, 2042cf9911fSPeter Grehan .bmAttributes = 0, 2052cf9911fSPeter Grehan MSETW(.wBytesPerInterval, 0), 2062cf9911fSPeter Grehan }, 2072cf9911fSPeter Grehan }; 2082cf9911fSPeter Grehan 2092cf9911fSPeter Grehan 2102cf9911fSPeter Grehan struct umouse_bos_desc { 2112cf9911fSPeter Grehan struct usb_bos_descriptor bosd; 2122cf9911fSPeter Grehan struct usb_devcap_ss_descriptor usbssd; 2132cf9911fSPeter Grehan } __packed; 2142cf9911fSPeter Grehan 2152cf9911fSPeter Grehan 2162cf9911fSPeter Grehan struct umouse_bos_desc umouse_bosd = { 2172cf9911fSPeter Grehan .bosd = { 2182cf9911fSPeter Grehan .bLength = sizeof(umouse_bosd.bosd), 2192cf9911fSPeter Grehan .bDescriptorType = UDESC_BOS, 2202cf9911fSPeter Grehan HSETW(.wTotalLength, sizeof(umouse_bosd)), 2212cf9911fSPeter Grehan .bNumDeviceCaps = 1, 2222cf9911fSPeter Grehan }, 2232cf9911fSPeter Grehan .usbssd = { 2242cf9911fSPeter Grehan .bLength = sizeof(umouse_bosd.usbssd), 2252cf9911fSPeter Grehan .bDescriptorType = UDESC_DEVICE_CAPABILITY, 2262cf9911fSPeter Grehan .bDevCapabilityType = 3, 2272cf9911fSPeter Grehan .bmAttributes = 0, 2282cf9911fSPeter Grehan HSETW(.wSpeedsSupported, 0x08), 2292cf9911fSPeter Grehan .bFunctionalitySupport = 3, 2302cf9911fSPeter Grehan .bU1DevExitLat = 0xa, /* dummy - not used */ 2312cf9911fSPeter Grehan .wU2DevExitLat = { 0x20, 0x00 }, 2322cf9911fSPeter Grehan } 2332cf9911fSPeter Grehan }; 2342cf9911fSPeter Grehan 2352cf9911fSPeter Grehan 2362cf9911fSPeter Grehan struct umouse_softc { 2372cf9911fSPeter Grehan struct usb_hci *hci; 2382cf9911fSPeter Grehan 2392cf9911fSPeter Grehan char *opt; 2402cf9911fSPeter Grehan 2412cf9911fSPeter Grehan struct umouse_report um_report; 2422cf9911fSPeter Grehan int newdata; 2432cf9911fSPeter Grehan struct { 2442cf9911fSPeter Grehan uint8_t idle; 2452cf9911fSPeter Grehan uint8_t protocol; 2462cf9911fSPeter Grehan uint8_t feature; 2472cf9911fSPeter Grehan } hid; 2482cf9911fSPeter Grehan 2492cf9911fSPeter Grehan pthread_mutex_t mtx; 2502cf9911fSPeter Grehan pthread_mutex_t ev_mtx; 2512cf9911fSPeter Grehan int polling; 2522cf9911fSPeter Grehan struct timeval prev_evt; 2532cf9911fSPeter Grehan }; 2542cf9911fSPeter Grehan 2552cf9911fSPeter Grehan static void 2562cf9911fSPeter Grehan umouse_event(uint8_t button, int x, int y, void *arg) 2572cf9911fSPeter Grehan { 2582cf9911fSPeter Grehan struct umouse_softc *sc; 2592cf9911fSPeter Grehan struct bhyvegc_image *gc; 2602cf9911fSPeter Grehan 2612cf9911fSPeter Grehan gc = console_get_image(); 2622cf9911fSPeter Grehan if (gc == NULL) { 2632cf9911fSPeter Grehan /* not ready */ 2642cf9911fSPeter Grehan return; 2652cf9911fSPeter Grehan } 2662cf9911fSPeter Grehan 2672cf9911fSPeter Grehan sc = arg; 2682cf9911fSPeter Grehan 2692cf9911fSPeter Grehan pthread_mutex_lock(&sc->mtx); 2702cf9911fSPeter Grehan 2712cf9911fSPeter Grehan sc->um_report.buttons = 0; 2722cf9911fSPeter Grehan sc->um_report.z = 0; 2732cf9911fSPeter Grehan 2742cf9911fSPeter Grehan if (button & 0x01) 2752cf9911fSPeter Grehan sc->um_report.buttons |= 0x01; /* left */ 2762cf9911fSPeter Grehan if (button & 0x02) 2772cf9911fSPeter Grehan sc->um_report.buttons |= 0x04; /* middle */ 2782cf9911fSPeter Grehan if (button & 0x04) 2792cf9911fSPeter Grehan sc->um_report.buttons |= 0x02; /* right */ 2802cf9911fSPeter Grehan if (button & 0x8) 2812cf9911fSPeter Grehan sc->um_report.z = 1; 2822cf9911fSPeter Grehan if (button & 0x10) 2832cf9911fSPeter Grehan sc->um_report.z = -1; 2842cf9911fSPeter Grehan 2852cf9911fSPeter Grehan /* scale coords to mouse resolution */ 2862cf9911fSPeter Grehan sc->um_report.x = MOUSE_MAX_X * x / gc->width; 287b9c1cdd1SPeter Grehan sc->um_report.y = MOUSE_MAX_Y * y / gc->height; 2882cf9911fSPeter Grehan sc->newdata = 1; 2892cf9911fSPeter Grehan pthread_mutex_unlock(&sc->mtx); 2902cf9911fSPeter Grehan 2912cf9911fSPeter Grehan pthread_mutex_lock(&sc->ev_mtx); 2922cf9911fSPeter Grehan sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT); 2932cf9911fSPeter Grehan pthread_mutex_unlock(&sc->ev_mtx); 2942cf9911fSPeter Grehan } 2952cf9911fSPeter Grehan 2962cf9911fSPeter Grehan static void * 2972cf9911fSPeter Grehan umouse_init(struct usb_hci *hci, char *opt) 2982cf9911fSPeter Grehan { 2992cf9911fSPeter Grehan struct umouse_softc *sc; 3002cf9911fSPeter Grehan 3012cf9911fSPeter Grehan sc = calloc(1, sizeof(struct umouse_softc)); 3022cf9911fSPeter Grehan sc->hci = hci; 3032cf9911fSPeter Grehan 3042cf9911fSPeter Grehan sc->hid.protocol = 1; /* REPORT protocol */ 3052cf9911fSPeter Grehan sc->opt = strdup(opt); 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 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) { 3512cf9911fSPeter Grehan DPRINTF(("umouse_request: port %d\r\n", 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, " 3602cf9911fSPeter Grehan "idx 0x%x, len %u\r\n", 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): 3662cf9911fSPeter Grehan DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)\r\n")); 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): 3772cf9911fSPeter Grehan DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x\r\n", 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 ?= " 3852cf9911fSPeter Grehan "sizeof(umouse_dev_desc) %lu\r\n", 3862cf9911fSPeter Grehan len, sizeof(umouse_dev_desc))); 3872cf9911fSPeter Grehan if ((value & 0xFF) != 0) { 3882cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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: 4012cf9911fSPeter Grehan DPRINTF(("umouse: (->UDESC_CONFIG)\r\n")); 4022cf9911fSPeter Grehan if ((value & 0xFF) != 0) { 4032cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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: 4172cf9911fSPeter Grehan DPRINTF(("umouse: (->UDESC_STRING)\r\n")); 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 4422cf9911fSPeter Grehan 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: 4602cf9911fSPeter Grehan DPRINTF(("umouse: USB3 BOS\r\n")); 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: 4712cf9911fSPeter Grehan DPRINTF(("umouse: unknown(%d)->ERROR\r\n", value >> 8)); 4722cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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) " 4802cf9911fSPeter Grehan "0x%x\r\n", (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: 4952cf9911fSPeter Grehan DPRINTF(("umouse: IO ERROR\r\n")); 4962cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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): 5032cf9911fSPeter Grehan DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)\r\n")); 5042cf9911fSPeter Grehan if (index != 0) { 5052cf9911fSPeter Grehan DPRINTF(("umouse get_interface, invalid index %d\r\n", 5062cf9911fSPeter Grehan index)); 5072cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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): 5232cf9911fSPeter Grehan DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)\r\n")); 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): 5382cf9911fSPeter Grehan DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)\r\n")); 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 */ 5492cf9911fSPeter Grehan DPRINTF(("umouse set address %u\r\n", value)); 5502cf9911fSPeter Grehan break; 5512cf9911fSPeter Grehan 5522cf9911fSPeter Grehan case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE): 5532cf9911fSPeter Grehan DPRINTF(("umouse set config %u\r\n", value)); 5542cf9911fSPeter Grehan break; 5552cf9911fSPeter Grehan 5562cf9911fSPeter Grehan case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 5572cf9911fSPeter Grehan DPRINTF(("umouse set descriptor %u\r\n", value)); 5582cf9911fSPeter Grehan break; 5592cf9911fSPeter Grehan 5602cf9911fSPeter Grehan 5612cf9911fSPeter Grehan case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 5622cf9911fSPeter Grehan DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x\r\n", 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): 5682cf9911fSPeter Grehan DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x\r\n", 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): 5772cf9911fSPeter Grehan DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)\r\n")); 5782cf9911fSPeter Grehan err = USB_ERR_IOERROR; 5792cf9911fSPeter Grehan goto done; 5802cf9911fSPeter Grehan 5812cf9911fSPeter Grehan case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 5822cf9911fSPeter Grehan DPRINTF(("umouse set interface %u\r\n", value)); 5832cf9911fSPeter Grehan break; 5842cf9911fSPeter Grehan 5852cf9911fSPeter Grehan case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE): 5862cf9911fSPeter Grehan DPRINTF(("umouse set isoch delay %u\r\n", value)); 5872cf9911fSPeter Grehan break; 5882cf9911fSPeter Grehan 5892cf9911fSPeter Grehan case UREQ(UR_SET_SEL, 0): 5902cf9911fSPeter Grehan DPRINTF(("umouse set sel\r\n")); 5912cf9911fSPeter Grehan break; 5922cf9911fSPeter Grehan 5932cf9911fSPeter Grehan case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 5942cf9911fSPeter Grehan DPRINTF(("umouse synch frame\r\n")); 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) " 6012cf9911fSPeter Grehan "0x%x\r\n", (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 { 6172cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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): 6422cf9911fSPeter Grehan DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored\r\n")); 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; 6472cf9911fSPeter Grehan DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x\r\n", 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; 6532cf9911fSPeter Grehan DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x\r\n", 6542cf9911fSPeter Grehan sc->hid.protocol)); 6552cf9911fSPeter Grehan break; 6562cf9911fSPeter Grehan 6572cf9911fSPeter Grehan default: 6582cf9911fSPeter Grehan DPRINTF(("**** umouse request unhandled\r\n")); 6592cf9911fSPeter Grehan err = USB_ERR_IOERROR; 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 6702cf9911fSPeter Grehan DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u\r\n", 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 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 6862cf9911fSPeter Grehan DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d\r\n", 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) { 7142cf9911fSPeter Grehan DPRINTF(("umouse no buffer provided for input\r\n")); 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 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 7752cf9911fSPeter Grehan umouse_remove(void *scarg) 7762cf9911fSPeter Grehan { 7772cf9911fSPeter Grehan 7782cf9911fSPeter Grehan return (0); 7792cf9911fSPeter Grehan } 7802cf9911fSPeter Grehan 7812cf9911fSPeter Grehan static int 7822cf9911fSPeter Grehan umouse_stop(void *scarg) 7832cf9911fSPeter Grehan { 7842cf9911fSPeter Grehan 7852cf9911fSPeter Grehan return (0); 7862cf9911fSPeter Grehan } 7872cf9911fSPeter Grehan 7882cf9911fSPeter Grehan 7892cf9911fSPeter Grehan struct usb_devemu ue_mouse = { 7902cf9911fSPeter Grehan .ue_emu = "tablet", 7912cf9911fSPeter Grehan .ue_usbver = 3, 7922cf9911fSPeter Grehan .ue_usbspeed = USB_SPEED_HIGH, 7932cf9911fSPeter Grehan .ue_init = umouse_init, 7942cf9911fSPeter Grehan .ue_request = umouse_request, 7952cf9911fSPeter Grehan .ue_data = umouse_data_handler, 7962cf9911fSPeter Grehan .ue_reset = umouse_reset, 7972cf9911fSPeter Grehan .ue_remove = umouse_remove, 7982cf9911fSPeter Grehan .ue_stop = umouse_stop 7992cf9911fSPeter Grehan }; 8002cf9911fSPeter Grehan USB_EMUL_SET(ue_mouse); 801