VirtualBox

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

Last change on this file since 47768 was 47768, checked in by vboxsync, 12 years ago

Devices/Input: add horizontal scrolling to the USB mouse device.

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