VirtualBox

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

Last change on this file since 49469 was 48947, checked in by vboxsync, 11 years ago

Devices: Whitespace and svn:keyword cleanups by scm.

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

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