VirtualBox

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

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

Devices,Main: another multi-touch build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.4 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 = */ (uint8_t)(sizeof(g_UsbHidMTReportDesc) & 0xFF),
735 (uint8_t)((sizeof(g_UsbHidMTReportDesc) >> 8) & 0xFF)
736};
737
738static const VUSBDESCINTERFACEEX g_UsbHidMInterfaceDesc =
739{
740 {
741 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
742 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
743 /* .bInterfaceNumber = */ 0,
744 /* .bAlternateSetting = */ 0,
745 /* .bNumEndpoints = */ 1,
746 /* .bInterfaceClass = */ 3 /* HID */,
747 /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
748 /* .bInterfaceProtocol = */ 2 /* Mouse */,
749 /* .iInterface = */ 0
750 },
751 /* .pvMore = */ NULL,
752 /* .pvClass = */ &g_UsbHidMIfHidDesc,
753 /* .cbClass = */ sizeof(g_UsbHidMIfHidDesc),
754 &g_aUsbHidMEndpointDescs[0],
755 /* .pIAD = */ NULL,
756 /* .cbIAD = */ 0
757};
758
759static const VUSBDESCINTERFACEEX g_UsbHidTInterfaceDesc =
760{
761 {
762 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
763 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
764 /* .bInterfaceNumber = */ 0,
765 /* .bAlternateSetting = */ 0,
766 /* .bNumEndpoints = */ 1,
767 /* .bInterfaceClass = */ 3 /* HID */,
768 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
769 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
770 /* .iInterface = */ 0
771 },
772 /* .pvMore = */ NULL,
773 /* .pvClass = */ &g_UsbHidTIfHidDesc,
774 /* .cbClass = */ sizeof(g_UsbHidTIfHidDesc),
775 &g_aUsbHidTEndpointDescs[0],
776 /* .pIAD = */ NULL,
777 /* .cbIAD = */ 0
778};
779
780static const VUSBDESCINTERFACEEX g_UsbHidMTInterfaceDesc =
781{
782 {
783 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
784 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
785 /* .bInterfaceNumber = */ 0,
786 /* .bAlternateSetting = */ 0,
787 /* .bNumEndpoints = */ 1,
788 /* .bInterfaceClass = */ 3 /* HID */,
789 /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
790 /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
791 /* .iInterface = */ 0
792 },
793 /* .pvMore = */ NULL,
794 /* .pvClass = */ &g_UsbHidMTIfHidDesc,
795 /* .cbClass = */ sizeof(g_UsbHidMTIfHidDesc),
796 &g_aUsbHidMTEndpointDescs[0],
797 /* .pIAD = */ NULL,
798 /* .cbIAD = */ 0
799};
800
801static const VUSBINTERFACE g_aUsbHidMInterfaces[] =
802{
803 { &g_UsbHidMInterfaceDesc, /* .cSettings = */ 1 },
804};
805
806static const VUSBINTERFACE g_aUsbHidTInterfaces[] =
807{
808 { &g_UsbHidTInterfaceDesc, /* .cSettings = */ 1 },
809};
810
811static const VUSBINTERFACE g_aUsbHidMTInterfaces[] =
812{
813 { &g_UsbHidMTInterfaceDesc, /* .cSettings = */ 1 },
814};
815
816static const VUSBDESCCONFIGEX g_UsbHidMConfigDesc =
817{
818 {
819 /* .bLength = */ sizeof(VUSBDESCCONFIG),
820 /* .bDescriptorType = */ VUSB_DT_CONFIG,
821 /* .wTotalLength = */ 0 /* recalculated on read */,
822 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMInterfaces),
823 /* .bConfigurationValue =*/ 1,
824 /* .iConfiguration = */ 0,
825 /* .bmAttributes = */ RT_BIT(7),
826 /* .MaxPower = */ 50 /* 100mA */
827 },
828 NULL, /* pvMore */
829 &g_aUsbHidMInterfaces[0],
830 NULL /* pvOriginal */
831};
832
833static const VUSBDESCCONFIGEX g_UsbHidTConfigDesc =
834{
835 {
836 /* .bLength = */ sizeof(VUSBDESCCONFIG),
837 /* .bDescriptorType = */ VUSB_DT_CONFIG,
838 /* .wTotalLength = */ 0 /* recalculated on read */,
839 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidTInterfaces),
840 /* .bConfigurationValue =*/ 1,
841 /* .iConfiguration = */ 0,
842 /* .bmAttributes = */ RT_BIT(7),
843 /* .MaxPower = */ 50 /* 100mA */
844 },
845 NULL, /* pvMore */
846 &g_aUsbHidTInterfaces[0],
847 NULL /* pvOriginal */
848};
849
850static const VUSBDESCCONFIGEX g_UsbHidMTConfigDesc =
851{
852 {
853 /* .bLength = */ sizeof(VUSBDESCCONFIG),
854 /* .bDescriptorType = */ VUSB_DT_CONFIG,
855 /* .wTotalLength = */ 0 /* recalculated on read */,
856 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMTInterfaces),
857 /* .bConfigurationValue =*/ 1,
858 /* .iConfiguration = */ 0,
859 /* .bmAttributes = */ RT_BIT(7),
860 /* .MaxPower = */ 50 /* 100mA */
861 },
862 NULL, /* pvMore */
863 &g_aUsbHidMTInterfaces[0],
864 NULL /* pvOriginal */
865};
866
867static const VUSBDESCDEVICE g_UsbHidMDeviceDesc =
868{
869 /* .bLength = */ sizeof(g_UsbHidMDeviceDesc),
870 /* .bDescriptorType = */ VUSB_DT_DEVICE,
871 /* .bcdUsb = */ 0x110, /* 1.1 */
872 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
873 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
874 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
875 /* .bMaxPacketSize0 = */ 8,
876 /* .idVendor = */ VBOX_USB_VENDOR,
877 /* .idProduct = */ USBHID_PID_MOUSE,
878 /* .bcdDevice = */ 0x0100, /* 1.0 */
879 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
880 /* .iProduct = */ USBHID_STR_ID_PRODUCT_M,
881 /* .iSerialNumber = */ 0,
882 /* .bNumConfigurations = */ 1
883};
884
885static const VUSBDESCDEVICE g_UsbHidTDeviceDesc =
886{
887 /* .bLength = */ sizeof(g_UsbHidTDeviceDesc),
888 /* .bDescriptorType = */ VUSB_DT_DEVICE,
889 /* .bcdUsb = */ 0x110, /* 1.1 */
890 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
891 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
892 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
893 /* .bMaxPacketSize0 = */ 8,
894 /* .idVendor = */ VBOX_USB_VENDOR,
895 /* .idProduct = */ USBHID_PID_TABLET,
896 /* .bcdDevice = */ 0x0100, /* 1.0 */
897 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
898 /* .iProduct = */ USBHID_STR_ID_PRODUCT_T,
899 /* .iSerialNumber = */ 0,
900 /* .bNumConfigurations = */ 1
901};
902
903static const VUSBDESCDEVICE g_UsbHidMTDeviceDesc =
904{
905 /* .bLength = */ sizeof(g_UsbHidMTDeviceDesc),
906 /* .bDescriptorType = */ VUSB_DT_DEVICE,
907 /* .bcdUsb = */ 0x110, /* 1.1 */
908 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
909 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
910 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
911 /* .bMaxPacketSize0 = */ 8,
912 /* .idVendor = */ VBOX_USB_VENDOR,
913 /* .idProduct = */ USBHID_PID_MULTI_TOUCH,
914 /* .bcdDevice = */ 0x0100, /* 1.0 */
915 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
916 /* .iProduct = */ USBHID_STR_ID_PRODUCT_MT,
917 /* .iSerialNumber = */ 0,
918 /* .bNumConfigurations = */ 1
919};
920
921static const PDMUSBDESCCACHE g_UsbHidMDescCache =
922{
923 /* .pDevice = */ &g_UsbHidMDeviceDesc,
924 /* .paConfigs = */ &g_UsbHidMConfigDesc,
925 /* .paLanguages = */ g_aUsbHidLanguages,
926 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
927 /* .fUseCachedDescriptors = */ true,
928 /* .fUseCachedStringsDescriptors = */ true
929};
930
931static const PDMUSBDESCCACHE g_UsbHidTDescCache =
932{
933 /* .pDevice = */ &g_UsbHidTDeviceDesc,
934 /* .paConfigs = */ &g_UsbHidTConfigDesc,
935 /* .paLanguages = */ g_aUsbHidLanguages,
936 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
937 /* .fUseCachedDescriptors = */ true,
938 /* .fUseCachedStringsDescriptors = */ true
939};
940
941static const PDMUSBDESCCACHE g_UsbHidMTDescCache =
942{
943 /* .pDevice = */ &g_UsbHidMTDeviceDesc,
944 /* .paConfigs = */ &g_UsbHidMTConfigDesc,
945 /* .paLanguages = */ g_aUsbHidLanguages,
946 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
947 /* .fUseCachedDescriptors = */ true,
948 /* .fUseCachedStringsDescriptors = */ true
949};
950
951
952/*******************************************************************************
953* Internal Functions *
954*******************************************************************************/
955
956/**
957 * Initializes an URB queue.
958 *
959 * @param pQueue The URB queue.
960 */
961static void usbHidQueueInit(PUSBHIDURBQUEUE pQueue)
962{
963 pQueue->pHead = NULL;
964 pQueue->ppTail = &pQueue->pHead;
965}
966
967
968
969/**
970 * Inserts an URB at the end of the queue.
971 *
972 * @param pQueue The URB queue.
973 * @param pUrb The URB to insert.
974 */
975DECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
976{
977 pUrb->Dev.pNext = NULL;
978 *pQueue->ppTail = pUrb;
979 pQueue->ppTail = &pUrb->Dev.pNext;
980}
981
982
983/**
984 * Unlinks the head of the queue and returns it.
985 *
986 * @returns The head entry.
987 * @param pQueue The URB queue.
988 */
989DECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
990{
991 PVUSBURB pUrb = pQueue->pHead;
992 if (pUrb)
993 {
994 PVUSBURB pNext = pUrb->Dev.pNext;
995 pQueue->pHead = pNext;
996 if (!pNext)
997 pQueue->ppTail = &pQueue->pHead;
998 else
999 pUrb->Dev.pNext = NULL;
1000 }
1001 return pUrb;
1002}
1003
1004
1005/**
1006 * Removes an URB from anywhere in the queue.
1007 *
1008 * @returns true if found, false if not.
1009 * @param pQueue The URB queue.
1010 * @param pUrb The URB to remove.
1011 */
1012DECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
1013{
1014 PVUSBURB pCur = pQueue->pHead;
1015 if (pCur == pUrb)
1016 {
1017 pQueue->pHead = pUrb->Dev.pNext;
1018 if (!pUrb->Dev.pNext)
1019 pQueue->ppTail = &pQueue->pHead;
1020 }
1021 else
1022 {
1023 while (pCur)
1024 {
1025 if (pCur->Dev.pNext == pUrb)
1026 {
1027 pCur->Dev.pNext = pUrb->Dev.pNext;
1028 break;
1029 }
1030 pCur = pCur->Dev.pNext;
1031 }
1032 if (!pCur)
1033 return false;
1034 if (!pUrb->Dev.pNext)
1035 pQueue->ppTail = &pCur->Dev.pNext;
1036 }
1037 pUrb->Dev.pNext = NULL;
1038 return true;
1039}
1040
1041
1042/**
1043 * Checks if the queue is empty or not.
1044 *
1045 * @returns true if it is, false if it isn't.
1046 * @param pQueue The URB queue.
1047 */
1048DECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
1049{
1050 return pQueue->pHead == NULL;
1051}
1052
1053
1054/**
1055 * Links an URB into the done queue.
1056 *
1057 * @param pThis The HID instance.
1058 * @param pUrb The URB.
1059 */
1060static void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
1061{
1062 usbHidQueueAddTail(&pThis->DoneQueue, pUrb);
1063
1064 if (pThis->fHaveDoneQueueWaiter)
1065 {
1066 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
1067 AssertRC(rc);
1068 }
1069}
1070
1071
1072
1073/**
1074 * Completes the URB with a stalled state, halting the pipe.
1075 */
1076static int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
1077{
1078 LogRelFlow(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n",
1079 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
1080
1081 pUrb->enmStatus = VUSBSTATUS_STALL;
1082
1083 /** @todo figure out if the stall is global or pipe-specific or both. */
1084 if (pEp)
1085 pEp->fHalted = true;
1086 else
1087 {
1088 pThis->aEps[0].fHalted = true;
1089 pThis->aEps[1].fHalted = true;
1090 }
1091
1092 usbHidLinkDone(pThis, pUrb);
1093 return VINF_SUCCESS;
1094}
1095
1096
1097/**
1098 * Completes the URB with a OK state.
1099 */
1100static int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, size_t cbData)
1101{
1102 LogRelFlow(("usbHidCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n",
1103 pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
1104
1105 pUrb->enmStatus = VUSBSTATUS_OK;
1106 pUrb->cbData = (uint32_t)cbData;
1107
1108 usbHidLinkDone(pThis, pUrb);
1109 return VINF_SUCCESS;
1110}
1111
1112
1113/**
1114 * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
1115 * usbHidHandleDefaultPipe.
1116 *
1117 * @returns VBox status code.
1118 * @param pThis The HID instance.
1119 * @param pUrb Set when usbHidHandleDefaultPipe is the
1120 * caller.
1121 * @param fSetConfig Set when usbHidUsbSetConfiguration is the
1122 * caller.
1123 */
1124static int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
1125{
1126 /*
1127 * Wait for the any command currently executing to complete before
1128 * resetting. (We cannot cancel its execution.) How we do this depends
1129 * on the reset method.
1130 */
1131
1132 /*
1133 * Reset the device state.
1134 */
1135 pThis->enmState = USBHIDREQSTATE_READY;
1136 pThis->fHasPendingChanges = false;
1137
1138 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
1139 pThis->aEps[i].fHalted = false;
1140
1141 if (!pUrb && !fSetConfig) /* (only device reset) */
1142 pThis->bConfigurationValue = 0; /* default */
1143
1144 /*
1145 * Ditch all pending URBs.
1146 */
1147 PVUSBURB pCurUrb;
1148 while ((pCurUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
1149 {
1150 pCurUrb->enmStatus = VUSBSTATUS_CRC;
1151 usbHidLinkDone(pThis, pCurUrb);
1152 }
1153
1154 if (pUrb)
1155 return usbHidCompleteOk(pThis, pUrb, 0);
1156 return VINF_SUCCESS;
1157}
1158
1159static int8_t clamp_i8(int32_t val)
1160{
1161 if (val > 127) {
1162 val = 127;
1163 } else if (val < -127) {
1164 val = -127;
1165 }
1166 return val;
1167}
1168
1169/**
1170 * Create a USB HID report report based on the currently accumulated data.
1171 */
1172static size_t usbHidFillReport(PUSBHIDTM_REPORT pReport,
1173 PUSBHIDM_ACCUM pAccumulated, USBHIDMODE enmMode)
1174{
1175 size_t cbCopy;
1176
1177 switch (enmMode)
1178 {
1179 case USBHIDMODE_ABSOLUTE:
1180 pReport->t.fButtons = pAccumulated->u.Absolute.fButtons;
1181 pReport->t.x = pAccumulated->u.Absolute.x;
1182 pReport->t.y = pAccumulated->u.Absolute.y;
1183
1184 cbCopy = sizeof(pReport->t);
1185 LogRel3(("Abs event, x=%d, y=%d, fButtons=%02x, report size %d\n",
1186 pReport->t.x, pReport->t.y, pReport->t.fButtons,
1187 cbCopy));
1188 break;
1189 case USBHIDMODE_RELATIVE:
1190 pReport->m.fButtons = pAccumulated->u.Relative.fButtons;
1191 pReport->m.dx = clamp_i8(pAccumulated->u.Relative.dx);
1192 pReport->m.dy = clamp_i8(pAccumulated->u.Relative.dy);
1193 pReport->m.dz = clamp_i8(pAccumulated->u.Relative.dz);
1194
1195 cbCopy = sizeof(pReport->m);
1196 LogRel3(("Rel event, dx=%d, dy=%d, dz=%d, fButtons=%02x, report size %d\n",
1197 pReport->m.dx, pReport->m.dy, pReport->m.dz,
1198 pReport->m.fButtons, cbCopy));
1199 break;
1200 default:
1201 AssertFailed(); /* Unexpected here. */
1202 break;
1203 }
1204
1205 /* Clear the accumulated movement. */
1206 RT_ZERO(*pAccumulated);
1207
1208 return cbCopy;
1209}
1210
1211DECLINLINE(MTCONTACT *) usbHidFindMTContact(MTCONTACT *paContacts, size_t cContacts,
1212 uint8_t u8Mask, uint8_t u8Value)
1213{
1214 size_t i;
1215 for (i = 0; i < cContacts; i++)
1216 {
1217 if ((paContacts[i].status & u8Mask) == u8Value)
1218 {
1219 return &paContacts[i];
1220 }
1221 }
1222
1223 return NULL;
1224}
1225
1226static int usbHidSendMultiTouchReport(PUSBHID pThis, PVUSBURB pUrb)
1227{
1228 uint8_t i;
1229 MTCONTACT *pRepContact;
1230 MTCONTACT *pCurContact;
1231
1232 /* Number of contacts to be reported. In hybrid mode the first report contains
1233 * total number of contacts and subsequent reports contain 0.
1234 */
1235 uint8_t cContacts = 0;
1236
1237 Assert(pThis->fHasPendingChanges);
1238
1239 if (!pThis->fTouchReporting)
1240 {
1241 pThis->fTouchReporting = true;
1242
1243 /* Update the reporting state with the new current state.
1244 * Also mark all active contacts in reporting state as dirty,
1245 * that is they must be reported to the guest.
1246 */
1247 for (i = 0; i < MT_CONTACT_MAX_COUNT; i++)
1248 {
1249 pRepContact = &pThis->aReportingContactState[i];
1250 pCurContact = &pThis->aCurrentContactState[i];
1251
1252 if (pCurContact->status & MT_CONTACT_S_ACTIVE)
1253 {
1254 if (pCurContact->status & MT_CONTACT_S_REUSED)
1255 {
1256 pCurContact->status &= ~MT_CONTACT_S_REUSED;
1257
1258 /* Keep x,y. Will report lost contact at this point. */
1259 pRepContact->id = pCurContact->oldId;
1260 pRepContact->flags = 0;
1261 pRepContact->status = MT_CONTACT_S_REUSED;
1262 }
1263 else if (pThis->aCurrentContactState[i].status & MT_CONTACT_S_CANCELLED)
1264 {
1265 pCurContact->status &= ~(MT_CONTACT_S_CANCELLED | MT_CONTACT_S_ACTIVE);
1266
1267 /* Keep x,y. Will report lost contact at this point. */
1268 pRepContact->id = pCurContact->id;
1269 pRepContact->flags = 0;
1270 pRepContact->status = 0;
1271 }
1272 else
1273 {
1274 if (pCurContact->flags == 0)
1275 {
1276 pCurContact->status &= ~MT_CONTACT_S_ACTIVE; /* Contact disapeared. */
1277 }
1278
1279 pRepContact->x = pCurContact->x;
1280 pRepContact->y = pCurContact->y;
1281 pRepContact->id = pCurContact->id;
1282 pRepContact->flags = pCurContact->flags;
1283 pRepContact->status = 0;
1284 }
1285
1286 cContacts++;
1287
1288 pRepContact->status |= MT_CONTACT_S_DIRTY;
1289 }
1290 else
1291 {
1292 pRepContact->status = 0;
1293 }
1294 }
1295 }
1296
1297 /* Report current state. */
1298 USBHIDMT_REPORT *p = (USBHIDMT_REPORT *)&pUrb->abData[0];
1299 RT_ZERO(*p);
1300
1301 p->idReport = REPORTID_TOUCH_EVENT;
1302 p->cContacts = cContacts;
1303
1304 uint8_t iReportedContact;
1305 for (iReportedContact = 0; iReportedContact < MT_CONTACTS_PER_REPORT; iReportedContact++)
1306 {
1307 /* Find the next not reported contact. */
1308 pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
1309 MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
1310
1311 if (!pRepContact)
1312 {
1313 LogRel3(("usbHid: no more touch contacts to report\n"));
1314 break;
1315 }
1316
1317 if (pRepContact->status & MT_CONTACT_S_REUSED)
1318 {
1319 /* Do not clear DIRTY flag for contacts which were reused.
1320 * Because two reports must be generated:
1321 * one for old contact off, and the second for new contact on.
1322 */
1323 pRepContact->status &= ~MT_CONTACT_S_REUSED;
1324 }
1325 else
1326 {
1327 pRepContact->status &= ~MT_CONTACT_S_DIRTY;
1328 }
1329
1330 p->aContacts[iReportedContact].fContact = pRepContact->flags;
1331 p->aContacts[iReportedContact].cContact = pRepContact->id;
1332 p->aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
1333 p->aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
1334 }
1335
1336 p->u32ScanTime = pThis->u32LastTouchScanTime * 10;
1337
1338 Assert(iReportedContact > 0);
1339
1340 /* Reset TouchReporting if all contacts reported. */
1341 pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
1342 MT_CONTACT_S_DIRTY, MT_CONTACT_S_DIRTY);
1343
1344 if (!pRepContact)
1345 {
1346 LogRel3(("usbHid: all touch contacts reported\n"));
1347 pThis->fTouchReporting = false;
1348 pThis->fHasPendingChanges = false;
1349 }
1350 else
1351 {
1352 pThis->fHasPendingChanges = true;
1353 }
1354
1355 LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", sizeof(USBHIDMT_REPORT), p));
1356 return usbHidCompleteOk(pThis, pUrb, sizeof(USBHIDMT_REPORT));
1357}
1358
1359/**
1360 * Sends a state report to the host if there is a pending URB.
1361 */
1362static int usbHidSendReport(PUSBHID pThis)
1363{
1364 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
1365
1366 if (pThis->enmMode == USBHIDMODE_MULTI_TOUCH)
1367 {
1368 /* This device uses a different reporting method and fHasPendingChanges maintenance. */
1369 if (pUrb)
1370 return usbHidSendMultiTouchReport(pThis, pUrb);
1371 return VINF_SUCCESS;
1372 }
1373
1374 if (pUrb)
1375 {
1376 PUSBHIDTM_REPORT pReport = (PUSBHIDTM_REPORT)&pUrb->abData[0];
1377 size_t cbCopy;
1378
1379 cbCopy = usbHidFillReport(pReport, &pThis->PtrDelta, pThis->enmMode);
1380 pThis->fHasPendingChanges = false;
1381 return usbHidCompleteOk(pThis, pUrb, cbCopy);
1382 }
1383 else
1384 {
1385 LogRelFlow(("No available URB for USB mouse\n"));
1386 pThis->fHasPendingChanges = true;
1387 }
1388 return VINF_EOF;
1389}
1390
1391/**
1392 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1393 */
1394static DECLCALLBACK(void *) usbHidMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1395{
1396 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
1397 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1398 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Lun0.IPort);
1399 return NULL;
1400}
1401
1402/**
1403 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
1404 */
1405static DECLCALLBACK(int) usbHidMousePutEvent(PPDMIMOUSEPORT pInterface,
1406 int32_t dx, int32_t dy, int32_t dz,
1407 int32_t dw, uint32_t fButtons)
1408{
1409 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1410 RTCritSectEnter(&pThis->CritSect);
1411
1412 /* Accumulate movement - the events from the front end may arrive
1413 * at a much higher rate than USB can handle.
1414 */
1415 pThis->PtrDelta.u.Relative.fButtons = fButtons;
1416 pThis->PtrDelta.u.Relative.dx += dx;
1417 pThis->PtrDelta.u.Relative.dy += dy;
1418 pThis->PtrDelta.u.Relative.dz -= dz; /* Inverted! */
1419
1420 /* Send a report if possible. */
1421 usbHidSendReport(pThis);
1422
1423 RTCritSectLeave(&pThis->CritSect);
1424 return VINF_SUCCESS;
1425}
1426
1427/**
1428 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
1429 */
1430static DECLCALLBACK(int) usbHidMousePutEventAbs(PPDMIMOUSEPORT pInterface,
1431 uint32_t x, uint32_t y,
1432 int32_t dz, int32_t dw,
1433 uint32_t fButtons)
1434{
1435 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1436 RTCritSectEnter(&pThis->CritSect);
1437
1438 Assert(pThis->enmMode == USBHIDMODE_ABSOLUTE);
1439
1440 /* Accumulate movement - the events from the front end may arrive
1441 * at a much higher rate than USB can handle. Probably not a real issue
1442 * when only the Z axis is relative (X/Y movement isn't technically
1443 * accumulated and only the last value is used).
1444 */
1445 pThis->PtrDelta.u.Absolute.fButtons = fButtons;
1446 pThis->PtrDelta.u.Absolute.x = x >> pThis->u8CoordShift;
1447 pThis->PtrDelta.u.Absolute.y = y >> pThis->u8CoordShift;
1448
1449 /* Send a report if possible. */
1450 usbHidSendReport(pThis);
1451
1452 RTCritSectLeave(&pThis->CritSect);
1453 return VINF_SUCCESS;
1454}
1455
1456/**
1457 * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMultiTouch}
1458 */
1459static DECLCALLBACK(int) usbHidMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
1460 uint8_t cContacts,
1461 const uint64_t *pau64Contacts,
1462 uint32_t u32ScanTime)
1463{
1464 uint8_t i;
1465 uint8_t j;
1466
1467 /* Make a copy of new contacts */
1468 MTCONTACT *paNewContacts = (MTCONTACT *)RTMemTmpAlloc(sizeof(MTCONTACT) * cContacts);
1469 if (!paNewContacts)
1470 return VERR_NO_MEMORY;
1471
1472 for (i = 0; i < cContacts; i++)
1473 {
1474 uint32_t u32Lo = RT_LO_U32(pau64Contacts[i]);
1475 uint32_t u32Hi = RT_HI_U32(pau64Contacts[i]);
1476 paNewContacts[i].x = (uint16_t)u32Lo;
1477 paNewContacts[i].y = (uint16_t)(u32Lo >> 16);
1478 paNewContacts[i].id = RT_BYTE1(u32Hi);
1479 paNewContacts[i].flags = RT_BYTE2(u32Hi) & (MT_CONTACT_F_IN_CONTACT | MT_CONTACT_F_IN_RANGE);
1480 paNewContacts[i].status = MT_CONTACT_S_DIRTY;
1481 paNewContacts[i].oldId = 0; /* Not used. */
1482 }
1483
1484 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1485 MTCONTACT *pCurContact = NULL;
1486 MTCONTACT *pNewContact = NULL;
1487
1488 RTCritSectEnter(&pThis->CritSect);
1489
1490 Assert(pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
1491
1492 /* Maintain a state of all current contacts.
1493 * Intr URBs will be completed according to the state.
1494 */
1495
1496 /* Mark all existing contacts as dirty. */
1497 for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
1498 pThis->aCurrentContactState[i].status |= MT_CONTACT_S_DIRTY;
1499
1500 /* Update existing contacts and mark new contacts. */
1501 for (i = 0; i < cContacts; i++)
1502 {
1503 pNewContact = &paNewContacts[i];
1504
1505 /* Find existing contact with the same id. */
1506 pCurContact = NULL;
1507 for (j = 0; j < RT_ELEMENTS(pThis->aCurrentContactState); j++)
1508 {
1509 if ( (pThis->aCurrentContactState[j].status & MT_CONTACT_S_ACTIVE) != 0
1510 && pThis->aCurrentContactState[j].id == pNewContact->id)
1511 {
1512 pCurContact = &pThis->aCurrentContactState[j];
1513 break;
1514 }
1515 }
1516
1517 if (pCurContact)
1518 {
1519 pNewContact->status &= ~MT_CONTACT_S_DIRTY;
1520
1521 pCurContact->x = pNewContact->x;
1522 pCurContact->y = pNewContact->y;
1523 if (pCurContact->flags == 0) /* Contact disappeared already. */
1524 {
1525 if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
1526 {
1527 pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
1528 pCurContact->oldId = pCurContact->id;
1529 }
1530 }
1531 pCurContact->flags = pNewContact->flags;
1532 pCurContact->status &= ~MT_CONTACT_S_DIRTY;
1533 }
1534 }
1535
1536 /* Append new contacts (the dirty one in the paNewContacts). */
1537 for (i = 0; i < cContacts; i++)
1538 {
1539 pNewContact = &paNewContacts[i];
1540
1541 if (pNewContact->status & MT_CONTACT_S_DIRTY)
1542 {
1543 /* It is a new contact, copy is to one of not ACTIVE or not updated existing contacts. */
1544 pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
1545 MT_CONTACT_S_ACTIVE, 0);
1546
1547 if (pCurContact)
1548 {
1549 *pCurContact = *pNewContact;
1550 pCurContact->status = MT_CONTACT_S_ACTIVE; /* Reset status. */
1551 }
1552 else
1553 {
1554 /* Dirty existing contacts can be reused. */
1555 pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
1556 MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY,
1557 MT_CONTACT_S_ACTIVE | MT_CONTACT_S_DIRTY);
1558
1559 if (pCurContact)
1560 {
1561 pCurContact->x = pNewContact->x;
1562 pCurContact->y = pNewContact->y;
1563 if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
1564 {
1565 pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
1566 pCurContact->oldId = pCurContact->id;
1567 }
1568 pCurContact->flags = pNewContact->flags;
1569 pCurContact->status &= ~MT_CONTACT_S_DIRTY;
1570 }
1571 else
1572 {
1573 LogRel3(("usbHid: dropped new contact: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
1574 pNewContact->x,
1575 pNewContact->y,
1576 pNewContact->id,
1577 pNewContact->flags,
1578 pNewContact->status,
1579 pNewContact->oldId
1580 ));
1581 }
1582 }
1583 }
1584 }
1585
1586 /* Mark still dirty existing contacts as cancelled, because a new set of contacts does not include them. */
1587 for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
1588 {
1589 pCurContact = &pThis->aCurrentContactState[i];
1590 if (pCurContact->status & MT_CONTACT_S_DIRTY)
1591 {
1592 pCurContact->status |= MT_CONTACT_S_CANCELLED;
1593 pCurContact->status &= ~MT_CONTACT_S_DIRTY;
1594 }
1595 }
1596
1597 pThis->u32LastTouchScanTime = u32ScanTime;
1598
1599 LogRel3(("usbHid: scanTime (ms): %d\n", pThis->u32LastTouchScanTime));
1600 for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
1601 {
1602 LogRel3(("usbHid: contact state[%d]: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
1603 i,
1604 pThis->aCurrentContactState[i].x,
1605 pThis->aCurrentContactState[i].y,
1606 pThis->aCurrentContactState[i].id,
1607 pThis->aCurrentContactState[i].flags,
1608 pThis->aCurrentContactState[i].status,
1609 pThis->aCurrentContactState[i].oldId
1610 ));
1611 }
1612
1613 pThis->fHasPendingChanges = true;
1614
1615 /* Send a report if possible. */
1616 usbHidSendReport(pThis);
1617
1618 RTCritSectLeave(&pThis->CritSect);
1619
1620 RTMemTmpFree(paNewContacts);
1621 return VINF_SUCCESS;
1622}
1623
1624/**
1625 * @copydoc PDMUSBREG::pfnUrbReap
1626 */
1627static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1628{
1629 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1630
1631 RTCritSectEnter(&pThis->CritSect);
1632
1633 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1634 if (!pUrb && cMillies)
1635 {
1636 /* Wait */
1637 pThis->fHaveDoneQueueWaiter = true;
1638 RTCritSectLeave(&pThis->CritSect);
1639
1640 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1641
1642 RTCritSectEnter(&pThis->CritSect);
1643 pThis->fHaveDoneQueueWaiter = false;
1644
1645 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1646 }
1647
1648 RTCritSectLeave(&pThis->CritSect);
1649
1650 if (pUrb)
1651 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1652 pUrb->pszDesc));
1653 return pUrb;
1654}
1655
1656
1657/**
1658 * @copydoc PDMUSBREG::pfnUrbCancel
1659 */
1660static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1661{
1662 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1663 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1664 pUrb->pszDesc));
1665 RTCritSectEnter(&pThis->CritSect);
1666
1667 /*
1668 * Remove the URB from the to-host queue and move it onto the done queue.
1669 */
1670 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1671 usbHidLinkDone(pThis, pUrb);
1672
1673 RTCritSectLeave(&pThis->CritSect);
1674 return VINF_SUCCESS;
1675}
1676
1677
1678/**
1679 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1680 * rather different from bulk requests because an interrupt read URB may complete
1681 * after arbitrarily long time.
1682 */
1683static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1684{
1685 /*
1686 * Stall the request if the pipe is halted.
1687 */
1688 if (RT_UNLIKELY(pEp->fHalted))
1689 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1690
1691 /*
1692 * Deal with the URB according to the state.
1693 */
1694 switch (pThis->enmState)
1695 {
1696 /*
1697 * We've data left to transfer to the host.
1698 */
1699 case USBHIDREQSTATE_DATA_TO_HOST:
1700 {
1701 AssertFailed();
1702 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1703 return usbHidCompleteOk(pThis, pUrb, 0);
1704 }
1705
1706 /*
1707 * Status transfer.
1708 */
1709 case USBHIDREQSTATE_STATUS:
1710 {
1711 AssertFailed();
1712 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1713 pThis->enmState = USBHIDREQSTATE_READY;
1714 return usbHidCompleteOk(pThis, pUrb, 0);
1715 }
1716
1717 case USBHIDREQSTATE_READY:
1718 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1719 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1720 pUrb, pUrb->pszDesc));
1721 /* If a report is pending, send it right away. */
1722 if (pThis->fHasPendingChanges)
1723 usbHidSendReport(pThis);
1724 return VINF_SUCCESS;
1725
1726 /*
1727 * Bad states, stall.
1728 */
1729 default:
1730 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1731 pThis->enmState, pUrb->cbData));
1732 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1733 }
1734}
1735
1736#define GET_REPORT 0x01
1737#define GET_IDLE 0x02
1738#define GET_PROTOCOL 0x03
1739#define SET_REPORT 0x09
1740#define SET_IDLE 0x0A
1741#define SET_PROTOCOL 0x0B
1742
1743static uint8_t sau8QASampleBlob[256] =
1744{
1745 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87,
1746 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88,
1747 0x07, 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6,
1748 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2,
1749 0x2e, 0x84, 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43,
1750 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc,
1751 0x47, 0x70, 0x1b, 0x59, 0x6f, 0x74, 0x43, 0xc4,
1752 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71,
1753 0xc7, 0x95, 0x0e, 0x31, 0x55, 0x21, 0xd3, 0xb5,
1754 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19,
1755 0x3e, 0xb3, 0xaf, 0x75, 0x81, 0x9d, 0x53, 0xb9,
1756 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c,
1757 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d, 0xa7, 0x26,
1758 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b,
1759 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0, 0x2a,
1760 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8,
1761 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1,
1762 0x0b, 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7,
1763 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b,
1764 0xe8, 0x8a, 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35,
1765 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc,
1766 0x2b, 0x53, 0x5c, 0x69, 0x52, 0xd5, 0xc8, 0x73,
1767 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff,
1768 0x05, 0xd8, 0x2b, 0x79, 0x9a, 0xe2, 0x34, 0x60,
1769 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc,
1770 0x80, 0xe3, 0x0f, 0xbd, 0x65, 0x20, 0x08, 0x13,
1771 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7,
1772 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe, 0x31, 0x48,
1773 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89,
1774 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a, 0xe4,
1775 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08,
1776 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2
1777};
1778
1779static int usbHidRequestClass(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1780{
1781 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1782
1783 if (pThis->enmMode != USBHIDMODE_MULTI_TOUCH)
1784 {
1785 LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1786 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1787 pSetup->wIndex, pSetup->wLength));
1788 return usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req");
1789 }
1790
1791 int rc = VINF_SUCCESS;
1792
1793 switch (pSetup->bRequest)
1794 {
1795 case SET_REPORT:
1796 case GET_REPORT:
1797 {
1798 uint8_t u8ReportType = RT_HI_U8(pSetup->wValue);
1799 uint8_t u8ReportID = RT_LO_U8(pSetup->wValue);
1800 LogRelFlow(("usbHid: %s: type %d, ID %d, data\n%.*Rhxd\n",
1801 pSetup->bRequest == GET_REPORT? "GET_REPORT": "SET_REPORT",
1802 u8ReportType, u8ReportID,
1803 pUrb->cbData - sizeof(VUSBSETUP), &pUrb->abData[sizeof(VUSBSETUP)]));
1804 uint32_t cbData = 0;
1805 if (pSetup->bRequest == GET_REPORT)
1806 {
1807 if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_MAX_COUNT)
1808 {
1809 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_MAX_COUNT;
1810 pUrb->abData[sizeof(VUSBSETUP) + 1] = MT_CONTACT_MAX_COUNT; /* Contact count maximum. */
1811 pUrb->abData[sizeof(VUSBSETUP) + 2] = 0; /* Device identifier */
1812 cbData = 3;
1813 }
1814 else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_QABLOB)
1815 {
1816 uint32_t cbLeft = pUrb->cbData;
1817 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_QABLOB; /* Report Id. */
1818 memcpy(&pUrb->abData[sizeof(VUSBSETUP) + 1],
1819 sau8QASampleBlob, sizeof(sau8QASampleBlob));
1820 cbData = sizeof(sau8QASampleBlob) + 1;
1821 }
1822 }
1823
1824 rc = usbHidCompleteOk(pThis, pUrb, sizeof(VUSBSETUP) + cbData);
1825 } break;
1826 default:
1827 {
1828 LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1829 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1830 pSetup->wIndex, pSetup->wLength));
1831 rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req MT");
1832 }
1833 }
1834
1835 return rc;
1836}
1837
1838/**
1839 * Handles request sent to the default control pipe.
1840 */
1841static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1842{
1843 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1844 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1845
1846 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1847 {
1848 switch (pSetup->bRequest)
1849 {
1850 case VUSB_REQ_GET_DESCRIPTOR:
1851 {
1852 switch (pSetup->bmRequestType)
1853 {
1854 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1855 {
1856 switch (pSetup->wValue >> 8)
1857 {
1858 case VUSB_DT_STRING:
1859 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1860 pSetup->wValue, pSetup->wIndex));
1861 break;
1862 default:
1863 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1864 pSetup->wValue, pSetup->wIndex));
1865 break;
1866 }
1867 break;
1868 }
1869
1870 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1871 {
1872 switch (pSetup->wValue >> 8)
1873 {
1874 uint32_t cbCopy;
1875 uint32_t cbDesc;
1876 const uint8_t *pDesc;
1877
1878 case DT_IF_HID_DESCRIPTOR:
1879 {
1880 switch (pThis->enmMode)
1881 {
1882 case USBHIDMODE_ABSOLUTE:
1883 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1884 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1885 break;
1886 case USBHIDMODE_RELATIVE:
1887 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1888 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1889 break;
1890 case USBHIDMODE_MULTI_TOUCH:
1891 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1892 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1893 break;
1894 }
1895 /* Returned data is written after the setup message. */
1896 cbCopy = pUrb->cbData - sizeof(*pSetup);
1897 cbCopy = RT_MIN(cbCopy, cbDesc);
1898 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1899 pSetup->wValue, pSetup->wIndex,
1900 cbCopy));
1901 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1902 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1903 }
1904
1905 case DT_IF_HID_REPORT:
1906 {
1907 switch (pThis->enmMode)
1908 {
1909 case USBHIDMODE_ABSOLUTE:
1910 {
1911 cbDesc = sizeof(g_UsbHidTReportDesc);
1912 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
1913 break;
1914 }
1915 case USBHIDMODE_RELATIVE:
1916 {
1917 cbDesc = sizeof(g_UsbHidMReportDesc);
1918 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
1919 break;
1920 }
1921 case USBHIDMODE_MULTI_TOUCH:
1922 {
1923 cbDesc = sizeof(g_UsbHidMTReportDesc);
1924 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
1925 break;
1926 }
1927 }
1928 /* Returned data is written after the setup message. */
1929 cbCopy = pUrb->cbData - sizeof(*pSetup);
1930 cbCopy = RT_MIN(cbCopy, cbDesc);
1931 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
1932 pSetup->wValue, pSetup->wIndex,
1933 cbCopy));
1934 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1935 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1936 }
1937
1938 default:
1939 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1940 pSetup->wValue, pSetup->wIndex));
1941 break;
1942 }
1943 break;
1944 }
1945
1946 default:
1947 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
1948 pSetup->bmRequestType));
1949 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1950 }
1951 break;
1952 }
1953
1954 case VUSB_REQ_GET_STATUS:
1955 {
1956 uint16_t wRet = 0;
1957
1958 if (pSetup->wLength != 2)
1959 {
1960 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
1961 pSetup->wLength));
1962 break;
1963 }
1964 Assert(pSetup->wValue == 0);
1965 switch (pSetup->bmRequestType)
1966 {
1967 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1968 {
1969 Assert(pSetup->wIndex == 0);
1970 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
1971 wRet = 0; /* Not self-powered, no remote wakeup. */
1972 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1973 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1974 }
1975
1976 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1977 {
1978 if (pSetup->wIndex == 0)
1979 {
1980 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1981 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1982 }
1983 else
1984 {
1985 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
1986 pSetup->wIndex));
1987 }
1988 break;
1989 }
1990
1991 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1992 {
1993 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1994 {
1995 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1996 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
1997 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1998 }
1999 else
2000 {
2001 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
2002 pSetup->wIndex));
2003 }
2004 break;
2005 }
2006
2007 default:
2008 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
2009 pSetup->bmRequestType));
2010 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
2011 }
2012 break;
2013 }
2014
2015 case VUSB_REQ_CLEAR_FEATURE:
2016 break;
2017 }
2018
2019 /** @todo implement this. */
2020 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2021 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2022 pSetup->wIndex, pSetup->wLength));
2023
2024 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
2025 }
2026 else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
2027 {
2028 /* Only VUSB_TO_INTERFACE is allowed. */
2029 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_INTERFACE)
2030 {
2031 return usbHidRequestClass(pThis, pEp, pUrb);
2032 }
2033
2034 LogRelFlow(("usbHid: invalid recipient of class req: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2035 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2036 pSetup->wIndex, pSetup->wLength));
2037 return usbHidCompleteStall(pThis, pEp, pUrb, "Invalid recip");
2038 }
2039 else
2040 {
2041 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2042 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2043 pSetup->wIndex, pSetup->wLength));
2044 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
2045 }
2046
2047 return VINF_SUCCESS;
2048}
2049
2050
2051/**
2052 * @copydoc PDMUSBREG::pfnUrbQueue
2053 */
2054static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
2055{
2056 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2057 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
2058 pUrb, pUrb->pszDesc, pUrb->EndPt));
2059 RTCritSectEnter(&pThis->CritSect);
2060
2061 /*
2062 * Parse on a per end-point basis.
2063 */
2064 int rc;
2065 switch (pUrb->EndPt)
2066 {
2067 case 0:
2068 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
2069 break;
2070
2071 case 0x81:
2072 AssertFailed();
2073 case 0x01:
2074 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
2075 break;
2076
2077 default:
2078 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
2079 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
2080 break;
2081 }
2082
2083 RTCritSectLeave(&pThis->CritSect);
2084 return rc;
2085}
2086
2087
2088/**
2089 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
2090 */
2091static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
2092{
2093 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2094 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
2095 pUsbIns->iInstance, uEndpoint));
2096
2097 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
2098 {
2099 RTCritSectEnter(&pThis->CritSect);
2100 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
2101 RTCritSectLeave(&pThis->CritSect);
2102 }
2103
2104 return VINF_SUCCESS;
2105}
2106
2107
2108/**
2109 * @copydoc PDMUSBREG::pfnUsbSetInterface
2110 */
2111static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
2112{
2113 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
2114 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
2115 Assert(bAlternateSetting == 0);
2116 return VINF_SUCCESS;
2117}
2118
2119
2120/**
2121 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
2122 */
2123static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
2124 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
2125{
2126 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2127 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
2128 pUsbIns->iInstance, bConfigurationValue));
2129 Assert(bConfigurationValue == 1);
2130 RTCritSectEnter(&pThis->CritSect);
2131
2132 /*
2133 * If the same config is applied more than once, it's a kind of reset.
2134 */
2135 if (pThis->bConfigurationValue == bConfigurationValue)
2136 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
2137 pThis->bConfigurationValue = bConfigurationValue;
2138
2139 /*
2140 * Set received event type to absolute or relative.
2141 */
2142 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
2143 pThis->enmMode == USBHIDMODE_RELATIVE,
2144 pThis->enmMode == USBHIDMODE_ABSOLUTE,
2145 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
2146
2147 RTCritSectLeave(&pThis->CritSect);
2148 return VINF_SUCCESS;
2149}
2150
2151
2152/**
2153 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
2154 */
2155static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
2156{
2157 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2158 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
2159 switch (pThis->enmMode)
2160 {
2161 case USBHIDMODE_ABSOLUTE:
2162 return &g_UsbHidTDescCache;
2163 case USBHIDMODE_RELATIVE:
2164 return &g_UsbHidMDescCache;
2165 case USBHIDMODE_MULTI_TOUCH:
2166 return &g_UsbHidMTDescCache;
2167 default:
2168 return NULL;
2169 }
2170}
2171
2172
2173/**
2174 * @copydoc PDMUSBREG::pfnUsbReset
2175 */
2176static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
2177{
2178 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2179 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
2180 RTCritSectEnter(&pThis->CritSect);
2181
2182 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
2183
2184 RTCritSectLeave(&pThis->CritSect);
2185 return rc;
2186}
2187
2188
2189/**
2190 * @copydoc PDMUSBREG::pfnDestruct
2191 */
2192static void usbHidDestruct(PPDMUSBINS pUsbIns)
2193{
2194 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2195 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
2196
2197 if (RTCritSectIsInitialized(&pThis->CritSect))
2198 {
2199 RTCritSectEnter(&pThis->CritSect);
2200 RTCritSectLeave(&pThis->CritSect);
2201 RTCritSectDelete(&pThis->CritSect);
2202 }
2203
2204 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2205 {
2206 RTSemEventDestroy(pThis->hEvtDoneQueue);
2207 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2208 }
2209}
2210
2211
2212/**
2213 * @copydoc PDMUSBREG::pfnConstruct
2214 */
2215static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2216{
2217 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2218 char szMode[64];
2219 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
2220
2221 /*
2222 * Perform the basic structure initialization first so the destructor
2223 * will not misbehave.
2224 */
2225 pThis->pUsbIns = pUsbIns;
2226 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2227 usbHidQueueInit(&pThis->ToHostQueue);
2228 usbHidQueueInit(&pThis->DoneQueue);
2229
2230 int rc = RTCritSectInit(&pThis->CritSect);
2231 AssertRCReturn(rc, rc);
2232
2233 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2234 AssertRCReturn(rc, rc);
2235
2236 /*
2237 * Validate and read the configuration.
2238 */
2239 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
2240 if (RT_FAILURE(rc))
2241 return rc;
2242 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
2243 if (RT_FAILURE(rc))
2244 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
2245 if (!RTStrCmp(szMode, "relative"))
2246 pThis->enmMode = USBHIDMODE_RELATIVE;
2247 else if (!RTStrCmp(szMode, "absolute"))
2248 pThis->enmMode = USBHIDMODE_ABSOLUTE;
2249 else if (!RTStrCmp(szMode, "multitouch"))
2250 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
2251 else
2252 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2253 N_("Invalid HID device mode"));
2254
2255 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
2256 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
2257 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
2258 pThis->Lun0.IPort.pfnPutEventMultiTouch = usbHidMousePutEventMultiTouch;
2259
2260 /*
2261 * Attach the mouse driver.
2262 */
2263 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
2264 if (RT_FAILURE(rc))
2265 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
2266
2267 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
2268 if (!pThis->Lun0.pDrv)
2269 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
2270
2271 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
2272 if (RT_FAILURE(rc))
2273 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
2274
2275 return VINF_SUCCESS;
2276}
2277
2278
2279/**
2280 * The USB Human Interface Device (HID) Mouse registration record.
2281 */
2282const PDMUSBREG g_UsbHidMou =
2283{
2284 /* u32Version */
2285 PDM_USBREG_VERSION,
2286 /* szName */
2287 "HidMouse",
2288 /* pszDescription */
2289 "USB HID Mouse.",
2290 /* fFlags */
2291 0,
2292 /* cMaxInstances */
2293 ~0U,
2294 /* cbInstance */
2295 sizeof(USBHID),
2296 /* pfnConstruct */
2297 usbHidConstruct,
2298 /* pfnDestruct */
2299 usbHidDestruct,
2300 /* pfnVMInitComplete */
2301 NULL,
2302 /* pfnVMPowerOn */
2303 NULL,
2304 /* pfnVMReset */
2305 NULL,
2306 /* pfnVMSuspend */
2307 NULL,
2308 /* pfnVMResume */
2309 NULL,
2310 /* pfnVMPowerOff */
2311 NULL,
2312 /* pfnHotPlugged */
2313 NULL,
2314 /* pfnHotUnplugged */
2315 NULL,
2316 /* pfnDriverAttach */
2317 NULL,
2318 /* pfnDriverDetach */
2319 NULL,
2320 /* pfnQueryInterface */
2321 NULL,
2322 /* pfnUsbReset */
2323 usbHidUsbReset,
2324 /* pfnUsbGetDescriptorCache */
2325 usbHidUsbGetDescriptorCache,
2326 /* pfnUsbSetConfiguration */
2327 usbHidUsbSetConfiguration,
2328 /* pfnUsbSetInterface */
2329 usbHidUsbSetInterface,
2330 /* pfnUsbClearHaltedEndpoint */
2331 usbHidUsbClearHaltedEndpoint,
2332 /* pfnUrbNew */
2333 NULL/*usbHidUrbNew*/,
2334 /* pfnUrbQueue */
2335 usbHidQueue,
2336 /* pfnUrbCancel */
2337 usbHidUrbCancel,
2338 /* pfnUrbReap */
2339 usbHidUrbReap,
2340 /* u32TheEnd */
2341 PDM_USBREG_VERSION
2342};
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