VirtualBox

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

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

Devices/input: more adjustments to the USB input device.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.2 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 bool 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 idContact;
247 uint16_t x;
248 uint16_t y;
249 uint8_t fButton;
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, 0x02, /* Logical */
394 /* Usage */ 0x09, 0x51, /* Contact Identifier */
395 /* Report Count */ 0x95, 0x01, /* 1 */
396 /* Report Size */ 0x75, 0x08, /* 8 */
397 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
398 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
399 /* Usage */ 0x09, 0x30, /* X */
400 /* Usage */ 0x09, 0x31, /* Y */
401 /* Logical Minimum */ 0x15, 0x00, /* 0 */
402 /* Logical Maximum */ 0x26, 0xFF,0x7F,/* 0x7fff */
403 /* Physical Minimum */ 0x35, 0x00, /* 0 */
404 /* Physical Maximum */ 0x46, 0xFF,0x7F,/* 0x7fff */
405 /* Report Size */ 0x75, 0x10, /* 16 */
406 /* Report Count */ 0x95, 0x02, /* 2 */
407 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
408 /* Usage Page */ 0x05, 0x0D, /* Digitisers */
409 /* Usage */ 0x09, 0x42, /* Tip Switch */
410 /* Logical Minimum */ 0x15, 0x00, /* 0 */
411 /* Logical Maximum */ 0x25, 0x01, /* 1 */
412 /* Report Count */ 0x95, 0x01, /* 1 */
413 /* Report Size */ 0x75, 0x01, /* 1 */
414 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
415 /* Report Count */ 0x95, 0x07, /* 7 */
416 /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
417 /* End Collection */ 0xC0,
418 /* Report ID */ 0x85, REPORTID_MAX_COUNT,
419 /* Usage */ 0x09, 0x55, /* Contact Count Maximum */
420 /* Report Count */ 0x95, 0x01, /* 1 */
421 /* Logical Maximum */ 0x25, 0x40, /* 64 */
422 /* Feature */ 0xB1, 0x03, /* Constant, Value, Absolute, Bit field */
423 /* End Collection */ 0xC0,
424};
425
426/** @todo Do these really have to all be duplicated three times? */
427/* Additional HID class interface descriptor. */
428static const uint8_t g_UsbHidMIfHidDesc[] =
429{
430 /* .bLength = */ 0x09,
431 /* .bDescriptorType = */ 0x21, /* HID */
432 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
433 /* .bCountryCode = */ 0,
434 /* .bNumDescriptors = */ 1,
435 /* .bDescriptorType = */ 0x22, /* Report */
436 /* .wDescriptorLength = */ sizeof(g_UsbHidMReportDesc), 0x00
437};
438
439/* Additional HID class interface descriptor. */
440static const uint8_t g_UsbHidTIfHidDesc[] =
441{
442 /* .bLength = */ 0x09,
443 /* .bDescriptorType = */ 0x21, /* HID */
444 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
445 /* .bCountryCode = */ 0,
446 /* .bNumDescriptors = */ 1,
447 /* .bDescriptorType = */ 0x22, /* Report */
448 /* .wDescriptorLength = */ sizeof(g_UsbHidTReportDesc), 0x00
449};
450
451/* Additional HID class interface descriptor. */
452static const uint8_t g_UsbHidMTIfHidDesc[] =
453{
454 /* .bLength = */ 0x09,
455 /* .bDescriptorType = */ 0x21, /* HID */
456 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
457 /* .bCountryCode = */ 0,
458 /* .bNumDescriptors = */ 1,
459 /* .bDescriptorType = */ 0x22, /* Report */
460 /* .wDescriptorLength = */ sizeof(g_UsbHidMTReportDesc), 0x00
461};
462
463static const VUSBDESCINTERFACEEX g_UsbHidMInterfaceDesc =
464{
465 {
466 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
467 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
468 /* .bInterfaceNumber = */ 0,
469 /* .bAlternateSetting = */ 0,
470 /* .bNumEndpoints = */ 1,
471 /* .bInterfaceClass = */ 3 /* HID */,
472 /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
473 /* .bInterfaceProtocol = */ 2 /* Mouse */,
474 /* .iInterface = */ 0
475 },
476 /* .pvMore = */ NULL,
477 /* .pvClass = */ &g_UsbHidMIfHidDesc,
478 /* .cbClass = */ sizeof(g_UsbHidMIfHidDesc),
479 &g_aUsbHidMEndpointDescs[0],
480 /* .pIAD = */ NULL,
481 /* .cbIAD = */ 0
482};
483
484static const VUSBDESCINTERFACEEX g_UsbHidTInterfaceDesc =
485{
486 {
487 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
488 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
489 /* .bInterfaceNumber = */ 0,
490 /* .bAlternateSetting = */ 0,
491 /* .bNumEndpoints = */ 1,
492 /* .bInterfaceClass = */ 3 /* HID */,
493 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
494 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
495 /* .iInterface = */ 0
496 },
497 /* .pvMore = */ NULL,
498 /* .pvClass = */ &g_UsbHidTIfHidDesc,
499 /* .cbClass = */ sizeof(g_UsbHidTIfHidDesc),
500 &g_aUsbHidTEndpointDescs[0],
501 /* .pIAD = */ NULL,
502 /* .cbIAD = */ 0
503};
504
505static const VUSBDESCINTERFACEEX g_UsbHidMTInterfaceDesc =
506{
507 {
508 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
509 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
510 /* .bInterfaceNumber = */ 0,
511 /* .bAlternateSetting = */ 0,
512 /* .bNumEndpoints = */ 1,
513 /* .bInterfaceClass = */ 3 /* HID */,
514 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
515 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
516 /* .iInterface = */ 0
517 },
518 /* .pvMore = */ NULL,
519 /* .pvClass = */ &g_UsbHidMTIfHidDesc,
520 /* .cbClass = */ sizeof(g_UsbHidMTIfHidDesc),
521 &g_aUsbHidTEndpointDescs[0],
522 /* .pIAD = */ NULL,
523 /* .cbIAD = */ 0
524};
525
526static const VUSBINTERFACE g_aUsbHidMInterfaces[] =
527{
528 { &g_UsbHidMInterfaceDesc, /* .cSettings = */ 1 },
529};
530
531static const VUSBINTERFACE g_aUsbHidTInterfaces[] =
532{
533 { &g_UsbHidTInterfaceDesc, /* .cSettings = */ 1 },
534};
535
536static const VUSBINTERFACE g_aUsbHidMTInterfaces[] =
537{
538 { &g_UsbHidMTInterfaceDesc, /* .cSettings = */ 1 },
539};
540
541static const VUSBDESCCONFIGEX g_UsbHidMConfigDesc =
542{
543 {
544 /* .bLength = */ sizeof(VUSBDESCCONFIG),
545 /* .bDescriptorType = */ VUSB_DT_CONFIG,
546 /* .wTotalLength = */ 0 /* recalculated on read */,
547 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMInterfaces),
548 /* .bConfigurationValue =*/ 1,
549 /* .iConfiguration = */ 0,
550 /* .bmAttributes = */ RT_BIT(7),
551 /* .MaxPower = */ 50 /* 100mA */
552 },
553 NULL, /* pvMore */
554 &g_aUsbHidMInterfaces[0],
555 NULL /* pvOriginal */
556};
557
558static const VUSBDESCCONFIGEX g_UsbHidTConfigDesc =
559{
560 {
561 /* .bLength = */ sizeof(VUSBDESCCONFIG),
562 /* .bDescriptorType = */ VUSB_DT_CONFIG,
563 /* .wTotalLength = */ 0 /* recalculated on read */,
564 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidTInterfaces),
565 /* .bConfigurationValue =*/ 1,
566 /* .iConfiguration = */ 0,
567 /* .bmAttributes = */ RT_BIT(7),
568 /* .MaxPower = */ 50 /* 100mA */
569 },
570 NULL, /* pvMore */
571 &g_aUsbHidTInterfaces[0],
572 NULL /* pvOriginal */
573};
574
575static const VUSBDESCCONFIGEX g_UsbHidMTConfigDesc =
576{
577 {
578 /* .bLength = */ sizeof(VUSBDESCCONFIG),
579 /* .bDescriptorType = */ VUSB_DT_CONFIG,
580 /* .wTotalLength = */ 0 /* recalculated on read */,
581 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMTInterfaces),
582 /* .bConfigurationValue =*/ 1,
583 /* .iConfiguration = */ 0,
584 /* .bmAttributes = */ RT_BIT(7),
585 /* .MaxPower = */ 50 /* 100mA */
586 },
587 NULL, /* pvMore */
588 &g_aUsbHidMTInterfaces[0],
589 NULL /* pvOriginal */
590};
591
592static const VUSBDESCDEVICE g_UsbHidMDeviceDesc =
593{
594 /* .bLength = */ sizeof(g_UsbHidMDeviceDesc),
595 /* .bDescriptorType = */ VUSB_DT_DEVICE,
596 /* .bcdUsb = */ 0x110, /* 1.1 */
597 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
598 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
599 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
600 /* .bMaxPacketSize0 = */ 8,
601 /* .idVendor = */ VBOX_USB_VENDOR,
602 /* .idProduct = */ USBHID_PID_MOUSE,
603 /* .bcdDevice = */ 0x0100, /* 1.0 */
604 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
605 /* .iProduct = */ USBHID_STR_ID_PRODUCT_M,
606 /* .iSerialNumber = */ 0,
607 /* .bNumConfigurations = */ 1
608};
609
610static const VUSBDESCDEVICE g_UsbHidTDeviceDesc =
611{
612 /* .bLength = */ sizeof(g_UsbHidTDeviceDesc),
613 /* .bDescriptorType = */ VUSB_DT_DEVICE,
614 /* .bcdUsb = */ 0x110, /* 1.1 */
615 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
616 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
617 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
618 /* .bMaxPacketSize0 = */ 8,
619 /* .idVendor = */ VBOX_USB_VENDOR,
620 /* .idProduct = */ USBHID_PID_TABLET,
621 /* .bcdDevice = */ 0x0100, /* 1.0 */
622 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
623 /* .iProduct = */ USBHID_STR_ID_PRODUCT_T,
624 /* .iSerialNumber = */ 0,
625 /* .bNumConfigurations = */ 1
626};
627
628static const VUSBDESCDEVICE g_UsbHidMTDeviceDesc =
629{
630 /* .bLength = */ sizeof(g_UsbHidMTDeviceDesc),
631 /* .bDescriptorType = */ VUSB_DT_DEVICE,
632 /* .bcdUsb = */ 0x110, /* 1.1 */
633 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
634 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
635 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
636 /* .bMaxPacketSize0 = */ 8,
637 /* .idVendor = */ VBOX_USB_VENDOR,
638 /* .idProduct = */ USBHID_PID_MULTI_TOUCH,
639 /* .bcdDevice = */ 0x0100, /* 1.0 */
640 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
641 /* .iProduct = */ USBHID_STR_ID_PRODUCT_MT,
642 /* .iSerialNumber = */ 0,
643 /* .bNumConfigurations = */ 1
644};
645
646static const PDMUSBDESCCACHE g_UsbHidMDescCache =
647{
648 /* .pDevice = */ &g_UsbHidMDeviceDesc,
649 /* .paConfigs = */ &g_UsbHidMConfigDesc,
650 /* .paLanguages = */ g_aUsbHidLanguages,
651 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
652 /* .fUseCachedDescriptors = */ true,
653 /* .fUseCachedStringsDescriptors = */ true
654};
655
656static const PDMUSBDESCCACHE g_UsbHidTDescCache =
657{
658 /* .pDevice = */ &g_UsbHidTDeviceDesc,
659 /* .paConfigs = */ &g_UsbHidTConfigDesc,
660 /* .paLanguages = */ g_aUsbHidLanguages,
661 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
662 /* .fUseCachedDescriptors = */ true,
663 /* .fUseCachedStringsDescriptors = */ true
664};
665
666static const PDMUSBDESCCACHE g_UsbHidMTDescCache =
667{
668 /* .pDevice = */ &g_UsbHidMTDeviceDesc,
669 /* .paConfigs = */ &g_UsbHidMTConfigDesc,
670 /* .paLanguages = */ g_aUsbHidLanguages,
671 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
672 /* .fUseCachedDescriptors = */ true,
673 /* .fUseCachedStringsDescriptors = */ true
674};
675
676
677/*******************************************************************************
678* Internal Functions *
679*******************************************************************************/
680
681/**
682 * Initializes an URB queue.
683 *
684 * @param pQueue The URB queue.
685 */
686static void usbHidQueueInit(PUSBHIDURBQUEUE pQueue)
687{
688 pQueue->pHead = NULL;
689 pQueue->ppTail = &pQueue->pHead;
690}
691
692
693
694/**
695 * Inserts an URB at the end of the queue.
696 *
697 * @param pQueue The URB queue.
698 * @param pUrb The URB to insert.
699 */
700DECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
701{
702 pUrb->Dev.pNext = NULL;
703 *pQueue->ppTail = pUrb;
704 pQueue->ppTail = &pUrb->Dev.pNext;
705}
706
707
708/**
709 * Unlinks the head of the queue and returns it.
710 *
711 * @returns The head entry.
712 * @param pQueue The URB queue.
713 */
714DECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
715{
716 PVUSBURB pUrb = pQueue->pHead;
717 if (pUrb)
718 {
719 PVUSBURB pNext = pUrb->Dev.pNext;
720 pQueue->pHead = pNext;
721 if (!pNext)
722 pQueue->ppTail = &pQueue->pHead;
723 else
724 pUrb->Dev.pNext = NULL;
725 }
726 return pUrb;
727}
728
729
730/**
731 * Removes an URB from anywhere in the queue.
732 *
733 * @returns true if found, false if not.
734 * @param pQueue The URB queue.
735 * @param pUrb The URB to remove.
736 */
737DECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
738{
739 PVUSBURB pCur = pQueue->pHead;
740 if (pCur == pUrb)
741 pQueue->pHead = pUrb->Dev.pNext;
742 else
743 {
744 while (pCur)
745 {
746 if (pCur->Dev.pNext == pUrb)
747 {
748 pCur->Dev.pNext = pUrb->Dev.pNext;
749 break;
750 }
751 pCur = pCur->Dev.pNext;
752 }
753 if (!pCur)
754 return false;
755 }
756 if (!pUrb->Dev.pNext)
757 pQueue->ppTail = &pQueue->pHead;
758 return true;
759}
760
761
762/**
763 * Checks if the queue is empty or not.
764 *
765 * @returns true if it is, false if it isn't.
766 * @param pQueue The URB queue.
767 */
768DECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
769{
770 return pQueue->pHead == NULL;
771}
772
773
774/**
775 * Links an URB into the done queue.
776 *
777 * @param pThis The HID instance.
778 * @param pUrb The URB.
779 */
780static void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
781{
782 usbHidQueueAddTail(&pThis->DoneQueue, pUrb);
783
784 if (pThis->fHaveDoneQueueWaiter)
785 {
786 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
787 AssertRC(rc);
788 }
789}
790
791
792
793/**
794 * Completes the URB with a stalled state, halting the pipe.
795 */
796static int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
797{
798 LogRelFlow(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n",
799 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
800
801 pUrb->enmStatus = VUSBSTATUS_STALL;
802
803 /** @todo figure out if the stall is global or pipe-specific or both. */
804 if (pEp)
805 pEp->fHalted = true;
806 else
807 {
808 pThis->aEps[0].fHalted = true;
809 pThis->aEps[1].fHalted = true;
810 }
811
812 usbHidLinkDone(pThis, pUrb);
813 return VINF_SUCCESS;
814}
815
816
817/**
818 * Completes the URB with a OK state.
819 */
820static int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, size_t cbData)
821{
822 LogRelFlow(("usbHidCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n",
823 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
824
825 pUrb->enmStatus = VUSBSTATUS_OK;
826 pUrb->cbData = (uint32_t)cbData;
827
828 usbHidLinkDone(pThis, pUrb);
829 return VINF_SUCCESS;
830}
831
832
833/**
834 * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
835 * usbHidHandleDefaultPipe.
836 *
837 * @returns VBox status code.
838 * @param pThis The HID instance.
839 * @param pUrb Set when usbHidHandleDefaultPipe is the
840 * caller.
841 * @param fSetConfig Set when usbHidUsbSetConfiguration is the
842 * caller.
843 */
844static int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
845{
846 /*
847 * Wait for the any command currently executing to complete before
848 * resetting. (We cannot cancel its execution.) How we do this depends
849 * on the reset method.
850 */
851
852 /*
853 * Reset the device state.
854 */
855 pThis->enmState = USBHIDREQSTATE_READY;
856 pThis->fHasPendingChanges = false;
857
858 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
859 pThis->aEps[i].fHalted = false;
860
861 if (!pUrb && !fSetConfig) /* (only device reset) */
862 pThis->bConfigurationValue = 0; /* default */
863
864 /*
865 * Ditch all pending URBs.
866 */
867 PVUSBURB pCurUrb;
868 while ((pCurUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
869 {
870 pCurUrb->enmStatus = VUSBSTATUS_CRC;
871 usbHidLinkDone(pThis, pCurUrb);
872 }
873
874 if (pUrb)
875 return usbHidCompleteOk(pThis, pUrb, 0);
876 return VINF_SUCCESS;
877}
878
879static int8_t clamp_i8(int32_t val)
880{
881 if (val > 127) {
882 val = 127;
883 } else if (val < -127) {
884 val = -127;
885 }
886 return val;
887}
888
889/**
890 * Create a USB HID report report based on the currently accumulated data.
891 */
892static size_t usbHidFillReport(PUSBHIDTM_REPORT pReport,
893 PUSBHIDM_ACCUM pAccumulated, USBHIDMODE enmMode)
894{
895 size_t cbCopy;
896
897 switch (enmMode)
898 {
899 case USBHIDMODE_ABSOLUTE:
900 {
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 }
911 case USBHIDMODE_RELATIVE:
912 {
913 pReport->m.fButtons = pAccumulated->u.Relative.fButtons;
914 pReport->m.dx = clamp_i8(pAccumulated->u.Relative.dx);
915 pReport->m.dy = clamp_i8(pAccumulated->u.Relative.dy);
916 pReport->m.dz = clamp_i8(pAccumulated->u.Relative.dz);
917
918 cbCopy = sizeof(pReport->m);
919 LogRel3(("Rel event, dx=%d, dy=%d, dz=%d, fButtons=%02x, report size %d\n",
920 pReport->m.dx, pReport->m.dy, pReport->m.dz,
921 pReport->m.fButtons, cbCopy));
922 break;
923 }
924 case USBHIDMODE_MULTI_TOUCH:
925 {
926 pReport->mt.idReport = REPORTID_MOUSE;
927 pReport->mt.idContact = pAccumulated->u.MultiTouch.cContact;
928 pReport->mt.x = pAccumulated->u.MultiTouch.x;
929 pReport->mt.y = pAccumulated->u.MultiTouch.y;
930 pReport->mt.fButton = pAccumulated->u.MultiTouch.fContact;
931
932 cbCopy = sizeof(pReport->t);
933 LogRel3(("Multi-touch event, x=%u, y=%u, report size %d\n",
934 pReport->mt.x, pReport->mt.y, cbCopy));
935 break;
936 }
937 }
938
939 /* Clear the accumulated movement. */
940 RT_ZERO(*pAccumulated);
941
942 return cbCopy;
943}
944
945/**
946 * Sends a state report to the host if there is a pending URB.
947 */
948static int usbHidSendReport(PUSBHID pThis)
949{
950 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
951
952 if (pUrb)
953 {
954 PUSBHIDTM_REPORT pReport = (PUSBHIDTM_REPORT)&pUrb->abData[0];
955 size_t cbCopy;
956
957 cbCopy = usbHidFillReport(pReport, &pThis->PtrDelta, pThis->enmMode);
958 pThis->fHasPendingChanges = false;
959 return usbHidCompleteOk(pThis, pUrb, cbCopy);
960 }
961 else
962 {
963 LogRelFlow(("No available URB for USB mouse\n"));
964 pThis->fHasPendingChanges = true;
965 }
966 return VINF_EOF;
967}
968
969/**
970 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
971 */
972static DECLCALLBACK(void *) usbHidMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
973{
974 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
975 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
976 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Lun0.IPort);
977 return NULL;
978}
979
980/**
981 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
982 */
983static DECLCALLBACK(int) usbHidMousePutEvent(PPDMIMOUSEPORT pInterface,
984 int32_t dx, int32_t dy, int32_t dz,
985 int32_t dw, uint32_t fButtons)
986{
987 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
988 RTCritSectEnter(&pThis->CritSect);
989
990 /* Accumulate movement - the events from the front end may arrive
991 * at a much higher rate than USB can handle.
992 */
993 pThis->PtrDelta.u.Relative.fButtons = fButtons;
994 pThis->PtrDelta.u.Relative.dx += dx;
995 pThis->PtrDelta.u.Relative.dy += dy;
996 pThis->PtrDelta.u.Relative.dz -= dz; /* Inverted! */
997
998 /* Send a report if possible. */
999 usbHidSendReport(pThis);
1000
1001 RTCritSectLeave(&pThis->CritSect);
1002 return VINF_SUCCESS;
1003}
1004
1005/**
1006 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
1007 */
1008static DECLCALLBACK(int) usbHidMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1009 uint32_t x, uint32_t y,
1010 int32_t dz, int32_t dw,
1011 uint32_t fButtons)
1012{
1013 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1014 RTCritSectEnter(&pThis->CritSect);
1015
1016 Assert(pThis->enmMode == USBHIDMODE_ABSOLUTE);
1017
1018 /* Accumulate movement - the events from the front end may arrive
1019 * at a much higher rate than USB can handle. Probably not a real issue
1020 * when only the Z axis is relative (X/Y movement isn't technically
1021 * accumulated and only the last value is used).
1022 */
1023 pThis->PtrDelta.u.Absolute.fButtons = fButtons;
1024 pThis->PtrDelta.u.Absolute.x = x >> pThis->u8CoordShift;
1025 pThis->PtrDelta.u.Absolute.y = y >> pThis->u8CoordShift;
1026
1027 /* Send a report if possible. */
1028 usbHidSendReport(pThis);
1029
1030 RTCritSectLeave(&pThis->CritSect);
1031 return VINF_SUCCESS;
1032}
1033
1034/**
1035 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMT}
1036 */
1037static DECLCALLBACK(int) usbHidMousePutEventMT(PPDMIMOUSEPORT pInterface,
1038 uint32_t x, uint32_t y,
1039 uint32_t cContact,
1040 bool fContact)
1041{
1042 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1043 RTCritSectEnter(&pThis->CritSect);
1044
1045 Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1046
1047 /* Accumulate movement - the events from the front end may arrive
1048 * at a much higher rate than USB can handle. Probably not a real issue
1049 * when only the Z axis is relative (X/Y movement isn't technically
1050 * accumulated and only the last value is used).
1051 */
1052 pThis->PtrDelta.u.MultiTouch.fContact = fContact;
1053 pThis->PtrDelta.u.MultiTouch.x = x;
1054 pThis->PtrDelta.u.MultiTouch.y = y;
1055 pThis->PtrDelta.u.MultiTouch.cContact = cContact;
1056
1057 /* Send a report if possible. */
1058 usbHidSendReport(pThis);
1059
1060 RTCritSectLeave(&pThis->CritSect);
1061 return VINF_SUCCESS;
1062}
1063
1064/**
1065 * @copydoc PDMUSBREG::pfnUrbReap
1066 */
1067static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1068{
1069 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1070 LogRelFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1071
1072 RTCritSectEnter(&pThis->CritSect);
1073
1074 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1075 if (!pUrb && cMillies)
1076 {
1077 /* Wait */
1078 pThis->fHaveDoneQueueWaiter = true;
1079 RTCritSectLeave(&pThis->CritSect);
1080
1081 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1082
1083 RTCritSectEnter(&pThis->CritSect);
1084 pThis->fHaveDoneQueueWaiter = false;
1085
1086 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1087 }
1088
1089 RTCritSectLeave(&pThis->CritSect);
1090
1091 if (pUrb)
1092 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1093 pUrb->pszDesc));
1094 return pUrb;
1095}
1096
1097
1098/**
1099 * @copydoc PDMUSBREG::pfnUrbCancel
1100 */
1101static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1102{
1103 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1104 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1105 pUrb->pszDesc));
1106 RTCritSectEnter(&pThis->CritSect);
1107
1108 /*
1109 * Remove the URB from the to-host queue and move it onto the done queue.
1110 */
1111 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1112 usbHidLinkDone(pThis, pUrb);
1113
1114 RTCritSectLeave(&pThis->CritSect);
1115 return VINF_SUCCESS;
1116}
1117
1118
1119/**
1120 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1121 * rather different from bulk requests because an interrupt read URB may complete
1122 * after arbitrarily long time.
1123 */
1124static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1125{
1126 /*
1127 * Stall the request if the pipe is halted.
1128 */
1129 if (RT_UNLIKELY(pEp->fHalted))
1130 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1131
1132 /*
1133 * Deal with the URB according to the state.
1134 */
1135 switch (pThis->enmState)
1136 {
1137 /*
1138 * We've data left to transfer to the host.
1139 */
1140 case USBHIDREQSTATE_DATA_TO_HOST:
1141 {
1142 AssertFailed();
1143 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1144 return usbHidCompleteOk(pThis, pUrb, 0);
1145 }
1146
1147 /*
1148 * Status transfer.
1149 */
1150 case USBHIDREQSTATE_STATUS:
1151 {
1152 AssertFailed();
1153 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1154 pThis->enmState = USBHIDREQSTATE_READY;
1155 return usbHidCompleteOk(pThis, pUrb, 0);
1156 }
1157
1158 case USBHIDREQSTATE_READY:
1159 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1160 /* If a report is pending, send it right away. */
1161 if (pThis->fHasPendingChanges)
1162 usbHidSendReport(pThis);
1163 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1164 pUrb, pUrb->pszDesc));
1165 return VINF_SUCCESS;
1166
1167 /*
1168 * Bad states, stall.
1169 */
1170 default:
1171 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1172 pThis->enmState, pUrb->cbData));
1173 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1174 }
1175}
1176
1177
1178/**
1179 * Handles request sent to the default control pipe.
1180 */
1181static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1182{
1183 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1184 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1185
1186 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1187 {
1188 switch (pSetup->bRequest)
1189 {
1190 case VUSB_REQ_GET_DESCRIPTOR:
1191 {
1192 switch (pSetup->bmRequestType)
1193 {
1194 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1195 {
1196 switch (pSetup->wValue >> 8)
1197 {
1198 case VUSB_DT_STRING:
1199 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1200 pSetup->wValue, pSetup->wIndex));
1201 break;
1202 default:
1203 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1204 pSetup->wValue, pSetup->wIndex));
1205 break;
1206 }
1207 break;
1208 }
1209
1210 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1211 {
1212 switch (pSetup->wValue >> 8)
1213 {
1214 uint32_t cbCopy;
1215 uint32_t cbDesc;
1216 const uint8_t *pDesc;
1217
1218 case DT_IF_HID_DESCRIPTOR:
1219 {
1220 switch (pThis->enmMode)
1221 {
1222 case USBHIDMODE_ABSOLUTE:
1223 {
1224 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1225 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1226 break;
1227 }
1228 case USBHIDMODE_RELATIVE:
1229 {
1230 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1231 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1232 break;
1233 }
1234 case USBHIDMODE_MULTI_TOUCH:
1235 {
1236 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1237 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1238 break;
1239 }
1240 }
1241 /* Returned data is written after the setup message. */
1242 cbCopy = pUrb->cbData - sizeof(*pSetup);
1243 cbCopy = RT_MIN(cbCopy, cbDesc);
1244 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1245 pSetup->wValue, pSetup->wIndex,
1246 cbCopy));
1247 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1248 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1249 }
1250
1251 case DT_IF_HID_REPORT:
1252 {
1253 switch (pThis->enmMode)
1254 {
1255 case USBHIDMODE_ABSOLUTE:
1256 {
1257 cbDesc = sizeof(g_UsbHidTReportDesc);
1258 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
1259 break;
1260 }
1261 case USBHIDMODE_RELATIVE:
1262 {
1263 cbDesc = sizeof(g_UsbHidMReportDesc);
1264 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
1265 break;
1266 }
1267 case USBHIDMODE_MULTI_TOUCH:
1268 {
1269 cbDesc = sizeof(g_UsbHidMTReportDesc);
1270 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
1271 break;
1272 }
1273 }
1274 /* Returned data is written after the setup message. */
1275 cbCopy = pUrb->cbData - sizeof(*pSetup);
1276 cbCopy = RT_MIN(cbCopy, cbDesc);
1277 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
1278 pSetup->wValue, pSetup->wIndex,
1279 cbCopy));
1280 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1281 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1282 }
1283
1284 default:
1285 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1286 pSetup->wValue, pSetup->wIndex));
1287 break;
1288 }
1289 break;
1290 }
1291
1292 default:
1293 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
1294 pSetup->bmRequestType));
1295 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1296 }
1297 break;
1298 }
1299
1300 case VUSB_REQ_GET_STATUS:
1301 {
1302 uint16_t wRet = 0;
1303
1304 if (pSetup->wLength != 2)
1305 {
1306 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
1307 pSetup->wLength));
1308 break;
1309 }
1310 Assert(pSetup->wValue == 0);
1311 switch (pSetup->bmRequestType)
1312 {
1313 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1314 {
1315 Assert(pSetup->wIndex == 0);
1316 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
1317 wRet = 0; /* Not self-powered, no remote wakeup. */
1318 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1319 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1320 }
1321
1322 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1323 {
1324 if (pSetup->wIndex == 0)
1325 {
1326 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1327 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1328 }
1329 else
1330 {
1331 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
1332 pSetup->wIndex));
1333 }
1334 break;
1335 }
1336
1337 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1338 {
1339 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1340 {
1341 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1342 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1343 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1344 }
1345 else
1346 {
1347 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
1348 pSetup->wIndex));
1349 }
1350 break;
1351 }
1352
1353 default:
1354 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
1355 pSetup->bmRequestType));
1356 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
1357 }
1358 break;
1359 }
1360
1361 case VUSB_REQ_CLEAR_FEATURE:
1362 break;
1363 }
1364
1365 /** @todo implement this. */
1366 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1367 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1368 pSetup->wIndex, pSetup->wLength));
1369
1370 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1371 }
1372 /* 3.1 Bulk-Only Mass Storage Reset */
1373 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
1374 && pSetup->bRequest == 0xff
1375 && !pSetup->wValue
1376 && !pSetup->wLength
1377 && pSetup->wIndex == 0)
1378 {
1379 LogRelFlow(("usbHidHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
1380 return usbHidResetWorker(pThis, pUrb, false /*fSetConfig*/);
1381 }
1382 else
1383 {
1384 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1385 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1386 pSetup->wIndex, pSetup->wLength));
1387 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1388 }
1389
1390 return VINF_SUCCESS;
1391}
1392
1393
1394/**
1395 * @copydoc PDMUSBREG::pfnUrbQueue
1396 */
1397static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1398{
1399 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1400 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
1401 pUrb, pUrb->pszDesc, pUrb->EndPt));
1402 RTCritSectEnter(&pThis->CritSect);
1403
1404 /*
1405 * Parse on a per end-point basis.
1406 */
1407 int rc;
1408 switch (pUrb->EndPt)
1409 {
1410 case 0:
1411 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1412 break;
1413
1414 case 0x81:
1415 AssertFailed();
1416 case 0x01:
1417 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
1418 break;
1419
1420 default:
1421 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1422 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1423 break;
1424 }
1425
1426 RTCritSectLeave(&pThis->CritSect);
1427 return rc;
1428}
1429
1430
1431/**
1432 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1433 */
1434static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1435{
1436 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1437 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
1438 pUsbIns->iInstance, uEndpoint));
1439
1440 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1441 {
1442 RTCritSectEnter(&pThis->CritSect);
1443 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1444 RTCritSectLeave(&pThis->CritSect);
1445 }
1446
1447 return VINF_SUCCESS;
1448}
1449
1450
1451/**
1452 * @copydoc PDMUSBREG::pfnUsbSetInterface
1453 */
1454static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1455{
1456 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
1457 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1458 Assert(bAlternateSetting == 0);
1459 return VINF_SUCCESS;
1460}
1461
1462
1463/**
1464 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1465 */
1466static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1467 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1468{
1469 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1470 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
1471 pUsbIns->iInstance, bConfigurationValue));
1472 Assert(bConfigurationValue == 1);
1473 RTCritSectEnter(&pThis->CritSect);
1474
1475 /*
1476 * If the same config is applied more than once, it's a kind of reset.
1477 */
1478 if (pThis->bConfigurationValue == bConfigurationValue)
1479 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1480 pThis->bConfigurationValue = bConfigurationValue;
1481
1482 /*
1483 * Set received event type to absolute or relative.
1484 */
1485 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
1486 pThis->enmMode == USBHIDMODE_RELATIVE,
1487 pThis->enmMode == USBHIDMODE_ABSOLUTE,
1488 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1489
1490 RTCritSectLeave(&pThis->CritSect);
1491 return VINF_SUCCESS;
1492}
1493
1494
1495/**
1496 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1497 */
1498static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1499{
1500 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1501 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1502 switch (pThis->enmMode)
1503 {
1504 case USBHIDMODE_ABSOLUTE:
1505 return &g_UsbHidTDescCache;
1506 case USBHIDMODE_RELATIVE:
1507 return &g_UsbHidMDescCache;
1508 case USBHIDMODE_MULTI_TOUCH:
1509 return &g_UsbHidMTDescCache;
1510 default:
1511 return NULL;
1512 }
1513}
1514
1515
1516/**
1517 * @copydoc PDMUSBREG::pfnUsbReset
1518 */
1519static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1520{
1521 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1522 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
1523 RTCritSectEnter(&pThis->CritSect);
1524
1525 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
1526
1527 RTCritSectLeave(&pThis->CritSect);
1528 return rc;
1529}
1530
1531
1532/**
1533 * @copydoc PDMUSBREG::pfnDestruct
1534 */
1535static void usbHidDestruct(PPDMUSBINS pUsbIns)
1536{
1537 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1538 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
1539
1540 if (RTCritSectIsInitialized(&pThis->CritSect))
1541 {
1542 RTCritSectEnter(&pThis->CritSect);
1543 RTCritSectLeave(&pThis->CritSect);
1544 RTCritSectDelete(&pThis->CritSect);
1545 }
1546
1547 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1548 {
1549 RTSemEventDestroy(pThis->hEvtDoneQueue);
1550 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1551 }
1552}
1553
1554
1555/**
1556 * @copydoc PDMUSBREG::pfnConstruct
1557 */
1558static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1559{
1560 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1561 char szMode[64];
1562 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
1563
1564 /*
1565 * Perform the basic structure initialization first so the destructor
1566 * will not misbehave.
1567 */
1568 pThis->pUsbIns = pUsbIns;
1569 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1570 usbHidQueueInit(&pThis->ToHostQueue);
1571 usbHidQueueInit(&pThis->DoneQueue);
1572
1573 int rc = RTCritSectInit(&pThis->CritSect);
1574 AssertRCReturn(rc, rc);
1575
1576 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1577 AssertRCReturn(rc, rc);
1578
1579 /*
1580 * Validate and read the configuration.
1581 */
1582 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
1583 if (RT_FAILURE(rc))
1584 return rc;
1585 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
1586 if (RT_FAILURE(rc))
1587 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
1588 if (!RTStrCmp(szMode, "relative"))
1589 pThis->enmMode = USBHIDMODE_RELATIVE;
1590 else if (!RTStrCmp(szMode, "absolute"))
1591 pThis->enmMode = USBHIDMODE_ABSOLUTE;
1592 else if (!RTStrCmp(szMode, "multitouch"))
1593 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
1594 else
1595 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
1596 N_("Invalid HID device mode"));
1597
1598 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
1599 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
1600 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
1601
1602 /*
1603 * Attach the mouse driver.
1604 */
1605 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
1606 if (RT_FAILURE(rc))
1607 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
1608
1609 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
1610 if (!pThis->Lun0.pDrv)
1611 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
1612
1613 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
1614 if (RT_FAILURE(rc))
1615 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
1616
1617 return VINF_SUCCESS;
1618}
1619
1620
1621/**
1622 * The USB Human Interface Device (HID) Mouse registration record.
1623 */
1624const PDMUSBREG g_UsbHidMou =
1625{
1626 /* u32Version */
1627 PDM_USBREG_VERSION,
1628 /* szName */
1629 "HidMouse",
1630 /* pszDescription */
1631 "USB HID Mouse.",
1632 /* fFlags */
1633 0,
1634 /* cMaxInstances */
1635 ~0U,
1636 /* cbInstance */
1637 sizeof(USBHID),
1638 /* pfnConstruct */
1639 usbHidConstruct,
1640 /* pfnDestruct */
1641 usbHidDestruct,
1642 /* pfnVMInitComplete */
1643 NULL,
1644 /* pfnVMPowerOn */
1645 NULL,
1646 /* pfnVMReset */
1647 NULL,
1648 /* pfnVMSuspend */
1649 NULL,
1650 /* pfnVMResume */
1651 NULL,
1652 /* pfnVMPowerOff */
1653 NULL,
1654 /* pfnHotPlugged */
1655 NULL,
1656 /* pfnHotUnplugged */
1657 NULL,
1658 /* pfnDriverAttach */
1659 NULL,
1660 /* pfnDriverDetach */
1661 NULL,
1662 /* pfnQueryInterface */
1663 NULL,
1664 /* pfnUsbReset */
1665 usbHidUsbReset,
1666 /* pfnUsbGetDescriptorCache */
1667 usbHidUsbGetDescriptorCache,
1668 /* pfnUsbSetConfiguration */
1669 usbHidUsbSetConfiguration,
1670 /* pfnUsbSetInterface */
1671 usbHidUsbSetInterface,
1672 /* pfnUsbClearHaltedEndpoint */
1673 usbHidUsbClearHaltedEndpoint,
1674 /* pfnUrbNew */
1675 NULL/*usbHidUrbNew*/,
1676 /* pfnUrbQueue */
1677 usbHidQueue,
1678 /* pfnUrbCancel */
1679 usbHidUrbCancel,
1680 /* pfnUrbReap */
1681 usbHidUrbReap,
1682 /* u32TheEnd */
1683 PDM_USBREG_VERSION
1684};
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