VirtualBox

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

Last change on this file since 97046 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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