]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/usb_mouse.c
bsdinstall zfsboot: Don't override ZFSBOOT_FORCE_4K_SECTORS if it is null.
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / usb_mouse.c
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 = 8,                    /* max packet size */
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
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 *
298 umouse_init(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         sc->hid.protocol = 1;   /* REPORT protocol */
306         pthread_mutex_init(&sc->mtx, NULL);
307         pthread_mutex_init(&sc->ev_mtx, NULL);
308
309         console_ptr_register(umouse_event, sc, 10);
310
311         return (sc);
312 }
313
314 #define UREQ(x,y)       ((x) | ((y) << 8))
315
316 static int
317 umouse_request(void *scarg, struct usb_data_xfer *xfer)
318 {
319         struct umouse_softc *sc;
320         struct usb_data_xfer_block *data;
321         const char *str;
322         uint16_t value;
323         uint16_t index;
324         uint16_t len;
325         uint16_t slen;
326         uint8_t *udata;
327         int     err;
328         int     i, idx;
329         int     eshort;
330
331         sc = scarg;
332
333         data = NULL;
334         udata = NULL;
335         idx = xfer->head;
336         for (i = 0; i < xfer->ndata; i++) {
337                 xfer->data[idx].bdone = 0;
338                 if (data == NULL && USB_DATA_OK(xfer,i)) {
339                         data = &xfer->data[idx];
340                         udata = data->buf;
341                 }
342
343                 xfer->data[idx].processed = 1;
344                 idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
345         }
346
347         err = USB_ERR_NORMAL_COMPLETION;
348         eshort = 0;
349
350         if (!xfer->ureq) {
351                 DPRINTF(("umouse_request: port %d", sc->hci->hci_port));
352                 goto done;
353         }
354
355         value = UGETW(xfer->ureq->wValue);
356         index = UGETW(xfer->ureq->wIndex);
357         len = UGETW(xfer->ureq->wLength);
358
359         DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
360                  "idx 0x%x, len %u",
361                  sc->hci->hci_port, xfer->ureq->bmRequestType,
362                  xfer->ureq->bRequest, value, index, len));
363
364         switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
365         case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
366                 DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)"));
367                 if (!data)
368                         break;
369
370                 *udata = umouse_confd.confd.bConfigurationValue;
371                 data->blen = len > 0 ? len - 1 : 0;
372                 eshort = data->blen > 0;
373                 data->bdone += 1;
374                 break;
375
376         case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
377                 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x",
378                         value >> 8));
379                 if (!data)
380                         break;
381
382                 switch (value >> 8) {
383                 case UDESC_DEVICE:
384                         DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
385                                  "sizeof(umouse_dev_desc) %lu",
386                                  len, sizeof(umouse_dev_desc)));
387                         if ((value & 0xFF) != 0) {
388                                 err = USB_ERR_STALLED;
389                                 goto done;
390                         }
391                         if (len > sizeof(umouse_dev_desc)) {
392                                 data->blen = len - sizeof(umouse_dev_desc);
393                                 len = sizeof(umouse_dev_desc);
394                         } else
395                                 data->blen = 0;
396                         memcpy(data->buf, &umouse_dev_desc, len);
397                         data->bdone += len;
398                         break;
399
400                 case UDESC_CONFIG:
401                         DPRINTF(("umouse: (->UDESC_CONFIG)"));
402                         if ((value & 0xFF) != 0) {
403                                 err = USB_ERR_STALLED;
404                                 goto done;
405                         }
406                         if (len > sizeof(umouse_confd)) {
407                                 data->blen = len - sizeof(umouse_confd);
408                                 len = sizeof(umouse_confd);
409                         } else
410                                 data->blen = 0;
411
412                         memcpy(data->buf, &umouse_confd, len);
413                         data->bdone += len;
414                         break;
415
416                 case UDESC_STRING:
417                         DPRINTF(("umouse: (->UDESC_STRING)"));
418                         str = NULL;
419                         if ((value & 0xFF) < UMSTR_MAX)
420                                 str = umouse_desc_strings[value & 0xFF];
421                         else
422                                 goto done;
423
424                         if ((value & 0xFF) == UMSTR_LANG) {
425                                 udata[0] = 4;
426                                 udata[1] = UDESC_STRING;
427                                 data->blen = len - 2;
428                                 len -= 2;
429                                 data->bdone += 2;
430
431                                 if (len >= 2) {
432                                         udata[2] = str[0];
433                                         udata[3] = str[1];
434                                         data->blen -= 2;
435                                         data->bdone += 2;
436                                 } else
437                                         data->blen = 0;
438
439                                 goto done;
440                         }
441
442                         slen = 2 + strlen(str) * 2;
443                         udata[0] = slen;
444                         udata[1] = UDESC_STRING;
445
446                         if (len > slen) {
447                                 data->blen = len - slen;
448                                 len = slen;
449                         } else
450                                 data->blen = 0;
451                         for (i = 2; i < len; i += 2) {
452                                 udata[i] = *str++;
453                                 udata[i+1] = '\0';
454                         }
455                         data->bdone += slen;
456
457                         break;
458
459                 case UDESC_BOS:
460                         DPRINTF(("umouse: USB3 BOS"));
461                         if (len > sizeof(umouse_bosd)) {
462                                 data->blen = len - sizeof(umouse_bosd);
463                                 len = sizeof(umouse_bosd);
464                         } else
465                                 data->blen = 0;
466                         memcpy(udata, &umouse_bosd, len);
467                         data->bdone += len;
468                         break;
469
470                 default:
471                         DPRINTF(("umouse: unknown(%d)->ERROR", value >> 8));
472                         err = USB_ERR_STALLED;
473                         goto done;
474                 }
475                 eshort = data->blen > 0;
476                 break;
477
478         case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
479                 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
480                          "0x%x", (value >> 8)));
481                 if (!data)
482                         break;
483
484                 switch (value >> 8) {
485                 case UMOUSE_REPORT_DESC_TYPE:
486                         if (len > sizeof(umouse_report_desc)) {
487                                 data->blen = len - sizeof(umouse_report_desc);
488                                 len = sizeof(umouse_report_desc);
489                         } else
490                                 data->blen = 0;
491                         memcpy(data->buf, umouse_report_desc, len);
492                         data->bdone += len;
493                         break;
494                 default:
495                         DPRINTF(("umouse: IO ERROR"));
496                         err = USB_ERR_STALLED;
497                         goto done;
498                 }
499                 eshort = data->blen > 0;
500                 break;
501
502         case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
503                 DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)"));
504                 if (index != 0) {
505                         DPRINTF(("umouse get_interface, invalid index %d",
506                                 index));
507                         err = USB_ERR_STALLED;
508                         goto done;
509                 }
510
511                 if (!data)
512                         break;
513
514                 if (len > 0) {
515                         *udata = 0;
516                         data->blen = len - 1;
517                 }
518                 eshort = data->blen > 0;
519                 data->bdone += 1;
520                 break;
521
522         case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
523                 DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)"));
524                 if (data != NULL && len > 1) {
525                         if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
526                                 USETW(udata, UDS_REMOTE_WAKEUP);
527                         else
528                                 USETW(udata, 0);
529                         data->blen = len - 2;
530                         data->bdone += 2;
531                 }
532
533                 eshort = data->blen > 0;
534                 break;
535
536         case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
537         case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
538                 DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)"));
539                 if (data != NULL && len > 1) {
540                         USETW(udata, 0);
541                         data->blen = len - 2;
542                         data->bdone += 2;
543                 }
544                 eshort = data->blen > 0;
545                 break;
546
547         case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
548                 /* XXX Controller should've handled this */
549                 DPRINTF(("umouse set address %u", value));
550                 break;
551
552         case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
553                 DPRINTF(("umouse set config %u", value));
554                 break;
555
556         case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
557                 DPRINTF(("umouse set descriptor %u", value));
558                 break;
559
560
561         case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
562                 DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
563                 if (value == UF_DEVICE_REMOTE_WAKEUP)
564                         sc->hid.feature = 0;
565                 break;
566
567         case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
568                 DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x", value));
569                 if (value == UF_DEVICE_REMOTE_WAKEUP)
570                         sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
571                 break;
572
573         case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
574         case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
575         case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
576         case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
577                 DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)"));
578                 err = USB_ERR_STALLED;
579                 goto done;
580
581         case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
582                 DPRINTF(("umouse set interface %u", value));
583                 break;
584
585         case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
586                 DPRINTF(("umouse set isoch delay %u", value));
587                 break;
588
589         case UREQ(UR_SET_SEL, 0):
590                 DPRINTF(("umouse set sel"));
591                 break;
592
593         case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
594                 DPRINTF(("umouse synch frame"));
595                 break;
596
597         /* HID device requests */
598
599         case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
600                 DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
601                          "0x%x", (value >> 8)));
602                 if (!data)
603                         break;
604
605                 if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
606                         /* TODO read from backend */
607
608                         if (len > sizeof(sc->um_report)) {
609                                 data->blen = len - sizeof(sc->um_report);
610                                 len = sizeof(sc->um_report);
611                         } else
612                                 data->blen = 0;
613
614                         memcpy(data->buf, &sc->um_report, len);
615                         data->bdone += len;
616                 } else {
617                         err = USB_ERR_STALLED;
618                         goto done;
619                 }
620                 eshort = data->blen > 0;
621                 break;
622
623         case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
624                 if (data != NULL && len > 0) {
625                         *udata = sc->hid.idle;
626                         data->blen = len - 1;
627                         data->bdone += 1;
628                 }
629                 eshort = data->blen > 0;
630                 break;
631
632         case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
633                 if (data != NULL && len > 0) {
634                         *udata = sc->hid.protocol;
635                         data->blen = len - 1;
636                         data->bdone += 1;
637                 }
638                 eshort = data->blen > 0;
639                 break;
640
641         case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
642                 DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored"));
643                 break;
644
645         case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
646                 sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
647                 DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x",
648                         sc->hid.idle));
649                 break;
650
651         case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
652                 sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
653                 DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x",
654                         sc->hid.protocol));
655                 break;
656
657         default:
658                 DPRINTF(("**** umouse request unhandled"));
659                 err = USB_ERR_STALLED;
660                 break;
661         }
662
663 done:
664         if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
665             (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
666                 data->blen = 0;
667         else if (eshort)
668                 err = USB_ERR_SHORT_XFER;
669
670         DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u",
671                 err, (data ? data->blen : 0), (data ? data->bdone : 0)));
672
673         return (err);
674 }
675
676 static int
677 umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
678      int epctx)
679 {
680         struct umouse_softc *sc;
681         struct usb_data_xfer_block *data;
682         uint8_t *udata;
683         int len, i, idx;
684         int err;
685
686         DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d",
687                 dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
688
689
690         /* find buffer to add data */
691         udata = NULL;
692         err = USB_ERR_NORMAL_COMPLETION;
693
694         /* handle xfer at first unprocessed item with buffer */
695         data = NULL;
696         idx = xfer->head;
697         for (i = 0; i < xfer->ndata; i++) {
698                 data = &xfer->data[idx];
699                 if (data->buf != NULL && data->blen != 0) {
700                         break;
701                 } else {
702                         data->processed = 1;
703                         data = NULL;
704                 }
705                 idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
706         }
707         if (!data)
708                 goto done;
709
710         udata = data->buf;
711         len = data->blen;
712
713         if (udata == NULL) {
714                 DPRINTF(("umouse no buffer provided for input"));
715                 err = USB_ERR_NOMEM;
716                 goto done;
717         }
718
719         sc = scarg;
720
721         if (dir) {
722
723                 pthread_mutex_lock(&sc->mtx);
724
725                 if (!sc->newdata) {
726                         err = USB_ERR_CANCELLED;
727                         USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
728                         pthread_mutex_unlock(&sc->mtx);
729                         goto done;
730                 }
731
732                 if (sc->polling) {
733                         err = USB_ERR_STALLED;
734                         USB_DATA_SET_ERRCODE(data, USB_STALL);
735                         pthread_mutex_unlock(&sc->mtx);
736                         goto done;
737                 }
738                 sc->polling = 1;
739
740                 if (len > 0) {
741                         sc->newdata = 0;
742
743                         data->processed = 1;
744                         data->bdone += 6;
745                         memcpy(udata, &sc->um_report, 6);
746                         data->blen = len - 6;
747                         if (data->blen > 0)
748                                 err = USB_ERR_SHORT_XFER;
749                 }
750
751                 sc->polling = 0;
752                 pthread_mutex_unlock(&sc->mtx);
753         } else {
754                 USB_DATA_SET_ERRCODE(data, USB_STALL);
755                 err = USB_ERR_STALLED;
756         }
757
758 done:
759         return (err);
760 }
761
762 static int
763 umouse_reset(void *scarg)
764 {
765         struct umouse_softc *sc;
766
767         sc = scarg;
768
769         sc->newdata = 0;
770
771         return (0);
772 }
773
774 static int
775 umouse_remove(void *scarg __unused)
776 {
777         return (0);
778 }
779
780 static int
781 umouse_stop(void *scarg __unused)
782 {
783         return (0);
784 }
785
786 #ifdef BHYVE_SNAPSHOT
787 static int
788 umouse_snapshot(void *scarg, struct vm_snapshot_meta *meta)
789 {
790         int ret;
791         struct umouse_softc *sc;
792
793         sc = scarg;
794
795         SNAPSHOT_VAR_OR_LEAVE(sc->um_report, meta, ret, done);
796         SNAPSHOT_VAR_OR_LEAVE(sc->newdata, meta, ret, done);
797         SNAPSHOT_VAR_OR_LEAVE(sc->hid.idle, meta, ret, done);
798         SNAPSHOT_VAR_OR_LEAVE(sc->hid.protocol, meta, ret, done);
799         SNAPSHOT_VAR_OR_LEAVE(sc->hid.feature, meta, ret, done);
800
801         SNAPSHOT_VAR_OR_LEAVE(sc->polling, meta, ret, done);
802         SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_sec, meta, ret, done);
803         SNAPSHOT_VAR_OR_LEAVE(sc->prev_evt.tv_usec, meta, ret, done);
804
805 done:
806         return (ret);
807 }
808 #endif
809
810 static struct usb_devemu ue_mouse = {
811         .ue_emu =       "tablet",
812         .ue_usbver =    3,
813         .ue_usbspeed =  USB_SPEED_HIGH,
814         .ue_init =      umouse_init,
815         .ue_request =   umouse_request,
816         .ue_data =      umouse_data_handler,
817         .ue_reset =     umouse_reset,
818         .ue_remove =    umouse_remove,
819         .ue_stop =      umouse_stop,
820 #ifdef BHYVE_SNAPSHOT
821         .ue_snapshot =  umouse_snapshot,
822 #endif
823 };
824 USB_EMUL_SET(ue_mouse);