VirtualBox

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

Last change on this file since 47418 was 47418, checked in by vboxsync, 12 years ago

Devices/Input/UsbMouse: multi-touch co-ordinate fix.

  • 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.215389.xyz. 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 RTCritSectEnter(&pThis->CritSect);
1041
1042 Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1043
1044 /* Accumulate movement - the events from the front end may arrive
1045 * at a much higher rate than USB can handle. Probably not a real issue
1046 * when only the Z axis is relative (X/Y movement isn't technically
1047 * accumulated and only the last value is used).
1048 */
1049 pThis->PtrDelta.u.MultiTouch.fContact = fContact;
1050 pThis->PtrDelta.u.MultiTouch.x = x >> pThis->u8CoordShift;
1051 pThis->PtrDelta.u.MultiTouch.y = y >> pThis->u8CoordShift;
1052 pThis->PtrDelta.u.MultiTouch.cContact = cContact;
1053
1054 /* Send a report if possible. */
1055 usbHidSendReport(pThis);
1056
1057 RTCritSectLeave(&pThis->CritSect);
1058 return VINF_SUCCESS;
1059}
1060
1061/**
1062 * @copydoc PDMUSBREG::pfnUrbReap
1063 */
1064static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1065{
1066 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1067 LogRelFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1068
1069 RTCritSectEnter(&pThis->CritSect);
1070
1071 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1072 if (!pUrb && cMillies)
1073 {
1074 /* Wait */
1075 pThis->fHaveDoneQueueWaiter = true;
1076 RTCritSectLeave(&pThis->CritSect);
1077
1078 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1079
1080 RTCritSectEnter(&pThis->CritSect);
1081 pThis->fHaveDoneQueueWaiter = false;
1082
1083 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1084 }
1085
1086 RTCritSectLeave(&pThis->CritSect);
1087
1088 if (pUrb)
1089 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1090 pUrb->pszDesc));
1091 return pUrb;
1092}
1093
1094
1095/**
1096 * @copydoc PDMUSBREG::pfnUrbCancel
1097 */
1098static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1099{
1100 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1101 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1102 pUrb->pszDesc));
1103 RTCritSectEnter(&pThis->CritSect);
1104
1105 /*
1106 * Remove the URB from the to-host queue and move it onto the done queue.
1107 */
1108 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1109 usbHidLinkDone(pThis, pUrb);
1110
1111 RTCritSectLeave(&pThis->CritSect);
1112 return VINF_SUCCESS;
1113}
1114
1115
1116/**
1117 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1118 * rather different from bulk requests because an interrupt read URB may complete
1119 * after arbitrarily long time.
1120 */
1121static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1122{
1123 /*
1124 * Stall the request if the pipe is halted.
1125 */
1126 if (RT_UNLIKELY(pEp->fHalted))
1127 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1128
1129 /*
1130 * Deal with the URB according to the state.
1131 */
1132 switch (pThis->enmState)
1133 {
1134 /*
1135 * We've data left to transfer to the host.
1136 */
1137 case USBHIDREQSTATE_DATA_TO_HOST:
1138 {
1139 AssertFailed();
1140 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1141 return usbHidCompleteOk(pThis, pUrb, 0);
1142 }
1143
1144 /*
1145 * Status transfer.
1146 */
1147 case USBHIDREQSTATE_STATUS:
1148 {
1149 AssertFailed();
1150 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1151 pThis->enmState = USBHIDREQSTATE_READY;
1152 return usbHidCompleteOk(pThis, pUrb, 0);
1153 }
1154
1155 case USBHIDREQSTATE_READY:
1156 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1157 /* If a report is pending, send it right away. */
1158 if (pThis->fHasPendingChanges)
1159 usbHidSendReport(pThis);
1160 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1161 pUrb, pUrb->pszDesc));
1162 return VINF_SUCCESS;
1163
1164 /*
1165 * Bad states, stall.
1166 */
1167 default:
1168 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1169 pThis->enmState, pUrb->cbData));
1170 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1171 }
1172}
1173
1174
1175/**
1176 * Handles request sent to the default control pipe.
1177 */
1178static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1179{
1180 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1181 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1182
1183 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1184 {
1185 switch (pSetup->bRequest)
1186 {
1187 case VUSB_REQ_GET_DESCRIPTOR:
1188 {
1189 switch (pSetup->bmRequestType)
1190 {
1191 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1192 {
1193 switch (pSetup->wValue >> 8)
1194 {
1195 case VUSB_DT_STRING:
1196 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1197 pSetup->wValue, pSetup->wIndex));
1198 break;
1199 default:
1200 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1201 pSetup->wValue, pSetup->wIndex));
1202 break;
1203 }
1204 break;
1205 }
1206
1207 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1208 {
1209 switch (pSetup->wValue >> 8)
1210 {
1211 uint32_t cbCopy;
1212 uint32_t cbDesc;
1213 const uint8_t *pDesc;
1214
1215 case DT_IF_HID_DESCRIPTOR:
1216 {
1217 switch (pThis->enmMode)
1218 {
1219 case USBHIDMODE_ABSOLUTE:
1220 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1221 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1222 break;
1223 case USBHIDMODE_RELATIVE:
1224 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1225 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1226 break;
1227 case USBHIDMODE_MULTI_TOUCH:
1228 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1229 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1230 break;
1231 }
1232 /* Returned data is written after the setup message. */
1233 cbCopy = pUrb->cbData - sizeof(*pSetup);
1234 cbCopy = RT_MIN(cbCopy, cbDesc);
1235 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1236 pSetup->wValue, pSetup->wIndex,
1237 cbCopy));
1238 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1239 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1240 }
1241
1242 case DT_IF_HID_REPORT:
1243 {
1244 switch (pThis->enmMode)
1245 {
1246 case USBHIDMODE_ABSOLUTE:
1247 {
1248 cbDesc = sizeof(g_UsbHidTReportDesc);
1249 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
1250 break;
1251 }
1252 case USBHIDMODE_RELATIVE:
1253 {
1254 cbDesc = sizeof(g_UsbHidMReportDesc);
1255 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
1256 break;
1257 }
1258 case USBHIDMODE_MULTI_TOUCH:
1259 {
1260 cbDesc = sizeof(g_UsbHidMTReportDesc);
1261 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
1262 break;
1263 }
1264 }
1265 /* Returned data is written after the setup message. */
1266 cbCopy = pUrb->cbData - sizeof(*pSetup);
1267 cbCopy = RT_MIN(cbCopy, cbDesc);
1268 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
1269 pSetup->wValue, pSetup->wIndex,
1270 cbCopy));
1271 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1272 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1273 }
1274
1275 default:
1276 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1277 pSetup->wValue, pSetup->wIndex));
1278 break;
1279 }
1280 break;
1281 }
1282
1283 default:
1284 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
1285 pSetup->bmRequestType));
1286 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1287 }
1288 break;
1289 }
1290
1291 case VUSB_REQ_GET_STATUS:
1292 {
1293 uint16_t wRet = 0;
1294
1295 if (pSetup->wLength != 2)
1296 {
1297 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
1298 pSetup->wLength));
1299 break;
1300 }
1301 Assert(pSetup->wValue == 0);
1302 switch (pSetup->bmRequestType)
1303 {
1304 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1305 {
1306 Assert(pSetup->wIndex == 0);
1307 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
1308 wRet = 0; /* Not self-powered, no remote wakeup. */
1309 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1310 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1311 }
1312
1313 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1314 {
1315 if (pSetup->wIndex == 0)
1316 {
1317 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1318 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1319 }
1320 else
1321 {
1322 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
1323 pSetup->wIndex));
1324 }
1325 break;
1326 }
1327
1328 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1329 {
1330 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1331 {
1332 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1333 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1334 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1335 }
1336 else
1337 {
1338 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
1339 pSetup->wIndex));
1340 }
1341 break;
1342 }
1343
1344 default:
1345 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
1346 pSetup->bmRequestType));
1347 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
1348 }
1349 break;
1350 }
1351
1352 case VUSB_REQ_CLEAR_FEATURE:
1353 break;
1354 }
1355
1356 /** @todo implement this. */
1357 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1358 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1359 pSetup->wIndex, pSetup->wLength));
1360
1361 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1362 }
1363 else
1364 {
1365 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1366 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1367 pSetup->wIndex, pSetup->wLength));
1368 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1369 }
1370
1371 return VINF_SUCCESS;
1372}
1373
1374
1375/**
1376 * @copydoc PDMUSBREG::pfnUrbQueue
1377 */
1378static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1379{
1380 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1381 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
1382 pUrb, pUrb->pszDesc, pUrb->EndPt));
1383 RTCritSectEnter(&pThis->CritSect);
1384
1385 /*
1386 * Parse on a per end-point basis.
1387 */
1388 int rc;
1389 switch (pUrb->EndPt)
1390 {
1391 case 0:
1392 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1393 break;
1394
1395 case 0x81:
1396 AssertFailed();
1397 case 0x01:
1398 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
1399 break;
1400
1401 default:
1402 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1403 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1404 break;
1405 }
1406
1407 RTCritSectLeave(&pThis->CritSect);
1408 return rc;
1409}
1410
1411
1412/**
1413 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1414 */
1415static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1416{
1417 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1418 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
1419 pUsbIns->iInstance, uEndpoint));
1420
1421 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1422 {
1423 RTCritSectEnter(&pThis->CritSect);
1424 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1425 RTCritSectLeave(&pThis->CritSect);
1426 }
1427
1428 return VINF_SUCCESS;
1429}
1430
1431
1432/**
1433 * @copydoc PDMUSBREG::pfnUsbSetInterface
1434 */
1435static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1436{
1437 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
1438 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1439 Assert(bAlternateSetting == 0);
1440 return VINF_SUCCESS;
1441}
1442
1443
1444/**
1445 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1446 */
1447static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1448 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1449{
1450 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1451 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
1452 pUsbIns->iInstance, bConfigurationValue));
1453 Assert(bConfigurationValue == 1);
1454 RTCritSectEnter(&pThis->CritSect);
1455
1456 /*
1457 * If the same config is applied more than once, it's a kind of reset.
1458 */
1459 if (pThis->bConfigurationValue == bConfigurationValue)
1460 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1461 pThis->bConfigurationValue = bConfigurationValue;
1462
1463 /*
1464 * Set received event type to absolute or relative.
1465 */
1466 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
1467 pThis->enmMode == USBHIDMODE_RELATIVE,
1468 pThis->enmMode == USBHIDMODE_ABSOLUTE,
1469 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1470
1471 RTCritSectLeave(&pThis->CritSect);
1472 return VINF_SUCCESS;
1473}
1474
1475
1476/**
1477 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1478 */
1479static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1480{
1481 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1482 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1483 switch (pThis->enmMode)
1484 {
1485 case USBHIDMODE_ABSOLUTE:
1486 return &g_UsbHidTDescCache;
1487 case USBHIDMODE_RELATIVE:
1488 return &g_UsbHidMDescCache;
1489 case USBHIDMODE_MULTI_TOUCH:
1490 return &g_UsbHidMTDescCache;
1491 default:
1492 return NULL;
1493 }
1494}
1495
1496
1497/**
1498 * @copydoc PDMUSBREG::pfnUsbReset
1499 */
1500static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1501{
1502 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1503 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
1504 RTCritSectEnter(&pThis->CritSect);
1505
1506 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
1507
1508 RTCritSectLeave(&pThis->CritSect);
1509 return rc;
1510}
1511
1512
1513/**
1514 * @copydoc PDMUSBREG::pfnDestruct
1515 */
1516static void usbHidDestruct(PPDMUSBINS pUsbIns)
1517{
1518 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1519 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
1520
1521 if (RTCritSectIsInitialized(&pThis->CritSect))
1522 {
1523 RTCritSectEnter(&pThis->CritSect);
1524 RTCritSectLeave(&pThis->CritSect);
1525 RTCritSectDelete(&pThis->CritSect);
1526 }
1527
1528 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1529 {
1530 RTSemEventDestroy(pThis->hEvtDoneQueue);
1531 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1532 }
1533}
1534
1535
1536/**
1537 * @copydoc PDMUSBREG::pfnConstruct
1538 */
1539static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1540{
1541 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1542 char szMode[64];
1543 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
1544
1545 /*
1546 * Perform the basic structure initialization first so the destructor
1547 * will not misbehave.
1548 */
1549 pThis->pUsbIns = pUsbIns;
1550 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1551 usbHidQueueInit(&pThis->ToHostQueue);
1552 usbHidQueueInit(&pThis->DoneQueue);
1553
1554 int rc = RTCritSectInit(&pThis->CritSect);
1555 AssertRCReturn(rc, rc);
1556
1557 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1558 AssertRCReturn(rc, rc);
1559
1560 /*
1561 * Validate and read the configuration.
1562 */
1563 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
1564 if (RT_FAILURE(rc))
1565 return rc;
1566 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
1567 if (RT_FAILURE(rc))
1568 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
1569 if (!RTStrCmp(szMode, "relative"))
1570 pThis->enmMode = USBHIDMODE_RELATIVE;
1571 else if (!RTStrCmp(szMode, "absolute"))
1572 pThis->enmMode = USBHIDMODE_ABSOLUTE;
1573 else if (!RTStrCmp(szMode, "multitouch"))
1574 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
1575 else
1576 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
1577 N_("Invalid HID device mode"));
1578
1579 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
1580 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
1581 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
1582 pThis->Lun0.IPort.pfnPutEventMT = usbHidMousePutEventMT;
1583
1584 /*
1585 * Attach the mouse driver.
1586 */
1587 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
1588 if (RT_FAILURE(rc))
1589 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
1590
1591 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
1592 if (!pThis->Lun0.pDrv)
1593 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
1594
1595 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
1596 if (RT_FAILURE(rc))
1597 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
1598
1599 return VINF_SUCCESS;
1600}
1601
1602
1603/**
1604 * The USB Human Interface Device (HID) Mouse registration record.
1605 */
1606const PDMUSBREG g_UsbHidMou =
1607{
1608 /* u32Version */
1609 PDM_USBREG_VERSION,
1610 /* szName */
1611 "HidMouse",
1612 /* pszDescription */
1613 "USB HID Mouse.",
1614 /* fFlags */
1615 0,
1616 /* cMaxInstances */
1617 ~0U,
1618 /* cbInstance */
1619 sizeof(USBHID),
1620 /* pfnConstruct */
1621 usbHidConstruct,
1622 /* pfnDestruct */
1623 usbHidDestruct,
1624 /* pfnVMInitComplete */
1625 NULL,
1626 /* pfnVMPowerOn */
1627 NULL,
1628 /* pfnVMReset */
1629 NULL,
1630 /* pfnVMSuspend */
1631 NULL,
1632 /* pfnVMResume */
1633 NULL,
1634 /* pfnVMPowerOff */
1635 NULL,
1636 /* pfnHotPlugged */
1637 NULL,
1638 /* pfnHotUnplugged */
1639 NULL,
1640 /* pfnDriverAttach */
1641 NULL,
1642 /* pfnDriverDetach */
1643 NULL,
1644 /* pfnQueryInterface */
1645 NULL,
1646 /* pfnUsbReset */
1647 usbHidUsbReset,
1648 /* pfnUsbGetDescriptorCache */
1649 usbHidUsbGetDescriptorCache,
1650 /* pfnUsbSetConfiguration */
1651 usbHidUsbSetConfiguration,
1652 /* pfnUsbSetInterface */
1653 usbHidUsbSetInterface,
1654 /* pfnUsbClearHaltedEndpoint */
1655 usbHidUsbClearHaltedEndpoint,
1656 /* pfnUrbNew */
1657 NULL/*usbHidUrbNew*/,
1658 /* pfnUrbQueue */
1659 usbHidQueue,
1660 /* pfnUrbCancel */
1661 usbHidUrbCancel,
1662 /* pfnUrbReap */
1663 usbHidUrbReap,
1664 /* u32TheEnd */
1665 PDM_USBREG_VERSION
1666};
Note: See TracBrowser for help on using the repository browser.

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