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