VirtualBox

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

Last change on this file since 90700 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 90.2 KB
Line 
1/* $Id: UsbMouse.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * UsbMouse - USB Human Interface Device Emulation (Mouse).
4 */
5
6/*
7 * Copyright (C) 2007-2020 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 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n", pSetup->wIndex));
2089 break;
2090 }
2091
2092 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
2093 {
2094 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
2095 {
2096 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
2097 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
2098 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
2099 }
2100 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n", pSetup->wIndex));
2101 break;
2102 }
2103
2104 default:
2105 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
2106 pSetup->bmRequestType));
2107 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
2108 }
2109 break;
2110 }
2111
2112 case VUSB_REQ_CLEAR_FEATURE:
2113 break;
2114 }
2115
2116 /** @todo implement this. */
2117 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2118 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2119 pSetup->wIndex, pSetup->wLength));
2120
2121 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
2122 }
2123 else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
2124 {
2125 /* Only VUSB_TO_INTERFACE is allowed. */
2126 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_INTERFACE)
2127 {
2128 return usbHidRequestClass(pThis, pEp, pUrb);
2129 }
2130
2131 LogRelFlow(("usbHid: invalid recipient of class req: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2132 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2133 pSetup->wIndex, pSetup->wLength));
2134 return usbHidCompleteStall(pThis, pEp, pUrb, "Invalid recip");
2135 }
2136 else
2137 {
2138 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2139 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2140 pSetup->wIndex, pSetup->wLength));
2141 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
2142 }
2143
2144 return VINF_SUCCESS;
2145}
2146
2147
2148/**
2149 * @interface_method_impl{PDMUSBREG,pfnUrbQueue}
2150 */
2151static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
2152{
2153 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2154 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
2155 pUrb, pUrb->pszDesc, pUrb->EndPt));
2156 RTCritSectEnter(&pThis->CritSect);
2157
2158 /*
2159 * Parse on a per end-point basis.
2160 */
2161 int rc;
2162 switch (pUrb->EndPt)
2163 {
2164 case 0:
2165 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
2166 break;
2167
2168 case 0x81:
2169 AssertFailed();
2170 RT_FALL_THRU();
2171 case 0x01:
2172 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
2173 break;
2174
2175 default:
2176 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
2177 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
2178 break;
2179 }
2180
2181 RTCritSectLeave(&pThis->CritSect);
2182 return rc;
2183}
2184
2185
2186/**
2187 * @interface_method_impl{PDMUSBREG,pfnUsbClearHaltedEndpoint}
2188 */
2189static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
2190{
2191 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2192 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
2193 pUsbIns->iInstance, uEndpoint));
2194
2195 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
2196 {
2197 RTCritSectEnter(&pThis->CritSect);
2198 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
2199 RTCritSectLeave(&pThis->CritSect);
2200 }
2201
2202 return VINF_SUCCESS;
2203}
2204
2205
2206/**
2207 * @interface_method_impl{PDMUSBREG,pfnUsbSetInterface}
2208 */
2209static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
2210{
2211 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
2212 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
2213 Assert(bAlternateSetting == 0);
2214 return VINF_SUCCESS;
2215}
2216
2217
2218/**
2219 * @interface_method_impl{PDMUSBREG,pfnUsbSetConfiguration}
2220 */
2221static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
2222 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
2223{
2224 RT_NOREF3(pvOldCfgDesc, pvOldIfState, pvNewCfgDesc);
2225 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2226 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
2227 pUsbIns->iInstance, bConfigurationValue));
2228 Assert(bConfigurationValue == 1);
2229 RTCritSectEnter(&pThis->CritSect);
2230
2231 /*
2232 * If the same config is applied more than once, it's a kind of reset.
2233 */
2234 if (pThis->bConfigurationValue == bConfigurationValue)
2235 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
2236 pThis->bConfigurationValue = bConfigurationValue;
2237
2238 /*
2239 * Set received event type to absolute or relative.
2240 */
2241 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
2242 pThis->enmMode == USBHIDMODE_RELATIVE,
2243 pThis->enmMode == USBHIDMODE_ABSOLUTE,
2244 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
2245
2246 RTCritSectLeave(&pThis->CritSect);
2247 return VINF_SUCCESS;
2248}
2249
2250
2251/**
2252 * @interface_method_impl{PDMUSBREG,pfnUsbGetDescriptorCache}
2253 */
2254static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
2255{
2256 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2257 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
2258 switch (pThis->enmMode)
2259 {
2260 case USBHIDMODE_ABSOLUTE:
2261 return &g_UsbHidTDescCache;
2262 case USBHIDMODE_RELATIVE:
2263 return &g_UsbHidMDescCache;
2264 case USBHIDMODE_MULTI_TOUCH:
2265 return &g_UsbHidMTDescCache;
2266 default:
2267 return NULL;
2268 }
2269}
2270
2271
2272/**
2273 * @interface_method_impl{PDMUSBREG,pfnUsbReset}
2274 */
2275static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
2276{
2277 RT_NOREF1(fResetOnLinux);
2278 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2279 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
2280 RTCritSectEnter(&pThis->CritSect);
2281
2282 /* We can not handle any input until device is configured again. */
2283 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv, false, false, false);
2284
2285 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
2286
2287 RTCritSectLeave(&pThis->CritSect);
2288 return rc;
2289}
2290
2291
2292/**
2293 * @interface_method_impl{PDMUSBREG,pfnDestruct}
2294 */
2295static DECLCALLBACK(void) usbHidDestruct(PPDMUSBINS pUsbIns)
2296{
2297 PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns);
2298 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2299 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
2300
2301 if (RTCritSectIsInitialized(&pThis->CritSect))
2302 {
2303 RTCritSectEnter(&pThis->CritSect);
2304 RTCritSectLeave(&pThis->CritSect);
2305 RTCritSectDelete(&pThis->CritSect);
2306 }
2307
2308 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2309 {
2310 RTSemEventDestroy(pThis->hEvtDoneQueue);
2311 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2312 }
2313}
2314
2315
2316/**
2317 * @interface_method_impl{PDMUSBREG,pfnConstruct}
2318 */
2319static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2320{
2321 RT_NOREF1(pCfgGlobal);
2322 PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns);
2323 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2324 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
2325
2326 /*
2327 * Perform the basic structure initialization first so the destructor
2328 * will not misbehave.
2329 */
2330 pThis->pUsbIns = pUsbIns;
2331 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2332 usbHidQueueInit(&pThis->ToHostQueue);
2333 usbHidQueueInit(&pThis->DoneQueue);
2334
2335 int rc = RTCritSectInit(&pThis->CritSect);
2336 AssertRCReturn(rc, rc);
2337
2338 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2339 AssertRCReturn(rc, rc);
2340
2341 /*
2342 * Validate and read the configuration.
2343 */
2344 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
2345 if (RT_FAILURE(rc))
2346 return rc;
2347 char szMode[64];
2348 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
2349 if (RT_FAILURE(rc))
2350 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
2351 if (!RTStrCmp(szMode, "relative"))
2352 pThis->enmMode = USBHIDMODE_RELATIVE;
2353 else if (!RTStrCmp(szMode, "absolute"))
2354 pThis->enmMode = USBHIDMODE_ABSOLUTE;
2355 else if (!RTStrCmp(szMode, "multitouch"))
2356 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
2357 else
2358 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2359 N_("Invalid HID device mode"));
2360
2361 LogRelFlow(("usbHidConstruct/#%u: mode '%s'\n", iInstance, szMode));
2362
2363 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
2364 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
2365 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
2366 pThis->Lun0.IPort.pfnPutEventMultiTouch = usbHidMousePutEventMultiTouch;
2367
2368 /*
2369 * Attach the mouse driver.
2370 */
2371 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
2372 if (RT_FAILURE(rc))
2373 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
2374
2375 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
2376 if (!pThis->Lun0.pDrv)
2377 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
2378
2379 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
2380 if (RT_FAILURE(rc))
2381 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
2382
2383 return VINF_SUCCESS;
2384}
2385
2386
2387/**
2388 * The USB Human Interface Device (HID) Mouse registration record.
2389 */
2390const PDMUSBREG g_UsbHidMou =
2391{
2392 /* u32Version */
2393 PDM_USBREG_VERSION,
2394 /* szName */
2395 "HidMouse",
2396 /* pszDescription */
2397 "USB HID Mouse.",
2398 /* fFlags */
2399 0,
2400 /* cMaxInstances */
2401 ~0U,
2402 /* cbInstance */
2403 sizeof(USBHID),
2404 /* pfnConstruct */
2405 usbHidConstruct,
2406 /* pfnDestruct */
2407 usbHidDestruct,
2408 /* pfnVMInitComplete */
2409 NULL,
2410 /* pfnVMPowerOn */
2411 NULL,
2412 /* pfnVMReset */
2413 NULL,
2414 /* pfnVMSuspend */
2415 NULL,
2416 /* pfnVMResume */
2417 NULL,
2418 /* pfnVMPowerOff */
2419 NULL,
2420 /* pfnHotPlugged */
2421 NULL,
2422 /* pfnHotUnplugged */
2423 NULL,
2424 /* pfnDriverAttach */
2425 NULL,
2426 /* pfnDriverDetach */
2427 NULL,
2428 /* pfnQueryInterface */
2429 NULL,
2430 /* pfnUsbReset */
2431 usbHidUsbReset,
2432 /* pfnUsbGetDescriptorCache */
2433 usbHidUsbGetDescriptorCache,
2434 /* pfnUsbSetConfiguration */
2435 usbHidUsbSetConfiguration,
2436 /* pfnUsbSetInterface */
2437 usbHidUsbSetInterface,
2438 /* pfnUsbClearHaltedEndpoint */
2439 usbHidUsbClearHaltedEndpoint,
2440 /* pfnUrbNew */
2441 NULL/*usbHidUrbNew*/,
2442 /* pfnUrbQueue */
2443 usbHidQueue,
2444 /* pfnUrbCancel */
2445 usbHidUrbCancel,
2446 /* pfnUrbReap */
2447 usbHidUrbReap,
2448 /* pfnWakeup */
2449 usbHidWakeup,
2450 /* u32TheEnd */
2451 PDM_USBREG_VERSION
2452};
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