14c87aefeSPatrick Mooney /*-
2*32640292SAndy Fiddaman * SPDX-License-Identifier: BSD-2-Clause
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
314c87aefeSPatrick Mooney #include <sys/time.h>
324c87aefeSPatrick Mooney
334c87aefeSPatrick Mooney #include <pthread.h>
344c87aefeSPatrick Mooney #include <stdio.h>
354c87aefeSPatrick Mooney #include <stdlib.h>
364c87aefeSPatrick Mooney #include <string.h>
374c87aefeSPatrick Mooney
384c87aefeSPatrick Mooney #include <dev/usb/usb.h>
394c87aefeSPatrick Mooney #include <dev/usb/usbdi.h>
404c87aefeSPatrick Mooney
414c87aefeSPatrick Mooney #include "usb_emul.h"
424c87aefeSPatrick Mooney #include "console.h"
434c87aefeSPatrick Mooney #include "bhyvegc.h"
44154972afSPatrick Mooney #include "debug.h"
454c87aefeSPatrick Mooney
464c87aefeSPatrick Mooney static int umouse_debug = 0;
47154972afSPatrick Mooney #define DPRINTF(params) if (umouse_debug) PRINTLN params
48154972afSPatrick Mooney #define WPRINTF(params) PRINTLN params
494c87aefeSPatrick Mooney
504c87aefeSPatrick Mooney /* USB endpoint context (1-15) for reporting mouse data events*/
514c87aefeSPatrick Mooney #define UMOUSE_INTR_ENDPT 1
524c87aefeSPatrick Mooney
534c87aefeSPatrick Mooney #define UMOUSE_REPORT_DESC_TYPE 0x22
544c87aefeSPatrick Mooney
554c87aefeSPatrick Mooney #define UMOUSE_GET_REPORT 0x01
564c87aefeSPatrick Mooney #define UMOUSE_GET_IDLE 0x02
574c87aefeSPatrick Mooney #define UMOUSE_GET_PROTOCOL 0x03
584c87aefeSPatrick Mooney #define UMOUSE_SET_REPORT 0x09
594c87aefeSPatrick Mooney #define UMOUSE_SET_IDLE 0x0A
604c87aefeSPatrick Mooney #define UMOUSE_SET_PROTOCOL 0x0B
614c87aefeSPatrick Mooney
624c87aefeSPatrick Mooney #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
634c87aefeSPatrick Mooney
644c87aefeSPatrick Mooney enum {
654c87aefeSPatrick Mooney UMSTR_LANG,
664c87aefeSPatrick Mooney UMSTR_MANUFACTURER,
674c87aefeSPatrick Mooney UMSTR_PRODUCT,
684c87aefeSPatrick Mooney UMSTR_SERIAL,
694c87aefeSPatrick Mooney UMSTR_CONFIG,
704c87aefeSPatrick Mooney UMSTR_MAX
714c87aefeSPatrick Mooney };
724c87aefeSPatrick Mooney
734c87aefeSPatrick Mooney static const char *umouse_desc_strings[] = {
746960cd89SAndy Fiddaman "\x09\x04",
754c87aefeSPatrick Mooney "BHYVE",
764c87aefeSPatrick Mooney "HID Tablet",
774c87aefeSPatrick Mooney "01",
784c87aefeSPatrick Mooney "HID Tablet Device",
794c87aefeSPatrick Mooney };
804c87aefeSPatrick Mooney
814c87aefeSPatrick Mooney struct umouse_hid_descriptor {
824c87aefeSPatrick Mooney uint8_t bLength;
834c87aefeSPatrick Mooney uint8_t bDescriptorType;
844c87aefeSPatrick Mooney uint8_t bcdHID[2];
854c87aefeSPatrick Mooney uint8_t bCountryCode;
864c87aefeSPatrick Mooney uint8_t bNumDescriptors;
874c87aefeSPatrick Mooney uint8_t bReportDescriptorType;
884c87aefeSPatrick Mooney uint8_t wItemLength[2];
894c87aefeSPatrick Mooney } __packed;
904c87aefeSPatrick Mooney
914c87aefeSPatrick Mooney struct umouse_config_desc {
924c87aefeSPatrick Mooney struct usb_config_descriptor confd;
934c87aefeSPatrick Mooney struct usb_interface_descriptor ifcd;
944c87aefeSPatrick Mooney struct umouse_hid_descriptor hidd;
954c87aefeSPatrick Mooney struct usb_endpoint_descriptor endpd;
964c87aefeSPatrick Mooney struct usb_endpoint_ss_comp_descriptor sscompd;
974c87aefeSPatrick Mooney } __packed;
984c87aefeSPatrick Mooney
994c87aefeSPatrick Mooney #define MOUSE_MAX_X 0x8000
1004c87aefeSPatrick Mooney #define MOUSE_MAX_Y 0x8000
1014c87aefeSPatrick Mooney
1024c87aefeSPatrick Mooney static const uint8_t umouse_report_desc[] = {
1034c87aefeSPatrick Mooney 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
1044c87aefeSPatrick Mooney 0x09, 0x02, /* USAGE (Mouse) */
1054c87aefeSPatrick Mooney 0xa1, 0x01, /* COLLECTION (Application) */
1064c87aefeSPatrick Mooney 0x09, 0x01, /* USAGE (Pointer) */
1074c87aefeSPatrick Mooney 0xa1, 0x00, /* COLLECTION (Physical) */
1084c87aefeSPatrick Mooney 0x05, 0x09, /* USAGE_PAGE (Button) */
1094c87aefeSPatrick Mooney 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
1104c87aefeSPatrick Mooney 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
1114c87aefeSPatrick Mooney 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
1124c87aefeSPatrick Mooney 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
1134c87aefeSPatrick Mooney 0x75, 0x01, /* REPORT_SIZE (1) */
1144c87aefeSPatrick Mooney 0x95, 0x03, /* REPORT_COUNT (3) */
1154c87aefeSPatrick Mooney 0x81, 0x02, /* INPUT (Data,Var,Abs); 3 buttons */
1164c87aefeSPatrick Mooney 0x75, 0x05, /* REPORT_SIZE (5) */
1174c87aefeSPatrick Mooney 0x95, 0x01, /* REPORT_COUNT (1) */
1184c87aefeSPatrick Mooney 0x81, 0x03, /* INPUT (Cnst,Var,Abs); padding */
1194c87aefeSPatrick Mooney 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
1204c87aefeSPatrick Mooney 0x09, 0x30, /* USAGE (X) */
1214c87aefeSPatrick Mooney 0x09, 0x31, /* USAGE (Y) */
1224c87aefeSPatrick Mooney 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */
1234c87aefeSPatrick Mooney 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (0x7fff) */
1244c87aefeSPatrick Mooney 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
1254c87aefeSPatrick Mooney 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (0x7fff) */
1264c87aefeSPatrick Mooney 0x75, 0x10, /* REPORT_SIZE (16) */
1274c87aefeSPatrick Mooney 0x95, 0x02, /* REPORT_COUNT (2) */
1284c87aefeSPatrick Mooney 0x81, 0x02, /* INPUT (Data,Var,Abs) */
1294c87aefeSPatrick Mooney 0x05, 0x01, /* USAGE Page (Generic Desktop) */
1304c87aefeSPatrick Mooney 0x09, 0x38, /* USAGE (Wheel) */
1314c87aefeSPatrick Mooney 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */
1324c87aefeSPatrick Mooney 0x45, 0x00, /* PHYSICAL_MAXIMUM (0) */
1334c87aefeSPatrick Mooney 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
1344c87aefeSPatrick Mooney 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
1354c87aefeSPatrick Mooney 0x75, 0x08, /* REPORT_SIZE (8) */
1364c87aefeSPatrick Mooney 0x95, 0x01, /* REPORT_COUNT (1) */
1374c87aefeSPatrick Mooney 0x81, 0x06, /* INPUT (Data,Var,Rel) */
1384c87aefeSPatrick Mooney 0xc0, /* END_COLLECTION */
1394c87aefeSPatrick Mooney 0xc0 /* END_COLLECTION */
1404c87aefeSPatrick Mooney };
1414c87aefeSPatrick Mooney
1424c87aefeSPatrick Mooney struct umouse_report {
1434c87aefeSPatrick Mooney uint8_t buttons; /* bits: 0 left, 1 right, 2 middle */
1444c87aefeSPatrick Mooney int16_t x; /* x position */
1454c87aefeSPatrick Mooney int16_t y; /* y position */
1464c87aefeSPatrick Mooney int8_t z; /* z wheel position */
1474c87aefeSPatrick Mooney } __packed;
1484c87aefeSPatrick Mooney
1494c87aefeSPatrick Mooney
1504c87aefeSPatrick Mooney #define MSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1514c87aefeSPatrick Mooney
1524c87aefeSPatrick Mooney static struct usb_device_descriptor umouse_dev_desc = {
1534c87aefeSPatrick Mooney .bLength = sizeof(umouse_dev_desc),
1544c87aefeSPatrick Mooney .bDescriptorType = UDESC_DEVICE,
1554c87aefeSPatrick Mooney MSETW(.bcdUSB, UD_USB_3_0),
1564c87aefeSPatrick Mooney .bMaxPacketSize = 8, /* max packet size */
1574c87aefeSPatrick Mooney MSETW(.idVendor, 0xFB5D), /* vendor */
1584c87aefeSPatrick Mooney MSETW(.idProduct, 0x0001), /* product */
1594c87aefeSPatrick Mooney MSETW(.bcdDevice, 0), /* device version */
1604c87aefeSPatrick Mooney .iManufacturer = UMSTR_MANUFACTURER,
1614c87aefeSPatrick Mooney .iProduct = UMSTR_PRODUCT,
1624c87aefeSPatrick Mooney .iSerialNumber = UMSTR_SERIAL,
1634c87aefeSPatrick Mooney .bNumConfigurations = 1,
1644c87aefeSPatrick Mooney };
1654c87aefeSPatrick Mooney
1664c87aefeSPatrick Mooney static struct umouse_config_desc umouse_confd = {
1674c87aefeSPatrick Mooney .confd = {
1684c87aefeSPatrick Mooney .bLength = sizeof(umouse_confd.confd),
1694c87aefeSPatrick Mooney .bDescriptorType = UDESC_CONFIG,
1704c87aefeSPatrick Mooney .wTotalLength[0] = sizeof(umouse_confd),
1714c87aefeSPatrick Mooney .bNumInterface = 1,
1724c87aefeSPatrick Mooney .bConfigurationValue = 1,
1734c87aefeSPatrick Mooney .iConfiguration = UMSTR_CONFIG,
1744c87aefeSPatrick Mooney .bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP,
1754c87aefeSPatrick Mooney .bMaxPower = 0,
1764c87aefeSPatrick Mooney },
1774c87aefeSPatrick Mooney .ifcd = {
1784c87aefeSPatrick Mooney .bLength = sizeof(umouse_confd.ifcd),
1794c87aefeSPatrick Mooney .bDescriptorType = UDESC_INTERFACE,
1804c87aefeSPatrick Mooney .bNumEndpoints = 1,
1814c87aefeSPatrick Mooney .bInterfaceClass = UICLASS_HID,
1824c87aefeSPatrick Mooney .bInterfaceSubClass = UISUBCLASS_BOOT,
1834c87aefeSPatrick Mooney .bInterfaceProtocol = UIPROTO_MOUSE,
1844c87aefeSPatrick Mooney },
1854c87aefeSPatrick Mooney .hidd = {
1864c87aefeSPatrick Mooney .bLength = sizeof(umouse_confd.hidd),
1874c87aefeSPatrick Mooney .bDescriptorType = 0x21,
1884c87aefeSPatrick Mooney .bcdHID = { 0x01, 0x10 },
1894c87aefeSPatrick Mooney .bCountryCode = 0,
1904c87aefeSPatrick Mooney .bNumDescriptors = 1,
1914c87aefeSPatrick Mooney .bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE,
1924c87aefeSPatrick Mooney .wItemLength = { sizeof(umouse_report_desc), 0 },
1934c87aefeSPatrick Mooney },
1944c87aefeSPatrick Mooney .endpd = {
1954c87aefeSPatrick Mooney .bLength = sizeof(umouse_confd.endpd),
1964c87aefeSPatrick Mooney .bDescriptorType = UDESC_ENDPOINT,
1974c87aefeSPatrick Mooney .bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT,
1984c87aefeSPatrick Mooney .bmAttributes = UE_INTERRUPT,
1994c87aefeSPatrick Mooney .wMaxPacketSize[0] = 8,
2004c87aefeSPatrick Mooney .bInterval = 0xA,
2014c87aefeSPatrick Mooney },
2024c87aefeSPatrick Mooney .sscompd = {
2034c87aefeSPatrick Mooney .bLength = sizeof(umouse_confd.sscompd),
2044c87aefeSPatrick Mooney .bDescriptorType = UDESC_ENDPOINT_SS_COMP,
2054c87aefeSPatrick Mooney .bMaxBurst = 0,
2064c87aefeSPatrick Mooney .bmAttributes = 0,
2074c87aefeSPatrick Mooney MSETW(.wBytesPerInterval, 0),
2084c87aefeSPatrick Mooney },
2094c87aefeSPatrick Mooney };
2104c87aefeSPatrick Mooney
2114c87aefeSPatrick Mooney
2124c87aefeSPatrick Mooney struct umouse_bos_desc {
2134c87aefeSPatrick Mooney struct usb_bos_descriptor bosd;
2144c87aefeSPatrick Mooney struct usb_devcap_ss_descriptor usbssd;
2154c87aefeSPatrick Mooney } __packed;
2164c87aefeSPatrick Mooney
2174c87aefeSPatrick Mooney
21859d65d31SAndy Fiddaman static struct umouse_bos_desc umouse_bosd = {
2194c87aefeSPatrick Mooney .bosd = {
2204c87aefeSPatrick Mooney .bLength = sizeof(umouse_bosd.bosd),
2214c87aefeSPatrick Mooney .bDescriptorType = UDESC_BOS,
2224c87aefeSPatrick Mooney HSETW(.wTotalLength, sizeof(umouse_bosd)),
2234c87aefeSPatrick Mooney .bNumDeviceCaps = 1,
2244c87aefeSPatrick Mooney },
2254c87aefeSPatrick Mooney .usbssd = {
2264c87aefeSPatrick Mooney .bLength = sizeof(umouse_bosd.usbssd),
2274c87aefeSPatrick Mooney .bDescriptorType = UDESC_DEVICE_CAPABILITY,
2284c87aefeSPatrick Mooney .bDevCapabilityType = 3,
2294c87aefeSPatrick Mooney .bmAttributes = 0,
2304c87aefeSPatrick Mooney HSETW(.wSpeedsSupported, 0x08),
2314c87aefeSPatrick Mooney .bFunctionalitySupport = 3,
2324c87aefeSPatrick Mooney .bU1DevExitLat = 0xa, /* dummy - not used */
2334c87aefeSPatrick Mooney .wU2DevExitLat = { 0x20, 0x00 },
2344c87aefeSPatrick Mooney }
2354c87aefeSPatrick Mooney };
2364c87aefeSPatrick Mooney
2374c87aefeSPatrick Mooney
2384c87aefeSPatrick Mooney struct umouse_softc {
2394c87aefeSPatrick Mooney struct usb_hci *hci;
2404c87aefeSPatrick Mooney
2414c87aefeSPatrick Mooney struct umouse_report um_report;
2424c87aefeSPatrick Mooney int newdata;
2434c87aefeSPatrick Mooney struct {
2444c87aefeSPatrick Mooney uint8_t idle;
2454c87aefeSPatrick Mooney uint8_t protocol;
2464c87aefeSPatrick Mooney uint8_t feature;
2474c87aefeSPatrick Mooney } hid;
2484c87aefeSPatrick Mooney
2494c87aefeSPatrick Mooney pthread_mutex_t mtx;
2504c87aefeSPatrick Mooney pthread_mutex_t ev_mtx;
2514c87aefeSPatrick Mooney int polling;
2524c87aefeSPatrick Mooney struct timeval prev_evt;
2534c87aefeSPatrick Mooney };
2544c87aefeSPatrick Mooney
2554c87aefeSPatrick Mooney static void
umouse_event(uint8_t button,int x,int y,void * arg)2564c87aefeSPatrick Mooney umouse_event(uint8_t button, int x, int y, void *arg)
2574c87aefeSPatrick Mooney {
2584c87aefeSPatrick Mooney struct umouse_softc *sc;
2594c87aefeSPatrick Mooney struct bhyvegc_image *gc;
2604c87aefeSPatrick Mooney
2614c87aefeSPatrick Mooney gc = console_get_image();
2624c87aefeSPatrick Mooney if (gc == NULL) {
2634c87aefeSPatrick Mooney /* not ready */
2644c87aefeSPatrick Mooney return;
2654c87aefeSPatrick Mooney }
2664c87aefeSPatrick Mooney
2674c87aefeSPatrick Mooney sc = arg;
2684c87aefeSPatrick Mooney
2694c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx);
2704c87aefeSPatrick Mooney
2714c87aefeSPatrick Mooney sc->um_report.buttons = 0;
2724c87aefeSPatrick Mooney sc->um_report.z = 0;
2734c87aefeSPatrick Mooney
2744c87aefeSPatrick Mooney if (button & 0x01)
2754c87aefeSPatrick Mooney sc->um_report.buttons |= 0x01; /* left */
2764c87aefeSPatrick Mooney if (button & 0x02)
2774c87aefeSPatrick Mooney sc->um_report.buttons |= 0x04; /* middle */
2784c87aefeSPatrick Mooney if (button & 0x04)
2794c87aefeSPatrick Mooney sc->um_report.buttons |= 0x02; /* right */
2804c87aefeSPatrick Mooney if (button & 0x8)
2814c87aefeSPatrick Mooney sc->um_report.z = 1;
2824c87aefeSPatrick Mooney if (button & 0x10)
2834c87aefeSPatrick Mooney sc->um_report.z = -1;
2844c87aefeSPatrick Mooney
2854c87aefeSPatrick Mooney /* scale coords to mouse resolution */
2864c87aefeSPatrick Mooney sc->um_report.x = MOUSE_MAX_X * x / gc->width;
2874c87aefeSPatrick Mooney sc->um_report.y = MOUSE_MAX_Y * y / gc->height;
2884c87aefeSPatrick Mooney sc->newdata = 1;
2894c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx);
2904c87aefeSPatrick Mooney
2914c87aefeSPatrick Mooney pthread_mutex_lock(&sc->ev_mtx);
2924c87aefeSPatrick Mooney sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT);
2934c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->ev_mtx);
2944c87aefeSPatrick Mooney }
2954c87aefeSPatrick Mooney
2964c87aefeSPatrick Mooney static void *
umouse_init(struct usb_hci * hci,nvlist_t * nvl)2972b948146SAndy Fiddaman umouse_init(struct usb_hci *hci, nvlist_t *nvl)
2984c87aefeSPatrick Mooney {
2994c87aefeSPatrick Mooney struct umouse_softc *sc;
3004c87aefeSPatrick Mooney
3014c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct umouse_softc));
3024c87aefeSPatrick Mooney sc->hci = hci;
3034c87aefeSPatrick Mooney
3044c87aefeSPatrick Mooney sc->hid.protocol = 1; /* REPORT protocol */
3054c87aefeSPatrick Mooney pthread_mutex_init(&sc->mtx, NULL);
3064c87aefeSPatrick Mooney pthread_mutex_init(&sc->ev_mtx, NULL);
3074c87aefeSPatrick Mooney
3084c87aefeSPatrick Mooney console_ptr_register(umouse_event, sc, 10);
3094c87aefeSPatrick Mooney
3104c87aefeSPatrick Mooney return (sc);
3114c87aefeSPatrick Mooney }
3124c87aefeSPatrick Mooney
3134c87aefeSPatrick Mooney #define UREQ(x,y) ((x) | ((y) << 8))
3144c87aefeSPatrick Mooney
3154c87aefeSPatrick Mooney static int
umouse_request(void * scarg,struct usb_data_xfer * xfer)3164c87aefeSPatrick Mooney umouse_request(void *scarg, struct usb_data_xfer *xfer)
3174c87aefeSPatrick Mooney {
3184c87aefeSPatrick Mooney struct umouse_softc *sc;
3194c87aefeSPatrick Mooney struct usb_data_xfer_block *data;
3204c87aefeSPatrick Mooney const char *str;
3214c87aefeSPatrick Mooney uint16_t value;
3224c87aefeSPatrick Mooney uint16_t index;
3234c87aefeSPatrick Mooney uint16_t len;
3244c87aefeSPatrick Mooney uint16_t slen;
3254c87aefeSPatrick Mooney uint8_t *udata;
3264c87aefeSPatrick Mooney int err;
3274c87aefeSPatrick Mooney int i, idx;
3284c87aefeSPatrick Mooney int eshort;
3294c87aefeSPatrick Mooney
3304c87aefeSPatrick Mooney sc = scarg;
3314c87aefeSPatrick Mooney
3324c87aefeSPatrick Mooney data = NULL;
3334c87aefeSPatrick Mooney udata = NULL;
3344c87aefeSPatrick Mooney idx = xfer->head;
3354c87aefeSPatrick Mooney for (i = 0; i < xfer->ndata; i++) {
3364c87aefeSPatrick Mooney xfer->data[idx].bdone = 0;
3374c87aefeSPatrick Mooney if (data == NULL && USB_DATA_OK(xfer,i)) {
3384c87aefeSPatrick Mooney data = &xfer->data[idx];
3394c87aefeSPatrick Mooney udata = data->buf;
3404c87aefeSPatrick Mooney }
3414c87aefeSPatrick Mooney
3424c87aefeSPatrick Mooney xfer->data[idx].processed = 1;
3434c87aefeSPatrick Mooney idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
3444c87aefeSPatrick Mooney }
3454c87aefeSPatrick Mooney
3464c87aefeSPatrick Mooney err = USB_ERR_NORMAL_COMPLETION;
3474c87aefeSPatrick Mooney eshort = 0;
3484c87aefeSPatrick Mooney
3494c87aefeSPatrick Mooney if (!xfer->ureq) {
350154972afSPatrick Mooney DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
3514c87aefeSPatrick Mooney goto done;
3524c87aefeSPatrick Mooney }
3534c87aefeSPatrick Mooney
3544c87aefeSPatrick Mooney value = UGETW(xfer->ureq->wValue);
3554c87aefeSPatrick Mooney index = UGETW(xfer->ureq->wIndex);
3564c87aefeSPatrick Mooney len = UGETW(xfer->ureq->wLength);
3574c87aefeSPatrick Mooney
3584c87aefeSPatrick Mooney DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
359154972afSPatrick Mooney "idx 0x%x, len %u",
3604c87aefeSPatrick Mooney sc->hci->hci_port, xfer->ureq->bmRequestType,
3614c87aefeSPatrick Mooney xfer->ureq->bRequest, value, index, len));
3624c87aefeSPatrick Mooney
3634c87aefeSPatrick Mooney switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
3644c87aefeSPatrick Mooney case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
365154972afSPatrick Mooney DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
3664c87aefeSPatrick Mooney if (!data)
3674c87aefeSPatrick Mooney break;
3684c87aefeSPatrick Mooney
3694c87aefeSPatrick Mooney *udata = umouse_confd.confd.bConfigurationValue;
3704c87aefeSPatrick Mooney data->blen = len > 0 ? len - 1 : 0;
3714c87aefeSPatrick Mooney eshort = data->blen > 0;
3724c87aefeSPatrick Mooney data->bdone += 1;
3734c87aefeSPatrick Mooney break;
3744c87aefeSPatrick Mooney
3754c87aefeSPatrick Mooney case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
376154972afSPatrick Mooney DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
3774c87aefeSPatrick Mooney value >> 8));
3784c87aefeSPatrick Mooney if (!data)
3794c87aefeSPatrick Mooney break;
3804c87aefeSPatrick Mooney
3814c87aefeSPatrick Mooney switch (value >> 8) {
3824c87aefeSPatrick Mooney case UDESC_DEVICE:
3834c87aefeSPatrick Mooney DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
384154972afSPatrick Mooney "sizeof(umouse_dev_desc) %lu",
3854c87aefeSPatrick Mooney len, sizeof(umouse_dev_desc)));
3864c87aefeSPatrick Mooney if ((value & 0xFF) != 0) {
3876960cd89SAndy Fiddaman err = USB_ERR_STALLED;
3884c87aefeSPatrick Mooney goto done;
3894c87aefeSPatrick Mooney }
3904c87aefeSPatrick Mooney if (len > sizeof(umouse_dev_desc)) {
3914c87aefeSPatrick Mooney data->blen = len - sizeof(umouse_dev_desc);
3924c87aefeSPatrick Mooney len = sizeof(umouse_dev_desc);
3934c87aefeSPatrick Mooney } else
3944c87aefeSPatrick Mooney data->blen = 0;
3954c87aefeSPatrick Mooney memcpy(data->buf, &umouse_dev_desc, len);
3964c87aefeSPatrick Mooney data->bdone += len;
3974c87aefeSPatrick Mooney break;
3984c87aefeSPatrick Mooney
3994c87aefeSPatrick Mooney case UDESC_CONFIG:
400154972afSPatrick Mooney DPRINTF(("umouse: (->UDESC_CONFIG)"));
4014c87aefeSPatrick Mooney if ((value & 0xFF) != 0) {
4026960cd89SAndy Fiddaman err = USB_ERR_STALLED;
4034c87aefeSPatrick Mooney goto done;
4044c87aefeSPatrick Mooney }
4054c87aefeSPatrick Mooney if (len > sizeof(umouse_confd)) {
4064c87aefeSPatrick Mooney data->blen = len - sizeof(umouse_confd);
4074c87aefeSPatrick Mooney len = sizeof(umouse_confd);
4084c87aefeSPatrick Mooney } else
4094c87aefeSPatrick Mooney data->blen = 0;
4104c87aefeSPatrick Mooney
4114c87aefeSPatrick Mooney memcpy(data->buf, &umouse_confd, len);
4124c87aefeSPatrick Mooney data->bdone += len;
4134c87aefeSPatrick Mooney break;
4144c87aefeSPatrick Mooney
4154c87aefeSPatrick Mooney case UDESC_STRING:
416154972afSPatrick Mooney DPRINTF(("umouse: (->UDESC_STRING)"));
4174c87aefeSPatrick Mooney str = NULL;
4184c87aefeSPatrick Mooney if ((value & 0xFF) < UMSTR_MAX)
4194c87aefeSPatrick Mooney str = umouse_desc_strings[value & 0xFF];
4204c87aefeSPatrick Mooney else
4214c87aefeSPatrick Mooney goto done;
4224c87aefeSPatrick Mooney
4234c87aefeSPatrick Mooney if ((value & 0xFF) == UMSTR_LANG) {
4244c87aefeSPatrick Mooney udata[0] = 4;
4254c87aefeSPatrick Mooney udata[1] = UDESC_STRING;
4264c87aefeSPatrick Mooney data->blen = len - 2;
4274c87aefeSPatrick Mooney len -= 2;
4284c87aefeSPatrick Mooney data->bdone += 2;
4294c87aefeSPatrick Mooney
4304c87aefeSPatrick Mooney if (len >= 2) {
4314c87aefeSPatrick Mooney udata[2] = str[0];
4324c87aefeSPatrick Mooney udata[3] = str[1];
4334c87aefeSPatrick Mooney data->blen -= 2;
4344c87aefeSPatrick Mooney data->bdone += 2;
4354c87aefeSPatrick Mooney } else
4364c87aefeSPatrick Mooney data->blen = 0;
4374c87aefeSPatrick Mooney
4384c87aefeSPatrick Mooney goto done;
4394c87aefeSPatrick Mooney }
4404c87aefeSPatrick Mooney
4414c87aefeSPatrick Mooney slen = 2 + strlen(str) * 2;
4424c87aefeSPatrick Mooney udata[0] = slen;
4434c87aefeSPatrick Mooney udata[1] = UDESC_STRING;
4444c87aefeSPatrick Mooney
4454c87aefeSPatrick Mooney if (len > slen) {
4464c87aefeSPatrick Mooney data->blen = len - slen;
4474c87aefeSPatrick Mooney len = slen;
4484c87aefeSPatrick Mooney } else
4494c87aefeSPatrick Mooney data->blen = 0;
4504c87aefeSPatrick Mooney for (i = 2; i < len; i += 2) {
4514c87aefeSPatrick Mooney udata[i] = *str++;
4524c87aefeSPatrick Mooney udata[i+1] = '\0';
4534c87aefeSPatrick Mooney }
4544c87aefeSPatrick Mooney data->bdone += slen;
4554c87aefeSPatrick Mooney
4564c87aefeSPatrick Mooney break;
4574c87aefeSPatrick Mooney
4584c87aefeSPatrick Mooney case UDESC_BOS:
459154972afSPatrick Mooney DPRINTF(("umouse: USB3 BOS"));
4604c87aefeSPatrick Mooney if (len > sizeof(umouse_bosd)) {
4614c87aefeSPatrick Mooney data->blen = len - sizeof(umouse_bosd);
4624c87aefeSPatrick Mooney len = sizeof(umouse_bosd);
4634c87aefeSPatrick Mooney } else
4644c87aefeSPatrick Mooney data->blen = 0;
4654c87aefeSPatrick Mooney memcpy(udata, &umouse_bosd, len);
4664c87aefeSPatrick Mooney data->bdone += len;
4674c87aefeSPatrick Mooney break;
4684c87aefeSPatrick Mooney
4694c87aefeSPatrick Mooney default:
470154972afSPatrick Mooney DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
4716960cd89SAndy Fiddaman err = USB_ERR_STALLED;
4724c87aefeSPatrick Mooney goto done;
4734c87aefeSPatrick Mooney }
4744c87aefeSPatrick Mooney eshort = data->blen > 0;
4754c87aefeSPatrick Mooney break;
4764c87aefeSPatrick Mooney
4774c87aefeSPatrick Mooney case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
4784c87aefeSPatrick Mooney DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
479154972afSPatrick Mooney "0x%x", (value >> 8)));
4804c87aefeSPatrick Mooney if (!data)
4814c87aefeSPatrick Mooney break;
4824c87aefeSPatrick Mooney
4834c87aefeSPatrick Mooney switch (value >> 8) {
4844c87aefeSPatrick Mooney case UMOUSE_REPORT_DESC_TYPE:
4854c87aefeSPatrick Mooney if (len > sizeof(umouse_report_desc)) {
4864c87aefeSPatrick Mooney data->blen = len - sizeof(umouse_report_desc);
4874c87aefeSPatrick Mooney len = sizeof(umouse_report_desc);
4884c87aefeSPatrick Mooney } else
4894c87aefeSPatrick Mooney data->blen = 0;
4904c87aefeSPatrick Mooney memcpy(data->buf, umouse_report_desc, len);
4914c87aefeSPatrick Mooney data->bdone += len;
4924c87aefeSPatrick Mooney break;
4934c87aefeSPatrick Mooney default:
494154972afSPatrick Mooney DPRINTF(("umouse: IO ERROR"));
4956960cd89SAndy Fiddaman err = USB_ERR_STALLED;
4964c87aefeSPatrick Mooney goto done;
4974c87aefeSPatrick Mooney }
4984c87aefeSPatrick Mooney eshort = data->blen > 0;
4994c87aefeSPatrick Mooney break;
5004c87aefeSPatrick Mooney
5014c87aefeSPatrick Mooney case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
502154972afSPatrick Mooney DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
5034c87aefeSPatrick Mooney if (index != 0) {
504154972afSPatrick Mooney DPRINTF(("umouse get_interface, invalid index %d",
5054c87aefeSPatrick Mooney index));
5066960cd89SAndy Fiddaman err = USB_ERR_STALLED;
5074c87aefeSPatrick Mooney goto done;
5084c87aefeSPatrick Mooney }
5094c87aefeSPatrick Mooney
5104c87aefeSPatrick Mooney if (!data)
5114c87aefeSPatrick Mooney break;
5124c87aefeSPatrick Mooney
5134c87aefeSPatrick Mooney if (len > 0) {
5144c87aefeSPatrick Mooney *udata = 0;
5154c87aefeSPatrick Mooney data->blen = len - 1;
5164c87aefeSPatrick Mooney }
5174c87aefeSPatrick Mooney eshort = data->blen > 0;
5184c87aefeSPatrick Mooney data->bdone += 1;
5194c87aefeSPatrick Mooney break;
5204c87aefeSPatrick Mooney
5214c87aefeSPatrick Mooney case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
522154972afSPatrick Mooney DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
5234c87aefeSPatrick Mooney if (data != NULL && len > 1) {
5244c87aefeSPatrick Mooney if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
5254c87aefeSPatrick Mooney USETW(udata, UDS_REMOTE_WAKEUP);
5264c87aefeSPatrick Mooney else
5274c87aefeSPatrick Mooney USETW(udata, 0);
5284c87aefeSPatrick Mooney data->blen = len - 2;
5294c87aefeSPatrick Mooney data->bdone += 2;
5304c87aefeSPatrick Mooney }
5314c87aefeSPatrick Mooney
5324c87aefeSPatrick Mooney eshort = data->blen > 0;
5334c87aefeSPatrick Mooney break;
5344c87aefeSPatrick Mooney
5354c87aefeSPatrick Mooney case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
5364c87aefeSPatrick Mooney case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
537154972afSPatrick Mooney DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
5384c87aefeSPatrick Mooney if (data != NULL && len > 1) {
5394c87aefeSPatrick Mooney USETW(udata, 0);
5404c87aefeSPatrick Mooney data->blen = len - 2;
5414c87aefeSPatrick Mooney data->bdone += 2;
5424c87aefeSPatrick Mooney }
5434c87aefeSPatrick Mooney eshort = data->blen > 0;
5444c87aefeSPatrick Mooney break;
5454c87aefeSPatrick Mooney
5464c87aefeSPatrick Mooney case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
5474c87aefeSPatrick Mooney /* XXX Controller should've handled this */
548154972afSPatrick Mooney DPRINTF(("umouse set address %u", value));
5494c87aefeSPatrick Mooney break;
5504c87aefeSPatrick Mooney
5514c87aefeSPatrick Mooney case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
552154972afSPatrick Mooney DPRINTF(("umouse set config %u", value));
5534c87aefeSPatrick Mooney break;
5544c87aefeSPatrick Mooney
5554c87aefeSPatrick Mooney case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
556154972afSPatrick Mooney DPRINTF(("umouse set descriptor %u", value));
5574c87aefeSPatrick Mooney break;
5584c87aefeSPatrick Mooney
5594c87aefeSPatrick Mooney
5604c87aefeSPatrick Mooney case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
561154972afSPatrick Mooney DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5624c87aefeSPatrick Mooney if (value == UF_DEVICE_REMOTE_WAKEUP)
5634c87aefeSPatrick Mooney sc->hid.feature = 0;
5644c87aefeSPatrick Mooney break;
5654c87aefeSPatrick Mooney
5664c87aefeSPatrick Mooney case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
567154972afSPatrick Mooney DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
5684c87aefeSPatrick Mooney if (value == UF_DEVICE_REMOTE_WAKEUP)
5694c87aefeSPatrick Mooney sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
5704c87aefeSPatrick Mooney break;
5714c87aefeSPatrick Mooney
5724c87aefeSPatrick Mooney case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
5734c87aefeSPatrick Mooney case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
5744c87aefeSPatrick Mooney case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
5754c87aefeSPatrick Mooney case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
576154972afSPatrick Mooney DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
5776960cd89SAndy Fiddaman err = USB_ERR_STALLED;
5784c87aefeSPatrick Mooney goto done;
5794c87aefeSPatrick Mooney
5804c87aefeSPatrick Mooney case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
581154972afSPatrick Mooney DPRINTF(("umouse set interface %u", value));
5824c87aefeSPatrick Mooney break;
5834c87aefeSPatrick Mooney
5844c87aefeSPatrick Mooney case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
585154972afSPatrick Mooney DPRINTF(("umouse set isoch delay %u", value));
5864c87aefeSPatrick Mooney break;
5874c87aefeSPatrick Mooney
5884c87aefeSPatrick Mooney case UREQ(UR_SET_SEL, 0):
589154972afSPatrick Mooney DPRINTF(("umouse set sel"));
5904c87aefeSPatrick Mooney break;
5914c87aefeSPatrick Mooney
5924c87aefeSPatrick Mooney case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
593154972afSPatrick Mooney DPRINTF(("umouse synch frame"));
5944c87aefeSPatrick Mooney break;
5954c87aefeSPatrick Mooney
5964c87aefeSPatrick Mooney /* HID device requests */
5974c87aefeSPatrick Mooney
5984c87aefeSPatrick Mooney case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
5994c87aefeSPatrick Mooney DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
600154972afSPatrick Mooney "0x%x", (value >> 8)));
6014c87aefeSPatrick Mooney if (!data)
6024c87aefeSPatrick Mooney break;
6034c87aefeSPatrick Mooney
6044c87aefeSPatrick Mooney if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
6054c87aefeSPatrick Mooney /* TODO read from backend */
6064c87aefeSPatrick Mooney
6074c87aefeSPatrick Mooney if (len > sizeof(sc->um_report)) {
6084c87aefeSPatrick Mooney data->blen = len - sizeof(sc->um_report);
6094c87aefeSPatrick Mooney len = sizeof(sc->um_report);
6104c87aefeSPatrick Mooney } else
6114c87aefeSPatrick Mooney data->blen = 0;
6124c87aefeSPatrick Mooney
6134c87aefeSPatrick Mooney memcpy(data->buf, &sc->um_report, len);
6144c87aefeSPatrick Mooney data->bdone += len;
6154c87aefeSPatrick Mooney } else {
6166960cd89SAndy Fiddaman err = USB_ERR_STALLED;
6174c87aefeSPatrick Mooney goto done;
6184c87aefeSPatrick Mooney }
6194c87aefeSPatrick Mooney eshort = data->blen > 0;
6204c87aefeSPatrick Mooney break;
6214c87aefeSPatrick Mooney
6224c87aefeSPatrick Mooney case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
6234c87aefeSPatrick Mooney if (data != NULL && len > 0) {
6244c87aefeSPatrick Mooney *udata = sc->hid.idle;
6254c87aefeSPatrick Mooney data->blen = len - 1;
6264c87aefeSPatrick Mooney data->bdone += 1;
6274c87aefeSPatrick Mooney }
6284c87aefeSPatrick Mooney eshort = data->blen > 0;
6294c87aefeSPatrick Mooney break;
6304c87aefeSPatrick Mooney
6314c87aefeSPatrick Mooney case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
6324c87aefeSPatrick Mooney if (data != NULL && len > 0) {
6334c87aefeSPatrick Mooney *udata = sc->hid.protocol;
6344c87aefeSPatrick Mooney data->blen = len - 1;
6354c87aefeSPatrick Mooney data->bdone += 1;
6364c87aefeSPatrick Mooney }
6374c87aefeSPatrick Mooney eshort = data->blen > 0;
6384c87aefeSPatrick Mooney break;
6394c87aefeSPatrick Mooney
6404c87aefeSPatrick Mooney case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
641154972afSPatrick Mooney DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
6424c87aefeSPatrick Mooney break;
6434c87aefeSPatrick Mooney
6444c87aefeSPatrick Mooney case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
6454c87aefeSPatrick Mooney sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
646154972afSPatrick Mooney DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
6474c87aefeSPatrick Mooney sc->hid.idle));
6484c87aefeSPatrick Mooney break;
6494c87aefeSPatrick Mooney
6504c87aefeSPatrick Mooney case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
6514c87aefeSPatrick Mooney sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
652154972afSPatrick Mooney DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
6534c87aefeSPatrick Mooney sc->hid.protocol));
6544c87aefeSPatrick Mooney break;
6554c87aefeSPatrick Mooney
6564c87aefeSPatrick Mooney default:
657154972afSPatrick Mooney DPRINTF(("**** umouse request unhandled"));
6586960cd89SAndy Fiddaman err = USB_ERR_STALLED;
6594c87aefeSPatrick Mooney break;
6604c87aefeSPatrick Mooney }
6614c87aefeSPatrick Mooney
6624c87aefeSPatrick Mooney done:
6634c87aefeSPatrick Mooney /* UT_WRITE is 0, so this is condition is never true. */
6644c87aefeSPatrick Mooney #ifdef __FreeBSD__
6654c87aefeSPatrick Mooney if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
6664c87aefeSPatrick Mooney (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
6674c87aefeSPatrick Mooney data->blen = 0;
6684c87aefeSPatrick Mooney else if (eshort)
6694c87aefeSPatrick Mooney err = USB_ERR_SHORT_XFER;
6704c87aefeSPatrick Mooney #else
6714c87aefeSPatrick Mooney if (eshort)
6724c87aefeSPatrick Mooney err = USB_ERR_SHORT_XFER;
6734c87aefeSPatrick Mooney #endif
6744c87aefeSPatrick Mooney
6754c87aefeSPatrick Mooney
676154972afSPatrick Mooney DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
6774c87aefeSPatrick Mooney err, (data ? data->blen : 0), (data ? data->bdone : 0)));
6784c87aefeSPatrick Mooney
6794c87aefeSPatrick Mooney return (err);
6804c87aefeSPatrick Mooney }
6814c87aefeSPatrick Mooney
6824c87aefeSPatrick Mooney static int
umouse_data_handler(void * scarg,struct usb_data_xfer * xfer,int dir,int epctx)6834c87aefeSPatrick Mooney umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
6844c87aefeSPatrick Mooney int epctx)
6854c87aefeSPatrick Mooney {
6864c87aefeSPatrick Mooney struct umouse_softc *sc;
6874c87aefeSPatrick Mooney struct usb_data_xfer_block *data;
6884c87aefeSPatrick Mooney uint8_t *udata;
6894c87aefeSPatrick Mooney int len, i, idx;
6904c87aefeSPatrick Mooney int err;
6914c87aefeSPatrick Mooney
692154972afSPatrick Mooney DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
6934c87aefeSPatrick Mooney dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
6944c87aefeSPatrick Mooney
6954c87aefeSPatrick Mooney
6964c87aefeSPatrick Mooney /* find buffer to add data */
6974c87aefeSPatrick Mooney udata = NULL;
6984c87aefeSPatrick Mooney err = USB_ERR_NORMAL_COMPLETION;
6994c87aefeSPatrick Mooney
7004c87aefeSPatrick Mooney /* handle xfer at first unprocessed item with buffer */
7014c87aefeSPatrick Mooney data = NULL;
7024c87aefeSPatrick Mooney idx = xfer->head;
7034c87aefeSPatrick Mooney for (i = 0; i < xfer->ndata; i++) {
7044c87aefeSPatrick Mooney data = &xfer->data[idx];
7054c87aefeSPatrick Mooney if (data->buf != NULL && data->blen != 0) {
7064c87aefeSPatrick Mooney break;
7074c87aefeSPatrick Mooney } else {
7084c87aefeSPatrick Mooney data->processed = 1;
7094c87aefeSPatrick Mooney data = NULL;
7104c87aefeSPatrick Mooney }
7114c87aefeSPatrick Mooney idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
7124c87aefeSPatrick Mooney }
7134c87aefeSPatrick Mooney if (!data)
7144c87aefeSPatrick Mooney goto done;
7154c87aefeSPatrick Mooney
7164c87aefeSPatrick Mooney udata = data->buf;
7174c87aefeSPatrick Mooney len = data->blen;
7184c87aefeSPatrick Mooney
7194c87aefeSPatrick Mooney if (udata == NULL) {
720154972afSPatrick Mooney DPRINTF(("umouse no buffer provided for input"));
7214c87aefeSPatrick Mooney err = USB_ERR_NOMEM;
7224c87aefeSPatrick Mooney goto done;
7234c87aefeSPatrick Mooney }
7244c87aefeSPatrick Mooney
7254c87aefeSPatrick Mooney sc = scarg;
7264c87aefeSPatrick Mooney
7274c87aefeSPatrick Mooney if (dir) {
7284c87aefeSPatrick Mooney
7294c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx);
7304c87aefeSPatrick Mooney
7314c87aefeSPatrick Mooney if (!sc->newdata) {
7324c87aefeSPatrick Mooney err = USB_ERR_CANCELLED;
7334c87aefeSPatrick Mooney USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
7344c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx);
7354c87aefeSPatrick Mooney goto done;
7364c87aefeSPatrick Mooney }
7374c87aefeSPatrick Mooney
7384c87aefeSPatrick Mooney if (sc->polling) {
7394c87aefeSPatrick Mooney err = USB_ERR_STALLED;
7404c87aefeSPatrick Mooney USB_DATA_SET_ERRCODE(data, USB_STALL);
7414c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx);
7424c87aefeSPatrick Mooney goto done;
7434c87aefeSPatrick Mooney }
7444c87aefeSPatrick Mooney sc->polling = 1;
7454c87aefeSPatrick Mooney
7464c87aefeSPatrick Mooney if (len > 0) {
7474c87aefeSPatrick Mooney sc->newdata = 0;
7484c87aefeSPatrick Mooney
7494c87aefeSPatrick Mooney data->processed = 1;
7504c87aefeSPatrick Mooney data->bdone += 6;
7514c87aefeSPatrick Mooney memcpy(udata, &sc->um_report, 6);
7524c87aefeSPatrick Mooney data->blen = len - 6;
7534c87aefeSPatrick Mooney if (data->blen > 0)
7544c87aefeSPatrick Mooney err = USB_ERR_SHORT_XFER;
7554c87aefeSPatrick Mooney }
7564c87aefeSPatrick Mooney
7574c87aefeSPatrick Mooney sc->polling = 0;
7584c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx);
7594c87aefeSPatrick Mooney } else {
7604c87aefeSPatrick Mooney USB_DATA_SET_ERRCODE(data, USB_STALL);
7614c87aefeSPatrick Mooney err = USB_ERR_STALLED;
7624c87aefeSPatrick Mooney }
7634c87aefeSPatrick Mooney
7644c87aefeSPatrick Mooney done:
7654c87aefeSPatrick Mooney return (err);
7664c87aefeSPatrick Mooney }
7674c87aefeSPatrick Mooney
7684c87aefeSPatrick Mooney static int
umouse_reset(void * scarg)7694c87aefeSPatrick Mooney umouse_reset(void *scarg)
7704c87aefeSPatrick Mooney {
7714c87aefeSPatrick Mooney struct umouse_softc *sc;
7724c87aefeSPatrick Mooney
7734c87aefeSPatrick Mooney sc = scarg;
7744c87aefeSPatrick Mooney
7754c87aefeSPatrick Mooney sc->newdata = 0;
7764c87aefeSPatrick Mooney
7774c87aefeSPatrick Mooney return (0);
7784c87aefeSPatrick Mooney }
7794c87aefeSPatrick Mooney
7804c87aefeSPatrick Mooney static int
umouse_remove(void * scarg)7814c87aefeSPatrick Mooney umouse_remove(void *scarg)
7824c87aefeSPatrick Mooney {
7834c87aefeSPatrick Mooney
7844c87aefeSPatrick Mooney return (0);
7854c87aefeSPatrick Mooney }
7864c87aefeSPatrick Mooney
7874c87aefeSPatrick Mooney static int
umouse_stop(void * scarg)7884c87aefeSPatrick Mooney umouse_stop(void *scarg)
7894c87aefeSPatrick Mooney {
7904c87aefeSPatrick Mooney
7914c87aefeSPatrick Mooney return (0);
7924c87aefeSPatrick Mooney }
7934c87aefeSPatrick Mooney
7944c87aefeSPatrick Mooney
79559d65d31SAndy Fiddaman static struct usb_devemu ue_mouse = {
7964c87aefeSPatrick Mooney .ue_emu = "tablet",
7974c87aefeSPatrick Mooney .ue_usbver = 3,
7984c87aefeSPatrick Mooney .ue_usbspeed = USB_SPEED_HIGH,
7994c87aefeSPatrick Mooney .ue_init = umouse_init,
8004c87aefeSPatrick Mooney .ue_request = umouse_request,
8014c87aefeSPatrick Mooney .ue_data = umouse_data_handler,
8024c87aefeSPatrick Mooney .ue_reset = umouse_reset,
8034c87aefeSPatrick Mooney .ue_remove = umouse_remove,
8044c87aefeSPatrick Mooney .ue_stop = umouse_stop
8054c87aefeSPatrick Mooney };
8064c87aefeSPatrick Mooney USB_EMUL_SET(ue_mouse);
807