VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/UsbMouse.cpp@ 47506

Last change on this file since 47506 was 47468, checked in by vboxsync, 11 years ago

Devices/Input: try to avoid losing multi-touch events if the guest is not fast enough.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.9 KB
Line 
1/** @file
2 * UsbMouse - USB Human Interface Device Emulation (Mouse).
3 */
4
5/*
6 * Copyright (C) 2007-2012 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17/*******************************************************************************
18* Header Files *
19*******************************************************************************/
20#define LOG_GROUP LOG_GROUP_USB_MOUSE
21#include <VBox/vmm/pdmusb.h>
22#include <VBox/log.h>
23#include <VBox/err.h>
24#include <iprt/assert.h>
25#include <iprt/critsect.h>
26#include <iprt/mem.h>
27#include <iprt/semaphore.h>
28#include <iprt/string.h>
29#include <iprt/uuid.h>
30#include "VBoxDD.h"
31
32
33/*******************************************************************************
34* Defined Constants And Macros *
35*******************************************************************************/
36/** @name USB HID string IDs
37 * @{ */
38#define USBHID_STR_ID_MANUFACTURER 1
39#define USBHID_STR_ID_PRODUCT_M 2
40#define USBHID_STR_ID_PRODUCT_T 3
41#define USBHID_STR_ID_PRODUCT_MT 4
42/** @} */
43
44/** @name USB HID specific descriptor types
45 * @{ */
46#define DT_IF_HID_DESCRIPTOR 0x21
47#define DT_IF_HID_REPORT 0x22
48/** @} */
49
50/** @name USB HID vendor and product IDs
51 * @{ */
52#define VBOX_USB_VENDOR 0x80EE
53#define USBHID_PID_MOUSE 0x0020
54#define USBHID_PID_TABLET 0x0021
55#define USBHID_PID_MULTI_TOUCH 0x0022
56/** @} */
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61
62/**
63 * The USB HID request state.
64 */
65typedef enum USBHIDREQSTATE
66{
67 /** Invalid status. */
68 USBHIDREQSTATE_INVALID = 0,
69 /** Ready to receive a new read request. */
70 USBHIDREQSTATE_READY,
71 /** Have (more) data for the host. */
72 USBHIDREQSTATE_DATA_TO_HOST,
73 /** Waiting to supply status information to the host. */
74 USBHIDREQSTATE_STATUS,
75 /** The end of the valid states. */
76 USBHIDREQSTATE_END
77} USBHIDREQSTATE;
78
79/**
80 * The device reporting mode.
81 * @todo Use an interface instead of an enum and switches.
82 */
83typedef enum USBHIDMODE
84{
85 /** Relative. */
86 USBHIDMODE_RELATIVE = 0,
87 /** Absolute. */
88 USBHIDMODE_ABSOLUTE,
89 /** Multi-touch. */
90 USBHIDMODE_MULTI_TOUCH
91} USBHIDMODE;
92
93
94/**
95 * Endpoint status data.
96 */
97typedef struct USBHIDEP
98{
99 bool fHalted;
100} USBHIDEP;
101/** Pointer to the endpoint status. */
102typedef USBHIDEP *PUSBHIDEP;
103
104
105/**
106 * A URB queue.
107 */
108typedef struct USBHIDURBQUEUE
109{
110 /** The head pointer. */
111 PVUSBURB pHead;
112 /** Where to insert the next entry. */
113 PVUSBURB *ppTail;
114} USBHIDURBQUEUE;
115/** Pointer to a URB queue. */
116typedef USBHIDURBQUEUE *PUSBHIDURBQUEUE;
117/** Pointer to a const URB queue. */
118typedef USBHIDURBQUEUE const *PCUSBHIDURBQUEUE;
119
120
121/**
122 * Mouse movement accumulator.
123 */
124typedef struct USBHIDM_ACCUM
125{
126 union
127 {
128 struct
129 {
130 uint32_t fButtons;
131 int32_t dx;
132 int32_t dy;
133 int32_t dz;
134 } Relative;
135 struct
136 {
137 uint32_t x;
138 uint32_t y;
139 uint32_t fButtons;
140 } Absolute;
141 struct
142 {
143 uint32_t fContact;
144 uint32_t x;
145 uint32_t y;
146 uint32_t cContact;
147 } MultiTouch;
148 } u;
149} USBHIDM_ACCUM, *PUSBHIDM_ACCUM;
150
151
152/**
153 * The USB HID instance data.
154 */
155typedef struct USBHID
156{
157 /** Pointer back to the PDM USB Device instance structure. */
158 PPDMUSBINS pUsbIns;
159 /** Critical section protecting the device state. */
160 RTCRITSECT CritSect;
161
162 /** The current configuration.
163 * (0 - default, 1 - the one supported configuration, i.e configured.) */
164 uint8_t bConfigurationValue;
165 /** Endpoint 0 is the default control pipe, 1 is the dev->host interrupt one. */
166 USBHIDEP aEps[2];
167 /** The state of the HID (state machine).*/
168 USBHIDREQSTATE enmState;
169
170 /** Pointer movement accumulator. */
171 USBHIDM_ACCUM PtrDelta;
172
173 /** Pending to-host queue.
174 * The URBs waiting here are waiting for data to become available.
175 */
176 USBHIDURBQUEUE ToHostQueue;
177
178 /** Done queue
179 * The URBs stashed here are waiting to be reaped. */
180 USBHIDURBQUEUE DoneQueue;
181 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
182 * is set. */
183 RTSEMEVENT hEvtDoneQueue;
184
185 /** Someone is waiting on the done queue. */
186 bool fHaveDoneQueueWaiter;
187 /** If device has pending changes. */
188 bool fHasPendingChanges;
189 /** Is this a relative, absolute or multi-touch pointing device? */
190 USBHIDMODE enmMode;
191 /** Tablet coordinate shift factor for old and broken operating systems. */
192 uint8_t u8CoordShift;
193
194 /**
195 * Mouse port - LUN#0.
196 *
197 * @implements PDMIBASE
198 * @implements PDMIMOUSEPORT
199 */
200 struct
201 {
202 /** The base interface for the mouse port. */
203 PDMIBASE IBase;
204 /** The mouse port base interface. */
205 PDMIMOUSEPORT IPort;
206
207 /** The base interface of the attached mouse driver. */
208 R3PTRTYPE(PPDMIBASE) pDrvBase;
209 /** The mouse interface of the attached mouse driver. */
210 R3PTRTYPE(PPDMIMOUSECONNECTOR) pDrv;
211 } Lun0;
212
213} USBHID;
214/** Pointer to the USB HID instance data. */
215typedef USBHID *PUSBHID;
216
217/**
218 * The USB HID report structure for relative device.
219 */
220typedef struct USBHIDM_REPORT
221{
222 uint8_t fButtons;
223 int8_t dx;
224 int8_t dy;
225 int8_t dz;
226} USBHIDM_REPORT, *PUSBHIDM_REPORT;
227
228/**
229 * The USB HID report structure for absolute device.
230 */
231
232typedef struct USBHIDT_REPORT
233{
234 uint16_t x;
235 uint16_t y;
236 uint8_t fButtons;
237} USBHIDT_REPORT, *PUSBHIDT_REPORT;
238
239/**
240 * The USB HID report structure for the multi-touch device.
241 */
242
243typedef struct USBHIDMT_REPORT
244{
245 uint8_t idReport;
246 uint8_t fContact;
247 uint16_t x;
248 uint16_t y;
249 uint8_t cContact;
250} USBHIDMT_REPORT, *PUSBHIDMT_REPORT;
251
252/**
253 * The combined USB HID report union for relative, absolute and multi-touch
254 * devices.
255 */
256typedef union USBHIDTM_REPORT
257{
258 USBHIDM_REPORT m;
259 USBHIDT_REPORT t;
260 USBHIDMT_REPORT mt;
261} USBHIDTM_REPORT, *PUSBHIDTM_REPORT;
262
263/*******************************************************************************
264* Global Variables *
265*******************************************************************************/
266static const PDMUSBDESCCACHESTRING g_aUsbHidStrings_en_US[] =
267{
268 { USBHID_STR_ID_MANUFACTURER, "VirtualBox" },
269 { USBHID_STR_ID_PRODUCT_M, "USB Mouse" },
270 { USBHID_STR_ID_PRODUCT_T, "USB Tablet" },
271 { USBHID_STR_ID_PRODUCT_MT, "USB Multi-Touch" },
272};
273
274static const PDMUSBDESCCACHELANG g_aUsbHidLanguages[] =
275{
276 { 0x0409, RT_ELEMENTS(g_aUsbHidStrings_en_US), g_aUsbHidStrings_en_US }
277};
278
279static const VUSBDESCENDPOINTEX g_aUsbHidMEndpointDescs[] =
280{
281 {
282 {
283 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
284 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
285 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
286 /* .bmAttributes = */ 3 /* interrupt */,
287 /* .wMaxPacketSize = */ 4,
288 /* .bInterval = */ 10,
289 },
290 /* .pvMore = */ NULL,
291 /* .pvClass = */ NULL,
292 /* .cbClass = */ 0
293 },
294};
295
296static const VUSBDESCENDPOINTEX g_aUsbHidTEndpointDescs[] =
297{
298 {
299 {
300 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
301 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
302 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
303 /* .bmAttributes = */ 3 /* interrupt */,
304 /* .wMaxPacketSize = */ 6,
305 /* .bInterval = */ 10,
306 },
307 /* .pvMore = */ NULL,
308 /* .pvClass = */ NULL,
309 /* .cbClass = */ 0
310 },
311};
312
313/* HID report descriptor (mouse). */
314static const uint8_t g_UsbHidMReportDesc[] =
315{
316 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
317 /* Usage */ 0x09, 0x02, /* Mouse */
318 /* Collection */ 0xA1, 0x01, /* Application */
319 /* Usage */ 0x09, 0x01, /* Pointer */
320 /* Collection */ 0xA1, 0x00, /* Physical */
321 /* Usage Page */ 0x05, 0x09, /* Button */
322 /* Usage Minimum */ 0x19, 0x01, /* Button 1 */
323 /* Usage Maximum */ 0x29, 0x05, /* Button 5 */
324 /* Logical Minimum */ 0x15, 0x00, /* 0 */
325 /* Logical Maximum */ 0x25, 0x01, /* 1 */
326 /* Report Count */ 0x95, 0x05, /* 5 */
327 /* Report Size */ 0x75, 0x01, /* 1 */
328 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
329 /* Report Count */ 0x95, 0x01, /* 1 */
330 /* Report Size */ 0x75, 0x03, /* 3 (padding bits) */
331 /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
332 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
333 /* Usage */ 0x09, 0x30, /* X */
334 /* Usage */ 0x09, 0x31, /* Y */
335 /* Usage */ 0x09, 0x38, /* Z (wheel) */
336 /* Logical Minimum */ 0x15, 0x81, /* -127 */
337 /* Logical Maximum */ 0x25, 0x7F, /* +127 */
338 /* Report Size */ 0x75, 0x08, /* 8 */
339 /* Report Count */ 0x95, 0x03, /* 3 */
340 /* Input */ 0x81, 0x06, /* Data, Value, Relative, Bit field */
341 /* End Collection */ 0xC0,
342 /* End Collection */ 0xC0,
343};
344
345/* HID report descriptor (tablet). */
346/* NB: The layout is far from random. Having the buttons and Z axis grouped
347 * together avoids alignment issues. Also, if X/Y is reported first, followed
348 * by buttons/Z, Windows gets phantom Z movement. That is likely a bug in Windows
349 * as OS X shows no such problem. When X/Y is reported last, Windows behaves
350 * properly.
351 */
352#define REPORTID_MOUSE 1
353#define REPORTID_MAX_COUNT 2
354
355static const uint8_t g_UsbHidTReportDesc[] =
356{
357 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
358 /* Usage */ 0x09, 0x02, /* Mouse */
359 /* Collection */ 0xA1, 0x01, /* Application */
360 /* Usage */ 0x09, 0x01, /* Pointer */
361 /* Collection */ 0xA1, 0x00, /* Physical */
362 /* Usage */ 0x09, 0x30, /* X */
363 /* Usage */ 0x09, 0x31, /* Y */
364 /* Logical Minimum */ 0x15, 0x00, /* 0 */
365 /* Logical Maximum */ 0x26, 0xFF,0x7F,/* 0x7fff */
366 /* Physical Minimum */ 0x35, 0x00, /* 0 */
367 /* Physical Maximum */ 0x46, 0xFF,0x7F,/* 0x7fff */
368 /* Report Size */ 0x75, 0x10, /* 16 */
369 /* Report Count */ 0x95, 0x02, /* 2 */
370 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
371 /* Usage Page */ 0x05, 0x09, /* Button */
372 /* Usage Minimum */ 0x19, 0x01, /* Button 1 */
373 /* Usage Maximum */ 0x29, 0x05, /* Button 5 */
374 /* Logical Minimum */ 0x15, 0x00, /* 0 */
375 /* Logical Maximum */ 0x25, 0x01, /* 1 */
376 /* Report Count */ 0x95, 0x05, /* 5 */
377 /* Report Size */ 0x75, 0x01, /* 1 */
378 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
379 /* Report Count */ 0x95, 0x01, /* 1 */
380 /* Report Size */ 0x75, 0x03, /* 3 (padding bits) */
381 /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
382 /* End Collection */ 0xC0,
383 /* End Collection */ 0xC0,
384};
385
386static const uint8_t g_UsbHidMTReportDesc[] =
387{
388 /* Usage Page */ 0x05, 0x0D, /* Digitisers */
389 /* Usage */ 0x09, 0x04, /* Touch Screen */
390 /* Collection */ 0xA1, 0x01, /* Application */
391 /* Report ID */ 0x85, REPORTID_MOUSE,
392 /* Usage */ 0x09, 0x22, /* Finger */
393 /* Collection */ 0xA1, 0x00, /* Physical */
394 /* Usage */ 0x09, 0x42, /* Tip Switch */
395 /* Usage */ 0x09, 0x32, /* In Range */
396 /* Logical Minimum */ 0x15, 0x00, /* 0 */
397 /* Logical Maximum */ 0x25, 0x01, /* 1 */
398 /* Report Count */ 0x95, 0x02, /* 2 */
399 /* Report Size */ 0x75, 0x01, /* 1 */
400 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
401 /* Report Count */ 0x95, 0x06, /* 6 (padding bits) */
402 /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
403 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
404 /* Usage */ 0x09, 0x30, /* X */
405 /* Usage */ 0x09, 0x31, /* Y */
406 /* Logical Minimum */ 0x15, 0x00, /* 0 */
407 /* Logical Maximum */ 0x26, 0xFF,0x7F,/* 0x7fff */
408 /* Physical Minimum */ 0x35, 0x00, /* 0 */
409 /* Physical Maximum */ 0x46, 0xFF,0x7F,/* 0x7fff */
410 /* Report Size */ 0x75, 0x10, /* 16 */
411 /* Report Count */ 0x95, 0x02, /* 2 */
412 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
413 /* Usage Page */ 0x05, 0x0D, /* Digitisers */
414 /* Usage */ 0x09, 0x51, /* Contact Identifier */
415 /* Report Count */ 0x95, 0x01, /* 1 */
416 /* Report Size */ 0x75, 0x08, /* 8 */
417 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
418 /* End Collection */ 0xC0,
419 /* Report ID */ 0x85, REPORTID_MAX_COUNT,
420 /* Usage */ 0x09, 0x55, /* Contact Count Maximum */
421 /* Report Count */ 0x95, 0x01, /* 1 */
422 /* Logical Maximum */ 0x25, 0x40, /* 64 */
423 /* Feature */ 0xB1, 0x03, /* Constant, Value, Absolute, Bit field */
424 /* End Collection */ 0xC0
425};
426
427/** @todo Do these really have to all be duplicated three times? */
428/* Additional HID class interface descriptor. */
429static const uint8_t g_UsbHidMIfHidDesc[] =
430{
431 /* .bLength = */ 0x09,
432 /* .bDescriptorType = */ 0x21, /* HID */
433 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
434 /* .bCountryCode = */ 0,
435 /* .bNumDescriptors = */ 1,
436 /* .bDescriptorType = */ 0x22, /* Report */
437 /* .wDescriptorLength = */ sizeof(g_UsbHidMReportDesc), 0x00
438};
439
440/* Additional HID class interface descriptor. */
441static const uint8_t g_UsbHidTIfHidDesc[] =
442{
443 /* .bLength = */ 0x09,
444 /* .bDescriptorType = */ 0x21, /* HID */
445 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
446 /* .bCountryCode = */ 0,
447 /* .bNumDescriptors = */ 1,
448 /* .bDescriptorType = */ 0x22, /* Report */
449 /* .wDescriptorLength = */ sizeof(g_UsbHidTReportDesc), 0x00
450};
451
452/* Additional HID class interface descriptor. */
453static const uint8_t g_UsbHidMTIfHidDesc[] =
454{
455 /* .bLength = */ 0x09,
456 /* .bDescriptorType = */ 0x21, /* HID */
457 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
458 /* .bCountryCode = */ 0,
459 /* .bNumDescriptors = */ 1,
460 /* .bDescriptorType = */ 0x22, /* Report */
461 /* .wDescriptorLength = */ sizeof(g_UsbHidMTReportDesc), 0x00
462};
463
464static const VUSBDESCINTERFACEEX g_UsbHidMInterfaceDesc =
465{
466 {
467 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
468 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
469 /* .bInterfaceNumber = */ 0,
470 /* .bAlternateSetting = */ 0,
471 /* .bNumEndpoints = */ 1,
472 /* .bInterfaceClass = */ 3 /* HID */,
473 /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
474 /* .bInterfaceProtocol = */ 2 /* Mouse */,
475 /* .iInterface = */ 0
476 },
477 /* .pvMore = */ NULL,
478 /* .pvClass = */ &g_UsbHidMIfHidDesc,
479 /* .cbClass = */ sizeof(g_UsbHidMIfHidDesc),
480 &g_aUsbHidMEndpointDescs[0],
481 /* .pIAD = */ NULL,
482 /* .cbIAD = */ 0
483};
484
485static const VUSBDESCINTERFACEEX g_UsbHidTInterfaceDesc =
486{
487 {
488 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
489 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
490 /* .bInterfaceNumber = */ 0,
491 /* .bAlternateSetting = */ 0,
492 /* .bNumEndpoints = */ 1,
493 /* .bInterfaceClass = */ 3 /* HID */,
494 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
495 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
496 /* .iInterface = */ 0
497 },
498 /* .pvMore = */ NULL,
499 /* .pvClass = */ &g_UsbHidTIfHidDesc,
500 /* .cbClass = */ sizeof(g_UsbHidTIfHidDesc),
501 &g_aUsbHidTEndpointDescs[0],
502 /* .pIAD = */ NULL,
503 /* .cbIAD = */ 0
504};
505
506static const VUSBDESCINTERFACEEX g_UsbHidMTInterfaceDesc =
507{
508 {
509 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
510 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
511 /* .bInterfaceNumber = */ 0,
512 /* .bAlternateSetting = */ 0,
513 /* .bNumEndpoints = */ 1,
514 /* .bInterfaceClass = */ 3 /* HID */,
515 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
516 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
517 /* .iInterface = */ 0
518 },
519 /* .pvMore = */ NULL,
520 /* .pvClass = */ &g_UsbHidMTIfHidDesc,
521 /* .cbClass = */ sizeof(g_UsbHidMTIfHidDesc),
522 &g_aUsbHidTEndpointDescs[0],
523 /* .pIAD = */ NULL,
524 /* .cbIAD = */ 0
525};
526
527static const VUSBINTERFACE g_aUsbHidMInterfaces[] =
528{
529 { &g_UsbHidMInterfaceDesc, /* .cSettings = */ 1 },
530};
531
532static const VUSBINTERFACE g_aUsbHidTInterfaces[] =
533{
534 { &g_UsbHidTInterfaceDesc, /* .cSettings = */ 1 },
535};
536
537static const VUSBINTERFACE g_aUsbHidMTInterfaces[] =
538{
539 { &g_UsbHidMTInterfaceDesc, /* .cSettings = */ 1 },
540};
541
542static const VUSBDESCCONFIGEX g_UsbHidMConfigDesc =
543{
544 {
545 /* .bLength = */ sizeof(VUSBDESCCONFIG),
546 /* .bDescriptorType = */ VUSB_DT_CONFIG,
547 /* .wTotalLength = */ 0 /* recalculated on read */,
548 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMInterfaces),
549 /* .bConfigurationValue =*/ 1,
550 /* .iConfiguration = */ 0,
551 /* .bmAttributes = */ RT_BIT(7),
552 /* .MaxPower = */ 50 /* 100mA */
553 },
554 NULL, /* pvMore */
555 &g_aUsbHidMInterfaces[0],
556 NULL /* pvOriginal */
557};
558
559static const VUSBDESCCONFIGEX g_UsbHidTConfigDesc =
560{
561 {
562 /* .bLength = */ sizeof(VUSBDESCCONFIG),
563 /* .bDescriptorType = */ VUSB_DT_CONFIG,
564 /* .wTotalLength = */ 0 /* recalculated on read */,
565 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidTInterfaces),
566 /* .bConfigurationValue =*/ 1,
567 /* .iConfiguration = */ 0,
568 /* .bmAttributes = */ RT_BIT(7),
569 /* .MaxPower = */ 50 /* 100mA */
570 },
571 NULL, /* pvMore */
572 &g_aUsbHidTInterfaces[0],
573 NULL /* pvOriginal */
574};
575
576static const VUSBDESCCONFIGEX g_UsbHidMTConfigDesc =
577{
578 {
579 /* .bLength = */ sizeof(VUSBDESCCONFIG),
580 /* .bDescriptorType = */ VUSB_DT_CONFIG,
581 /* .wTotalLength = */ 0 /* recalculated on read */,
582 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMTInterfaces),
583 /* .bConfigurationValue =*/ 1,
584 /* .iConfiguration = */ 0,
585 /* .bmAttributes = */ RT_BIT(7),
586 /* .MaxPower = */ 50 /* 100mA */
587 },
588 NULL, /* pvMore */
589 &g_aUsbHidMTInterfaces[0],
590 NULL /* pvOriginal */
591};
592
593static const VUSBDESCDEVICE g_UsbHidMDeviceDesc =
594{
595 /* .bLength = */ sizeof(g_UsbHidMDeviceDesc),
596 /* .bDescriptorType = */ VUSB_DT_DEVICE,
597 /* .bcdUsb = */ 0x110, /* 1.1 */
598 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
599 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
600 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
601 /* .bMaxPacketSize0 = */ 8,
602 /* .idVendor = */ VBOX_USB_VENDOR,
603 /* .idProduct = */ USBHID_PID_MOUSE,
604 /* .bcdDevice = */ 0x0100, /* 1.0 */
605 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
606 /* .iProduct = */ USBHID_STR_ID_PRODUCT_M,
607 /* .iSerialNumber = */ 0,
608 /* .bNumConfigurations = */ 1
609};
610
611static const VUSBDESCDEVICE g_UsbHidTDeviceDesc =
612{
613 /* .bLength = */ sizeof(g_UsbHidTDeviceDesc),
614 /* .bDescriptorType = */ VUSB_DT_DEVICE,
615 /* .bcdUsb = */ 0x110, /* 1.1 */
616 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
617 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
618 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
619 /* .bMaxPacketSize0 = */ 8,
620 /* .idVendor = */ VBOX_USB_VENDOR,
621 /* .idProduct = */ USBHID_PID_TABLET,
622 /* .bcdDevice = */ 0x0100, /* 1.0 */
623 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
624 /* .iProduct = */ USBHID_STR_ID_PRODUCT_T,
625 /* .iSerialNumber = */ 0,
626 /* .bNumConfigurations = */ 1
627};
628
629static const VUSBDESCDEVICE g_UsbHidMTDeviceDesc =
630{
631 /* .bLength = */ sizeof(g_UsbHidMTDeviceDesc),
632 /* .bDescriptorType = */ VUSB_DT_DEVICE,
633 /* .bcdUsb = */ 0x110, /* 1.1 */
634 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
635 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
636 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
637 /* .bMaxPacketSize0 = */ 8,
638 /* .idVendor = */ VBOX_USB_VENDOR,
639 /* .idProduct = */ USBHID_PID_MULTI_TOUCH,
640 /* .bcdDevice = */ 0x0100, /* 1.0 */
641 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
642 /* .iProduct = */ USBHID_STR_ID_PRODUCT_MT,
643 /* .iSerialNumber = */ 0,
644 /* .bNumConfigurations = */ 1
645};
646
647static const PDMUSBDESCCACHE g_UsbHidMDescCache =
648{
649 /* .pDevice = */ &g_UsbHidMDeviceDesc,
650 /* .paConfigs = */ &g_UsbHidMConfigDesc,
651 /* .paLanguages = */ g_aUsbHidLanguages,
652 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
653 /* .fUseCachedDescriptors = */ true,
654 /* .fUseCachedStringsDescriptors = */ true
655};
656
657static const PDMUSBDESCCACHE g_UsbHidTDescCache =
658{
659 /* .pDevice = */ &g_UsbHidTDeviceDesc,
660 /* .paConfigs = */ &g_UsbHidTConfigDesc,
661 /* .paLanguages = */ g_aUsbHidLanguages,
662 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
663 /* .fUseCachedDescriptors = */ true,
664 /* .fUseCachedStringsDescriptors = */ true
665};
666
667static const PDMUSBDESCCACHE g_UsbHidMTDescCache =
668{
669 /* .pDevice = */ &g_UsbHidMTDeviceDesc,
670 /* .paConfigs = */ &g_UsbHidMTConfigDesc,
671 /* .paLanguages = */ g_aUsbHidLanguages,
672 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
673 /* .fUseCachedDescriptors = */ true,
674 /* .fUseCachedStringsDescriptors = */ true
675};
676
677
678/*******************************************************************************
679* Internal Functions *
680*******************************************************************************/
681
682/**
683 * Initializes an URB queue.
684 *
685 * @param pQueue The URB queue.
686 */
687static void usbHidQueueInit(PUSBHIDURBQUEUE pQueue)
688{
689 pQueue->pHead = NULL;
690 pQueue->ppTail = &pQueue->pHead;
691}
692
693
694
695/**
696 * Inserts an URB at the end of the queue.
697 *
698 * @param pQueue The URB queue.
699 * @param pUrb The URB to insert.
700 */
701DECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
702{
703 pUrb->Dev.pNext = NULL;
704 *pQueue->ppTail = pUrb;
705 pQueue->ppTail = &pUrb->Dev.pNext;
706}
707
708
709/**
710 * Unlinks the head of the queue and returns it.
711 *
712 * @returns The head entry.
713 * @param pQueue The URB queue.
714 */
715DECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
716{
717 PVUSBURB pUrb = pQueue->pHead;
718 if (pUrb)
719 {
720 PVUSBURB pNext = pUrb->Dev.pNext;
721 pQueue->pHead = pNext;
722 if (!pNext)
723 pQueue->ppTail = &pQueue->pHead;
724 else
725 pUrb->Dev.pNext = NULL;
726 }
727 return pUrb;
728}
729
730
731/**
732 * Removes an URB from anywhere in the queue.
733 *
734 * @returns true if found, false if not.
735 * @param pQueue The URB queue.
736 * @param pUrb The URB to remove.
737 */
738DECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
739{
740 PVUSBURB pCur = pQueue->pHead;
741 if (pCur == pUrb)
742 pQueue->pHead = pUrb->Dev.pNext;
743 else
744 {
745 while (pCur)
746 {
747 if (pCur->Dev.pNext == pUrb)
748 {
749 pCur->Dev.pNext = pUrb->Dev.pNext;
750 break;
751 }
752 pCur = pCur->Dev.pNext;
753 }
754 if (!pCur)
755 return false;
756 }
757 if (!pUrb->Dev.pNext)
758 pQueue->ppTail = &pQueue->pHead;
759 return true;
760}
761
762
763/**
764 * Checks if the queue is empty or not.
765 *
766 * @returns true if it is, false if it isn't.
767 * @param pQueue The URB queue.
768 */
769DECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
770{
771 return pQueue->pHead == NULL;
772}
773
774
775/**
776 * Links an URB into the done queue.
777 *
778 * @param pThis The HID instance.
779 * @param pUrb The URB.
780 */
781static void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
782{
783 usbHidQueueAddTail(&pThis->DoneQueue, pUrb);
784
785 if (pThis->fHaveDoneQueueWaiter)
786 {
787 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
788 AssertRC(rc);
789 }
790}
791
792
793
794/**
795 * Completes the URB with a stalled state, halting the pipe.
796 */
797static int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
798{
799 LogRelFlow(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n",
800 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
801
802 pUrb->enmStatus = VUSBSTATUS_STALL;
803
804 /** @todo figure out if the stall is global or pipe-specific or both. */
805 if (pEp)
806 pEp->fHalted = true;
807 else
808 {
809 pThis->aEps[0].fHalted = true;
810 pThis->aEps[1].fHalted = true;
811 }
812
813 usbHidLinkDone(pThis, pUrb);
814 return VINF_SUCCESS;
815}
816
817
818/**
819 * Completes the URB with a OK state.
820 */
821static int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, size_t cbData)
822{
823 LogRelFlow(("usbHidCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n",
824 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
825
826 pUrb->enmStatus = VUSBSTATUS_OK;
827 pUrb->cbData = (uint32_t)cbData;
828
829 usbHidLinkDone(pThis, pUrb);
830 return VINF_SUCCESS;
831}
832
833
834/**
835 * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
836 * usbHidHandleDefaultPipe.
837 *
838 * @returns VBox status code.
839 * @param pThis The HID instance.
840 * @param pUrb Set when usbHidHandleDefaultPipe is the
841 * caller.
842 * @param fSetConfig Set when usbHidUsbSetConfiguration is the
843 * caller.
844 */
845static int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
846{
847 /*
848 * Wait for the any command currently executing to complete before
849 * resetting. (We cannot cancel its execution.) How we do this depends
850 * on the reset method.
851 */
852
853 /*
854 * Reset the device state.
855 */
856 pThis->enmState = USBHIDREQSTATE_READY;
857 pThis->fHasPendingChanges = false;
858
859 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
860 pThis->aEps[i].fHalted = false;
861
862 if (!pUrb && !fSetConfig) /* (only device reset) */
863 pThis->bConfigurationValue = 0; /* default */
864
865 /*
866 * Ditch all pending URBs.
867 */
868 PVUSBURB pCurUrb;
869 while ((pCurUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
870 {
871 pCurUrb->enmStatus = VUSBSTATUS_CRC;
872 usbHidLinkDone(pThis, pCurUrb);
873 }
874
875 if (pUrb)
876 return usbHidCompleteOk(pThis, pUrb, 0);
877 return VINF_SUCCESS;
878}
879
880static int8_t clamp_i8(int32_t val)
881{
882 if (val > 127) {
883 val = 127;
884 } else if (val < -127) {
885 val = -127;
886 }
887 return val;
888}
889
890/**
891 * Create a USB HID report report based on the currently accumulated data.
892 */
893static size_t usbHidFillReport(PUSBHIDTM_REPORT pReport,
894 PUSBHIDM_ACCUM pAccumulated, USBHIDMODE enmMode)
895{
896 size_t cbCopy;
897
898 switch (enmMode)
899 {
900 case USBHIDMODE_ABSOLUTE:
901 pReport->t.fButtons = pAccumulated->u.Absolute.fButtons;
902 pReport->t.x = pAccumulated->u.Absolute.x;
903 pReport->t.y = pAccumulated->u.Absolute.y;
904
905 cbCopy = sizeof(pReport->t);
906 LogRel3(("Abs event, x=%d, y=%d, fButtons=%02x, report size %d\n",
907 pReport->t.x, pReport->t.y, pReport->t.fButtons,
908 cbCopy));
909 break;
910 case USBHIDMODE_RELATIVE:
911 pReport->m.fButtons = pAccumulated->u.Relative.fButtons;
912 pReport->m.dx = clamp_i8(pAccumulated->u.Relative.dx);
913 pReport->m.dy = clamp_i8(pAccumulated->u.Relative.dy);
914 pReport->m.dz = clamp_i8(pAccumulated->u.Relative.dz);
915
916 cbCopy = sizeof(pReport->m);
917 LogRel3(("Rel event, dx=%d, dy=%d, dz=%d, fButtons=%02x, report size %d\n",
918 pReport->m.dx, pReport->m.dy, pReport->m.dz,
919 pReport->m.fButtons, cbCopy));
920 break;
921 case USBHIDMODE_MULTI_TOUCH:
922 pReport->mt.idReport = REPORTID_MOUSE;
923 pReport->mt.cContact = pAccumulated->u.MultiTouch.cContact;
924 pReport->mt.x = pAccumulated->u.MultiTouch.x;
925 pReport->mt.y = pAccumulated->u.MultiTouch.y;
926 pReport->mt.fContact = pAccumulated->u.MultiTouch.fContact;
927
928 cbCopy = sizeof(pReport->mt);
929 LogRel3(("Multi-touch event, x=%u, y=%u, cContact=%u, fContact=%02x, report size %d\n",
930 (unsigned)pReport->mt.x, (unsigned)pReport->mt.y,
931 (unsigned)pReport->mt.cContact, (unsigned)pReport->mt.fContact,
932 cbCopy));
933 break;
934 }
935
936 /* Clear the accumulated movement. */
937 RT_ZERO(*pAccumulated);
938
939 return cbCopy;
940}
941
942/**
943 * Sends a state report to the host if there is a pending URB.
944 */
945static int usbHidSendReport(PUSBHID pThis)
946{
947 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
948
949 if (pUrb)
950 {
951 PUSBHIDTM_REPORT pReport = (PUSBHIDTM_REPORT)&pUrb->abData[0];
952 size_t cbCopy;
953
954 cbCopy = usbHidFillReport(pReport, &pThis->PtrDelta, pThis->enmMode);
955 pThis->fHasPendingChanges = false;
956 return usbHidCompleteOk(pThis, pUrb, cbCopy);
957 }
958 else
959 {
960 LogRelFlow(("No available URB for USB mouse\n"));
961 pThis->fHasPendingChanges = true;
962 }
963 return VINF_EOF;
964}
965
966/**
967 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
968 */
969static DECLCALLBACK(void *) usbHidMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
970{
971 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
972 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
973 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Lun0.IPort);
974 return NULL;
975}
976
977/**
978 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
979 */
980static DECLCALLBACK(int) usbHidMousePutEvent(PPDMIMOUSEPORT pInterface,
981 int32_t dx, int32_t dy, int32_t dz,
982 int32_t dw, uint32_t fButtons)
983{
984 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
985 RTCritSectEnter(&pThis->CritSect);
986
987 /* Accumulate movement - the events from the front end may arrive
988 * at a much higher rate than USB can handle.
989 */
990 pThis->PtrDelta.u.Relative.fButtons = fButtons;
991 pThis->PtrDelta.u.Relative.dx += dx;
992 pThis->PtrDelta.u.Relative.dy += dy;
993 pThis->PtrDelta.u.Relative.dz -= dz; /* Inverted! */
994
995 /* Send a report if possible. */
996 usbHidSendReport(pThis);
997
998 RTCritSectLeave(&pThis->CritSect);
999 return VINF_SUCCESS;
1000}
1001
1002/**
1003 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
1004 */
1005static DECLCALLBACK(int) usbHidMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1006 uint32_t x, uint32_t y,
1007 int32_t dz, int32_t dw,
1008 uint32_t fButtons)
1009{
1010 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1011 RTCritSectEnter(&pThis->CritSect);
1012
1013 Assert(pThis->enmMode == USBHIDMODE_ABSOLUTE);
1014
1015 /* Accumulate movement - the events from the front end may arrive
1016 * at a much higher rate than USB can handle. Probably not a real issue
1017 * when only the Z axis is relative (X/Y movement isn't technically
1018 * accumulated and only the last value is used).
1019 */
1020 pThis->PtrDelta.u.Absolute.fButtons = fButtons;
1021 pThis->PtrDelta.u.Absolute.x = x >> pThis->u8CoordShift;
1022 pThis->PtrDelta.u.Absolute.y = y >> pThis->u8CoordShift;
1023
1024 /* Send a report if possible. */
1025 usbHidSendReport(pThis);
1026
1027 RTCritSectLeave(&pThis->CritSect);
1028 return VINF_SUCCESS;
1029}
1030
1031/**
1032 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMT}
1033 */
1034static DECLCALLBACK(int) usbHidMousePutEventMT(PPDMIMOUSEPORT pInterface,
1035 uint32_t x, uint32_t y,
1036 uint32_t cContact,
1037 uint32_t fContact)
1038{
1039 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1040 if (pThis->fHasPendingChanges)
1041 return VERR_TRY_AGAIN;
1042 RTCritSectEnter(&pThis->CritSect);
1043
1044 Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1045
1046 /* Accumulate movement - the events from the front end may arrive
1047 * at a much higher rate than USB can handle. Probably not a real issue
1048 * when only the Z axis is relative (X/Y movement isn't technically
1049 * accumulated and only the last value is used).
1050 */
1051 pThis->PtrDelta.u.MultiTouch.fContact = fContact;
1052 pThis->PtrDelta.u.MultiTouch.x = x >> pThis->u8CoordShift;
1053 pThis->PtrDelta.u.MultiTouch.y = y >> pThis->u8CoordShift;
1054 pThis->PtrDelta.u.MultiTouch.cContact = cContact;
1055
1056 /* Send a report if possible. */
1057 usbHidSendReport(pThis);
1058
1059 RTCritSectLeave(&pThis->CritSect);
1060 return VINF_SUCCESS;
1061}
1062
1063/**
1064 * @copydoc PDMUSBREG::pfnUrbReap
1065 */
1066static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1067{
1068 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1069 LogRelFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1070
1071 RTCritSectEnter(&pThis->CritSect);
1072
1073 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1074 if (!pUrb && cMillies)
1075 {
1076 /* Wait */
1077 pThis->fHaveDoneQueueWaiter = true;
1078 RTCritSectLeave(&pThis->CritSect);
1079
1080 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1081
1082 RTCritSectEnter(&pThis->CritSect);
1083 pThis->fHaveDoneQueueWaiter = false;
1084
1085 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1086 }
1087
1088 RTCritSectLeave(&pThis->CritSect);
1089
1090 if (pUrb)
1091 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1092 pUrb->pszDesc));
1093 return pUrb;
1094}
1095
1096
1097/**
1098 * @copydoc PDMUSBREG::pfnUrbCancel
1099 */
1100static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1101{
1102 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1103 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1104 pUrb->pszDesc));
1105 RTCritSectEnter(&pThis->CritSect);
1106
1107 /*
1108 * Remove the URB from the to-host queue and move it onto the done queue.
1109 */
1110 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1111 usbHidLinkDone(pThis, pUrb);
1112
1113 RTCritSectLeave(&pThis->CritSect);
1114 return VINF_SUCCESS;
1115}
1116
1117
1118/**
1119 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1120 * rather different from bulk requests because an interrupt read URB may complete
1121 * after arbitrarily long time.
1122 */
1123static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1124{
1125 /*
1126 * Stall the request if the pipe is halted.
1127 */
1128 if (RT_UNLIKELY(pEp->fHalted))
1129 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1130
1131 /*
1132 * Deal with the URB according to the state.
1133 */
1134 switch (pThis->enmState)
1135 {
1136 /*
1137 * We've data left to transfer to the host.
1138 */
1139 case USBHIDREQSTATE_DATA_TO_HOST:
1140 {
1141 AssertFailed();
1142 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1143 return usbHidCompleteOk(pThis, pUrb, 0);
1144 }
1145
1146 /*
1147 * Status transfer.
1148 */
1149 case USBHIDREQSTATE_STATUS:
1150 {
1151 AssertFailed();
1152 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1153 pThis->enmState = USBHIDREQSTATE_READY;
1154 return usbHidCompleteOk(pThis, pUrb, 0);
1155 }
1156
1157 case USBHIDREQSTATE_READY:
1158 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1159 /* If a report is pending, send it right away. */
1160 if (pThis->fHasPendingChanges)
1161 usbHidSendReport(pThis);
1162 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1163 pUrb, pUrb->pszDesc));
1164 return VINF_SUCCESS;
1165
1166 /*
1167 * Bad states, stall.
1168 */
1169 default:
1170 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1171 pThis->enmState, pUrb->cbData));
1172 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1173 }
1174}
1175
1176
1177/**
1178 * Handles request sent to the default control pipe.
1179 */
1180static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1181{
1182 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1183 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1184
1185 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1186 {
1187 switch (pSetup->bRequest)
1188 {
1189 case VUSB_REQ_GET_DESCRIPTOR:
1190 {
1191 switch (pSetup->bmRequestType)
1192 {
1193 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1194 {
1195 switch (pSetup->wValue >> 8)
1196 {
1197 case VUSB_DT_STRING:
1198 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1199 pSetup->wValue, pSetup->wIndex));
1200 break;
1201 default:
1202 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1203 pSetup->wValue, pSetup->wIndex));
1204 break;
1205 }
1206 break;
1207 }
1208
1209 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1210 {
1211 switch (pSetup->wValue >> 8)
1212 {
1213 uint32_t cbCopy;
1214 uint32_t cbDesc;
1215 const uint8_t *pDesc;
1216
1217 case DT_IF_HID_DESCRIPTOR:
1218 {
1219 switch (pThis->enmMode)
1220 {
1221 case USBHIDMODE_ABSOLUTE:
1222 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1223 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1224 break;
1225 case USBHIDMODE_RELATIVE:
1226 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1227 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1228 break;
1229 case USBHIDMODE_MULTI_TOUCH:
1230 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1231 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1232 break;
1233 }
1234 /* Returned data is written after the setup message. */
1235 cbCopy = pUrb->cbData - sizeof(*pSetup);
1236 cbCopy = RT_MIN(cbCopy, cbDesc);
1237 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1238 pSetup->wValue, pSetup->wIndex,
1239 cbCopy));
1240 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1241 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1242 }
1243
1244 case DT_IF_HID_REPORT:
1245 {
1246 switch (pThis->enmMode)
1247 {
1248 case USBHIDMODE_ABSOLUTE:
1249 {
1250 cbDesc = sizeof(g_UsbHidTReportDesc);
1251 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
1252 break;
1253 }
1254 case USBHIDMODE_RELATIVE:
1255 {
1256 cbDesc = sizeof(g_UsbHidMReportDesc);
1257 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
1258 break;
1259 }
1260 case USBHIDMODE_MULTI_TOUCH:
1261 {
1262 cbDesc = sizeof(g_UsbHidMTReportDesc);
1263 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
1264 break;
1265 }
1266 }
1267 /* Returned data is written after the setup message. */
1268 cbCopy = pUrb->cbData - sizeof(*pSetup);
1269 cbCopy = RT_MIN(cbCopy, cbDesc);
1270 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
1271 pSetup->wValue, pSetup->wIndex,
1272 cbCopy));
1273 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1274 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1275 }
1276
1277 default:
1278 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1279 pSetup->wValue, pSetup->wIndex));
1280 break;
1281 }
1282 break;
1283 }
1284
1285 default:
1286 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
1287 pSetup->bmRequestType));
1288 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1289 }
1290 break;
1291 }
1292
1293 case VUSB_REQ_GET_STATUS:
1294 {
1295 uint16_t wRet = 0;
1296
1297 if (pSetup->wLength != 2)
1298 {
1299 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
1300 pSetup->wLength));
1301 break;
1302 }
1303 Assert(pSetup->wValue == 0);
1304 switch (pSetup->bmRequestType)
1305 {
1306 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1307 {
1308 Assert(pSetup->wIndex == 0);
1309 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
1310 wRet = 0; /* Not self-powered, no remote wakeup. */
1311 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1312 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1313 }
1314
1315 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1316 {
1317 if (pSetup->wIndex == 0)
1318 {
1319 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1320 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1321 }
1322 else
1323 {
1324 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
1325 pSetup->wIndex));
1326 }
1327 break;
1328 }
1329
1330 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1331 {
1332 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1333 {
1334 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1335 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1336 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1337 }
1338 else
1339 {
1340 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
1341 pSetup->wIndex));
1342 }
1343 break;
1344 }
1345
1346 default:
1347 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
1348 pSetup->bmRequestType));
1349 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
1350 }
1351 break;
1352 }
1353
1354 case VUSB_REQ_CLEAR_FEATURE:
1355 break;
1356 }
1357
1358 /** @todo implement this. */
1359 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1360 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1361 pSetup->wIndex, pSetup->wLength));
1362
1363 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1364 }
1365 else
1366 {
1367 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1368 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1369 pSetup->wIndex, pSetup->wLength));
1370 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1371 }
1372
1373 return VINF_SUCCESS;
1374}
1375
1376
1377/**
1378 * @copydoc PDMUSBREG::pfnUrbQueue
1379 */
1380static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1381{
1382 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1383 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
1384 pUrb, pUrb->pszDesc, pUrb->EndPt));
1385 RTCritSectEnter(&pThis->CritSect);
1386
1387 /*
1388 * Parse on a per end-point basis.
1389 */
1390 int rc;
1391 switch (pUrb->EndPt)
1392 {
1393 case 0:
1394 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1395 break;
1396
1397 case 0x81:
1398 AssertFailed();
1399 case 0x01:
1400 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
1401 break;
1402
1403 default:
1404 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1405 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1406 break;
1407 }
1408
1409 RTCritSectLeave(&pThis->CritSect);
1410 return rc;
1411}
1412
1413
1414/**
1415 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1416 */
1417static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1418{
1419 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1420 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
1421 pUsbIns->iInstance, uEndpoint));
1422
1423 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1424 {
1425 RTCritSectEnter(&pThis->CritSect);
1426 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1427 RTCritSectLeave(&pThis->CritSect);
1428 }
1429
1430 return VINF_SUCCESS;
1431}
1432
1433
1434/**
1435 * @copydoc PDMUSBREG::pfnUsbSetInterface
1436 */
1437static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1438{
1439 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
1440 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1441 Assert(bAlternateSetting == 0);
1442 return VINF_SUCCESS;
1443}
1444
1445
1446/**
1447 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1448 */
1449static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1450 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1451{
1452 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1453 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
1454 pUsbIns->iInstance, bConfigurationValue));
1455 Assert(bConfigurationValue == 1);
1456 RTCritSectEnter(&pThis->CritSect);
1457
1458 /*
1459 * If the same config is applied more than once, it's a kind of reset.
1460 */
1461 if (pThis->bConfigurationValue == bConfigurationValue)
1462 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1463 pThis->bConfigurationValue = bConfigurationValue;
1464
1465 /*
1466 * Set received event type to absolute or relative.
1467 */
1468 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
1469 pThis->enmMode == USBHIDMODE_RELATIVE,
1470 pThis->enmMode == USBHIDMODE_ABSOLUTE,
1471 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1472
1473 RTCritSectLeave(&pThis->CritSect);
1474 return VINF_SUCCESS;
1475}
1476
1477
1478/**
1479 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1480 */
1481static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1482{
1483 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1484 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1485 switch (pThis->enmMode)
1486 {
1487 case USBHIDMODE_ABSOLUTE:
1488 return &g_UsbHidTDescCache;
1489 case USBHIDMODE_RELATIVE:
1490 return &g_UsbHidMDescCache;
1491 case USBHIDMODE_MULTI_TOUCH:
1492 return &g_UsbHidMTDescCache;
1493 default:
1494 return NULL;
1495 }
1496}
1497
1498
1499/**
1500 * @copydoc PDMUSBREG::pfnUsbReset
1501 */
1502static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1503{
1504 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1505 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
1506 RTCritSectEnter(&pThis->CritSect);
1507
1508 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
1509
1510 RTCritSectLeave(&pThis->CritSect);
1511 return rc;
1512}
1513
1514
1515/**
1516 * @copydoc PDMUSBREG::pfnDestruct
1517 */
1518static void usbHidDestruct(PPDMUSBINS pUsbIns)
1519{
1520 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1521 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
1522
1523 if (RTCritSectIsInitialized(&pThis->CritSect))
1524 {
1525 RTCritSectEnter(&pThis->CritSect);
1526 RTCritSectLeave(&pThis->CritSect);
1527 RTCritSectDelete(&pThis->CritSect);
1528 }
1529
1530 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1531 {
1532 RTSemEventDestroy(pThis->hEvtDoneQueue);
1533 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1534 }
1535}
1536
1537
1538/**
1539 * @copydoc PDMUSBREG::pfnConstruct
1540 */
1541static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1542{
1543 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1544 char szMode[64];
1545 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
1546
1547 /*
1548 * Perform the basic structure initialization first so the destructor
1549 * will not misbehave.
1550 */
1551 pThis->pUsbIns = pUsbIns;
1552 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1553 usbHidQueueInit(&pThis->ToHostQueue);
1554 usbHidQueueInit(&pThis->DoneQueue);
1555
1556 int rc = RTCritSectInit(&pThis->CritSect);
1557 AssertRCReturn(rc, rc);
1558
1559 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1560 AssertRCReturn(rc, rc);
1561
1562 /*
1563 * Validate and read the configuration.
1564 */
1565 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
1566 if (RT_FAILURE(rc))
1567 return rc;
1568 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
1569 if (RT_FAILURE(rc))
1570 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
1571 if (!RTStrCmp(szMode, "relative"))
1572 pThis->enmMode = USBHIDMODE_RELATIVE;
1573 else if (!RTStrCmp(szMode, "absolute"))
1574 pThis->enmMode = USBHIDMODE_ABSOLUTE;
1575 else if (!RTStrCmp(szMode, "multitouch"))
1576 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
1577 else
1578 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
1579 N_("Invalid HID device mode"));
1580
1581 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
1582 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
1583 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
1584 pThis->Lun0.IPort.pfnPutEventMT = usbHidMousePutEventMT;
1585
1586 /*
1587 * Attach the mouse driver.
1588 */
1589 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
1590 if (RT_FAILURE(rc))
1591 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
1592
1593 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
1594 if (!pThis->Lun0.pDrv)
1595 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
1596
1597 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
1598 if (RT_FAILURE(rc))
1599 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
1600
1601 return VINF_SUCCESS;
1602}
1603
1604
1605/**
1606 * The USB Human Interface Device (HID) Mouse registration record.
1607 */
1608const PDMUSBREG g_UsbHidMou =
1609{
1610 /* u32Version */
1611 PDM_USBREG_VERSION,
1612 /* szName */
1613 "HidMouse",
1614 /* pszDescription */
1615 "USB HID Mouse.",
1616 /* fFlags */
1617 0,
1618 /* cMaxInstances */
1619 ~0U,
1620 /* cbInstance */
1621 sizeof(USBHID),
1622 /* pfnConstruct */
1623 usbHidConstruct,
1624 /* pfnDestruct */
1625 usbHidDestruct,
1626 /* pfnVMInitComplete */
1627 NULL,
1628 /* pfnVMPowerOn */
1629 NULL,
1630 /* pfnVMReset */
1631 NULL,
1632 /* pfnVMSuspend */
1633 NULL,
1634 /* pfnVMResume */
1635 NULL,
1636 /* pfnVMPowerOff */
1637 NULL,
1638 /* pfnHotPlugged */
1639 NULL,
1640 /* pfnHotUnplugged */
1641 NULL,
1642 /* pfnDriverAttach */
1643 NULL,
1644 /* pfnDriverDetach */
1645 NULL,
1646 /* pfnQueryInterface */
1647 NULL,
1648 /* pfnUsbReset */
1649 usbHidUsbReset,
1650 /* pfnUsbGetDescriptorCache */
1651 usbHidUsbGetDescriptorCache,
1652 /* pfnUsbSetConfiguration */
1653 usbHidUsbSetConfiguration,
1654 /* pfnUsbSetInterface */
1655 usbHidUsbSetInterface,
1656 /* pfnUsbClearHaltedEndpoint */
1657 usbHidUsbClearHaltedEndpoint,
1658 /* pfnUrbNew */
1659 NULL/*usbHidUrbNew*/,
1660 /* pfnUrbQueue */
1661 usbHidQueue,
1662 /* pfnUrbCancel */
1663 usbHidUrbCancel,
1664 /* pfnUrbReap */
1665 usbHidUrbReap,
1666 /* u32TheEnd */
1667 PDM_USBREG_VERSION
1668};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette