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