2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
34 #include <machine/vmm_snapshot.h>
41 #include <dev/usb/usb.h>
42 #include <dev/usb/usbdi.h>
49 static int umouse_debug = 0;
50 #define DPRINTF(params) if (umouse_debug) PRINTLN params
51 #define WPRINTF(params) PRINTLN params
53 /* USB endpoint context (1-15) for reporting mouse data events*/
54 #define UMOUSE_INTR_ENDPT 1
56 #define UMOUSE_REPORT_DESC_TYPE 0x22
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
65 #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
76 static const char *umouse_desc_strings[] = {
84 struct umouse_hid_descriptor {
86 uint8_t bDescriptorType;
89 uint8_t bNumDescriptors;
90 uint8_t bReportDescriptorType;
91 uint8_t wItemLength[2];
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;
102 #define MOUSE_MAX_X 0x8000
103 #define MOUSE_MAX_Y 0x8000
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 */
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 */
153 #define MSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
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,
169 static struct umouse_config_desc umouse_confd = {
171 .bLength = sizeof(umouse_confd.confd),
172 .bDescriptorType = UDESC_CONFIG,
173 .wTotalLength[0] = sizeof(umouse_confd),
175 .bConfigurationValue = 1,
176 .iConfiguration = UMSTR_CONFIG,
177 .bmAttributes = UC_BUS_POWERED | UC_REMOTE_WAKEUP,
181 .bLength = sizeof(umouse_confd.ifcd),
182 .bDescriptorType = UDESC_INTERFACE,
184 .bInterfaceClass = UICLASS_HID,
185 .bInterfaceSubClass = UISUBCLASS_BOOT,
186 .bInterfaceProtocol = UIPROTO_MOUSE,
189 .bLength = sizeof(umouse_confd.hidd),
190 .bDescriptorType = 0x21,
191 .bcdHID = { 0x01, 0x10 },
193 .bNumDescriptors = 1,
194 .bReportDescriptorType = UMOUSE_REPORT_DESC_TYPE,
195 .wItemLength = { sizeof(umouse_report_desc), 0 },
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,
206 .bLength = sizeof(umouse_confd.sscompd),
207 .bDescriptorType = UDESC_ENDPOINT_SS_COMP,
210 MSETW(.wBytesPerInterval, 0),
215 struct umouse_bos_desc {
216 struct usb_bos_descriptor bosd;
217 struct usb_devcap_ss_descriptor usbssd;
221 struct umouse_bos_desc umouse_bosd = {
223 .bLength = sizeof(umouse_bosd.bosd),
224 .bDescriptorType = UDESC_BOS,
225 HSETW(.wTotalLength, sizeof(umouse_bosd)),
229 .bLength = sizeof(umouse_bosd.usbssd),
230 .bDescriptorType = UDESC_DEVICE_CAPABILITY,
231 .bDevCapabilityType = 3,
233 HSETW(.wSpeedsSupported, 0x08),
234 .bFunctionalitySupport = 3,
235 .bU1DevExitLat = 0xa, /* dummy - not used */
236 .wU2DevExitLat = { 0x20, 0x00 },
241 struct umouse_softc {
246 struct umouse_report um_report;
255 pthread_mutex_t ev_mtx;
257 struct timeval prev_evt;
261 umouse_event(uint8_t button, int x, int y, void *arg)
263 struct umouse_softc *sc;
264 struct bhyvegc_image *gc;
266 gc = console_get_image();
274 pthread_mutex_lock(&sc->mtx);
276 sc->um_report.buttons = 0;
280 sc->um_report.buttons |= 0x01; /* left */
282 sc->um_report.buttons |= 0x04; /* middle */
284 sc->um_report.buttons |= 0x02; /* right */
288 sc->um_report.z = -1;
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;
294 pthread_mutex_unlock(&sc->mtx);
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);
302 umouse_init(struct usb_hci *hci, char *opt)
304 struct umouse_softc *sc;
306 sc = calloc(1, sizeof(struct umouse_softc));
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);
314 console_ptr_register(umouse_event, sc, 10);
319 #define UREQ(x,y) ((x) | ((y) << 8))
322 umouse_request(void *scarg, struct usb_data_xfer *xfer)
324 struct umouse_softc *sc;
325 struct usb_data_xfer_block *data;
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];
348 xfer->data[idx].processed = 1;
349 idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
352 err = USB_ERR_NORMAL_COMPLETION;
356 DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
360 value = UGETW(xfer->ureq->wValue);
361 index = UGETW(xfer->ureq->wIndex);
362 len = UGETW(xfer->ureq->wLength);
364 DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
366 sc->hci->hci_port, xfer->ureq->bmRequestType,
367 xfer->ureq->bRequest, value, index, len));
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)"));
375 *udata = umouse_confd.confd.bConfigurationValue;
376 data->blen = len > 0 ? len - 1 : 0;
377 eshort = data->blen > 0;
381 case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
382 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
387 switch (value >> 8) {
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;
396 if (len > sizeof(umouse_dev_desc)) {
397 data->blen = len - sizeof(umouse_dev_desc);
398 len = sizeof(umouse_dev_desc);
401 memcpy(data->buf, &umouse_dev_desc, len);
406 DPRINTF(("umouse: (->UDESC_CONFIG)"));
407 if ((value & 0xFF) != 0) {
408 err = USB_ERR_STALLED;
411 if (len > sizeof(umouse_confd)) {
412 data->blen = len - sizeof(umouse_confd);
413 len = sizeof(umouse_confd);
417 memcpy(data->buf, &umouse_confd, len);
422 DPRINTF(("umouse: (->UDESC_STRING)"));
424 if ((value & 0xFF) < UMSTR_MAX)
425 str = umouse_desc_strings[value & 0xFF];
429 if ((value & 0xFF) == UMSTR_LANG) {
431 udata[1] = UDESC_STRING;
432 data->blen = len - 2;
447 slen = 2 + strlen(str) * 2;
449 udata[1] = UDESC_STRING;
452 data->blen = len - slen;
456 for (i = 2; i < len; i += 2) {
465 DPRINTF(("umouse: USB3 BOS"));
466 if (len > sizeof(umouse_bosd)) {
467 data->blen = len - sizeof(umouse_bosd);
468 len = sizeof(umouse_bosd);
471 memcpy(udata, &umouse_bosd, len);
476 DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
477 err = USB_ERR_STALLED;
480 eshort = data->blen > 0;
483 case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
484 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
485 "0x%x", (value >> 8)));
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);
496 memcpy(data->buf, umouse_report_desc, len);
500 DPRINTF(("umouse: IO ERROR"));
501 err = USB_ERR_STALLED;
504 eshort = data->blen > 0;
507 case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
508 DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
510 DPRINTF(("umouse get_interface, invalid index %d",
512 err = USB_ERR_STALLED;
521 data->blen = len - 1;
523 eshort = data->blen > 0;
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);
534 data->blen = len - 2;
538 eshort = data->blen > 0;
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) {
546 data->blen = len - 2;
549 eshort = data->blen > 0;
552 case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
553 /* XXX Controller should've handled this */
554 DPRINTF(("umouse set address %u", value));
557 case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
558 DPRINTF(("umouse set config %u", value));
561 case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
562 DPRINTF(("umouse set descriptor %u", value));
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)
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;
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;
586 case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
587 DPRINTF(("umouse set interface %u", value));
590 case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
591 DPRINTF(("umouse set isoch delay %u", value));
594 case UREQ(UR_SET_SEL, 0):
595 DPRINTF(("umouse set sel"));
598 case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
599 DPRINTF(("umouse synch frame"));
602 /* HID device requests */
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)));
610 if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
611 /* TODO read from backend */
613 if (len > sizeof(sc->um_report)) {
614 data->blen = len - sizeof(sc->um_report);
615 len = sizeof(sc->um_report);
619 memcpy(data->buf, &sc->um_report, len);
622 err = USB_ERR_STALLED;
625 eshort = data->blen > 0;
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;
634 eshort = data->blen > 0;
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;
643 eshort = data->blen > 0;
646 case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
647 DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
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",
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",
663 DPRINTF(("**** umouse request unhandled"));
664 err = USB_ERR_STALLED;
669 if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
670 (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
673 err = USB_ERR_SHORT_XFER;
675 DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
676 err, (data ? data->blen : 0), (data ? data->bdone : 0)));
682 umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
685 struct umouse_softc *sc;
686 struct usb_data_xfer_block *data;
691 DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
692 dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
695 /* find buffer to add data */
697 err = USB_ERR_NORMAL_COMPLETION;
699 /* handle xfer at first unprocessed item with buffer */
702 for (i = 0; i < xfer->ndata; i++) {
703 data = &xfer->data[idx];
704 if (data->buf != NULL && data->blen != 0) {
710 idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
719 DPRINTF(("umouse no buffer provided for input"));
728 pthread_mutex_lock(&sc->mtx);
731 err = USB_ERR_CANCELLED;
732 USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
733 pthread_mutex_unlock(&sc->mtx);
738 err = USB_ERR_STALLED;
739 USB_DATA_SET_ERRCODE(data, USB_STALL);
740 pthread_mutex_unlock(&sc->mtx);
750 memcpy(udata, &sc->um_report, 6);
751 data->blen = len - 6;
753 err = USB_ERR_SHORT_XFER;
757 pthread_mutex_unlock(&sc->mtx);
759 USB_DATA_SET_ERRCODE(data, USB_STALL);
760 err = USB_ERR_STALLED;
768 umouse_reset(void *scarg)
770 struct umouse_softc *sc;
780 umouse_remove(void *scarg)
787 umouse_stop(void *scarg)
793 #ifdef BHYVE_SNAPSHOT
795 umouse_snapshot(void *scarg, struct vm_snapshot_meta *meta)
798 struct umouse_softc *sc;
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);
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);
817 struct usb_devemu ue_mouse = {
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,
831 USB_EMUL_SET(ue_mouse);