VirtualBox

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

Last change on this file since 62956 was 62956, checked in by vboxsync, 9 years ago

@copydoc -> @interface_method_impl

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

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