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