VirtualBox

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

Last change on this file since 51546 was 49814, checked in by vboxsync, 11 years ago

Devices/USB: First part of the rework, move most of the work to dedicated threads to improve performance

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.7 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 LogFlowFunc(("pUsbIns=%p cMillies=%u\n", pUsbIns, cMillies));
1672
1673 RTCritSectEnter(&pThis->CritSect);
1674
1675 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1676 if (!pUrb && cMillies)
1677 {
1678 /* Wait */
1679 pThis->fHaveDoneQueueWaiter = true;
1680 RTCritSectLeave(&pThis->CritSect);
1681
1682 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1683
1684 RTCritSectEnter(&pThis->CritSect);
1685 pThis->fHaveDoneQueueWaiter = false;
1686
1687 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1688 }
1689
1690 RTCritSectLeave(&pThis->CritSect);
1691
1692 if (pUrb)
1693 LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1694 pUrb->pszDesc));
1695 return pUrb;
1696}
1697
1698/**
1699 * @copydoc PDMUSBREG::pfnWakeup
1700 */
1701static DECLCALLBACK(int) usbHidWakeup(PPDMUSBINS pUsbIns)
1702{
1703 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1704
1705 return RTSemEventSignal(pThis->hEvtDoneQueue);
1706}
1707
1708/**
1709 * @copydoc PDMUSBREG::pfnUrbCancel
1710 */
1711static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1712{
1713 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1714 LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
1715 pUrb->pszDesc));
1716 RTCritSectEnter(&pThis->CritSect);
1717
1718 /*
1719 * Remove the URB from the to-host queue and move it onto the done queue.
1720 */
1721 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
1722 usbHidLinkDone(pThis, pUrb);
1723
1724 RTCritSectLeave(&pThis->CritSect);
1725 return VINF_SUCCESS;
1726}
1727
1728
1729/**
1730 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1731 * rather different from bulk requests because an interrupt read URB may complete
1732 * after arbitrarily long time.
1733 */
1734static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1735{
1736 /*
1737 * Stall the request if the pipe is halted.
1738 */
1739 if (RT_UNLIKELY(pEp->fHalted))
1740 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1741
1742 /*
1743 * Deal with the URB according to the state.
1744 */
1745 switch (pThis->enmState)
1746 {
1747 /*
1748 * We've data left to transfer to the host.
1749 */
1750 case USBHIDREQSTATE_DATA_TO_HOST:
1751 {
1752 AssertFailed();
1753 LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1754 return usbHidCompleteOk(pThis, pUrb, 0);
1755 }
1756
1757 /*
1758 * Status transfer.
1759 */
1760 case USBHIDREQSTATE_STATUS:
1761 {
1762 AssertFailed();
1763 LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
1764 pThis->enmState = USBHIDREQSTATE_READY;
1765 return usbHidCompleteOk(pThis, pUrb, 0);
1766 }
1767
1768 case USBHIDREQSTATE_READY:
1769 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
1770 LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
1771 pUrb, pUrb->pszDesc));
1772 /* If a report is pending, send it right away. */
1773 if (pThis->fHasPendingChanges)
1774 usbHidSendReport(pThis);
1775 return VINF_SUCCESS;
1776
1777 /*
1778 * Bad states, stall.
1779 */
1780 default:
1781 LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
1782 pThis->enmState, pUrb->cbData));
1783 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1784 }
1785}
1786
1787#define GET_REPORT 0x01
1788#define GET_IDLE 0x02
1789#define GET_PROTOCOL 0x03
1790#define SET_REPORT 0x09
1791#define SET_IDLE 0x0A
1792#define SET_PROTOCOL 0x0B
1793
1794static uint8_t sau8QASampleBlob[256] =
1795{
1796 0xfc, 0x28, 0xfe, 0x84, 0x40, 0xcb, 0x9a, 0x87,
1797 0x0d, 0xbe, 0x57, 0x3c, 0xb6, 0x70, 0x09, 0x88,
1798 0x07, 0x97, 0x2d, 0x2b, 0xe3, 0x38, 0x34, 0xb6,
1799 0x6c, 0xed, 0xb0, 0xf7, 0xe5, 0x9c, 0xf6, 0xc2,
1800 0x2e, 0x84, 0x1b, 0xe8, 0xb4, 0x51, 0x78, 0x43,
1801 0x1f, 0x28, 0x4b, 0x7c, 0x2d, 0x53, 0xaf, 0xfc,
1802 0x47, 0x70, 0x1b, 0x59, 0x6f, 0x74, 0x43, 0xc4,
1803 0xf3, 0x47, 0x18, 0x53, 0x1a, 0xa2, 0xa1, 0x71,
1804 0xc7, 0x95, 0x0e, 0x31, 0x55, 0x21, 0xd3, 0xb5,
1805 0x1e, 0xe9, 0x0c, 0xba, 0xec, 0xb8, 0x89, 0x19,
1806 0x3e, 0xb3, 0xaf, 0x75, 0x81, 0x9d, 0x53, 0xb9,
1807 0x41, 0x57, 0xf4, 0x6d, 0x39, 0x25, 0x29, 0x7c,
1808 0x87, 0xd9, 0xb4, 0x98, 0x45, 0x7d, 0xa7, 0x26,
1809 0x9c, 0x65, 0x3b, 0x85, 0x68, 0x89, 0xd7, 0x3b,
1810 0xbd, 0xff, 0x14, 0x67, 0xf2, 0x2b, 0xf0, 0x2a,
1811 0x41, 0x54, 0xf0, 0xfd, 0x2c, 0x66, 0x7c, 0xf8,
1812 0xc0, 0x8f, 0x33, 0x13, 0x03, 0xf1, 0xd3, 0xc1,
1813 0x0b, 0x89, 0xd9, 0x1b, 0x62, 0xcd, 0x51, 0xb7,
1814 0x80, 0xb8, 0xaf, 0x3a, 0x10, 0xc1, 0x8a, 0x5b,
1815 0xe8, 0x8a, 0x56, 0xf0, 0x8c, 0xaa, 0xfa, 0x35,
1816 0xe9, 0x42, 0xc4, 0xd8, 0x55, 0xc3, 0x38, 0xcc,
1817 0x2b, 0x53, 0x5c, 0x69, 0x52, 0xd5, 0xc8, 0x73,
1818 0x02, 0x38, 0x7c, 0x73, 0xb6, 0x41, 0xe7, 0xff,
1819 0x05, 0xd8, 0x2b, 0x79, 0x9a, 0xe2, 0x34, 0x60,
1820 0x8f, 0xa3, 0x32, 0x1f, 0x09, 0x78, 0x62, 0xbc,
1821 0x80, 0xe3, 0x0f, 0xbd, 0x65, 0x20, 0x08, 0x13,
1822 0xc1, 0xe2, 0xee, 0x53, 0x2d, 0x86, 0x7e, 0xa7,
1823 0x5a, 0xc5, 0xd3, 0x7d, 0x98, 0xbe, 0x31, 0x48,
1824 0x1f, 0xfb, 0xda, 0xaf, 0xa2, 0xa8, 0x6a, 0x89,
1825 0xd6, 0xbf, 0xf2, 0xd3, 0x32, 0x2a, 0x9a, 0xe4,
1826 0xcf, 0x17, 0xb7, 0xb8, 0xf4, 0xe1, 0x33, 0x08,
1827 0x24, 0x8b, 0xc4, 0x43, 0xa5, 0xe5, 0x24, 0xc2
1828};
1829
1830static int usbHidRequestClass(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1831{
1832 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1833
1834 if (pThis->enmMode != USBHIDMODE_MULTI_TOUCH)
1835 {
1836 LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1837 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1838 pSetup->wIndex, pSetup->wLength));
1839 return usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req");
1840 }
1841
1842 int rc = VINF_SUCCESS;
1843
1844 switch (pSetup->bRequest)
1845 {
1846 case SET_REPORT:
1847 case GET_REPORT:
1848 {
1849 uint8_t u8ReportType = RT_HI_U8(pSetup->wValue);
1850 uint8_t u8ReportID = RT_LO_U8(pSetup->wValue);
1851 LogRelFlow(("usbHid: %s: type %d, ID %d, data\n%.*Rhxd\n",
1852 pSetup->bRequest == GET_REPORT? "GET_REPORT": "SET_REPORT",
1853 u8ReportType, u8ReportID,
1854 pUrb->cbData - sizeof(VUSBSETUP), &pUrb->abData[sizeof(VUSBSETUP)]));
1855 if (pSetup->bRequest == GET_REPORT)
1856 {
1857 uint32_t cbData = 0; /* 0 means that the report is unsupported. */
1858
1859 if (u8ReportType == 1 && u8ReportID == REPORTID_TOUCH_POINTER)
1860 {
1861 USBHIDMT_REPORT_POINTER *p = (USBHIDMT_REPORT_POINTER *)&pUrb->abData[sizeof(VUSBSETUP)];
1862 /* The actual state should be reported here. */
1863 p->idReport = REPORTID_TOUCH_POINTER;
1864 p->fButtons = 0;
1865 p->x = 0;
1866 p->y = 0;
1867 cbData = sizeof(USBHIDMT_REPORT_POINTER);
1868 }
1869 else if (u8ReportType == 1 && u8ReportID == REPORTID_TOUCH_EVENT)
1870 {
1871 USBHIDMT_REPORT *p = (USBHIDMT_REPORT *)&pUrb->abData[sizeof(VUSBSETUP)];
1872 /* The actual state should be reported here. */
1873 RT_ZERO(*p);
1874 p->idReport = REPORTID_TOUCH_EVENT;
1875 cbData = sizeof(USBHIDMT_REPORT);
1876 }
1877 else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_MAX_COUNT)
1878 {
1879 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_MAX_COUNT;
1880 pUrb->abData[sizeof(VUSBSETUP) + 1] = MT_CONTACT_MAX_COUNT; /* Contact count maximum. */
1881 pUrb->abData[sizeof(VUSBSETUP) + 2] = 0; /* Device identifier */
1882 cbData = 3;
1883 }
1884 else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_QABLOB)
1885 {
1886 uint32_t cbLeft = pUrb->cbData;
1887 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_QABLOB; /* Report Id. */
1888 memcpy(&pUrb->abData[sizeof(VUSBSETUP) + 1],
1889 sau8QASampleBlob, sizeof(sau8QASampleBlob));
1890 cbData = sizeof(sau8QASampleBlob) + 1;
1891 }
1892 else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_DEVCONFIG)
1893 {
1894 pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_DEVCONFIG;
1895 pUrb->abData[sizeof(VUSBSETUP) + 1] = 2; /* Device mode:
1896 * "HID touch device supporting contact
1897 * identifier and contact count maximum."
1898 */
1899 pUrb->abData[sizeof(VUSBSETUP) + 2] = 0; /* Device identifier */
1900 cbData = 3;
1901 }
1902
1903 if (cbData > 0)
1904 {
1905 rc = usbHidCompleteOk(pThis, pUrb, sizeof(VUSBSETUP) + cbData);
1906 }
1907 else
1908 {
1909 rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported GET_REPORT MT");
1910 }
1911 }
1912 else
1913 {
1914 /* SET_REPORT */
1915 rc = usbHidCompleteOk(pThis, pUrb, pUrb->cbData);
1916 }
1917 } break;
1918 default:
1919 {
1920 LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1921 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
1922 pSetup->wIndex, pSetup->wLength));
1923 rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req MT");
1924 }
1925 }
1926
1927 return rc;
1928}
1929
1930/**
1931 * Handles request sent to the default control pipe.
1932 */
1933static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1934{
1935 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1936 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1937
1938 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1939 {
1940 switch (pSetup->bRequest)
1941 {
1942 case VUSB_REQ_GET_DESCRIPTOR:
1943 {
1944 switch (pSetup->bmRequestType)
1945 {
1946 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1947 {
1948 switch (pSetup->wValue >> 8)
1949 {
1950 case VUSB_DT_STRING:
1951 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
1952 pSetup->wValue, pSetup->wIndex));
1953 break;
1954 default:
1955 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
1956 pSetup->wValue, pSetup->wIndex));
1957 break;
1958 }
1959 break;
1960 }
1961
1962 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1963 {
1964 switch (pSetup->wValue >> 8)
1965 {
1966 uint32_t cbCopy;
1967 uint32_t cbDesc;
1968 const uint8_t *pDesc;
1969
1970 case DT_IF_HID_DESCRIPTOR:
1971 {
1972 switch (pThis->enmMode)
1973 {
1974 case USBHIDMODE_ABSOLUTE:
1975 cbDesc = sizeof(g_UsbHidTIfHidDesc);
1976 pDesc = (const uint8_t *)&g_UsbHidTIfHidDesc;
1977 break;
1978 case USBHIDMODE_RELATIVE:
1979 cbDesc = sizeof(g_UsbHidMIfHidDesc);
1980 pDesc = (const uint8_t *)&g_UsbHidMIfHidDesc;
1981 break;
1982 case USBHIDMODE_MULTI_TOUCH:
1983 cbDesc = sizeof(g_UsbHidMTIfHidDesc);
1984 pDesc = (const uint8_t *)&g_UsbHidMTIfHidDesc;
1985 break;
1986 default:
1987 cbDesc = 0;
1988 pDesc = 0;
1989 break;
1990 }
1991 /* Returned data is written after the setup message. */
1992 cbCopy = pUrb->cbData - sizeof(*pSetup);
1993 cbCopy = RT_MIN(cbCopy, cbDesc);
1994 LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
1995 pSetup->wValue, pSetup->wIndex,
1996 cbCopy));
1997 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
1998 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
1999 }
2000
2001 case DT_IF_HID_REPORT:
2002 {
2003 switch (pThis->enmMode)
2004 {
2005 case USBHIDMODE_ABSOLUTE:
2006 cbDesc = sizeof(g_UsbHidTReportDesc);
2007 pDesc = (const uint8_t *)&g_UsbHidTReportDesc;
2008 break;
2009 case USBHIDMODE_RELATIVE:
2010 cbDesc = sizeof(g_UsbHidMReportDesc);
2011 pDesc = (const uint8_t *)&g_UsbHidMReportDesc;
2012 break;
2013 case USBHIDMODE_MULTI_TOUCH:
2014 cbDesc = sizeof(g_UsbHidMTReportDesc);
2015 pDesc = (const uint8_t *)&g_UsbHidMTReportDesc;
2016 break;
2017 default:
2018 cbDesc = 0;
2019 pDesc = 0;
2020 break;
2021 }
2022 /* Returned data is written after the setup message. */
2023 cbCopy = pUrb->cbData - sizeof(*pSetup);
2024 cbCopy = RT_MIN(cbCopy, cbDesc);
2025 LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
2026 pSetup->wValue, pSetup->wIndex,
2027 cbCopy));
2028 memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
2029 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
2030 }
2031
2032 default:
2033 LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
2034 pSetup->wValue, pSetup->wIndex));
2035 break;
2036 }
2037 break;
2038 }
2039
2040 default:
2041 LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
2042 pSetup->bmRequestType));
2043 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
2044 }
2045 break;
2046 }
2047
2048 case VUSB_REQ_GET_STATUS:
2049 {
2050 uint16_t wRet = 0;
2051
2052 if (pSetup->wLength != 2)
2053 {
2054 LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
2055 pSetup->wLength));
2056 break;
2057 }
2058 Assert(pSetup->wValue == 0);
2059 switch (pSetup->bmRequestType)
2060 {
2061 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
2062 {
2063 Assert(pSetup->wIndex == 0);
2064 LogRelFlow(("usbHid: GET_STATUS (device)\n"));
2065 wRet = 0; /* Not self-powered, no remote wakeup. */
2066 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
2067 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
2068 }
2069
2070 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
2071 {
2072 if (pSetup->wIndex == 0)
2073 {
2074 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
2075 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
2076 }
2077 else
2078 {
2079 LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
2080 pSetup->wIndex));
2081 }
2082 break;
2083 }
2084
2085 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
2086 {
2087 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
2088 {
2089 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
2090 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
2091 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
2092 }
2093 else
2094 {
2095 LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
2096 pSetup->wIndex));
2097 }
2098 break;
2099 }
2100
2101 default:
2102 LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
2103 pSetup->bmRequestType));
2104 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
2105 }
2106 break;
2107 }
2108
2109 case VUSB_REQ_CLEAR_FEATURE:
2110 break;
2111 }
2112
2113 /** @todo implement this. */
2114 LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2115 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2116 pSetup->wIndex, pSetup->wLength));
2117
2118 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
2119 }
2120 else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
2121 {
2122 /* Only VUSB_TO_INTERFACE is allowed. */
2123 if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_INTERFACE)
2124 {
2125 return usbHidRequestClass(pThis, pEp, pUrb);
2126 }
2127
2128 LogRelFlow(("usbHid: invalid recipient of class req: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2129 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2130 pSetup->wIndex, pSetup->wLength));
2131 return usbHidCompleteStall(pThis, pEp, pUrb, "Invalid recip");
2132 }
2133 else
2134 {
2135 LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
2136 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
2137 pSetup->wIndex, pSetup->wLength));
2138 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
2139 }
2140
2141 return VINF_SUCCESS;
2142}
2143
2144
2145/**
2146 * @copydoc PDMUSBREG::pfnUrbQueue
2147 */
2148static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
2149{
2150 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2151 LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
2152 pUrb, pUrb->pszDesc, pUrb->EndPt));
2153 RTCritSectEnter(&pThis->CritSect);
2154
2155 /*
2156 * Parse on a per end-point basis.
2157 */
2158 int rc;
2159 switch (pUrb->EndPt)
2160 {
2161 case 0:
2162 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
2163 break;
2164
2165 case 0x81:
2166 AssertFailed();
2167 case 0x01:
2168 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
2169 break;
2170
2171 default:
2172 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
2173 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
2174 break;
2175 }
2176
2177 RTCritSectLeave(&pThis->CritSect);
2178 return rc;
2179}
2180
2181
2182/**
2183 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
2184 */
2185static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
2186{
2187 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2188 LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
2189 pUsbIns->iInstance, uEndpoint));
2190
2191 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
2192 {
2193 RTCritSectEnter(&pThis->CritSect);
2194 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
2195 RTCritSectLeave(&pThis->CritSect);
2196 }
2197
2198 return VINF_SUCCESS;
2199}
2200
2201
2202/**
2203 * @copydoc PDMUSBREG::pfnUsbSetInterface
2204 */
2205static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
2206{
2207 LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
2208 pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
2209 Assert(bAlternateSetting == 0);
2210 return VINF_SUCCESS;
2211}
2212
2213
2214/**
2215 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
2216 */
2217static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
2218 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
2219{
2220 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2221 LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
2222 pUsbIns->iInstance, bConfigurationValue));
2223 Assert(bConfigurationValue == 1);
2224 RTCritSectEnter(&pThis->CritSect);
2225
2226 /*
2227 * If the same config is applied more than once, it's a kind of reset.
2228 */
2229 if (pThis->bConfigurationValue == bConfigurationValue)
2230 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
2231 pThis->bConfigurationValue = bConfigurationValue;
2232
2233 /*
2234 * Set received event type to absolute or relative.
2235 */
2236 pThis->Lun0.pDrv->pfnReportModes(pThis->Lun0.pDrv,
2237 pThis->enmMode == USBHIDMODE_RELATIVE,
2238 pThis->enmMode == USBHIDMODE_ABSOLUTE,
2239 pThis->enmMode == USBHIDMODE_MULTI_TOUCH);
2240
2241 RTCritSectLeave(&pThis->CritSect);
2242 return VINF_SUCCESS;
2243}
2244
2245
2246/**
2247 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
2248 */
2249static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
2250{
2251 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2252 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
2253 switch (pThis->enmMode)
2254 {
2255 case USBHIDMODE_ABSOLUTE:
2256 return &g_UsbHidTDescCache;
2257 case USBHIDMODE_RELATIVE:
2258 return &g_UsbHidMDescCache;
2259 case USBHIDMODE_MULTI_TOUCH:
2260 return &g_UsbHidMTDescCache;
2261 default:
2262 return NULL;
2263 }
2264}
2265
2266
2267/**
2268 * @copydoc PDMUSBREG::pfnUsbReset
2269 */
2270static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
2271{
2272 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2273 LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
2274 RTCritSectEnter(&pThis->CritSect);
2275
2276 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
2277
2278 RTCritSectLeave(&pThis->CritSect);
2279 return rc;
2280}
2281
2282
2283/**
2284 * @copydoc PDMUSBREG::pfnDestruct
2285 */
2286static void usbHidDestruct(PPDMUSBINS pUsbIns)
2287{
2288 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2289 LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
2290
2291 if (RTCritSectIsInitialized(&pThis->CritSect))
2292 {
2293 RTCritSectEnter(&pThis->CritSect);
2294 RTCritSectLeave(&pThis->CritSect);
2295 RTCritSectDelete(&pThis->CritSect);
2296 }
2297
2298 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
2299 {
2300 RTSemEventDestroy(pThis->hEvtDoneQueue);
2301 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2302 }
2303}
2304
2305
2306/**
2307 * @copydoc PDMUSBREG::pfnConstruct
2308 */
2309static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
2310{
2311 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
2312 char szMode[64];
2313 LogRelFlow(("usbHidConstruct/#%u:\n", iInstance));
2314
2315 /*
2316 * Perform the basic structure initialization first so the destructor
2317 * will not misbehave.
2318 */
2319 pThis->pUsbIns = pUsbIns;
2320 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
2321 usbHidQueueInit(&pThis->ToHostQueue);
2322 usbHidQueueInit(&pThis->DoneQueue);
2323
2324 int rc = RTCritSectInit(&pThis->CritSect);
2325 AssertRCReturn(rc, rc);
2326
2327 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
2328 AssertRCReturn(rc, rc);
2329
2330 /*
2331 * Validate and read the configuration.
2332 */
2333 rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
2334 if (RT_FAILURE(rc))
2335 return rc;
2336 rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
2337 if (RT_FAILURE(rc))
2338 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
2339 if (!RTStrCmp(szMode, "relative"))
2340 pThis->enmMode = USBHIDMODE_RELATIVE;
2341 else if (!RTStrCmp(szMode, "absolute"))
2342 pThis->enmMode = USBHIDMODE_ABSOLUTE;
2343 else if (!RTStrCmp(szMode, "multitouch"))
2344 pThis->enmMode = USBHIDMODE_MULTI_TOUCH;
2345 else
2346 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
2347 N_("Invalid HID device mode"));
2348
2349 LogRelFlow(("usbHidConstruct/#%u: mode '%s'\n", iInstance, szMode));
2350
2351 pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
2352 pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
2353 pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
2354 pThis->Lun0.IPort.pfnPutEventMultiTouch = usbHidMousePutEventMultiTouch;
2355
2356 /*
2357 * Attach the mouse driver.
2358 */
2359 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
2360 if (RT_FAILURE(rc))
2361 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
2362
2363 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
2364 if (!pThis->Lun0.pDrv)
2365 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
2366
2367 rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
2368 if (RT_FAILURE(rc))
2369 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
2370
2371 return VINF_SUCCESS;
2372}
2373
2374
2375/**
2376 * The USB Human Interface Device (HID) Mouse registration record.
2377 */
2378const PDMUSBREG g_UsbHidMou =
2379{
2380 /* u32Version */
2381 PDM_USBREG_VERSION,
2382 /* szName */
2383 "HidMouse",
2384 /* pszDescription */
2385 "USB HID Mouse.",
2386 /* fFlags */
2387 0,
2388 /* cMaxInstances */
2389 ~0U,
2390 /* cbInstance */
2391 sizeof(USBHID),
2392 /* pfnConstruct */
2393 usbHidConstruct,
2394 /* pfnDestruct */
2395 usbHidDestruct,
2396 /* pfnVMInitComplete */
2397 NULL,
2398 /* pfnVMPowerOn */
2399 NULL,
2400 /* pfnVMReset */
2401 NULL,
2402 /* pfnVMSuspend */
2403 NULL,
2404 /* pfnVMResume */
2405 NULL,
2406 /* pfnVMPowerOff */
2407 NULL,
2408 /* pfnHotPlugged */
2409 NULL,
2410 /* pfnHotUnplugged */
2411 NULL,
2412 /* pfnDriverAttach */
2413 NULL,
2414 /* pfnDriverDetach */
2415 NULL,
2416 /* pfnQueryInterface */
2417 NULL,
2418 /* pfnUsbReset */
2419 usbHidUsbReset,
2420 /* pfnUsbGetDescriptorCache */
2421 usbHidUsbGetDescriptorCache,
2422 /* pfnUsbSetConfiguration */
2423 usbHidUsbSetConfiguration,
2424 /* pfnUsbSetInterface */
2425 usbHidUsbSetInterface,
2426 /* pfnUsbClearHaltedEndpoint */
2427 usbHidUsbClearHaltedEndpoint,
2428 /* pfnUrbNew */
2429 NULL/*usbHidUrbNew*/,
2430 /* pfnUrbQueue */
2431 usbHidQueue,
2432 /* pfnUrbCancel */
2433 usbHidUrbCancel,
2434 /* pfnUrbReap */
2435 usbHidUrbReap,
2436 /* pfnWakeup */
2437 usbHidWakeup,
2438 /* u32TheEnd */
2439 PDM_USBREG_VERSION
2440};
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