VirtualBox

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

Last change on this file since 90993 was 90993, checked in by vboxsync, 3 years ago

UsbMouse: Reworked URB processing to make it simpler and more uniform. Now lines up with UsbKbd.

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