VirtualBox

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

Last change on this file since 56636 was 56292, checked in by vboxsync, 10 years ago

Devices: Updated (C) year.

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