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