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