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