VirtualBox

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

Last change on this file since 69922 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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