sed(1): Appease older GCC.
[freebsd-src.git] / usr.sbin / bhyve / usb_mouse.c
blob633fc57906e09d0f8a1d3fb516a13bcbf4b1b576
1 /*-
2 * Copyright (c) 2014 Leon Dang <ldang@nahannisys.com>
3 * All rights reserved.
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.
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.
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/time.h>
32 #include <pthread.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #include <dev/usb/usb.h>
38 #include <dev/usb/usbdi.h>
40 #include "usb_emul.h"
41 #include "console.h"
42 #include "bhyvegc.h"
44 static int umouse_debug = 0;
45 #define DPRINTF(params) if (umouse_debug) printf params
46 #define WPRINTF(params) printf params
48 /* USB endpoint context (1-15) for reporting mouse data events*/
49 #define UMOUSE_INTR_ENDPT 1
51 #define UMOUSE_REPORT_DESC_TYPE 0x22
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
60 #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
62 enum {
63 UMSTR_LANG,
64 UMSTR_MANUFACTURER,
65 UMSTR_PRODUCT,
66 UMSTR_SERIAL,
67 UMSTR_CONFIG,
68 UMSTR_MAX
71 static const char *umouse_desc_strings[] = {
72 "\x04\x09",
73 "BHYVE",
74 "HID Tablet",
75 "01",
76 "HID Tablet Device",
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;
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;
97 #define MOUSE_MAX_X 0x8000
98 #define MOUSE_MAX_Y 0x8000
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 */
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;
148 #define MSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
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,
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,
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,
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 },
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,
200 .sscompd = {
201 .bLength = sizeof(umouse_confd.sscompd),
202 .bDescriptorType = UDESC_ENDPOINT_SS_COMP,
203 .bMaxBurst = 0,
204 .bmAttributes = 0,
205 MSETW(.wBytesPerInterval, 0),
210 struct umouse_bos_desc {
211 struct usb_bos_descriptor bosd;
212 struct usb_devcap_ss_descriptor usbssd;
213 } __packed;
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,
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 },
236 struct umouse_softc {
237 struct usb_hci *hci;
239 char *opt;
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;
249 pthread_mutex_t mtx;
250 pthread_mutex_t ev_mtx;
251 int polling;
252 struct timeval prev_evt;
255 static void
256 umouse_event(uint8_t button, int x, int y, void *arg)
258 struct umouse_softc *sc;
259 struct bhyvegc_image *gc;
261 gc = console_get_image();
262 if (gc == NULL) {
263 /* not ready */
264 return;
267 sc = arg;
269 pthread_mutex_lock(&sc->mtx);
271 sc->um_report.buttons = 0;
272 sc->um_report.z = 0;
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;
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);
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);
296 static void *
297 umouse_init(struct usb_hci *hci, char *opt)
299 struct umouse_softc *sc;
301 sc = calloc(1, sizeof(struct umouse_softc));
302 sc->hci = hci;
304 sc->hid.protocol = 1; /* REPORT protocol */
305 sc->opt = strdup(opt);
306 pthread_mutex_init(&sc->mtx, NULL);
307 pthread_mutex_init(&sc->ev_mtx, NULL);
309 console_ptr_register(umouse_event, sc, 10);
311 return (sc);
314 #define UREQ(x,y) ((x) | ((y) << 8))
316 static int
317 umouse_request(void *scarg, struct usb_data_xfer *xfer)
319 struct umouse_softc *sc;
320 struct usb_data_xfer_block *data;
321 const char *str;
322 uint16_t value;
323 uint16_t index;
324 uint16_t len;
325 uint16_t slen;
326 uint8_t *udata;
327 int err;
328 int i, idx;
329 int eshort;
331 sc = scarg;
333 data = NULL;
334 udata = NULL;
335 idx = xfer->head;
336 for (i = 0; i < xfer->ndata; i++) {
337 xfer->data[idx].bdone = 0;
338 if (data == NULL && USB_DATA_OK(xfer,i)) {
339 data = &xfer->data[idx];
340 udata = data->buf;
343 xfer->data[idx].processed = 1;
344 idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
347 err = USB_ERR_NORMAL_COMPLETION;
348 eshort = 0;
350 if (!xfer->ureq) {
351 DPRINTF(("umouse_request: port %d\r\n", sc->hci->hci_port));
352 goto done;
355 value = UGETW(xfer->ureq->wValue);
356 index = UGETW(xfer->ureq->wIndex);
357 len = UGETW(xfer->ureq->wLength);
359 DPRINTF(("umouse_request: port %d, type 0x%x, req 0x%x, val 0x%x, "
360 "idx 0x%x, len %u\r\n",
361 sc->hci->hci_port, xfer->ureq->bmRequestType,
362 xfer->ureq->bRequest, value, index, len));
364 switch (UREQ(xfer->ureq->bRequest, xfer->ureq->bmRequestType)) {
365 case UREQ(UR_GET_CONFIG, UT_READ_DEVICE):
366 DPRINTF(("umouse: (UR_GET_CONFIG, UT_READ_DEVICE)\r\n"));
367 if (!data)
368 break;
370 *udata = umouse_confd.confd.bConfigurationValue;
371 data->blen = len > 0 ? len - 1 : 0;
372 eshort = data->blen > 0;
373 data->bdone += 1;
374 break;
376 case UREQ(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
377 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_DEVICE) val %x\r\n",
378 value >> 8));
379 if (!data)
380 break;
382 switch (value >> 8) {
383 case UDESC_DEVICE:
384 DPRINTF(("umouse: (->UDESC_DEVICE) len %u ?= "
385 "sizeof(umouse_dev_desc) %lu\r\n",
386 len, sizeof(umouse_dev_desc)));
387 if ((value & 0xFF) != 0) {
388 err = USB_ERR_IOERROR;
389 goto done;
391 if (len > sizeof(umouse_dev_desc)) {
392 data->blen = len - sizeof(umouse_dev_desc);
393 len = sizeof(umouse_dev_desc);
394 } else
395 data->blen = 0;
396 memcpy(data->buf, &umouse_dev_desc, len);
397 data->bdone += len;
398 break;
400 case UDESC_CONFIG:
401 DPRINTF(("umouse: (->UDESC_CONFIG)\r\n"));
402 if ((value & 0xFF) != 0) {
403 err = USB_ERR_IOERROR;
404 goto done;
406 if (len > sizeof(umouse_confd)) {
407 data->blen = len - sizeof(umouse_confd);
408 len = sizeof(umouse_confd);
409 } else
410 data->blen = 0;
412 memcpy(data->buf, &umouse_confd, len);
413 data->bdone += len;
414 break;
416 case UDESC_STRING:
417 DPRINTF(("umouse: (->UDESC_STRING)\r\n"));
418 str = NULL;
419 if ((value & 0xFF) < UMSTR_MAX)
420 str = umouse_desc_strings[value & 0xFF];
421 else
422 goto done;
424 if ((value & 0xFF) == UMSTR_LANG) {
425 udata[0] = 4;
426 udata[1] = UDESC_STRING;
427 data->blen = len - 2;
428 len -= 2;
429 data->bdone += 2;
431 if (len >= 2) {
432 udata[2] = str[0];
433 udata[3] = str[1];
434 data->blen -= 2;
435 data->bdone += 2;
436 } else
437 data->blen = 0;
439 goto done;
442 slen = 2 + strlen(str) * 2;
443 udata[0] = slen;
444 udata[1] = UDESC_STRING;
446 if (len > slen) {
447 data->blen = len - slen;
448 len = slen;
449 } else
450 data->blen = 0;
451 for (i = 2; i < len; i += 2) {
452 udata[i] = *str++;
453 udata[i+1] = '\0';
455 data->bdone += slen;
457 break;
459 case UDESC_BOS:
460 DPRINTF(("umouse: USB3 BOS\r\n"));
461 if (len > sizeof(umouse_bosd)) {
462 data->blen = len - sizeof(umouse_bosd);
463 len = sizeof(umouse_bosd);
464 } else
465 data->blen = 0;
466 memcpy(udata, &umouse_bosd, len);
467 data->bdone += len;
468 break;
470 default:
471 DPRINTF(("umouse: unknown(%d)->ERROR\r\n", value >> 8));
472 err = USB_ERR_IOERROR;
473 goto done;
475 eshort = data->blen > 0;
476 break;
478 case UREQ(UR_GET_DESCRIPTOR, UT_READ_INTERFACE):
479 DPRINTF(("umouse: (UR_GET_DESCRIPTOR, UT_READ_INTERFACE) "
480 "0x%x\r\n", (value >> 8)));
481 if (!data)
482 break;
484 switch (value >> 8) {
485 case UMOUSE_REPORT_DESC_TYPE:
486 if (len > sizeof(umouse_report_desc)) {
487 data->blen = len - sizeof(umouse_report_desc);
488 len = sizeof(umouse_report_desc);
489 } else
490 data->blen = 0;
491 memcpy(data->buf, umouse_report_desc, len);
492 data->bdone += len;
493 break;
494 default:
495 DPRINTF(("umouse: IO ERROR\r\n"));
496 err = USB_ERR_IOERROR;
497 goto done;
499 eshort = data->blen > 0;
500 break;
502 case UREQ(UR_GET_INTERFACE, UT_READ_INTERFACE):
503 DPRINTF(("umouse: (UR_GET_INTERFACE, UT_READ_INTERFACE)\r\n"));
504 if (index != 0) {
505 DPRINTF(("umouse get_interface, invalid index %d\r\n",
506 index));
507 err = USB_ERR_IOERROR;
508 goto done;
511 if (!data)
512 break;
514 if (len > 0) {
515 *udata = 0;
516 data->blen = len - 1;
518 eshort = data->blen > 0;
519 data->bdone += 1;
520 break;
522 case UREQ(UR_GET_STATUS, UT_READ_DEVICE):
523 DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_DEVICE)\r\n"));
524 if (data != NULL && len > 1) {
525 if (sc->hid.feature == UF_DEVICE_REMOTE_WAKEUP)
526 USETW(udata, UDS_REMOTE_WAKEUP);
527 else
528 USETW(udata, 0);
529 data->blen = len - 2;
530 data->bdone += 2;
533 eshort = data->blen > 0;
534 break;
536 case UREQ(UR_GET_STATUS, UT_READ_INTERFACE):
537 case UREQ(UR_GET_STATUS, UT_READ_ENDPOINT):
538 DPRINTF(("umouse: (UR_GET_STATUS, UT_READ_INTERFACE)\r\n"));
539 if (data != NULL && len > 1) {
540 USETW(udata, 0);
541 data->blen = len - 2;
542 data->bdone += 2;
544 eshort = data->blen > 0;
545 break;
547 case UREQ(UR_SET_ADDRESS, UT_WRITE_DEVICE):
548 /* XXX Controller should've handled this */
549 DPRINTF(("umouse set address %u\r\n", value));
550 break;
552 case UREQ(UR_SET_CONFIG, UT_WRITE_DEVICE):
553 DPRINTF(("umouse set config %u\r\n", value));
554 break;
556 case UREQ(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
557 DPRINTF(("umouse set descriptor %u\r\n", value));
558 break;
561 case UREQ(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
562 DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x\r\n", value));
563 if (value == UF_DEVICE_REMOTE_WAKEUP)
564 sc->hid.feature = 0;
565 break;
567 case UREQ(UR_SET_FEATURE, UT_WRITE_DEVICE):
568 DPRINTF(("umouse: (UR_SET_FEATURE, UT_WRITE_DEVICE) %x\r\n", value));
569 if (value == UF_DEVICE_REMOTE_WAKEUP)
570 sc->hid.feature = UF_DEVICE_REMOTE_WAKEUP;
571 break;
573 case UREQ(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
574 case UREQ(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
575 case UREQ(UR_SET_FEATURE, UT_WRITE_INTERFACE):
576 case UREQ(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
577 DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_INTERFACE)\r\n"));
578 err = USB_ERR_IOERROR;
579 goto done;
581 case UREQ(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
582 DPRINTF(("umouse set interface %u\r\n", value));
583 break;
585 case UREQ(UR_ISOCH_DELAY, UT_WRITE_DEVICE):
586 DPRINTF(("umouse set isoch delay %u\r\n", value));
587 break;
589 case UREQ(UR_SET_SEL, 0):
590 DPRINTF(("umouse set sel\r\n"));
591 break;
593 case UREQ(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
594 DPRINTF(("umouse synch frame\r\n"));
595 break;
597 /* HID device requests */
599 case UREQ(UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE):
600 DPRINTF(("umouse: (UMOUSE_GET_REPORT, UT_READ_CLASS_INTERFACE) "
601 "0x%x\r\n", (value >> 8)));
602 if (!data)
603 break;
605 if ((value >> 8) == 0x01 && len >= sizeof(sc->um_report)) {
606 /* TODO read from backend */
608 if (len > sizeof(sc->um_report)) {
609 data->blen = len - sizeof(sc->um_report);
610 len = sizeof(sc->um_report);
611 } else
612 data->blen = 0;
614 memcpy(data->buf, &sc->um_report, len);
615 data->bdone += len;
616 } else {
617 err = USB_ERR_IOERROR;
618 goto done;
620 eshort = data->blen > 0;
621 break;
623 case UREQ(UMOUSE_GET_IDLE, UT_READ_CLASS_INTERFACE):
624 if (data != NULL && len > 0) {
625 *udata = sc->hid.idle;
626 data->blen = len - 1;
627 data->bdone += 1;
629 eshort = data->blen > 0;
630 break;
632 case UREQ(UMOUSE_GET_PROTOCOL, UT_READ_CLASS_INTERFACE):
633 if (data != NULL && len > 0) {
634 *udata = sc->hid.protocol;
635 data->blen = len - 1;
636 data->bdone += 1;
638 eshort = data->blen > 0;
639 break;
641 case UREQ(UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE):
642 DPRINTF(("umouse: (UMOUSE_SET_REPORT, UT_WRITE_CLASS_INTERFACE) ignored\r\n"));
643 break;
645 case UREQ(UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE):
646 sc->hid.idle = UGETW(xfer->ureq->wValue) >> 8;
647 DPRINTF(("umouse: (UMOUSE_SET_IDLE, UT_WRITE_CLASS_INTERFACE) %x\r\n",
648 sc->hid.idle));
649 break;
651 case UREQ(UMOUSE_SET_PROTOCOL, UT_WRITE_CLASS_INTERFACE):
652 sc->hid.protocol = UGETW(xfer->ureq->wValue) >> 8;
653 DPRINTF(("umouse: (UR_CLEAR_FEATURE, UT_WRITE_CLASS_INTERFACE) %x\r\n",
654 sc->hid.protocol));
655 break;
657 default:
658 DPRINTF(("**** umouse request unhandled\r\n"));
659 err = USB_ERR_IOERROR;
660 break;
663 done:
664 if (xfer->ureq && (xfer->ureq->bmRequestType & UT_WRITE) &&
665 (err == USB_ERR_NORMAL_COMPLETION) && (data != NULL))
666 data->blen = 0;
667 else if (eshort)
668 err = USB_ERR_SHORT_XFER;
670 DPRINTF(("umouse request error code %d (0=ok), blen %u txlen %u\r\n",
671 err, (data ? data->blen : 0), (data ? data->bdone : 0)));
673 return (err);
676 static int
677 umouse_data_handler(void *scarg, struct usb_data_xfer *xfer, int dir,
678 int epctx)
680 struct umouse_softc *sc;
681 struct usb_data_xfer_block *data;
682 uint8_t *udata;
683 int len, i, idx;
684 int err;
686 DPRINTF(("umouse handle data - DIR=%s|EP=%d, blen %d\r\n",
687 dir ? "IN" : "OUT", epctx, xfer->data[0].blen));
690 /* find buffer to add data */
691 udata = NULL;
692 err = USB_ERR_NORMAL_COMPLETION;
694 /* handle xfer at first unprocessed item with buffer */
695 data = NULL;
696 idx = xfer->head;
697 for (i = 0; i < xfer->ndata; i++) {
698 data = &xfer->data[idx];
699 if (data->buf != NULL && data->blen != 0) {
700 break;
701 } else {
702 data->processed = 1;
703 data = NULL;
705 idx = (idx + 1) % USB_MAX_XFER_BLOCKS;
707 if (!data)
708 goto done;
710 udata = data->buf;
711 len = data->blen;
713 if (udata == NULL) {
714 DPRINTF(("umouse no buffer provided for input\r\n"));
715 err = USB_ERR_NOMEM;
716 goto done;
719 sc = scarg;
721 if (dir) {
723 pthread_mutex_lock(&sc->mtx);
725 if (!sc->newdata) {
726 err = USB_ERR_CANCELLED;
727 USB_DATA_SET_ERRCODE(&xfer->data[xfer->head], USB_NAK);
728 pthread_mutex_unlock(&sc->mtx);
729 goto done;
732 if (sc->polling) {
733 err = USB_ERR_STALLED;
734 USB_DATA_SET_ERRCODE(data, USB_STALL);
735 pthread_mutex_unlock(&sc->mtx);
736 goto done;
738 sc->polling = 1;
740 if (len > 0) {
741 sc->newdata = 0;
743 data->processed = 1;
744 data->bdone += 6;
745 memcpy(udata, &sc->um_report, 6);
746 data->blen = len - 6;
747 if (data->blen > 0)
748 err = USB_ERR_SHORT_XFER;
751 sc->polling = 0;
752 pthread_mutex_unlock(&sc->mtx);
753 } else {
754 USB_DATA_SET_ERRCODE(data, USB_STALL);
755 err = USB_ERR_STALLED;
758 done:
759 return (err);
762 static int
763 umouse_reset(void *scarg)
765 struct umouse_softc *sc;
767 sc = scarg;
769 sc->newdata = 0;
771 return (0);
774 static int
775 umouse_remove(void *scarg)
778 return (0);
781 static int
782 umouse_stop(void *scarg)
785 return (0);
789 struct usb_devemu ue_mouse = {
790 .ue_emu = "tablet",
791 .ue_usbver = 3,
792 .ue_usbspeed = USB_SPEED_HIGH,
793 .ue_init = umouse_init,
794 .ue_request = umouse_request,
795 .ue_data = umouse_data_handler,
796 .ue_reset = umouse_reset,
797 .ue_remove = umouse_remove,
798 .ue_stop = umouse_stop
800 USB_EMUL_SET(ue_mouse);