VirtualBox

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

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

Devices\Input\UsbMouse: implemented GET_REPORT stubs; report the latest state.

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