1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/time.h> 33 34 #include <machine/vmm_snapshot.h> 35 36 #include <pthread.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 41 #include <dev/usb/usb.h> 42 #include <dev/usb/usbdi.h> 43 44 #include "usb_emul.h" 45 #include "console.h" 46 #include "bhyvegc.h" 47 #include "debug.h" 48 49 static int umouse_debug = 0; 50 #define DPRINTF(params) if (umouse_debug) PRINTLN params 51 #define WPRINTF(params) PRINTLN params 52 53 /* USB endpoint context (1-15) for reporting mouse data events*/ 54 #define UMOUSE_INTR_ENDPT 1 55 56 #define UMOUSE_REPORT_DESC_TYPE 0x22 57 58 #define UMOUSE_GET_REPORT 0x01 59 #define UMOUSE_GET_IDLE 0x02 60 #define UMOUSE_GET_PROTOCOL 0x03 61 #define UMOUSE_SET_REPORT 0x09 62 #define UMOUSE_SET_IDLE 0x0A 63 #define UMOUSE_SET_PROTOCOL 0x0B 64 65 #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 66 67 enum { 68 UMSTR_LANG, 69 UMSTR_MANUFACTURER, 70 UMSTR_PRODUCT, 71 UMSTR_SERIAL, 72 UMSTR_CONFIG, 73 UMSTR_MAX 74 }; 75 76 static const char *umouse_desc_strings[] = { 77 "\x04\x09", 78 "BHYVE", 79 "HID Tablet", 80 "01", 81 "HID Tablet Device", 82 }; 83 84 struct umouse_hid_descriptor { 85 uint8_t bLength; 86 uint8_t bDescriptorType; 87 uint8_t bcdHID[2]; 88 uint8_t bCountryCode; 89 uint8_t bNumDescriptors; 90 uint8_t bReportDescriptorType; 91 uint8_t wItemLength[2]; 92 } __packed; 93 94 struct umouse_config_desc { 95 struct usb_config_descriptor confd; 96 struct usb_interface_descriptor ifcd; 97 struct umouse_hid_descriptor hidd; 98 struct usb_endpoint_descriptor endpd; 99 struct usb_endpoint_ss_comp_descriptor sscompd; 100 } __packed; 101 102 #define MOUSE_MAX_X 0x8000 103 #define MOUSE_MAX_Y 0x8000 104 105 static const uint8_t umouse_report_desc[] = { 106 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 107 0x09, 0x02, /* USAGE (Mouse) */ 108 0xa1, 0x01, /* COLLECTION (Application) */ 109 0x09, 0x01, /* USAGE (Pointer) */ 110 0xa1, 0x00, /* COLLECTION (Physical) */ 111 0x05, 0x09, /* USAGE_PAGE (Button) */ 112 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ 113 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */ 114 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 115 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 116 0x75, 0x01, /* REPORT_SIZE (1) */ 117 0x95, 0x03, /* REPORT_COUNT (3) */ 118 0x81, 0x02, /* INPUT (Data,Var,Abs); 3 buttons */ 119 0x75, 0x05, /* REPORT_SIZE (5) */ 120 0x95, 0x01, /* REPORT_COUNT (1) */ 121 0x81, 0x03, /* INPUT (Cnst,Var,Abs); padding */ 122 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 123 0x09, 0x30, /* USAGE (X) */ 124 0x09, 0x31, /* USAGE (Y) */ 125 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ 126 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (0x7fff) */ 127 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 128 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (0x7fff) */ 129 0x75, 0x10, /* REPORT_SIZE (16) */ 130 0x95, 0x02, /* REPORT_COUNT (2) */ 131 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 132 0x05, 0x01, /* USAGE Page (Generic Desktop) */ 133 0x09, 0x38, /* USAGE (Wheel) */ 134 0x35, 0x00, /* PHYSICAL_MINIMUM (0) */ 135 0x45, 0x00, /* PHYSICAL_MAXIMUM (0) */ 136 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ 137 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ 138 0x75, 0x08, /* REPORT_SIZE (8) */ 139 0x95, 0x01, /* REPORT_COUNT (1) */ 140 0x81, 0x06, /* INPUT (Data,Var,Rel) */ 141 0xc0, /* END_COLLECTION */ 142 0xc0 /* END_COLLECTION */ 143 }; 144 145 struct umouse_report { 146 uint8_t buttons; /* bits: 0 left, 1 right, 2 middle */ 147 int16_t x; /* x position */ 148 int16_t y; /* y position */ 149 int8_t z; /* z wheel position */ 150 } __packed; 151 152 153 #define MSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 154 155 static struct usb_device_descriptor umouse_dev_desc = { 156 .bLength = sizeof(umouse_dev_desc), 157 .bDescriptorType = UDESC_DEVICE, 158 MSETW(.bcdUSB, UD_USB_3_0), 159 .bMaxPacketSize = 8, /* max packet size */ 160 MSETW(.idVendor, 0xFB5D), /* vendor */ 161 MSETW(.idProduct, 0x0001), /* product */ 162 MSETW(.bcdDevice, 0), /* device version */ 163 .iManufacturer = UMSTR_MANUFACTURER, 164 .iProduct = UMSTR_PRODUCT, 165 .iSerialNumber = UMSTR_SERIAL, 166 .bNumConfigurations = 1, 167 }; 168 169 static struct umouse_config_desc umouse_confd = { 170 .confd = { 171 .bLength = sizeof(umouse_confd.confd), 172 .bDescriptorType = UDESC_CONFIG, 173 .wTotalLength[0] = sizeof(umouse_confd), 174 .bNumInterface = 1, 175 .bConfigurationValue = 1, 176 .iConfiguration = UMSTR_CONFIG, 177 .bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP, 178 .bMaxPower = 0, 179 }, 180 .ifcd = { 181 .bLength = sizeof(umouse_confd.ifcd), 182 .bDescriptorType = UDESC_INTERFACE, 183 .bNumEndpoints = 1, 184 .bInterfaceClass = UICLASS_HID, 185 .bInterfaceSubClass = UISUBCLASS_BOOT, 186 .bInterfaceProtocol = UIPROTO_MOUSE, 187 }, 188 .hidd = { 189 .bLength = sizeof(umouse_confd.hidd), 190 .bDescriptorType = 0x21, 191 .bcdHID = { 0x01, 0x10 }, 192 .bCountryCode = 0, 193 .bNumDescriptors = 1, 194 .bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE, 195 .wItemLength = { sizeof(umouse_report_desc), 0 }, 196 }, 197 .endpd = { 198 .bLength = sizeof(umouse_confd.endpd), 199 .bDescriptorType = UDESC_ENDPOINT, 200 .bEndpointAddress = UE_DIR_IN | UMOUSE_INTR_ENDPT, 201 .bmAttributes = UE_INTERRUPT, 202 .wMaxPacketSize[0] = 8, 203 .bInterval = 0xA, 204 }, 205 .sscompd = { 206 .bLength = sizeof(umouse_confd.sscompd), 207 .bDescriptorType = UDESC_ENDPOINT_SS_COMP, 208 .bMaxBurst = 0, 209 .bmAttributes = 0, 210 MSETW(.wBytesPerInterval, 0), 211 }, 212 }; 213 214 215 struct umouse_bos_desc { 216 struct usb_bos_descriptor bosd; 217 struct usb_devcap_ss_descriptor usbssd; 218 } __packed; 219 220 221 struct umouse_bos_desc umouse_bosd = { 222 .bosd = { 223 .bLength = sizeof(umouse_bosd.bosd), 224 .bDescriptorType = UDESC_BOS, 225 HSETW(.wTotalLength, sizeof(umouse_bosd)), 226 .bNumDeviceCaps = 1, 227 }, 228 .usbssd = { 229 .bLength = sizeof(umouse_bosd.usbssd), 230 .bDescriptorType = UDESC_DEVICE_CAPABILITY, 231 .bDevCapabilityType = 3, 232 .bmAttributes = 0, 233 HSETW(.wSpeedsSupported, 0x08), 234 .bFunctionalitySupport = 3, 235 .bU1DevExitLat = 0xa, /* dummy - not used */ 236 .wU2DevExitLat = { 0x20, 0x00 }, 237 } 238 }; 239 240 241 struct umouse_softc { 242 struct usb_hci *hci; 243 244 char *opt; 245 246 struct umouse_report um_report; 247 int newdata; 248 struct { 249 uint8_t idle; 250 uint8_t protocol; 251 uint8_t feature; 252 } hid; 253 254 pthread_mutex_t mtx; 255 pthread_mutex_t ev_mtx; 256 int polling; 257 struct timeval prev_evt; 258 }; 259 260 static void 261 umouse_event(uint8_t button, int x, int y, void *arg) 262 { 263 struct umouse_softc *sc; 264 struct bhyvegc_image *gc; 265 266 gc = console_get_image(); 267 if (gc == NULL) { 268 /* not ready */ 269 return; 270 } 271 272 sc = arg; 273 274 pthread_mutex_lock(&sc->mtx); 275 276 sc->um_report.buttons = 0; 277 sc->um_report.z = 0; 278 279 if (button & 0x01) 280 sc->um_report.buttons |= 0x01; /* left */ 281 if (button & 0x02) 282 sc->um_report.buttons |= 0x04; /* middle */ 283 if (button & 0x04) 284 sc->um_report.buttons |= 0x02; /* right */ 285 if (button & 0x8) 286 sc->um_report.z = 1; 287 if (button & 0x10) 288 sc->um_report.z = -1; 289 290 /* scale coords to mouse resolution */ 291 sc->um_report.x = MOUSE_MAX_X * x / gc->width; 292 sc->um_report.y = MOUSE_MAX_Y * y / gc->height; 293 sc->newdata = 1; 294 pthread_mutex_unlock(&sc->mtx); 295 296 pthread_mutex_lock(&sc->ev_mtx); 297 sc->hci->hci_intr(sc->hci, UE_DIR_IN | UMOUSE_INTR_ENDPT); 298 pthread_mutex_unlock(&sc->ev_mtx); 299 } 300 301 static void * 302 umouse_init(struct usb_hci *hci, char *opt) 303 { 304 struct umouse_softc *sc; 305 306 sc = calloc(1, sizeof(struct umouse_softc)); 307 sc->hci = hci; 308 309 sc->hid.protocol = 1; /* REPORT protocol */ 310 sc->opt = strdup(opt); 311 pthread_mutex_init(&sc->mtx, NULL); 312 pthread_mutex_init(&sc->ev_mtx, NULL); 313 314 console_ptr_register(umouse_event, sc, 10); 315 316 return (sc); 317 } 318 319 #define UREQ(x,y) ((x) | ((y) << 8)) 320 321 static int 322 umouse_request(void *scarg, struct usb_data_xfer *xfer) 323 { 324 struct umouse_softc *sc; 325 struct usb_data_xfer_block *data; 326 const char *str; 327 uint16_t value; 328 uint16_t index; 329 uint16_t len; 330 uint16_t slen; 331 uint8_t *udata; 332 int err; 333 int i, idx; 334 int eshort; 335 336 sc = scarg; 337 338 data = NULL; 339 udata = NULL; 340 idx = xfer->head; 341 for (i = 0; i < xfer->ndata; i++) { 342 xfer->data[idx].bdone = 0; 343 if (data == NULL && USB_DATA_OK(xfer,i)) { 344 data = &xfer->data[idx]; 345 udata = data->buf; 346 } 347 348 xfer->data[idx].processed = 1; 349 idx = (idx + 1) % USB_MAX_XFER_BLOCKS; 350 } 351 352 err = USB_ERR_NORMAL_COMPLETION; 353 eshort = 0; 354 355 if (!xfer->ureq) { 356 DPRINTF(("umouse_request: port %d", sc->hci->hci_port)); 357 goto done; 358 } 359 360 value = UGETW(xfer->ureq->wValue); 361 index = UGETW(xfer->ureq->wIndex); 362 len = UGETW(xfer->ureq->wLength); 363 364 DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, " 365 "idx 0x%x, len %u", 366 sc->hci->hci_port, xfer->ureq->bmRequestType, 367 xfer->ureq->bRequest, value, index, len)); 368 369 switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) { 370 case UREQ(UR_GET_CONFIG, UT_READ_DEVICE): 371 DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)")); 372 if (!data) 373 break; 374 375 *udata = umouse_confd.confd.bConfigurationValue; 376 data->blen = len > 0 ? len - 1 : 0; 377 eshort = data->blen > 0; 378 data->bdone += 1; 379 break; 380 381 case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE): 382 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x", 383 value >> 8)); 384 if (!data) 385 break; 386 387 switch (value >> 8) { 388 case UDESC_DEVICE: 389 DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= " 390 "sizeof(umouse_dev_desc) %lu", 391 len, sizeof(umouse_dev_desc))); 392 if ((value & 0xFF) != 0) { 393 err = USB_ERR_STALLED; 394 goto done; 395 } 396 if (len > sizeof(umouse_dev_desc)) { 397 data->blen = len - sizeof(umouse_dev_desc); 398 len = sizeof(umouse_dev_desc); 399 } else 400 data->blen = 0; 401 memcpy(data->buf, &umouse_dev_desc, len); 402 data->bdone += len; 403 break; 404 405 case UDESC_CONFIG: 406 DPRINTF(("umouse: (->UDESC_CONFIG)")); 407 if ((value & 0xFF) != 0) { 408 err = USB_ERR_STALLED; 409 goto done; 410 } 411 if (len > sizeof(umouse_confd)) { 412 data->blen = len - sizeof(umouse_confd); 413 len = sizeof(umouse_confd); 414 } else 415 data->blen = 0; 416 417 memcpy(data->buf, &umouse_confd, len); 418 data->bdone += len; 419 break; 420 421 case UDESC_STRING: 422 DPRINTF(("umouse: (->UDESC_STRING)")); 423 str = NULL; 424 if ((value & 0xFF) < UMSTR_MAX) 425 str = umouse_desc_strings[value & 0xFF]; 426 else 427 goto done; 428 429 if ((value & 0xFF) == UMSTR_LANG) { 430 udata[0] = 4; 431 udata[1] = UDESC_STRING; 432 data->blen = len - 2; 433 len -= 2; 434 data->bdone += 2; 435 436 if (len >= 2) { 437 udata[2] = str[0]; 438 udata[3] = str[1]; 439 data->blen -= 2; 440 data->bdone += 2; 441 } else 442 data->blen = 0; 443 444 goto done; 445 } 446 447 slen = 2 + strlen(str) * 2; 448 udata[0] = slen; 449 udata[1] = UDESC_STRING; 450 451 if (len > slen) { 452 data->blen = len - slen; 453 len = slen; 454 } else 455 data->blen = 0; 456 for (i = 2; i < len; i += 2) { 457 udata[i] = *str++; 458 udata[i+1] = '\0'; 459 } 460 data->bdone += slen; 461 462 break; 463 464 case UDESC_BOS: 465 DPRINTF(("umouse: USB3 BOS")); 466 if (len > sizeof(umouse_bosd)) { 467 data->blen = len - sizeof(umouse_bosd); 468 len = sizeof(umouse_bosd); 469 } else 470 data->blen = 0; 471 memcpy(udata, &umouse_bosd, len); 472 data->bdone += len; 473 break; 474 475 default: 476 DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8)); 477 err = USB_ERR_STALLED; 478 goto done; 479 } 480 eshort = data->blen > 0; 481 break; 482 483 case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE): 484 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) " 485 "0x%x", (value >> 8))); 486 if (!data) 487 break; 488 489 switch (value >> 8) { 490 case UMOUSE_REPORT_DESC_TYPE: 491 if (len > sizeof(umouse_report_desc)) { 492 data->blen = len - sizeof(umouse_report_desc); 493 len = sizeof(umouse_report_desc); 494 } else 495 data->blen = 0; 496 memcpy(data->buf, umouse_report_desc, len); 497 data->bdone += len; 498 break; 499 default: 500 DPRINTF(("umouse: IO ERROR")); 501 err = USB_ERR_STALLED; 502 goto done; 503 } 504 eshort = data->blen > 0; 505 break; 506 507 case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE): 508 DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)")); 509 if (index != 0) { 510 DPRINTF(("umouse get_interface, invalid index %d", 511 index)); 512 err = USB_ERR_STALLED; 513 goto done; 514 } 515 516 if (!data) 517 break; 518 519 if (len > 0) { 520 *udata = 0; 521 data->blen = len - 1; 522 } 523 eshort = data->blen > 0; 524 data->bdone += 1; 525 break; 526 527 case UREQ(UR_GET_STATUS, UT_READ_DEVICE): 528 DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)")); 529 if (data != NULL && len > 1) { 530 if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP) 531 USETW(udata, UDS_REMOTE_WAKEUP); 532 else 533 USETW(udata, 0); 534 data->blen = len - 2; 535 data->bdone += 2; 536 } 537 538 eshort = data->blen > 0; 539 break; 540 541 case UREQ(UR_GET_STATUS, UT_READ_INTERFACE): 542 case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT): 543 DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)")); 544 if (data != NULL && len > 1) { 545 USETW(udata, 0); 546 data->blen = len - 2; 547 data->bdone += 2; 548 } 549 eshort = data->blen > 0; 550 break; 551 552 case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE): 553 /* XXX Controller should've handled this */ 554 DPRINTF(("umouse set address %u", value)); 555 break; 556 557 case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE): 558 DPRINTF(("umouse set config %u", value)); 559 break; 560 561 case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): 562 DPRINTF(("umouse set descriptor %u", value)); 563 break; 564 565 566 case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): 567 DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value)); 568 if (value == UF_DEVICE_REMOTE_WAKEUP) 569 sc->hid.feature = 0; 570 break; 571 572 case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE): 573 DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value)); 574 if (value == UF_DEVICE_REMOTE_WAKEUP) 575 sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP; 576 break; 577 578 case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): 579 case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): 580 case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE): 581 case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT): 582 DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)")); 583 err = USB_ERR_STALLED; 584 goto done; 585 586 case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE): 587 DPRINTF(("umouse set interface %u", value)); 588 break; 589 590 case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE): 591 DPRINTF(("umouse set isoch delay %u", value)); 592 break; 593 594 case UREQ(UR_SET_SEL, 0): 595 DPRINTF(("umouse set sel")); 596 break; 597 598 case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): 599 DPRINTF(("umouse synch frame")); 600 break; 601 602 /* HID device requests */ 603 604 case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE): 605 DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) " 606 "0x%x", (value >> 8))); 607 if (!data) 608 break; 609 610 if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) { 611 /* TODO read from backend */ 612 613 if (len > sizeof(sc->um_report)) { 614 data->blen = len - sizeof(sc->um_report); 615 len = sizeof(sc->um_report); 616 } else 617 data->blen = 0; 618 619 memcpy(data->buf, &sc->um_report, len); 620 data->bdone += len; 621 } else { 622 err = USB_ERR_STALLED; 623 goto done; 624 } 625 eshort = data->blen > 0; 626 break; 627 628 case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE): 629 if (data != NULL && len > 0) { 630 *udata = sc->hid.idle; 631 data->blen = len - 1; 632 data->bdone += 1; 633 } 634 eshort = data->blen > 0; 635 break; 636 637 case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE): 638 if (data != NULL && len > 0) { 639 *udata = sc->hid.protocol; 640 data->blen = len - 1; 641 data->bdone += 1; 642 } 643 eshort = data->blen > 0; 644 break; 645 646 case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE): 647 DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored")); 648 break; 649 650 case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE): 651 sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8; 652 DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x", 653 sc->hid.idle)); 654 break; 655 656 case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE): 657 sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8; 658 DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x", 659 sc->hid.protocol)); 660 break; 661 662 default: 663 DPRINTF(("**** umouse request unhandled")); 664 err = USB_ERR_STALLED; 665 break; 666 } 667 668 done: 669 if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) && 670 (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL)) 671 data->blen = 0; 672 else if (eshort) 673 err = USB_ERR_SHORT_XFER; 674 675 DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u", 676 err, (data ? data->blen : 0), (data ? data->bdone : 0))); 677 678 return (err); 679 } 680 681 static int 682 umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir, 683 int epctx) 684 { 685 struct umouse_softc *sc; 686 struct usb_data_xfer_block *data; 687 uint8_t *udata; 688 int len, i, idx; 689 int err; 690 691 DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d", 692 dir ? "IN" : "OUT", epctx, xfer->data[0].blen)); 693 694 695 /* find buffer to add data */ 696 udata = NULL; 697 err = USB_ERR_NORMAL_COMPLETION; 698 699 /* handle xfer at first unprocessed item with buffer */ 700 data = NULL; 701 idx = xfer->head; 702 for (i = 0; i < xfer->ndata; i++) { 703 data = &xfer->data[idx]; 704 if (data->buf != NULL && data->blen != 0) { 705 break; 706 } else { 707 data->processed = 1; 708 data = NULL; 709 } 710 idx = (idx + 1) % USB_MAX_XFER_BLOCKS; 711 } 712 if (!data) 713 goto done; 714 715 udata = data->buf; 716 len = data->blen; 717 718 if (udata == NULL) { 719 DPRINTF(("umouse no buffer provided for input")); 720 err = USB_ERR_NOMEM; 721 goto done; 722 } 723 724 sc = scarg; 725 726 if (dir) { 727 728 pthread_mutex_lock(&sc->mtx); 729 730 if (!sc->newdata) { 731 err = USB_ERR_CANCELLED; 732 USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK); 733 pthread_mutex_unlock(&sc->mtx); 734 goto done; 735 } 736 737 if (sc->polling) { 738 err = USB_ERR_STALLED; 739 USB_DATA_SET_ERRCODE(data, USB_STALL); 740 pthread_mutex_unlock(&sc->mtx); 741 goto done; 742 } 743 sc->polling = 1; 744 745 if (len > 0) { 746 sc->newdata = 0; 747 748 data->processed = 1; 749 data->bdone += 6; 750 memcpy(udata, &sc->um_report, 6); 751 data->blen = len - 6; 752 if (data->blen > 0) 753 err = USB_ERR_SHORT_XFER; 754 } 755 756 sc->polling = 0; 757 pthread_mutex_unlock(&sc->mtx); 758 } else { 759 USB_DATA_SET_ERRCODE(data, USB_STALL); 760 err = USB_ERR_STALLED; 761 } 762 763 done: 764 return (err); 765 } 766 767 static int 768 umouse_reset(void *scarg) 769 { 770 struct umouse_softc *sc; 771 772 sc = scarg; 773 774 sc->newdata = 0; 775 776 return (0); 777 } 778 779 static int 780 umouse_remove(void *scarg) 781 { 782 783 return (0); 784 } 785 786 static int 787 umouse_stop(void *scarg) 788 { 789 790 return (0); 791 } 792 793 #ifdef BHYVE_SNAPSHOT 794 static int 795 umouse_snapshot(void *scarg, struct vm_snapshot_meta *meta) 796 { 797 int ret; 798 struct umouse_softc *sc; 799 800 sc = scarg; 801 802 SNAPSHOT_VAR_OR_LEAVE(sc->um_report, meta, ret, done); 803 SNAPSHOT_VAR_OR_LEAVE(sc->newdata, meta, ret, done); 804 SNAPSHOT_VAR_OR_LEAVE(sc->hid.idle, meta, ret, done); 805 SNAPSHOT_VAR_OR_LEAVE(sc->hid.protocol, meta, ret, done); 806 SNAPSHOT_VAR_OR_LEAVE(sc->hid.feature, meta, ret, done); 807 808 SNAPSHOT_VAR_OR_LEAVE(sc->polling, meta, ret, done); 809 SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_sec, meta, ret, done); 810 SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_usec, meta, ret, done); 811 812 done: 813 return (ret); 814 } 815 #endif 816 817 struct usb_devemu ue_mouse = { 818 .ue_emu = "tablet", 819 .ue_usbver = 3, 820 .ue_usbspeed = USB_SPEED_HIGH, 821 .ue_init = umouse_init, 822 .ue_request = umouse_request, 823 .ue_data = umouse_data_handler, 824 .ue_reset = umouse_reset, 825 .ue_remove = umouse_remove, 826 .ue_stop = umouse_stop, 827 #ifdef BHYVE_SNAPSHOT 828 .ue_snapshot = umouse_snapshot, 829 #endif 830 }; 831 USB_EMUL_SET(ue_mouse); 832