VirtualBox

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

Last change on this file was 102484, checked in by vboxsync, 5 months ago

UsbMouse: Windows guests require that touch events with active contacts be repeated even in the absence of any changes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use