VirtualBox

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

Last change on this file since 63942 was 63478, checked in by vboxsync, 8 years ago

Devices: warnings (clang)

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

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