VirtualBox

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

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

include,Devices,Main,VirtualBox: multi-touch input.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.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 } u;
142} USBHIDM_ACCUM, *PUSBHIDM_ACCUM;
143
144#define MT_CONTACTS_PER_REPORT 5
145
146#define MT_CONTACT_MAX_COUNT 10
147
148#define MT_CONTACT_F_IN_CONTACT 0x01
149#define MT_CONTACT_F_IN_RANGE 0x02
150
151#define MT_CONTACT_S_ACTIVE 0x01 /* Contact must be reported to the guest. */
152#define MT_CONTACT_S_CANCELLED 0x02 /* Contact loss must be reported to the guest. */
153#define MT_CONTACT_S_REUSED 0x04 /* Report contact loss for the oldId and then new contact for the id. */
154#define MT_CONTACT_S_DIRTY 0x08 /* Temporary flag used to track already processed elements. */
155
156typedef struct MTCONTACT
157{
158 uint16_t x;
159 uint16_t y;
160 uint8_t id;
161 uint8_t flags;
162 uint8_t status;
163 uint8_t oldId; /* Valid only if MT_CONTACT_S_REUSED is set. */
164} MTCONTACT;
165
166
167/**
168 * The USB HID instance data.
169 */
170typedef struct USBHID
171{
172 /** Pointer back to the PDM USB Device instance structure. */
173 PPDMUSBINS pUsbIns;
174 /** Critical section protecting the device state. */
175 RTCRITSECT CritSect;
176
177 /** The current configuration.
178 * (0 - default, 1 - the one supported configuration, i.e configured.) */
179 uint8_t bConfigurationValue;
180 /** Endpoint 0 is the default control pipe, 1 is the dev->host interrupt one. */
181 USBHIDEP aEps[2];
182 /** The state of the HID (state machine).*/
183 USBHIDREQSTATE enmState;
184
185 /** Pointer movement accumulator. */
186 USBHIDM_ACCUM PtrDelta;
187
188 /** Pending to-host queue.
189 * The URBs waiting here are waiting for data to become available.
190 */
191 USBHIDURBQUEUE ToHostQueue;
192
193 /** Done queue
194 * The URBs stashed here are waiting to be reaped. */
195 USBHIDURBQUEUE DoneQueue;
196 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
197 * is set. */
198 RTSEMEVENT hEvtDoneQueue;
199
200 /** Someone is waiting on the done queue. */
201 bool fHaveDoneQueueWaiter;
202 /** If device has pending changes. */
203 bool fHasPendingChanges;
204 /** Is this a relative, absolute or multi-touch pointing device? */
205 USBHIDMODE enmMode;
206 /** Tablet coordinate shift factor for old and broken operating systems. */
207 uint8_t u8CoordShift;
208
209 /**
210 * Mouse port - LUN#0.
211 *
212 * @implements PDMIBASE
213 * @implements PDMIMOUSEPORT
214 */
215 struct
216 {
217 /** The base interface for the mouse port. */
218 PDMIBASE IBase;
219 /** The mouse port base interface. */
220 PDMIMOUSEPORT IPort;
221
222 /** The base interface of the attached mouse driver. */
223 R3PTRTYPE(PPDMIBASE) pDrvBase;
224 /** The mouse interface of the attached mouse driver. */
225 R3PTRTYPE(PPDMIMOUSECONNECTOR) pDrv;
226 } Lun0;
227
228 MTCONTACT aCurrentContactState[MT_CONTACT_MAX_COUNT];
229 MTCONTACT aReportingContactState[MT_CONTACT_MAX_COUNT];
230 uint32_t u32LastTouchScanTime;
231 bool fTouchReporting;
232} USBHID;
233/** Pointer to the USB HID instance data. */
234typedef USBHID *PUSBHID;
235
236#pragma pack(1)
237/**
238 * The USB HID report structure for relative device.
239 */
240typedef struct USBHIDM_REPORT
241{
242 uint8_t fButtons;
243 int8_t dx;
244 int8_t dy;
245 int8_t dz;
246} USBHIDM_REPORT, *PUSBHIDM_REPORT;
247
248/**
249 * The USB HID report structure for absolute device.
250 */
251
252typedef struct USBHIDT_REPORT
253{
254 uint16_t x;
255 uint16_t y;
256 uint8_t fButtons;
257} USBHIDT_REPORT, *PUSBHIDT_REPORT;
258
259/**
260 * The combined USB HID report union for relative and absolute
261 * devices.
262 */
263typedef union USBHIDTM_REPORT
264{
265 USBHIDM_REPORT m;
266 USBHIDT_REPORT t;
267} USBHIDTM_REPORT, *PUSBHIDTM_REPORT;
268
269/**
270 * The USB HID report structure for the multi-touch device.
271 */
272typedef struct USBHIDMT_REPORT
273{
274 uint8_t idReport;
275 uint8_t cContacts;
276 struct
277 {
278 uint8_t fContact;
279 uint8_t cContact;
280 uint16_t x;
281 uint16_t y;
282 } aContacts[MT_CONTACTS_PER_REPORT];
283 uint32_t u32ScanTime;
284} USBHIDMT_REPORT, *PUSBHIDMT_REPORT;
285#pragma pack()
286
287/*******************************************************************************
288* Global Variables *
289*******************************************************************************/
290static const PDMUSBDESCCACHESTRING g_aUsbHidStrings_en_US[] =
291{
292 { USBHID_STR_ID_MANUFACTURER, "VirtualBox" },
293 { USBHID_STR_ID_PRODUCT_M, "USB Mouse" },
294 { USBHID_STR_ID_PRODUCT_T, "USB Tablet" },
295 { USBHID_STR_ID_PRODUCT_MT, "USB Multi-Touch" },
296};
297
298static const PDMUSBDESCCACHELANG g_aUsbHidLanguages[] =
299{
300 { 0x0409, RT_ELEMENTS(g_aUsbHidStrings_en_US), g_aUsbHidStrings_en_US }
301};
302
303static const VUSBDESCENDPOINTEX g_aUsbHidMEndpointDescs[] =
304{
305 {
306 {
307 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
308 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
309 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
310 /* .bmAttributes = */ 3 /* interrupt */,
311 /* .wMaxPacketSize = */ 4,
312 /* .bInterval = */ 10,
313 },
314 /* .pvMore = */ NULL,
315 /* .pvClass = */ NULL,
316 /* .cbClass = */ 0
317 },
318};
319
320static const VUSBDESCENDPOINTEX g_aUsbHidTEndpointDescs[] =
321{
322 {
323 {
324 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
325 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
326 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
327 /* .bmAttributes = */ 3 /* interrupt */,
328 /* .wMaxPacketSize = */ 6,
329 /* .bInterval = */ 10,
330 },
331 /* .pvMore = */ NULL,
332 /* .pvClass = */ NULL,
333 /* .cbClass = */ 0
334 },
335};
336
337static const VUSBDESCENDPOINTEX g_aUsbHidMTEndpointDescs[] =
338{
339 {
340 {
341 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
342 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
343 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
344 /* .bmAttributes = */ 3 /* interrupt */,
345 /* .wMaxPacketSize = */ 64,
346 /* .bInterval = */ 10,
347 },
348 /* .pvMore = */ NULL,
349 /* .pvClass = */ NULL,
350 /* .cbClass = */ 0
351 },
352};
353
354/* HID report descriptor (mouse). */
355static const uint8_t g_UsbHidMReportDesc[] =
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 Page */ 0x05, 0x09, /* Button */
363 /* Usage Minimum */ 0x19, 0x01, /* Button 1 */
364 /* Usage Maximum */ 0x29, 0x05, /* Button 5 */
365 /* Logical Minimum */ 0x15, 0x00, /* 0 */
366 /* Logical Maximum */ 0x25, 0x01, /* 1 */
367 /* Report Count */ 0x95, 0x05, /* 5 */
368 /* Report Size */ 0x75, 0x01, /* 1 */
369 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
370 /* Report Count */ 0x95, 0x01, /* 1 */
371 /* Report Size */ 0x75, 0x03, /* 3 (padding bits) */
372 /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
373 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
374 /* Usage */ 0x09, 0x30, /* X */
375 /* Usage */ 0x09, 0x31, /* Y */
376 /* Usage */ 0x09, 0x38, /* Z (wheel) */
377 /* Logical Minimum */ 0x15, 0x81, /* -127 */
378 /* Logical Maximum */ 0x25, 0x7F, /* +127 */
379 /* Report Size */ 0x75, 0x08, /* 8 */
380 /* Report Count */ 0x95, 0x03, /* 3 */
381 /* Input */ 0x81, 0x06, /* Data, Value, Relative, Bit field */
382 /* End Collection */ 0xC0,
383 /* End Collection */ 0xC0,
384};
385
386/* HID report descriptor (tablet). */
387/* NB: The layout is far from random. Having the buttons and Z axis grouped
388 * together avoids alignment issues. Also, if X/Y is reported first, followed
389 * by buttons/Z, Windows gets phantom Z movement. That is likely a bug in Windows
390 * as OS X shows no such problem. When X/Y is reported last, Windows behaves
391 * properly.
392 */
393#define REPORTID_MOUSE 1
394#define REPORTID_MAX_COUNT 2
395
396static const uint8_t g_UsbHidTReportDesc[] =
397{
398 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
399 /* Usage */ 0x09, 0x02, /* Mouse */
400 /* Collection */ 0xA1, 0x01, /* Application */
401 /* Usage */ 0x09, 0x01, /* Pointer */
402 /* Collection */ 0xA1, 0x00, /* Physical */
403 /* Usage */ 0x09, 0x30, /* X */
404 /* Usage */ 0x09, 0x31, /* Y */
405 /* Logical Minimum */ 0x15, 0x00, /* 0 */
406 /* Logical Maximum */ 0x26, 0xFF,0x7F,/* 0x7fff */
407 /* Physical Minimum */ 0x35, 0x00, /* 0 */
408 /* Physical Maximum */ 0x46, 0xFF,0x7F,/* 0x7fff */
409 /* Report Size */ 0x75, 0x10, /* 16 */
410 /* Report Count */ 0x95, 0x02, /* 2 */
411 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
412 /* Usage Page */ 0x05, 0x09, /* Button */
413 /* Usage Minimum */ 0x19, 0x01, /* Button 1 */
414 /* Usage Maximum */ 0x29, 0x05, /* Button 5 */
415 /* Logical Minimum */ 0x15, 0x00, /* 0 */
416 /* Logical Maximum */ 0x25, 0x01, /* 1 */
417 /* Report Count */ 0x95, 0x05, /* 5 */
418 /* Report Size */ 0x75, 0x01, /* 1 */
419 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
420 /* Report Count */ 0x95, 0x01, /* 1 */
421 /* Report Size */ 0x75, 0x03, /* 3 (padding bits) */
422 /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
423 /* End Collection */ 0xC0,
424 /* End Collection */ 0xC0,
425};
426
427/*
428 * Multi-touch device implementation based on "Windows Pointer Device Data Delivery Protocol"
429 * specification.
430 */
431
432#define REPORTID_TOUCH_POINTER 1
433#define REPORTID_TOUCH_EVENT 2
434#define REPORTID_TOUCH_MAX_COUNT 3
435#define REPORTID_TOUCH_QABLOB 4
436#define REPORTID_TOUCH_DEVCONFIG 5
437
438static const uint8_t g_UsbHidMTReportDesc[] =
439{
440/* Usage Page (Digitizer) */ 0x05, 0x0D,
441/* Usage (Touch Screen) */ 0x09, 0x04,
442/* Collection (Application) */ 0xA1, 0x01,
443/* Report ID */ 0x85, REPORTID_TOUCH_EVENT,
444/* Usage Page (Digitizer) */ 0x05, 0x0D,
445/* Usage (Contact count) */ 0x09, 0x54,
446/* Report Size (8) */ 0x75, 0x08,
447/* Logical Minimum (0) */ 0x15, 0x00,
448/* Logical Maximum (12) */ 0x25, 0x0C,
449/* Report Count (1) */ 0x95, 0x01,
450/* Input (Var) */ 0x81, 0x02,
451
452/* MT_CONTACTS_PER_REPORT structs u8TipSwitch, u8ContactIdentifier, u16X, u16Y */
453/* 1 of 5 */
454/* Usage (Finger) */ 0x09, 0x22,
455/* Collection (Logical) */ 0xA1, 0x02,
456/* Usage (Tip Switch) */ 0x09, 0x42,
457/* Logical Minimum (0) */ 0x15, 0x00,
458/* Logical Maximum (1) */ 0x25, 0x01,
459/* Report Size (1) */ 0x75, 0x01,
460/* Report Count (1) */ 0x95, 0x01,
461/* Input (Var) */ 0x81, 0x02,
462
463/* Usage (In Range) */ 0x09, 0x32,
464/* Logical Minimum (0) */ 0x15, 0x00,
465/* Logical Maximum (1) */ 0x25, 0x01,
466/* Report Size (1) */ 0x75, 0x01,
467/* Report Count (1) */ 0x95, 0x01,
468/* Input (Var) */ 0x81, 0x02,
469
470/* Report Count (6) */ 0x95, 0x06,
471/* Input (Cnst,Var) */ 0x81, 0x03,
472
473/* Report Size (8) */ 0x75, 0x08,
474/* Usage (Contact identifier) */ 0x09, 0x51,
475/* Report Count (1) */ 0x95, 0x01,
476/* Logical Minimum (0) */ 0x15, 0x00,
477/* Logical Maximum (32) */ 0x25, 0x20,
478/* Input (Var) */ 0x81, 0x02,
479
480/* Usage Page (Generic Desktop) */ 0x05, 0x01,
481/* Logical Maximum (32K) */ 0x26, 0xFF, 0x7F,
482/* Report Size (16) */ 0x75, 0x10,
483/* Usage (X) */ 0x09, 0x30,
484/* Input (Var) */ 0x81, 0x02,
485
486/* Usage (Y) */ 0x09, 0x31,
487/* Input (Var) */ 0x81, 0x02,
488/* End Collection */ 0xC0,
489/* 2 of 5 */
490/* Usage Page (Digitizer) */ 0x05, 0x0D,
491/* Usage (Finger) */ 0x09, 0x22,
492/* Collection (Logical) */ 0xA1, 0x02,
493/* Usage (Tip Switch) */ 0x09, 0x42,
494/* Logical Minimum (0) */ 0x15, 0x00,
495/* Logical Maximum (1) */ 0x25, 0x01,
496/* Report Size (1) */ 0x75, 0x01,
497/* Report Count (1) */ 0x95, 0x01,
498/* Input (Var) */ 0x81, 0x02,
499/* Usage (In Range) */ 0x09, 0x32,
500/* Logical Minimum (0) */ 0x15, 0x00,
501/* Logical Maximum (1) */ 0x25, 0x01,
502/* Report Size (1) */ 0x75, 0x01,
503/* Report Count (1) */ 0x95, 0x01,
504/* Input (Var) */ 0x81, 0x02,
505/* Report Count (6) */ 0x95, 0x06,
506/* Input (Cnst,Var) */ 0x81, 0x03,
507/* Report Size (8) */ 0x75, 0x08,
508/* Usage (Contact identifier) */ 0x09, 0x51,
509/* Report Count (1) */ 0x95, 0x01,
510/* Logical Minimum (0) */ 0x15, 0x00,
511/* Logical Maximum (32) */ 0x25, 0x20,
512/* Input (Var) */ 0x81, 0x02,
513/* Usage Page (Generic Desktop) */ 0x05, 0x01,
514/* Logical Maximum (32K) */ 0x26, 0xFF, 0x7F,
515/* Report Size (16) */ 0x75, 0x10,
516/* Usage (X) */ 0x09, 0x30,
517/* Input (Var) */ 0x81, 0x02,
518/* Usage (Y) */ 0x09, 0x31,
519/* Input (Var) */ 0x81, 0x02,
520/* End Collection */ 0xC0,
521/* 3 of 5 */
522/* Usage Page (Digitizer) */ 0x05, 0x0D,
523/* Usage (Finger) */ 0x09, 0x22,
524/* Collection (Logical) */ 0xA1, 0x02,
525/* Usage (Tip Switch) */ 0x09, 0x42,
526/* Logical Minimum (0) */ 0x15, 0x00,
527/* Logical Maximum (1) */ 0x25, 0x01,
528/* Report Size (1) */ 0x75, 0x01,
529/* Report Count (1) */ 0x95, 0x01,
530/* Input (Var) */ 0x81, 0x02,
531/* Usage (In Range) */ 0x09, 0x32,
532/* Logical Minimum (0) */ 0x15, 0x00,
533/* Logical Maximum (1) */ 0x25, 0x01,
534/* Report Size (1) */ 0x75, 0x01,
535/* Report Count (1) */ 0x95, 0x01,
536/* Input (Var) */ 0x81, 0x02,
537/* Report Count (6) */ 0x95, 0x06,
538/* Input (Cnst,Var) */ 0x81, 0x03,
539/* Report Size (8) */ 0x75, 0x08,
540/* Usage (Contact identifier) */ 0x09, 0x51,
541/* Report Count (1) */ 0x95, 0x01,
542/* Logical Minimum (0) */ 0x15, 0x00,
543/* Logical Maximum (32) */ 0x25, 0x20,
544/* Input (Var) */ 0x81, 0x02,
545/* Usage Page (Generic Desktop) */ 0x05, 0x01,
546/* Logical Maximum (32K) */ 0x26, 0xFF, 0x7F,
547/* Report Size (16) */ 0x75, 0x10,
548/* Usage (X) */ 0x09, 0x30,
549/* Input (Var) */ 0x81, 0x02,
550/* Usage (Y) */ 0x09, 0x31,
551/* Input (Var) */ 0x81, 0x02,
552/* End Collection */ 0xC0,
553/* 4 of 5 */
554/* Usage Page (Digitizer) */ 0x05, 0x0D,
555/* Usage (Finger) */ 0x09, 0x22,
556/* Collection (Logical) */ 0xA1, 0x02,
557/* Usage (Tip Switch) */ 0x09, 0x42,
558/* Logical Minimum (0) */ 0x15, 0x00,
559/* Logical Maximum (1) */ 0x25, 0x01,
560/* Report Size (1) */ 0x75, 0x01,
561/* Report Count (1) */ 0x95, 0x01,
562/* Input (Var) */ 0x81, 0x02,
563/* Usage (In Range) */ 0x09, 0x32,
564/* Logical Minimum (0) */ 0x15, 0x00,
565/* Logical Maximum (1) */ 0x25, 0x01,
566/* Report Size (1) */ 0x75, 0x01,
567/* Report Count (1) */ 0x95, 0x01,
568/* Input (Var) */ 0x81, 0x02,
569/* Report Count (6) */ 0x95, 0x06,
570/* Input (Cnst,Var) */ 0x81, 0x03,
571/* Report Size (8) */ 0x75, 0x08,
572/* Usage (Contact identifier) */ 0x09, 0x51,
573/* Report Count (1) */ 0x95, 0x01,
574/* Logical Minimum (0) */ 0x15, 0x00,
575/* Logical Maximum (32) */ 0x25, 0x20,
576/* Input (Var) */ 0x81, 0x02,
577/* Usage Page (Generic Desktop) */ 0x05, 0x01,
578/* Logical Maximum (32K) */ 0x26, 0xFF, 0x7F,
579/* Report Size (16) */ 0x75, 0x10,
580/* Usage (X) */ 0x09, 0x30,
581/* Input (Var) */ 0x81, 0x02,
582/* Usage (Y) */ 0x09, 0x31,
583/* Input (Var) */ 0x81, 0x02,
584/* End Collection */ 0xC0,
585/* 5 of 5 */
586/* Usage Page (Digitizer) */ 0x05, 0x0D,
587/* Usage (Finger) */ 0x09, 0x22,
588/* Collection (Logical) */ 0xA1, 0x02,
589/* Usage (Tip Switch) */ 0x09, 0x42,
590/* Logical Minimum (0) */ 0x15, 0x00,
591/* Logical Maximum (1) */ 0x25, 0x01,
592/* Report Size (1) */ 0x75, 0x01,
593/* Report Count (1) */ 0x95, 0x01,
594/* Input (Var) */ 0x81, 0x02,
595/* Usage (In Range) */ 0x09, 0x32,
596/* Logical Minimum (0) */ 0x15, 0x00,
597/* Logical Maximum (1) */ 0x25, 0x01,
598/* Report Size (1) */ 0x75, 0x01,
599/* Report Count (1) */ 0x95, 0x01,
600/* Input (Var) */ 0x81, 0x02,
601/* Report Count (6) */ 0x95, 0x06,
602/* Input (Cnst,Var) */ 0x81, 0x03,
603/* Report Size (8) */ 0x75, 0x08,
604/* Usage (Contact identifier) */ 0x09, 0x51,
605/* Report Count (1) */ 0x95, 0x01,
606/* Logical Minimum (0) */ 0x15, 0x00,
607/* Logical Maximum (32) */ 0x25, 0x20,
608/* Input (Var) */ 0x81, 0x02,
609/* Usage Page (Generic Desktop) */ 0x05, 0x01,
610/* Logical Maximum (32K) */ 0x26, 0xFF, 0x7F,
611/* Report Size (16) */ 0x75, 0x10,
612/* Usage (X) */ 0x09, 0x30,
613/* Input (Var) */ 0x81, 0x02,
614/* Usage (Y) */ 0x09, 0x31,
615/* Input (Var) */ 0x81, 0x02,
616/* End Collection */ 0xC0,
617
618/* Note: "Scan time" usage is required for all touch devices (in 100microseconds units). */
619/* Usage Page (Digitizer) */ 0x05, 0x0D,
620/* Logical Minimum (0) */ 0x17, 0x00, 0x00, 0x00, 0x00,
621/* Logical Maximum (2147483647) */ 0x27, 0xFF, 0xFF, 0xFF, 0x7F,
622/* Report Size (32) */ 0x75, 0x20,
623/* Report Count (1) */ 0x95, 0x01,
624/* Unit Exponent (0) */ 0x55, 0x00,
625/* Unit (None) */ 0x65, 0x00,
626/* Usage (Scan time) */ 0x09, 0x56,
627/* Input (Var) */ 0x81, 0x02,
628
629/* Report ID */ 0x85, REPORTID_TOUCH_MAX_COUNT,
630/* Usage (Contact count maximum) */ 0x09, 0x55,
631/* Usage (Device identifier) */ 0x09, 0x53,
632/* Report Size (8) */ 0x75, 0x08,
633/* Report Count (2) */ 0x95, 0x02,
634/* Logical Maximum (255) */ 0x26, 0xFF, 0x00,
635/* Feature (Var) */ 0xB1, 0x02,
636
637/* Usage Page (Vendor-Defined 1) */ 0x06, 0x00, 0xFF,
638/* Usage (QA blob) */ 0x09, 0xC5,
639/* Report ID */ 0x85, REPORTID_TOUCH_QABLOB,
640/* Logical Minimum (0) */ 0x15, 0x00,
641/* Logical Maximum (255) */ 0x26, 0xFF, 0x00,
642/* Report Size (8) */ 0x75, 0x08,
643/* Report Count (256) */ 0x96, 0x00, 0x01,
644/* Feature (Var) */ 0xB1, 0x02,
645/* End Collection */ 0xC0,
646
647/* Note: the pointer report is required by specification:
648 * "The report descriptor for a multiple input device must include at least
649 * one top-level collection for the primary device and a separate top-level
650 * collection for the mouse."
651 */
652/* Usage Page (Generic Desktop) */ 0x05, 0x01,
653/* Usage (Pointer) */ 0x09, 0x01,
654/* Collection (Application) */ 0xA1, 0x01,
655/* Report ID */ 0x85, REPORTID_TOUCH_POINTER,
656/* Usage (Pointer) */ 0x09, 0x01,
657/* Collection (Logical) */ 0xA1, 0x02,
658/* Usage Page (Button) */ 0x05, 0x09,
659/* Usage Minimum (Button 1) */ 0x19, 0x01,
660/* Usage Maximum (Button 2) */ 0x29, 0x02,
661/* Logical Minimum (0) */ 0x15, 0x00,
662/* Logical Maximum (1) */ 0x25, 0x01,
663/* Report Count (2) */ 0x95, 0x02,
664/* Report Size (1) */ 0x75, 0x01,
665/* Input (Var) */ 0x81, 0x02,
666/* Report Count (1) */ 0x95, 0x01,
667/* Report Size (6) */ 0x75, 0x06,
668/* Input (Cnst,Ary,Abs) */ 0x81, 0x01,
669/* Usage Page (Generic Desktop) */ 0x05, 0x01,
670/* Usage (X) */ 0x09, 0x30,
671/* Usage (Y) */ 0x09, 0x31,
672/* Logical Minimum (0) */ 0x16, 0x00, 0x00,
673/* Logical Maximum (32K) */ 0x26, 0xFF, 0x7F,
674/* Physical Minimum (0) */ 0x36, 0x00, 0x00,
675/* Physical Maximum (32K) */ 0x46, 0xFF, 0x7F,
676/* Unit (None) */ 0x66, 0x00, 0x00,
677/* Report Size (16) */ 0x75, 0x10,
678/* Report Count (2) */ 0x95, 0x02,
679/* Input (Var) */ 0x81, 0x02,
680/* End Collection */ 0xC0,
681/* End Collection */ 0xC0,
682
683/* Usage Page (Digitizer) */ 0x05, 0x0D,
684/* Usage (Device configuration) */ 0x09, 0x0E,
685/* Collection (Application) */ 0xA1, 0x01,
686/* Report ID */ 0x85, REPORTID_TOUCH_DEVCONFIG,
687/* Usage (Device settings) */ 0x09, 0x23,
688/* Collection (Logical) */ 0xA1, 0x02,
689/* Usage (Device mode) */ 0x09, 0x52,
690/* Usage (Device identifier) */ 0x09, 0x53,
691/* Logical Minimum (0) */ 0x15, 0x00,
692/* Logical Maximum (10) */ 0x25, 0x0A,
693/* Report Size (8) */ 0x75, 0x08,
694/* Report Count (2) */ 0x95, 0x02,
695/* Feature (Var) */ 0xB1, 0x02,
696/* End Collection */ 0xC0,
697/* End Collection */ 0xC0
698};
699
700/** @todo Do these really have to all be duplicated three times? */
701/* Additional HID class interface descriptor. */
702static const uint8_t g_UsbHidMIfHidDesc[] =
703{
704 /* .bLength = */ 0x09,
705 /* .bDescriptorType = */ 0x21, /* HID */
706 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
707 /* .bCountryCode = */ 0,
708 /* .bNumDescriptors = */ 1,
709 /* .bDescriptorType = */ 0x22, /* Report */
710 /* .wDescriptorLength = */ sizeof(g_UsbHidMReportDesc), 0x00
711};
712
713/* Additional HID class interface descriptor. */
714static const uint8_t g_UsbHidTIfHidDesc[] =
715{
716 /* .bLength = */ 0x09,
717 /* .bDescriptorType = */ 0x21, /* HID */
718 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
719 /* .bCountryCode = */ 0,
720 /* .bNumDescriptors = */ 1,
721 /* .bDescriptorType = */ 0x22, /* Report */
722 /* .wDescriptorLength = */ sizeof(g_UsbHidTReportDesc), 0x00
723};
724
725/* Additional HID class interface descriptor. */
726static const uint8_t g_UsbHidMTIfHidDesc[] =
727{
728 /* .bLength = */ 0x09,
729 /* .bDescriptorType = */ 0x21, /* HID */
730 /* .bcdHID = */ 0x10, 0x02, /* 2.1 */
731 /* .bCountryCode = */ 0,
732 /* .bNumDescriptors = */ 1,
733 /* .bDescriptorType = */ 0x22, /* Report */
734 /* .wDescriptorLength = */ RT_LO_U8(sizeof(g_UsbHidMTReportDesc)), RT_HI_U8(sizeof(g_UsbHidMTReportDesc))
735};
736
737static const VUSBDESCINTERFACEEX g_UsbHidMInterfaceDesc =
738{
739 {
740 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
741 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
742 /* .bInterfaceNumber = */ 0,
743 /* .bAlternateSetting = */ 0,
744 /* .bNumEndpoints = */ 1,
745 /* .bInterfaceClass = */ 3 /* HID */,
746 /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
747 /* .bInterfaceProtocol = */ 2 /* Mouse */,
748 /* .iInterface = */ 0
749 },
750 /* .pvMore = */ NULL,
751 /* .pvClass = */ &g_UsbHidMIfHidDesc,
752 /* .cbClass = */ sizeof(g_UsbHidMIfHidDesc),
753 &g_aUsbHidMEndpointDescs[0],
754 /* .pIAD = */ NULL,
755 /* .cbIAD = */ 0
756};
757
758static const VUSBDESCINTERFACEEX g_UsbHidTInterfaceDesc =
759{
760 {
761 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
762 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
763 /* .bInterfaceNumber = */ 0,
764 /* .bAlternateSetting = */ 0,
765 /* .bNumEndpoints = */ 1,
766 /* .bInterfaceClass = */ 3 /* HID */,
767 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
768 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
769 /* .iInterface = */ 0
770 },
771 /* .pvMore = */ NULL,
772 /* .pvClass = */ &g_UsbHidTIfHidDesc,
773 /* .cbClass = */ sizeof(g_UsbHidTIfHidDesc),
774 &g_aUsbHidTEndpointDescs[0],
775 /* .pIAD = */ NULL,
776 /* .cbIAD = */ 0
777};
778
779static const VUSBDESCINTERFACEEX g_UsbHidMTInterfaceDesc =
780{
781 {
782 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
783 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
784 /* .bInterfaceNumber = */ 0,
785 /* .bAlternateSetting = */ 0,
786 /* .bNumEndpoints = */ 1,
787 /* .bInterfaceClass = */ 3 /* HID */,
788 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
789 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
790 /* .iInterface = */ 0
791 },
792 /* .pvMore = */ NULL,
793 /* .pvClass = */ &g_UsbHidMTIfHidDesc,
794 /* .cbClass = */ sizeof(g_UsbHidMTIfHidDesc),
795 &g_aUsbHidMTEndpointDescs[0],
796 /* .pIAD = */ NULL,
797 /* .cbIAD = */ 0
798};
799
800static const VUSBINTERFACE g_aUsbHidMInterfaces[] =
801{
802 { &g_UsbHidMInterfaceDesc, /* .cSettings = */ 1 },
803};
804
805static const VUSBINTERFACE g_aUsbHidTInterfaces[] =
806{
807 { &g_UsbHidTInterfaceDesc, /* .cSettings = */ 1 },
808};
809
810static const VUSBINTERFACE g_aUsbHidMTInterfaces[] =
811{
812 { &g_UsbHidMTInterfaceDesc, /* .cSettings = */ 1 },
813};
814
815static const VUSBDESCCONFIGEX g_UsbHidMConfigDesc =
816{
817 {
818 /* .bLength = */ sizeof(VUSBDESCCONFIG),
819 /* .bDescriptorType = */ VUSB_DT_CONFIG,
820 /* .wTotalLength = */ 0 /* recalculated on read */,
821 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMInterfaces),
822 /* .bConfigurationValue =*/ 1,
823 /* .iConfiguration = */ 0,
824 /* .bmAttributes = */ RT_BIT(7),
825 /* .MaxPower = */ 50 /* 100mA */
826 },
827 NULL, /* pvMore */
828 &g_aUsbHidMInterfaces[0],
829 NULL /* pvOriginal */
830};
831
832static const VUSBDESCCONFIGEX g_UsbHidTConfigDesc =
833{
834 {
835 /* .bLength = */ sizeof(VUSBDESCCONFIG),
836 /* .bDescriptorType = */ VUSB_DT_CONFIG,
837 /* .wTotalLength = */ 0 /* recalculated on read */,
838 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidTInterfaces),
839 /* .bConfigurationValue =*/ 1,
840 /* .iConfiguration = */ 0,
841 /* .bmAttributes = */ RT_BIT(7),
842 /* .MaxPower = */ 50 /* 100mA */
843 },
844 NULL, /* pvMore */
845 &g_aUsbHidTInterfaces[0],
846 NULL /* pvOriginal */
847};
848
849static const VUSBDESCCONFIGEX g_UsbHidMTConfigDesc =
850{
851 {
852 /* .bLength = */ sizeof(VUSBDESCCONFIG),
853 /* .bDescriptorType = */ VUSB_DT_CONFIG,
854 /* .wTotalLength = */ 0 /* recalculated on read */,
855 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMTInterfaces),
856 /* .bConfigurationValue =*/ 1,
857 /* .iConfiguration = */ 0,
858 /* .bmAttributes = */ RT_BIT(7),
859 /* .MaxPower = */ 50 /* 100mA */
860 },
861 NULL, /* pvMore */
862 &g_aUsbHidMTInterfaces[0],
863 NULL /* pvOriginal */
864};
865
866static const VUSBDESCDEVICE g_UsbHidMDeviceDesc =
867{
868 /* .bLength = */ sizeof(g_UsbHidMDeviceDesc),
869 /* .bDescriptorType = */ VUSB_DT_DEVICE,
870 /* .bcdUsb = */ 0x110, /* 1.1 */
871 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
872 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
873 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
874 /* .bMaxPacketSize0 = */ 8,
875 /* .idVendor = */ VBOX_USB_VENDOR,
876 /* .idProduct = */ USBHID_PID_MOUSE,
877 /* .bcdDevice = */ 0x0100, /* 1.0 */
878 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
879 /* .iProduct = */ USBHID_STR_ID_PRODUCT_M,
880 /* .iSerialNumber = */ 0,
881 /* .bNumConfigurations = */ 1
882};
883
884static const VUSBDESCDEVICE g_UsbHidTDeviceDesc =
885{
886 /* .bLength = */ sizeof(g_UsbHidTDeviceDesc),
887 /* .bDescriptorType = */ VUSB_DT_DEVICE,
888 /* .bcdUsb = */ 0x110, /* 1.1 */
889 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
890 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
891 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
892 /* .bMaxPacketSize0 = */ 8,
893 /* .idVendor = */ VBOX_USB_VENDOR,
894 /* .idProduct = */ USBHID_PID_TABLET,
895 /* .bcdDevice = */ 0x0100, /* 1.0 */
896 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
897 /* .iProduct = */ USBHID_STR_ID_PRODUCT_T,
898 /* .iSerialNumber = */ 0,
899 /* .bNumConfigurations = */ 1
900};
901
902static const VUSBDESCDEVICE g_UsbHidMTDeviceDesc =
903{
904 /* .bLength = */ sizeof(g_UsbHidMTDeviceDesc),
905 /* .bDescriptorType = */ VUSB_DT_DEVICE,
906 /* .bcdUsb = */ 0x110, /* 1.1 */
907 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
908 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
909 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
910 /* .bMaxPacketSize0 = */ 8,
911 /* .idVendor = */ VBOX_USB_VENDOR,
912 /* .idProduct = */ USBHID_PID_MULTI_TOUCH,
913 /* .bcdDevice = */ 0x0100, /* 1.0 */
914 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
915 /* .iProduct = */ USBHID_STR_ID_PRODUCT_MT,
916 /* .iSerialNumber = */ 0,
917 /* .bNumConfigurations = */ 1
918};
919
920static const PDMUSBDESCCACHE g_UsbHidMDescCache =
921{
922 /* .pDevice = */ &g_UsbHidMDeviceDesc,
923 /* .paConfigs = */ &g_UsbHidMConfigDesc,
924 /* .paLanguages = */ g_aUsbHidLanguages,
925 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
926 /* .fUseCachedDescriptors = */ true,
927 /* .fUseCachedStringsDescriptors = */ true
928};
929
930static const PDMUSBDESCCACHE g_UsbHidTDescCache =
931{
932 /* .pDevice = */ &g_UsbHidTDeviceDesc,
933 /* .paConfigs = */ &g_UsbHidTConfigDesc,
934 /* .paLanguages = */ g_aUsbHidLanguages,
935 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
936 /* .fUseCachedDescriptors = */ true,
937 /* .fUseCachedStringsDescriptors = */ true
938};
939
940static const PDMUSBDESCCACHE g_UsbHidMTDescCache =
941{
942 /* .pDevice = */ &g_UsbHidMTDeviceDesc,
943 /* .paConfigs = */ &g_UsbHidMTConfigDesc,
944 /* .paLanguages = */ g_aUsbHidLanguages,
945 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
946 /* .fUseCachedDescriptors = */ true,
947 /* .fUseCachedStringsDescriptors = */ true
948};
949
950
951/*******************************************************************************
952* Internal Functions *
953*******************************************************************************/
954
955/**
956 * Initializes an URB queue.
957 *
958 * @param pQueue The URB queue.
959 */
960static void usbHidQueueInit(PUSBHIDURBQUEUE pQueue)
961{
962 pQueue->pHead = NULL;
963 pQueue->ppTail = &pQueue->pHead;
964}
965
966
967
968/**
969 * Inserts an URB at the end of the queue.
970 *
971 * @param pQueue The URB queue.
972 * @param pUrb The URB to insert.
973 */
974DECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
975{
976 pUrb->Dev.pNext = NULL;
977 *pQueue->ppTail = pUrb;
978 pQueue->ppTail = &pUrb->Dev.pNext;
979}
980
981
982/**
983 * Unlinks the head of the queue and returns it.
984 *
985 * @returns The head entry.
986 * @param pQueue The URB queue.
987 */
988DECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
989{
990 PVUSBURB pUrb = pQueue->pHead;
991 if (pUrb)
992 {
993 PVUSBURB pNext = pUrb->Dev.pNext;
994 pQueue->pHead = pNext;
995 if (!pNext)
996 pQueue->ppTail = &pQueue->pHead;
997 else
998 pUrb->Dev.pNext = NULL;
999 }
1000 return pUrb;
1001}
1002
1003
1004/**
1005 * Removes an URB from anywhere in the queue.
1006 *
1007 * @returns true if found, false if not.
1008 * @param pQueue The URB queue.
1009 * @param pUrb The URB to remove.
1010 */
1011DECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
1012{
1013 PVUSBURB pCur = pQueue->pHead;
1014 if (pCur == pUrb)
1015 {
1016 pQueue->pHead = pUrb->Dev.pNext;
1017 if (!pUrb->Dev.pNext)
1018 pQueue->ppTail = &pQueue->pHead;
1019 }
1020 else
1021 {
1022 while (pCur)
1023 {
1024 if (pCur->Dev.pNext == pUrb)
1025 {
1026 pCur->Dev.pNext = pUrb->Dev.pNext;
1027 break;
1028 }
1029 pCur = pCur->Dev.pNext;
1030 }
1031 if (!pCur)
1032 return false;
1033 if (!pUrb->Dev.pNext)
1034 pQueue->ppTail = &pCur->Dev.pNext;
1035 }
1036 pUrb->Dev.pNext = NULL;
1037 return true;
1038}
1039
1040
1041/**
1042 * Checks if the queue is empty or not.
1043 *
1044 * @returns true if it is, false if it isn't.
1045 * @param pQueue The URB queue.
1046 */
1047DECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
1048{
1049 return pQueue->pHead == NULL;
1050}
1051
1052
1053/**
1054 * Links an URB into the done queue.
1055 *
1056 * @param pThis The HID instance.
1057 * @param pUrb The URB.
1058 */
1059static void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
1060{
1061 usbHidQueueAddTail(&pThis->DoneQueue, pUrb);
1062
1063 if (pThis->fHaveDoneQueueWaiter)
1064 {
1065 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
1066 AssertRC(rc);
1067 }
1068}
1069
1070
1071
1072/**
1073 * Completes the URB with a stalled state, halting the pipe.
1074 */
1075static int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
1076{
1077 LogRelFlow(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n",
1078 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
1079
1080 pUrb->enmStatus = VUSBSTATUS_STALL;
1081
1082 /** @todo figure out if the stall is global or pipe-specific or both. */
1083 if (pEp)
1084 pEp->fHalted = true;
1085 else
1086 {
1087 pThis->aEps[0].fHalted = true;
1088 pThis->aEps[1].fHalted = true;
1089 }
1090
1091 usbHidLinkDone(pThis, pUrb);
1092 return VINF_SUCCESS;
1093}
1094
1095
1096/**
1097 * Completes the URB with a OK state.
1098 */
1099static int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, size_t cbData)
1100{
1101 LogRelFlow(("usbHidCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n",
1102 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
1103
1104 pUrb->enmStatus = VUSBSTATUS_OK;
1105 pUrb->cbData = (uint32_t)cbData;
1106
1107 usbHidLinkDone(pThis, pUrb);
1108 return VINF_SUCCESS;
1109}
1110
1111
1112/**
1113 * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
1114 * usbHidHandleDefaultPipe.
1115 *
1116 * @returns VBox status code.
1117 * @param pThis The HID instance.
1118 * @param pUrb Set when usbHidHandleDefaultPipe is the
1119 * caller.
1120 * @param fSetConfig Set when usbHidUsbSetConfiguration is the
1121 * caller.
1122 */
1123static int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
1124{
1125 /*
1126 * Wait for the any command currently executing to complete before
1127 * resetting. (We cannot cancel its execution.) How we do this depends
1128 * on the reset method.
1129 */
1130
1131 /*
1132 * Reset the device state.
1133 */
1134 pThis->enmState = USBHIDREQSTATE_READY;
1135 pThis->fHasPendingChanges = false;
1136
1137 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
1138 pThis->aEps[i].fHalted = false;
1139
1140 if (!pUrb && !fSetConfig) /* (only device reset) */
1141 pThis->bConfigurationValue = 0; /* default */
1142
1143 /*
1144 * Ditch all pending URBs.
1145 */
1146 PVUSBURB pCurUrb;
1147 while ((pCurUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
1148 {
1149 pCurUrb->enmStatus = VUSBSTATUS_CRC;
1150 usbHidLinkDone(pThis, pCurUrb);
1151 }
1152
1153 if (pUrb)
1154 return usbHidCompleteOk(pThis, pUrb, 0);
1155 return VINF_SUCCESS;
1156}
1157
1158static int8_t clamp_i8(int32_t val)
1159{
1160 if (val > 127) {
1161 val = 127;
1162 } else if (val < -127) {
1163 val = -127;
1164 }
1165 return val;
1166}
1167
1168/**
1169 * Create a USB HID report report based on the currently accumulated data.
1170 */
1171static size_t usbHidFillReport(PUSBHIDTM_REPORT pReport,
1172 PUSBHIDM_ACCUM pAccumulated, USBHIDMODE enmMode)
1173{
1174 size_t cbCopy;
1175
1176 switch (enmMode)
1177 {
1178 case USBHIDMODE_ABSOLUTE:
1179 pReport->t.fButtons = pAccumulated->u.Absolute.fButtons;
1180 pReport->t.x = pAccumulated->u.Absolute.x;
1181 pReport->t.y = pAccumulated->u.Absolute.y;
1182
1183 cbCopy = sizeof(pReport->t);
1184 LogRel3(("Abs event, x=%d, y=%d, fButtons=%02x, report size %d\n",
1185 pReport->t.x, pReport->t.y, pReport->t.fButtons,
1186 cbCopy));
1187 break;
1188 case USBHIDMODE_RELATIVE:
1189 pReport->m.fButtons = pAccumulated->u.Relative.fButtons;
1190 pReport->m.dx = clamp_i8(pAccumulated->u.Relative.dx);
1191 pReport->m.dy = clamp_i8(pAccumulated->u.Relative.dy);
1192 pReport->m.dz = clamp_i8(pAccumulated->u.Relative.dz);
1193
1194 cbCopy = sizeof(pReport->m);
1195 LogRel3(("Rel event, dx=%d, dy=%d, dz=%d, fButtons=%02x, report size %d\n",
1196 pReport->m.dx, pReport->m.dy, pReport->m.dz,
1197 pReport->m.fButtons, cbCopy));
1198 break;
1199 }
1200
1201 /* Clear the accumulated movement. */
1202 RT_ZERO(*pAccumulated);
1203
1204 return cbCopy;
1205}
1206
1207DECLINLINE(MTCONTACT *) usbHidFindMTContact(MTCONTACT *paContacts, size_t cContacts,
1208 uint8_t u8Mask, uint8_t u8Value)
1209{
1210 size_t i;
1211 for (i = 0; i < cContacts; i++)
1212 {
1213 if ((paContacts[i].status & u8Mask) == u8Value)
1214 {
1215 return &paContacts[i];
1216 }
1217 }
1218
1219 return NULL;
1220}
1221
1222static int usbHidSendMultiTouchReport(PUSBHID pThis, PVUSBURB pUrb)
1223{
1224 uint8_t i;
1225 MTCONTACT *pRepContact;
1226 MTCONTACT *pCurContact;
1227
1228 /* Number of contacts to be reported. In hybrid mode the first report contains
1229 * total number of contacts and subsequent reports contain 0.
1230 */
1231 uint8_t cContacts = 0;
1232
1233 Assert(pThis->fHasPendingChanges);
1234
1235 if (!pThis->fTouchReporting)
1236 {
1237 pThis->fTouchReporting = true;
1238
1239 /* Update the reporting state with the new current state.
1240 * Also mark all active contacts in reporting state as dirty,
1241 * that is they must be reported to the guest.
1242 */
1243 for (i = 0; i < MT_CONTACT_MAX_COUNT; i++)
1244 {
1245 pRepContact = &pThis->aReportingContactState[i];
1246 pCurContact = &pThis->aCurrentContactState[i];
1247
1248 if (pCurContact->status & MT_CONTACT_S_ACTIVE)
1249 {
1250 if (pCurContact->status & MT_CONTACT_S_REUSED)
1251 {
1252 pCurContact->status &= ~MT_CONTACT_S_REUSED;
1253
1254 /* Keep x,y. Will report lost contact at this point. */
1255 pRepContact->id = pCurContact->oldId;
1256 pRepContact->flags = 0;
1257 pRepContact->status = MT_CONTACT_S_REUSED;
1258 }
1259 else if (pThis->aCurrentContactState[i].status & MT_CONTACT_S_CANCELLED)
1260 {
1261 pCurContact->status &= ~(MT_CONTACT_S_CANCELLED | MT_CONTACT_S_ACTIVE);
1262
1263 /* Keep x,y. Will report lost contact at this point. */
1264 pRepContact->id = pCurContact->id;
1265 pRepContact->flags = 0;
1266 pRepContact->status = 0;
1267 }
1268 else
1269 {
1270 if (pCurContact->flags == 0)
1271 {
1272 pCurContact->status &= ~MT_CONTACT_S_ACTIVE; /* Contact disapeared. */
1273 }
1274
1275 pRepContact->x = pCurContact->x;
1276 pRepContact->y = pCurContact->y;
1277 pRepContact->id = pCurContact->id;
1278 pRepContact->flags = pCurContact->flags;
1279 pRepContact->status = 0;
1280 }
1281
1282 cContacts++;
1283
1284 pRepContact->status |= MT_CONTACT_S_DIRTY;
1285 }
1286 else
1287 {
1288 pRepContact->status = 0;
1289 }
1290 }
1291 }
1292
1293 /* Report current state. */
1294 USBHIDMT_REPORT *p = (USBHIDMT_REPORT *)&pUrb->abData[0];
1295 RT_ZERO(*p);
1296
1297 p->idReport = REPORTID_TOUCH_EVENT;
1298 p->cContacts = cContacts;
1299
1300 uint8_t iReportedContact;
1301 for (iReportedContact = 0; iReportedContact < MT_CONTACTS_PER_REPORT; iReportedContact++)
1302 {
1303 /* Find the next not reported contact. */
1304 pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
1305 MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
1306
1307 if (!pRepContact)
1308 {
1309 LogRel3(("usbHid: no more touch contacts to report\n"));
1310 break;
1311 }
1312
1313 if (pRepContact->status & MT_CONTACT_S_REUSED)
1314 {
1315 /* Do not clear DIRTY flag for contacts which were reused.
1316 * Because two reports must be generated:
1317 * one for old contact off, and the second for new contact on.
1318 */
1319 pRepContact->status &= ~MT_CONTACT_S_REUSED;
1320 }
1321 else
1322 {
1323 pRepContact->status &= ~MT_CONTACT_S_DIRTY;
1324 }
1325
1326 p->aContacts[iReportedContact].fContact = pRepContact->flags;
1327 p->aContacts[iReportedContact].cContact = pRepContact->id;
1328 p->aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
1329 p->aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
1330 }
1331
1332 p->u32ScanTime = pThis->u32LastTouchScanTime * 10;
1333
1334 Assert(iReportedContact > 0);
1335
1336 /* Reset TouchReporting if all contacts reported. */
1337 pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
1338 MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
1339
1340 if (!pRepContact)
1341 {
1342 LogRel3(("usbHid: all touch contacts reported\n"));
1343 pThis->fTouchReporting = false;
1344 pThis->fHasPendingChanges = false;
1345 }
1346 else
1347 {
1348 pThis->fHasPendingChanges = true;
1349 }
1350
1351 LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", sizeof(USBHIDMT_REPORT), p));
1352 return usbHidCompleteOk(pThis, pUrb, sizeof(USBHIDMT_REPORT));
1353}
1354
1355/**
1356 * Sends a state report to the host if there is a pending URB.
1357 */
1358static int usbHidSendReport(PUSBHID pThis)
1359{
1360 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
1361
1362 if (pThis->enmMode == USBHIDMODE_MULTI_TOUCH)
1363 {
1364 /* This device uses a different reporting method and fHasPendingChanges maintenance. */
1365 if (pUrb)
1366 return usbHidSendMultiTouchReport(pThis, pUrb);
1367 return VINF_SUCCESS;
1368 }
1369
1370 if (pUrb)
1371 {
1372 PUSBHIDTM_REPORT pReport = (PUSBHIDTM_REPORT)&pUrb->abData[0];
1373 size_t cbCopy;
1374
1375 cbCopy = usbHidFillReport(pReport, &pThis->PtrDelta, pThis->enmMode);
1376 pThis->fHasPendingChanges = false;
1377 return usbHidCompleteOk(pThis, pUrb, cbCopy);
1378 }
1379 else
1380 {
1381 LogRelFlow(("No available URB for USB mouse\n"));
1382 pThis->fHasPendingChanges = true;
1383 }
1384 return VINF_EOF;
1385}
1386
1387/**
1388 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1389 */
1390static DECLCALLBACK(void *) usbHidMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1391{
1392 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
1393 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1394 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Lun0.IPort);
1395 return NULL;
1396}
1397
1398/**
1399 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
1400 */
1401static DECLCALLBACK(int) usbHidMousePutEvent(PPDMIMOUSEPORT pInterface,
1402 int32_t dx, int32_t dy, int32_t dz,
1403 int32_t dw, uint32_t fButtons)
1404{
1405 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1406 RTCritSectEnter(&pThis->CritSect);
1407
1408 /* Accumulate movement - the events from the front end may arrive
1409 * at a much higher rate than USB can handle.
1410 */
1411 pThis->PtrDelta.u.Relative.fButtons = fButtons;
1412 pThis->PtrDelta.u.Relative.dx += dx;
1413 pThis->PtrDelta.u.Relative.dy += dy;
1414 pThis->PtrDelta.u.Relative.dz -= dz; /* Inverted! */
1415
1416 /* Send a report if possible. */
1417 usbHidSendReport(pThis);
1418
1419 RTCritSectLeave(&pThis->CritSect);
1420 return VINF_SUCCESS;
1421}
1422
1423/**
1424 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
1425 */
1426static DECLCALLBACK(int) usbHidMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1427 uint32_t x, uint32_t y,
1428 int32_t dz, int32_t dw,
1429 uint32_t fButtons)
1430{
1431 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1432 RTCritSectEnter(&pThis->CritSect);
1433
1434 Assert(pThis->enmMode == USBHIDMODE_ABSOLUTE);
1435
1436 /* Accumulate movement - the events from the front end may arrive
1437 * at a much higher rate than USB can handle. Probably not a real issue
1438 * when only the Z axis is relative (X/Y movement isn't technically
1439 * accumulated and only the last value is used).
1440 */
1441 pThis->PtrDelta.u.Absolute.fButtons = fButtons;
1442 pThis->PtrDelta.u.Absolute.x = x >> pThis->u8CoordShift;
1443 pThis->PtrDelta.u.Absolute.y = y >> pThis->u8CoordShift;
1444
1445 /* Send a report if possible. */
1446 usbHidSendReport(pThis);
1447
1448 RTCritSectLeave(&pThis->CritSect);
1449 return VINF_SUCCESS;
1450}
1451
1452/**
1453 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMultiTouch}
1454 */
1455static DECLCALLBACK(int) usbHidMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
1456 uint8_t cContacts,
1457 const uint64_t *pau64Contacts,
1458 uint32_t u32ScanTime)
1459{
1460 uint8_t i;
1461 uint8_t j;
1462
1463 /* Make a copy of new contacts */
1464 MTCONTACT *paNewContacts = (MTCONTACT *)RTMemTmpAlloc(sizeof(MTCONTACT) * cContacts);
1465 if (!paNewContacts)
1466 return VERR_NO_MEMORY;
1467
1468 for (i = 0; i < cContacts; i++)
1469 {
1470 paNewContacts[i].x = RT_LO_U16(RT_LO_U32(pau64Contacts[i]));
1471 paNewContacts[i].y = RT_HI_U16(RT_LO_U32(pau64Contacts[i]));
1472 paNewContacts[i].id = RT_BYTE1(RT_HI_U32(pau64Contacts[i]));
1473 paNewContacts[i].flags = RT_BYTE2(RT_HI_U32(pau64Contacts[i])) & (MT_CONTACT_F_IN_CONTACT | MT_CONTACT_F_IN_RANGE);
1474 paNewContacts[i].status = MT_CONTACT_S_DIRTY;
1475 paNewContacts[i].oldId = 0; /* Not used. */
1476 }
1477
1478 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1479 MTCONTACT *pCurContact = NULL;
1480 MTCONTACT *pNewContact = NULL;
1481
1482 RTCritSectEnter(&pThis->CritSect);
1483
1484 Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1485
1486 /* Maintain a state of all current contacts.
1487 * Intr URBs will be completed according to the state.
1488 */
1489
1490 /* Mark all existing contacts as dirty. */
1491 for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
1492 pThis->aCurrentContactState[i].status |= MT_CONTACT_S_DIRTY;
1493
1494 /* Update existing contacts and mark new contacts. */
1495 for (i = 0; i < cContacts; i++)
1496 {
1497 pNewContact = &paNewContacts[i];
1498
1499 /* Find existing contact with the same id. */
1500 pCurContact = NULL;
1501 for (j = 0; j < RT_ELEMENTS(pThis->aCurrentContactState); j++)
1502 {
1503 if ( (pThis->aCurrentContactState[j].status & MT_CONTACT_S_ACTIVE) != 0
1504 && pThis->aCurrentContactState[j].id == pNewContact->id)
1505 {
1506 pCurContact = &pThis->aCurrentContactState[j];
1507 break;
1508 }
1509 }
1510
1511 if (pCurContact)
1512 {
1513 pNewContact->status &= ~MT_CONTACT_S_DIRTY;
1514
1515 pCurContact->x = pNewContact->x;
1516 pCurContact->y = pNewContact->y;
1517 if (pCurContact->flags == 0) /* Contact disappeared already. */
1518 {
1519 if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
1520 {
1521 pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
1522 pCurContact->oldId = pCurContact->id;
1523 }
1524 }
1525 pCurContact->flags = pNewContact->flags;
1526 pCurContact->status &= ~MT_CONTACT_S_DIRTY;
1527 }
1528 }
1529
1530 /* Append new contacts (the dirty one in the paNewContacts). */
1531 for (i = 0; i < cContacts; i++)
1532 {
1533 pNewContact = &paNewContacts[i];
1534
1535 if (pNewContact->status & MT_CONTACT_S_DIRTY)
1536 {
1537 /* It is a new contact, copy is to one of not ACTIVE or not updated existing contacts. */
1538 pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
1539 MT_CONTACT_S_ACTIVE, 0);
1540
1541 if (pCurContact)
1542 {
1543 *pCurContact = *pNewContact;
1544 pCurContact->status = MT_CONTACT_S_ACTIVE; /* Reset status. */
1545 }
1546 else
1547 {
1548 /* Dirty existing contacts can be reused. */
1549 pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
1550 MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY,
1551 MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY);
1552
1553 if (pCurContact)
1554 {
1555 pCurContact->x = pNewContact->x;
1556 pCurContact->y = pNewContact->y;
1557 if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
1558 {
1559 pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
1560 pCurContact->oldId = pCurContact->id;
1561 }
1562 pCurContact->flags = pNewContact->flags;
1563 pCurContact->status &= ~MT_CONTACT_S_DIRTY;
1564 }
1565 else
1566 {
1567 LogRel3(("usbHid: dropped new contact: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
1568 pNewContact->x,
1569 pNewContact->y,
1570 pNewContact->id,
1571 pNewContact->flags,
1572 pNewContact->status,
1573 pNewContact->oldId
1574 ));
1575 }
1576 }
1577 }
1578 }
1579
1580 /* Mark still dirty existing contacts as cancelled, because a new set of contacts does not include them. */
1581 for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
1582 {
1583 pCurContact = &pThis->aCurrentContactState[i];
1584 if (pCurContact->status & MT_CONTACT_S_DIRTY)
1585 {
1586 pCurContact->status |= MT_CONTACT_S_CANCELLED;
1587 pCurContact->status &= ~MT_CONTACT_S_DIRTY;
1588 }
1589 }
1590
1591 pThis->u32LastTouchScanTime = u32ScanTime;
1592
1593 LogRel3(("usbHid: scanTime (ms): %d\n", pThis->u32LastTouchScanTime));
1594 for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
1595 {
1596 LogRel3(("usbHid: contact state[%d]: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
1597 i,
1598 pThis->aCurrentContactState[i].x,
1599 pThis->aCurrentContactState[i].y,
1600 pThis->aCurrentContactState[i].id,
1601 pThis->aCurrentContactState[i].flags,
1602 pThis->aCurrentContactState[i].status,
1603 pThis->aCurrentContactState[i].oldId
1604 ));
1605 }
1606
1607 pThis->fHasPendingChanges = true;
1608
1609 /* Send a report if possible. */
1610 usbHidSendReport(pThis);
1611
1612 RTCritSectLeave(&pThis->CritSect);
1613
1614 RTMemTmpFree(paNewContacts);
1615 return VINF_SUCCESS;
1616}
1617
1618/**
1619 * @copydoc PDMUSBREG::pfnUrbReap
1620 */
1621static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1622{
1623 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1624
1625 RTCritSectEnter(&pThis->CritSect);
1626
1627 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1628 if (!pUrb && cMillies)
1629 {
1630 /* Wait */
1631 pThis->fHaveDoneQueueWaiter = true;
1632 RTCritSectLeave(&pThis->CritSect);
1633
1634 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1635
1636 RTCritSectEnter(&pThis->CritSect);
1637 pThis->fHaveDoneQueueWaiter = false;
1638
1639 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1640 }
1641
1642 RTCritSectLeave(&pThis->CritSect);
1643
1644 if (pUrb)
1645 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1646 pUrb->pszDesc));
1647 return pUrb;
1648}
1649
1650
1651/**
1652 * @copydoc PDMUSBREG::pfnUrbCancel
1653 */
1654static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1655{
1656 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1657 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1658 pUrb->pszDesc));
1659 RTCritSectEnter(&pThis->CritSect);
1660
1661 /*
1662 * Remove the URB from the to-host queue and move it onto the done queue.
1663 */
1664 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1665 usbHidLinkDone(pThis, pUrb);
1666
1667 RTCritSectLeave(&pThis->CritSect);
1668 return VINF_SUCCESS;
1669}
1670
1671
1672/**
1673 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1674 * rather different from bulk requests because an interrupt read URB may complete
1675 * after arbitrarily long time.
1676 */
1677static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1678{
1679 /*
1680 * Stall the request if the pipe is halted.
1681 */
1682 if (RT_UNLIKELY(pEp->fHalted))
1683 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1684
1685 /*
1686 * Deal with the URB according to the state.
1687 */
1688 switch (pThis->enmState)
1689 {
1690 /*
1691 * We've data left to transfer to the host.
1692 */
1693 case USBHIDREQSTATE_DATA_TO_HOST:
1694 {
1695 AssertFailed();
1696 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1697 return usbHidCompleteOk(pThis, pUrb, 0);
1698 }
1699
1700 /*
1701 * Status transfer.
1702 */
1703 case USBHIDREQSTATE_STATUS:
1704 {
1705 AssertFailed();
1706 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1707 pThis->enmState = USBHIDREQSTATE_READY;
1708 return usbHidCompleteOk(pThis, pUrb, 0);
1709 }
1710
1711 case USBHIDREQSTATE_READY:
1712 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1713 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1714 pUrb, pUrb->pszDesc));
1715 /* If a report is pending, send it right away. */
1716 if (pThis->fHasPendingChanges)
1717 usbHidSendReport(pThis);
1718 return VINF_SUCCESS;
1719
1720 /*
1721 * Bad states, stall.
1722 */
1723 default:
1724 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1725 pThis->enmState, pUrb->cbData));
1726 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1727 }
1728}
1729
1730#define GET_REPORT 0x01
1731#define GET_IDLE 0x02
1732#define GET_PROTOCOL 0x03
1733#define SET_REPORT 0x09
1734#define SET_IDLE 0x0A
1735#define SET_PROTOCOL 0x0B
1736
1737static uint8_t sau8QASampleBlob[256] =
1738{
1739 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87,
1740 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88,
1741 0x07, 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6,
1742 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2,
1743 0x2e, 0x84, 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43,
1744 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc,
1745 0x47, 0x70, 0x1b, 0x59, 0x6f, 0x74, 0x43, 0xc4,
1746 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71,
1747 0xc7, 0x95, 0x0e, 0x31, 0x55, 0x21, 0xd3, 0xb5,
1748 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19,
1749 0x3e, 0xb3, 0xaf, 0x75, 0x81, 0x9d, 0x53, 0xb9,
1750 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c,
1751 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d, 0xa7, 0x26,
1752 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b,
1753 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0, 0x2a,
1754 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8,
1755 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1,
1756 0x0b, 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7,
1757 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b,
1758 0xe8, 0x8a, 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35,
1759 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc,
1760 0x2b, 0x53, 0x5c, 0x69, 0x52, 0xd5, 0xc8, 0x73,
1761 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff,
1762 0x05, 0xd8, 0x2b, 0x79, 0x9a, 0xe2, 0x34, 0x60,
1763 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc,
1764 0x80, 0xe3, 0x0f, 0xbd, 0x65, 0x20, 0x08, 0x13,
1765 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7,
1766 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe, 0x31, 0x48,
1767 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89,
1768 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a, 0xe4,
1769 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08,
1770 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2
1771};
1772
1773static int usbHidRequestClass(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1774{
1775 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1776
1777 if (pThis->enmMode != USBHIDMODE_MULTI_TOUCH)
1778 {
1779 LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1780 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1781 pSetup->wIndex, pSetup->wLength));
1782 return usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req");
1783 }
1784
1785 int rc = VINF_SUCCESS;
1786
1787 switch (pSetup->bRequest)
1788 {
1789 case SET_REPORT:
1790 case GET_REPORT:
1791 {
1792 uint8_t u8ReportType = RT_HI_U8(pSetup->wValue);
1793 uint8_t u8ReportID = RT_LO_U8(pSetup->wValue);
1794 LogRelFlow(("usbHid: %s: type %d, ID %d, data\n%.*Rhxd\n",
1795 pSetup->bRequest == GET_REPORT? "GET_REPORT": "SET_REPORT",
1796 u8ReportType, u8ReportID,
1797 pUrb->cbData - sizeof(VUSBSETUP), &pUrb->abData[sizeof(VUSBSETUP)]));
1798 uint32_t cbData = 0;
1799 if (pSetup->bRequest == GET_REPORT)
1800 {
1801 if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_MAX_COUNT)
1802 {
1803 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_MAX_COUNT;
1804 pUrb->abData[sizeof(VUSBSETUP) + 1] = MT_CONTACT_MAX_COUNT; /* Contact count maximum. */
1805 pUrb->abData[sizeof(VUSBSETUP) + 2] = 0; /* Device identifier */
1806 cbData = 3;
1807 }
1808 else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_QABLOB)
1809 {
1810 uint32_t cbLeft = pUrb->cbData;
1811 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_QABLOB; /* Report Id. */
1812 memcpy(&pUrb->abData[sizeof(VUSBSETUP) + 1],
1813 sau8QASampleBlob, sizeof(sau8QASampleBlob));
1814 cbData = sizeof(sau8QASampleBlob) + 1;
1815 }
1816 }
1817
1818 rc = usbHidCompleteOk(pThis, pUrb, sizeof(VUSBSETUP) + cbData);
1819 } break;
1820 default:
1821 {
1822 LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1823 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1824 pSetup->wIndex, pSetup->wLength));
1825 rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req MT");
1826 }
1827 }
1828
1829 return rc;
1830}
1831
1832/**
1833 * Handles request sent to the default control pipe.
1834 */
1835static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1836{
1837 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1838 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1839
1840 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1841 {
1842 switch (pSetup->bRequest)
1843 {
1844 case VUSB_REQ_GET_DESCRIPTOR:
1845 {
1846 switch (pSetup->bmRequestType)
1847 {
1848 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1849 {
1850 switch (pSetup->wValue >> 8)
1851 {
1852 case VUSB_DT_STRING:
1853 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1854 pSetup->wValue, pSetup->wIndex));
1855 break;
1856 default:
1857 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1858 pSetup->wValue, pSetup->wIndex));
1859 break;
1860 }
1861 break;
1862 }
1863
1864 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1865 {
1866 switch (pSetup->wValue >> 8)
1867 {
1868 uint32_t cbCopy;
1869 uint32_t cbDesc;
1870 const uint8_t *pDesc;
1871
1872 case DT_IF_HID_DESCRIPTOR:
1873 {
1874 switch (pThis->enmMode)
1875 {
1876 case USBHIDMODE_ABSOLUTE:
1877 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1878 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1879 break;
1880 case USBHIDMODE_RELATIVE:
1881 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1882 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1883 break;
1884 case USBHIDMODE_MULTI_TOUCH:
1885 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1886 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1887 break;
1888 }
1889 /* Returned data is written after the setup message. */
1890 cbCopy = pUrb->cbData - sizeof(*pSetup);
1891 cbCopy = RT_MIN(cbCopy, cbDesc);
1892 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1893 pSetup->wValue, pSetup->wIndex,
1894 cbCopy));
1895 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1896 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1897 }
1898
1899 case DT_IF_HID_REPORT:
1900 {
1901 switch (pThis->enmMode)
1902 {
1903 case USBHIDMODE_ABSOLUTE:
1904 {
1905 cbDesc = sizeof(g_UsbHidTReportDesc);
1906 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
1907 break;
1908 }
1909 case USBHIDMODE_RELATIVE:
1910 {
1911 cbDesc = sizeof(g_UsbHidMReportDesc);
1912 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
1913 break;
1914 }
1915 case USBHIDMODE_MULTI_TOUCH:
1916 {
1917 cbDesc = sizeof(g_UsbHidMTReportDesc);
1918 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
1919 break;
1920 }
1921 }
1922 /* Returned data is written after the setup message. */
1923 cbCopy = pUrb->cbData - sizeof(*pSetup);
1924 cbCopy = RT_MIN(cbCopy, cbDesc);
1925 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
1926 pSetup->wValue, pSetup->wIndex,
1927 cbCopy));
1928 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1929 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1930 }
1931
1932 default:
1933 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1934 pSetup->wValue, pSetup->wIndex));
1935 break;
1936 }
1937 break;
1938 }
1939
1940 default:
1941 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
1942 pSetup->bmRequestType));
1943 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1944 }
1945 break;
1946 }
1947
1948 case VUSB_REQ_GET_STATUS:
1949 {
1950 uint16_t wRet = 0;
1951
1952 if (pSetup->wLength != 2)
1953 {
1954 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
1955 pSetup->wLength));
1956 break;
1957 }
1958 Assert(pSetup->wValue == 0);
1959 switch (pSetup->bmRequestType)
1960 {
1961 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1962 {
1963 Assert(pSetup->wIndex == 0);
1964 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
1965 wRet = 0; /* Not self-powered, no remote wakeup. */
1966 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1967 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1968 }
1969
1970 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1971 {
1972 if (pSetup->wIndex == 0)
1973 {
1974 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1975 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1976 }
1977 else
1978 {
1979 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
1980 pSetup->wIndex));
1981 }
1982 break;
1983 }
1984
1985 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1986 {
1987 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1988 {
1989 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1990 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1991 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1992 }
1993 else
1994 {
1995 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
1996 pSetup->wIndex));
1997 }
1998 break;
1999 }
2000
2001 default:
2002 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
2003 pSetup->bmRequestType));
2004 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
2005 }
2006 break;
2007 }
2008
2009 case VUSB_REQ_CLEAR_FEATURE:
2010 break;
2011 }
2012
2013 /** @todo implement this. */
2014 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2015 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2016 pSetup->wIndex, pSetup->wLength));
2017
2018 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
2019 }
2020 else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
2021 {
2022 /* Only VUSB_TO_INTERFACE is allowed. */
2023 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_INTERFACE)
2024 {
2025 return usbHidRequestClass(pThis, pEp, pUrb);
2026 }
2027
2028 LogRelFlow(("usbHid: invalid recipient of class req: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2029 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2030 pSetup->wIndex, pSetup->wLength));
2031 return usbHidCompleteStall(pThis, pEp, pUrb, "Invalid recip");
2032 }
2033 else
2034 {
2035 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2036 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2037 pSetup->wIndex, pSetup->wLength));
2038 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
2039 }
2040
2041 return VINF_SUCCESS;
2042}
2043
2044
2045/**
2046 * @copydoc PDMUSBREG::pfnUrbQueue
2047 */
2048static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
2049{
2050 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2051 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
2052 pUrb, pUrb->pszDesc, pUrb->EndPt));
2053 RTCritSectEnter(&pThis->CritSect);
2054
2055 /*
2056 * Parse on a per end-point basis.
2057 */
2058 int rc;
2059 switch (pUrb->EndPt)
2060 {
2061 case 0:
2062 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
2063 break;
2064
2065 case 0x81:
2066 AssertFailed();
2067 case 0x01:
2068 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
2069 break;
2070
2071 default:
2072 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
2073 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
2074 break;
2075 }
2076
2077 RTCritSectLeave(&pThis->CritSect);
2078 return rc;
2079}
2080
2081
2082/**
2083 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
2084 */
2085static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
2086{
2087 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2088 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
2089 pUsbIns->iInstance, uEndpoint));
2090
2091 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
2092 {
2093 RTCritSectEnter(&pThis->CritSect);
2094 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
2095 RTCritSectLeave(&pThis->CritSect);
2096 }
2097
2098 return VINF_SUCCESS;
2099}
2100
2101
2102/**
2103 * @copydoc PDMUSBREG::pfnUsbSetInterface
2104 */
2105static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
2106{
2107 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
2108 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
2109 Assert(bAlternateSetting == 0);
2110 return VINF_SUCCESS;
2111}
2112
2113
2114/**
2115 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
2116 */
2117static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
2118 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
2119{
2120 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2121 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
2122 pUsbIns->iInstance, bConfigurationValue));
2123 Assert(bConfigurationValue == 1);
2124 RTCritSectEnter(&pThis->CritSect);
2125
2126 /*
2127 * If the same config is applied more than once, it's a kind of reset.
2128 */
2129 if (pThis->bConfigurationValue == bConfigurationValue)
2130 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
2131 pThis->bConfigurationValue = bConfigurationValue;
2132
2133 /*
2134 * Set received event type to absolute or relative.
2135 */
2136 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
2137 pThis->enmMode == USBHIDMODE_RELATIVE,
2138 pThis->enmMode == USBHIDMODE_ABSOLUTE,
2139 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
2140
2141 RTCritSectLeave(&pThis->CritSect);
2142 return VINF_SUCCESS;
2143}
2144
2145
2146/**
2147 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
2148 */
2149static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
2150{
2151 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2152 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
2153 switch (pThis->enmMode)
2154 {
2155 case USBHIDMODE_ABSOLUTE:
2156 return &g_UsbHidTDescCache;
2157 case USBHIDMODE_RELATIVE:
2158 return &g_UsbHidMDescCache;
2159 case USBHIDMODE_MULTI_TOUCH:
2160 return &g_UsbHidMTDescCache;
2161 default:
2162 return NULL;
2163 }
2164}
2165
2166
2167/**
2168 * @copydoc PDMUSBREG::pfnUsbReset
2169 */
2170static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
2171{
2172 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2173 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
2174 RTCritSectEnter(&pThis->CritSect);
2175
2176 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
2177
2178 RTCritSectLeave(&pThis->CritSect);
2179 return rc;
2180}
2181
2182
2183/**
2184 * @copydoc PDMUSBREG::pfnDestruct
2185 */
2186static void usbHidDestruct(PPDMUSBINS pUsbIns)
2187{
2188 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2189 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
2190
2191 if (RTCritSectIsInitialized(&pThis->CritSect))
2192 {
2193 RTCritSectEnter(&pThis->CritSect);
2194 RTCritSectLeave(&pThis->CritSect);
2195 RTCritSectDelete(&pThis->CritSect);
2196 }
2197
2198 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2199 {
2200 RTSemEventDestroy(pThis->hEvtDoneQueue);
2201 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2202 }
2203}
2204
2205
2206/**
2207 * @copydoc PDMUSBREG::pfnConstruct
2208 */
2209static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2210{
2211 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2212 char szMode[64];
2213 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
2214
2215 /*
2216 * Perform the basic structure initialization first so the destructor
2217 * will not misbehave.
2218 */
2219 pThis->pUsbIns = pUsbIns;
2220 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2221 usbHidQueueInit(&pThis->ToHostQueue);
2222 usbHidQueueInit(&pThis->DoneQueue);
2223
2224 int rc = RTCritSectInit(&pThis->CritSect);
2225 AssertRCReturn(rc, rc);
2226
2227 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2228 AssertRCReturn(rc, rc);
2229
2230 /*
2231 * Validate and read the configuration.
2232 */
2233 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
2234 if (RT_FAILURE(rc))
2235 return rc;
2236 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
2237 if (RT_FAILURE(rc))
2238 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
2239 if (!RTStrCmp(szMode, "relative"))
2240 pThis->enmMode = USBHIDMODE_RELATIVE;
2241 else if (!RTStrCmp(szMode, "absolute"))
2242 pThis->enmMode = USBHIDMODE_ABSOLUTE;
2243 else if (!RTStrCmp(szMode, "multitouch"))
2244 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
2245 else
2246 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2247 N_("Invalid HID device mode"));
2248
2249 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
2250 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
2251 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
2252 pThis->Lun0.IPort.pfnPutEventMultiTouch = usbHidMousePutEventMultiTouch;
2253
2254 /*
2255 * Attach the mouse driver.
2256 */
2257 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
2258 if (RT_FAILURE(rc))
2259 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
2260
2261 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
2262 if (!pThis->Lun0.pDrv)
2263 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
2264
2265 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
2266 if (RT_FAILURE(rc))
2267 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
2268
2269 return VINF_SUCCESS;
2270}
2271
2272
2273/**
2274 * The USB Human Interface Device (HID) Mouse registration record.
2275 */
2276const PDMUSBREG g_UsbHidMou =
2277{
2278 /* u32Version */
2279 PDM_USBREG_VERSION,
2280 /* szName */
2281 "HidMouse",
2282 /* pszDescription */
2283 "USB HID Mouse.",
2284 /* fFlags */
2285 0,
2286 /* cMaxInstances */
2287 ~0U,
2288 /* cbInstance */
2289 sizeof(USBHID),
2290 /* pfnConstruct */
2291 usbHidConstruct,
2292 /* pfnDestruct */
2293 usbHidDestruct,
2294 /* pfnVMInitComplete */
2295 NULL,
2296 /* pfnVMPowerOn */
2297 NULL,
2298 /* pfnVMReset */
2299 NULL,
2300 /* pfnVMSuspend */
2301 NULL,
2302 /* pfnVMResume */
2303 NULL,
2304 /* pfnVMPowerOff */
2305 NULL,
2306 /* pfnHotPlugged */
2307 NULL,
2308 /* pfnHotUnplugged */
2309 NULL,
2310 /* pfnDriverAttach */
2311 NULL,
2312 /* pfnDriverDetach */
2313 NULL,
2314 /* pfnQueryInterface */
2315 NULL,
2316 /* pfnUsbReset */
2317 usbHidUsbReset,
2318 /* pfnUsbGetDescriptorCache */
2319 usbHidUsbGetDescriptorCache,
2320 /* pfnUsbSetConfiguration */
2321 usbHidUsbSetConfiguration,
2322 /* pfnUsbSetInterface */
2323 usbHidUsbSetInterface,
2324 /* pfnUsbClearHaltedEndpoint */
2325 usbHidUsbClearHaltedEndpoint,
2326 /* pfnUrbNew */
2327 NULL/*usbHidUrbNew*/,
2328 /* pfnUrbQueue */
2329 usbHidQueue,
2330 /* pfnUrbCancel */
2331 usbHidUrbCancel,
2332 /* pfnUrbReap */
2333 usbHidUrbReap,
2334 /* u32TheEnd */
2335 PDM_USBREG_VERSION
2336};
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