VirtualBox

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

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

pdmifs: fix putEventMT definition.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 57.3 KB
Line 
1/** @file
2 * UsbMouse - USB Human Interface Device Emulation (Mouse).
3 */
4
5/*
6 * Copyright (C) 2007-2012 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17/*******************************************************************************
18* Header Files *
19*******************************************************************************/
20#define LOG_GROUP LOG_GROUP_USB_MOUSE
21#include <VBox/vmm/pdmusb.h>
22#include <VBox/log.h>
23#include <VBox/err.h>
24#include <iprt/assert.h>
25#include <iprt/critsect.h>
26#include <iprt/mem.h>
27#include <iprt/semaphore.h>
28#include <iprt/string.h>
29#include <iprt/uuid.h>
30#include "VBoxDD.h"
31
32
33/*******************************************************************************
34* Defined Constants And Macros *
35*******************************************************************************/
36/** @name USB HID string IDs
37 * @{ */
38#define USBHID_STR_ID_MANUFACTURER 1
39#define USBHID_STR_ID_PRODUCT_M 2
40#define USBHID_STR_ID_PRODUCT_T 3
41#define USBHID_STR_ID_PRODUCT_MT 4
42/** @} */
43
44/** @name USB HID specific descriptor types
45 * @{ */
46#define DT_IF_HID_DESCRIPTOR 0x21
47#define DT_IF_HID_REPORT 0x22
48/** @} */
49
50/** @name USB HID vendor and product IDs
51 * @{ */
52#define VBOX_USB_VENDOR 0x80EE
53#define USBHID_PID_MOUSE 0x0020
54#define USBHID_PID_TABLET 0x0021
55#define USBHID_PID_MULTI_TOUCH 0x0022
56/** @} */
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61
62/**
63 * The USB HID request state.
64 */
65typedef enum USBHIDREQSTATE
66{
67 /** Invalid status. */
68 USBHIDREQSTATE_INVALID = 0,
69 /** Ready to receive a new read request. */
70 USBHIDREQSTATE_READY,
71 /** Have (more) data for the host. */
72 USBHIDREQSTATE_DATA_TO_HOST,
73 /** Waiting to supply status information to the host. */
74 USBHIDREQSTATE_STATUS,
75 /** The end of the valid states. */
76 USBHIDREQSTATE_END
77} USBHIDREQSTATE;
78
79/**
80 * The device reporting mode.
81 * @todo Use an interface instead of an enum and switches.
82 */
83typedef enum USBHIDMODE
84{
85 /** Relative. */
86 USBHIDMODE_RELATIVE = 0,
87 /** Absolute. */
88 USBHIDMODE_ABSOLUTE,
89 /** Multi-touch. */
90 USBHIDMODE_MULTI_TOUCH
91} USBHIDMODE;
92
93
94/**
95 * Endpoint status data.
96 */
97typedef struct USBHIDEP
98{
99 bool fHalted;
100} USBHIDEP;
101/** Pointer to the endpoint status. */
102typedef USBHIDEP *PUSBHIDEP;
103
104
105/**
106 * A URB queue.
107 */
108typedef struct USBHIDURBQUEUE
109{
110 /** The head pointer. */
111 PVUSBURB pHead;
112 /** Where to insert the next entry. */
113 PVUSBURB *ppTail;
114} USBHIDURBQUEUE;
115/** Pointer to a URB queue. */
116typedef USBHIDURBQUEUE *PUSBHIDURBQUEUE;
117/** Pointer to a const URB queue. */
118typedef USBHIDURBQUEUE const *PCUSBHIDURBQUEUE;
119
120
121/**
122 * Mouse movement accumulator.
123 */
124typedef struct USBHIDM_ACCUM
125{
126 union
127 {
128 struct
129 {
130 uint32_t fButtons;
131 int32_t dx;
132 int32_t dy;
133 int32_t dz;
134 } Relative;
135 struct
136 {
137 uint32_t x;
138 uint32_t y;
139 uint32_t fButtons;
140 } Absolute;
141 struct
142 {
143 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 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 {
902 pReport->t.fButtons = pAccumulated->u.Absolute.fButtons;
903 pReport->t.x = pAccumulated->u.Absolute.x;
904 pReport->t.y = pAccumulated->u.Absolute.y;
905
906 cbCopy = sizeof(pReport->t);
907 LogRel3(("Abs event, x=%d, y=%d, fButtons=%02x, report size %d\n",
908 pReport->t.x, pReport->t.y, pReport->t.fButtons,
909 cbCopy));
910 break;
911 }
912 case USBHIDMODE_RELATIVE:
913 {
914 pReport->m.fButtons = pAccumulated->u.Relative.fButtons;
915 pReport->m.dx = clamp_i8(pAccumulated->u.Relative.dx);
916 pReport->m.dy = clamp_i8(pAccumulated->u.Relative.dy);
917 pReport->m.dz = clamp_i8(pAccumulated->u.Relative.dz);
918
919 cbCopy = sizeof(pReport->m);
920 LogRel3(("Rel event, dx=%d, dy=%d, dz=%d, fButtons=%02x, report size %d\n",
921 pReport->m.dx, pReport->m.dy, pReport->m.dz,
922 pReport->m.fButtons, cbCopy));
923 break;
924 }
925 case USBHIDMODE_MULTI_TOUCH:
926 {
927 pReport->mt.idReport = REPORTID_MOUSE;
928 pReport->mt.cContact = pAccumulated->u.MultiTouch.cContact;
929 pReport->mt.x = pAccumulated->u.MultiTouch.x;
930 pReport->mt.y = pAccumulated->u.MultiTouch.y;
931 pReport->mt.fContact = pAccumulated->u.MultiTouch.fContact;
932
933 cbCopy = sizeof(pReport->t);
934 LogRel3(("Multi-touch event, x=%u, y=%u, report size %d\n",
935 pReport->mt.x, pReport->mt.y, cbCopy));
936 break;
937 }
938 }
939
940 /* Clear the accumulated movement. */
941 RT_ZERO(*pAccumulated);
942
943 return cbCopy;
944}
945
946/**
947 * Sends a state report to the host if there is a pending URB.
948 */
949static int usbHidSendReport(PUSBHID pThis)
950{
951 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
952
953 if (pUrb)
954 {
955 PUSBHIDTM_REPORT pReport = (PUSBHIDTM_REPORT)&pUrb->abData[0];
956 size_t cbCopy;
957
958 cbCopy = usbHidFillReport(pReport, &pThis->PtrDelta, pThis->enmMode);
959 pThis->fHasPendingChanges = false;
960 return usbHidCompleteOk(pThis, pUrb, cbCopy);
961 }
962 else
963 {
964 LogRelFlow(("No available URB for USB mouse\n"));
965 pThis->fHasPendingChanges = true;
966 }
967 return VINF_EOF;
968}
969
970/**
971 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
972 */
973static DECLCALLBACK(void *) usbHidMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
974{
975 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
976 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
977 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Lun0.IPort);
978 return NULL;
979}
980
981/**
982 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
983 */
984static DECLCALLBACK(int) usbHidMousePutEvent(PPDMIMOUSEPORT pInterface,
985 int32_t dx, int32_t dy, int32_t dz,
986 int32_t dw, uint32_t fButtons)
987{
988 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
989 RTCritSectEnter(&pThis->CritSect);
990
991 /* Accumulate movement - the events from the front end may arrive
992 * at a much higher rate than USB can handle.
993 */
994 pThis->PtrDelta.u.Relative.fButtons = fButtons;
995 pThis->PtrDelta.u.Relative.dx += dx;
996 pThis->PtrDelta.u.Relative.dy += dy;
997 pThis->PtrDelta.u.Relative.dz -= dz; /* Inverted! */
998
999 /* Send a report if possible. */
1000 usbHidSendReport(pThis);
1001
1002 RTCritSectLeave(&pThis->CritSect);
1003 return VINF_SUCCESS;
1004}
1005
1006/**
1007 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
1008 */
1009static DECLCALLBACK(int) usbHidMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1010 uint32_t x, uint32_t y,
1011 int32_t dz, int32_t dw,
1012 uint32_t fButtons)
1013{
1014 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1015 RTCritSectEnter(&pThis->CritSect);
1016
1017 Assert(pThis->enmMode == USBHIDMODE_ABSOLUTE);
1018
1019 /* Accumulate movement - the events from the front end may arrive
1020 * at a much higher rate than USB can handle. Probably not a real issue
1021 * when only the Z axis is relative (X/Y movement isn't technically
1022 * accumulated and only the last value is used).
1023 */
1024 pThis->PtrDelta.u.Absolute.fButtons = fButtons;
1025 pThis->PtrDelta.u.Absolute.x = x >> pThis->u8CoordShift;
1026 pThis->PtrDelta.u.Absolute.y = y >> pThis->u8CoordShift;
1027
1028 /* Send a report if possible. */
1029 usbHidSendReport(pThis);
1030
1031 RTCritSectLeave(&pThis->CritSect);
1032 return VINF_SUCCESS;
1033}
1034
1035/**
1036 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMT}
1037 */
1038static DECLCALLBACK(int) usbHidMousePutEventMT(PPDMIMOUSEPORT pInterface,
1039 uint32_t x, uint32_t y,
1040 uint32_t cContact,
1041 uint32_t fContact)
1042{
1043 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1044 RTCritSectEnter(&pThis->CritSect);
1045
1046 Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1047
1048 /* Accumulate movement - the events from the front end may arrive
1049 * at a much higher rate than USB can handle. Probably not a real issue
1050 * when only the Z axis is relative (X/Y movement isn't technically
1051 * accumulated and only the last value is used).
1052 */
1053 pThis->PtrDelta.u.MultiTouch.fContact = fContact;
1054 pThis->PtrDelta.u.MultiTouch.x = x;
1055 pThis->PtrDelta.u.MultiTouch.y = y;
1056 pThis->PtrDelta.u.MultiTouch.cContact = cContact;
1057
1058 /* Send a report if possible. */
1059 usbHidSendReport(pThis);
1060
1061 RTCritSectLeave(&pThis->CritSect);
1062 return VINF_SUCCESS;
1063}
1064
1065/**
1066 * @copydoc PDMUSBREG::pfnUrbReap
1067 */
1068static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1069{
1070 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1071 LogRelFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1072
1073 RTCritSectEnter(&pThis->CritSect);
1074
1075 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1076 if (!pUrb && cMillies)
1077 {
1078 /* Wait */
1079 pThis->fHaveDoneQueueWaiter = true;
1080 RTCritSectLeave(&pThis->CritSect);
1081
1082 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1083
1084 RTCritSectEnter(&pThis->CritSect);
1085 pThis->fHaveDoneQueueWaiter = false;
1086
1087 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1088 }
1089
1090 RTCritSectLeave(&pThis->CritSect);
1091
1092 if (pUrb)
1093 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1094 pUrb->pszDesc));
1095 return pUrb;
1096}
1097
1098
1099/**
1100 * @copydoc PDMUSBREG::pfnUrbCancel
1101 */
1102static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1103{
1104 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1105 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1106 pUrb->pszDesc));
1107 RTCritSectEnter(&pThis->CritSect);
1108
1109 /*
1110 * Remove the URB from the to-host queue and move it onto the done queue.
1111 */
1112 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1113 usbHidLinkDone(pThis, pUrb);
1114
1115 RTCritSectLeave(&pThis->CritSect);
1116 return VINF_SUCCESS;
1117}
1118
1119
1120/**
1121 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1122 * rather different from bulk requests because an interrupt read URB may complete
1123 * after arbitrarily long time.
1124 */
1125static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1126{
1127 /*
1128 * Stall the request if the pipe is halted.
1129 */
1130 if (RT_UNLIKELY(pEp->fHalted))
1131 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1132
1133 /*
1134 * Deal with the URB according to the state.
1135 */
1136 switch (pThis->enmState)
1137 {
1138 /*
1139 * We've data left to transfer to the host.
1140 */
1141 case USBHIDREQSTATE_DATA_TO_HOST:
1142 {
1143 AssertFailed();
1144 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1145 return usbHidCompleteOk(pThis, pUrb, 0);
1146 }
1147
1148 /*
1149 * Status transfer.
1150 */
1151 case USBHIDREQSTATE_STATUS:
1152 {
1153 AssertFailed();
1154 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1155 pThis->enmState = USBHIDREQSTATE_READY;
1156 return usbHidCompleteOk(pThis, pUrb, 0);
1157 }
1158
1159 case USBHIDREQSTATE_READY:
1160 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1161 /* If a report is pending, send it right away. */
1162 if (pThis->fHasPendingChanges)
1163 usbHidSendReport(pThis);
1164 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1165 pUrb, pUrb->pszDesc));
1166 return VINF_SUCCESS;
1167
1168 /*
1169 * Bad states, stall.
1170 */
1171 default:
1172 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1173 pThis->enmState, pUrb->cbData));
1174 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1175 }
1176}
1177
1178
1179/**
1180 * Handles request sent to the default control pipe.
1181 */
1182static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1183{
1184 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1185 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1186
1187 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1188 {
1189 switch (pSetup->bRequest)
1190 {
1191 case VUSB_REQ_GET_DESCRIPTOR:
1192 {
1193 switch (pSetup->bmRequestType)
1194 {
1195 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1196 {
1197 switch (pSetup->wValue >> 8)
1198 {
1199 case VUSB_DT_STRING:
1200 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1201 pSetup->wValue, pSetup->wIndex));
1202 break;
1203 default:
1204 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1205 pSetup->wValue, pSetup->wIndex));
1206 break;
1207 }
1208 break;
1209 }
1210
1211 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1212 {
1213 switch (pSetup->wValue >> 8)
1214 {
1215 uint32_t cbCopy;
1216 uint32_t cbDesc;
1217 const uint8_t *pDesc;
1218
1219 case DT_IF_HID_DESCRIPTOR:
1220 {
1221 switch (pThis->enmMode)
1222 {
1223 case USBHIDMODE_ABSOLUTE:
1224 {
1225 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1226 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1227 break;
1228 }
1229 case USBHIDMODE_RELATIVE:
1230 {
1231 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1232 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1233 break;
1234 }
1235 case USBHIDMODE_MULTI_TOUCH:
1236 {
1237 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1238 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1239 break;
1240 }
1241 }
1242 /* Returned data is written after the setup message. */
1243 cbCopy = pUrb->cbData - sizeof(*pSetup);
1244 cbCopy = RT_MIN(cbCopy, cbDesc);
1245 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1246 pSetup->wValue, pSetup->wIndex,
1247 cbCopy));
1248 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1249 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1250 }
1251
1252 case DT_IF_HID_REPORT:
1253 {
1254 switch (pThis->enmMode)
1255 {
1256 case USBHIDMODE_ABSOLUTE:
1257 {
1258 cbDesc = sizeof(g_UsbHidTReportDesc);
1259 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
1260 break;
1261 }
1262 case USBHIDMODE_RELATIVE:
1263 {
1264 cbDesc = sizeof(g_UsbHidMReportDesc);
1265 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
1266 break;
1267 }
1268 case USBHIDMODE_MULTI_TOUCH:
1269 {
1270 cbDesc = sizeof(g_UsbHidMTReportDesc);
1271 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
1272 break;
1273 }
1274 }
1275 /* Returned data is written after the setup message. */
1276 cbCopy = pUrb->cbData - sizeof(*pSetup);
1277 cbCopy = RT_MIN(cbCopy, cbDesc);
1278 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
1279 pSetup->wValue, pSetup->wIndex,
1280 cbCopy));
1281 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1282 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1283 }
1284
1285 default:
1286 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1287 pSetup->wValue, pSetup->wIndex));
1288 break;
1289 }
1290 break;
1291 }
1292
1293 default:
1294 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
1295 pSetup->bmRequestType));
1296 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1297 }
1298 break;
1299 }
1300
1301 case VUSB_REQ_GET_STATUS:
1302 {
1303 uint16_t wRet = 0;
1304
1305 if (pSetup->wLength != 2)
1306 {
1307 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
1308 pSetup->wLength));
1309 break;
1310 }
1311 Assert(pSetup->wValue == 0);
1312 switch (pSetup->bmRequestType)
1313 {
1314 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1315 {
1316 Assert(pSetup->wIndex == 0);
1317 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
1318 wRet = 0; /* Not self-powered, no remote wakeup. */
1319 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1320 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1321 }
1322
1323 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1324 {
1325 if (pSetup->wIndex == 0)
1326 {
1327 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1328 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1329 }
1330 else
1331 {
1332 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
1333 pSetup->wIndex));
1334 }
1335 break;
1336 }
1337
1338 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1339 {
1340 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1341 {
1342 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1343 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1344 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1345 }
1346 else
1347 {
1348 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
1349 pSetup->wIndex));
1350 }
1351 break;
1352 }
1353
1354 default:
1355 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
1356 pSetup->bmRequestType));
1357 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
1358 }
1359 break;
1360 }
1361
1362 case VUSB_REQ_CLEAR_FEATURE:
1363 break;
1364 }
1365
1366 /** @todo implement this. */
1367 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1368 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1369 pSetup->wIndex, pSetup->wLength));
1370
1371 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1372 }
1373 /* 3.1 Bulk-Only Mass Storage Reset */
1374 else if ( pSetup->bmRequestType == (VUSB_REQ_CLASS | VUSB_TO_INTERFACE)
1375 && pSetup->bRequest == 0xff
1376 && !pSetup->wValue
1377 && !pSetup->wLength
1378 && pSetup->wIndex == 0)
1379 {
1380 LogRelFlow(("usbHidHandleDefaultPipe: Bulk-Only Mass Storage Reset\n"));
1381 return usbHidResetWorker(pThis, pUrb, false /*fSetConfig*/);
1382 }
1383 else
1384 {
1385 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1386 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1387 pSetup->wIndex, pSetup->wLength));
1388 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1389 }
1390
1391 return VINF_SUCCESS;
1392}
1393
1394
1395/**
1396 * @copydoc PDMUSBREG::pfnUrbQueue
1397 */
1398static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1399{
1400 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1401 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
1402 pUrb, pUrb->pszDesc, pUrb->EndPt));
1403 RTCritSectEnter(&pThis->CritSect);
1404
1405 /*
1406 * Parse on a per end-point basis.
1407 */
1408 int rc;
1409 switch (pUrb->EndPt)
1410 {
1411 case 0:
1412 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1413 break;
1414
1415 case 0x81:
1416 AssertFailed();
1417 case 0x01:
1418 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
1419 break;
1420
1421 default:
1422 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1423 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1424 break;
1425 }
1426
1427 RTCritSectLeave(&pThis->CritSect);
1428 return rc;
1429}
1430
1431
1432/**
1433 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1434 */
1435static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1436{
1437 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1438 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
1439 pUsbIns->iInstance, uEndpoint));
1440
1441 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1442 {
1443 RTCritSectEnter(&pThis->CritSect);
1444 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1445 RTCritSectLeave(&pThis->CritSect);
1446 }
1447
1448 return VINF_SUCCESS;
1449}
1450
1451
1452/**
1453 * @copydoc PDMUSBREG::pfnUsbSetInterface
1454 */
1455static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1456{
1457 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
1458 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1459 Assert(bAlternateSetting == 0);
1460 return VINF_SUCCESS;
1461}
1462
1463
1464/**
1465 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1466 */
1467static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1468 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1469{
1470 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1471 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
1472 pUsbIns->iInstance, bConfigurationValue));
1473 Assert(bConfigurationValue == 1);
1474 RTCritSectEnter(&pThis->CritSect);
1475
1476 /*
1477 * If the same config is applied more than once, it's a kind of reset.
1478 */
1479 if (pThis->bConfigurationValue == bConfigurationValue)
1480 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1481 pThis->bConfigurationValue = bConfigurationValue;
1482
1483 /*
1484 * Set received event type to absolute or relative.
1485 */
1486 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
1487 pThis->enmMode == USBHIDMODE_RELATIVE,
1488 pThis->enmMode == USBHIDMODE_ABSOLUTE,
1489 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1490
1491 RTCritSectLeave(&pThis->CritSect);
1492 return VINF_SUCCESS;
1493}
1494
1495
1496/**
1497 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1498 */
1499static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1500{
1501 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1502 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1503 switch (pThis->enmMode)
1504 {
1505 case USBHIDMODE_ABSOLUTE:
1506 return &g_UsbHidTDescCache;
1507 case USBHIDMODE_RELATIVE:
1508 return &g_UsbHidMDescCache;
1509 case USBHIDMODE_MULTI_TOUCH:
1510 return &g_UsbHidMTDescCache;
1511 default:
1512 return NULL;
1513 }
1514}
1515
1516
1517/**
1518 * @copydoc PDMUSBREG::pfnUsbReset
1519 */
1520static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1521{
1522 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1523 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
1524 RTCritSectEnter(&pThis->CritSect);
1525
1526 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
1527
1528 RTCritSectLeave(&pThis->CritSect);
1529 return rc;
1530}
1531
1532
1533/**
1534 * @copydoc PDMUSBREG::pfnDestruct
1535 */
1536static void usbHidDestruct(PPDMUSBINS pUsbIns)
1537{
1538 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1539 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
1540
1541 if (RTCritSectIsInitialized(&pThis->CritSect))
1542 {
1543 RTCritSectEnter(&pThis->CritSect);
1544 RTCritSectLeave(&pThis->CritSect);
1545 RTCritSectDelete(&pThis->CritSect);
1546 }
1547
1548 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1549 {
1550 RTSemEventDestroy(pThis->hEvtDoneQueue);
1551 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1552 }
1553}
1554
1555
1556/**
1557 * @copydoc PDMUSBREG::pfnConstruct
1558 */
1559static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1560{
1561 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1562 char szMode[64];
1563 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
1564
1565 /*
1566 * Perform the basic structure initialization first so the destructor
1567 * will not misbehave.
1568 */
1569 pThis->pUsbIns = pUsbIns;
1570 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1571 usbHidQueueInit(&pThis->ToHostQueue);
1572 usbHidQueueInit(&pThis->DoneQueue);
1573
1574 int rc = RTCritSectInit(&pThis->CritSect);
1575 AssertRCReturn(rc, rc);
1576
1577 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1578 AssertRCReturn(rc, rc);
1579
1580 /*
1581 * Validate and read the configuration.
1582 */
1583 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
1584 if (RT_FAILURE(rc))
1585 return rc;
1586 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
1587 if (RT_FAILURE(rc))
1588 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
1589 if (!RTStrCmp(szMode, "relative"))
1590 pThis->enmMode = USBHIDMODE_RELATIVE;
1591 else if (!RTStrCmp(szMode, "absolute"))
1592 pThis->enmMode = USBHIDMODE_ABSOLUTE;
1593 else if (!RTStrCmp(szMode, "multitouch"))
1594 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
1595 else
1596 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
1597 N_("Invalid HID device mode"));
1598
1599 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
1600 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
1601 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
1602
1603 /*
1604 * Attach the mouse driver.
1605 */
1606 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
1607 if (RT_FAILURE(rc))
1608 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
1609
1610 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
1611 if (!pThis->Lun0.pDrv)
1612 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
1613
1614 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
1615 if (RT_FAILURE(rc))
1616 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
1617
1618 return VINF_SUCCESS;
1619}
1620
1621
1622/**
1623 * The USB Human Interface Device (HID) Mouse registration record.
1624 */
1625const PDMUSBREG g_UsbHidMou =
1626{
1627 /* u32Version */
1628 PDM_USBREG_VERSION,
1629 /* szName */
1630 "HidMouse",
1631 /* pszDescription */
1632 "USB HID Mouse.",
1633 /* fFlags */
1634 0,
1635 /* cMaxInstances */
1636 ~0U,
1637 /* cbInstance */
1638 sizeof(USBHID),
1639 /* pfnConstruct */
1640 usbHidConstruct,
1641 /* pfnDestruct */
1642 usbHidDestruct,
1643 /* pfnVMInitComplete */
1644 NULL,
1645 /* pfnVMPowerOn */
1646 NULL,
1647 /* pfnVMReset */
1648 NULL,
1649 /* pfnVMSuspend */
1650 NULL,
1651 /* pfnVMResume */
1652 NULL,
1653 /* pfnVMPowerOff */
1654 NULL,
1655 /* pfnHotPlugged */
1656 NULL,
1657 /* pfnHotUnplugged */
1658 NULL,
1659 /* pfnDriverAttach */
1660 NULL,
1661 /* pfnDriverDetach */
1662 NULL,
1663 /* pfnQueryInterface */
1664 NULL,
1665 /* pfnUsbReset */
1666 usbHidUsbReset,
1667 /* pfnUsbGetDescriptorCache */
1668 usbHidUsbGetDescriptorCache,
1669 /* pfnUsbSetConfiguration */
1670 usbHidUsbSetConfiguration,
1671 /* pfnUsbSetInterface */
1672 usbHidUsbSetInterface,
1673 /* pfnUsbClearHaltedEndpoint */
1674 usbHidUsbClearHaltedEndpoint,
1675 /* pfnUrbNew */
1676 NULL/*usbHidUrbNew*/,
1677 /* pfnUrbQueue */
1678 usbHidQueue,
1679 /* pfnUrbCancel */
1680 usbHidUrbCancel,
1681 /* pfnUrbReap */
1682 usbHidUrbReap,
1683 /* u32TheEnd */
1684 PDM_USBREG_VERSION
1685};
Note: See TracBrowser for help on using the repository browser.

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