VirtualBox

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

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

Touchpad: First part of touchpad support, PDM interface and device emulation (see bugref:9891).

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

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