VirtualBox

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

Last change on this file since 47645 was 47613, checked in by vboxsync, 11 years ago

Input/UsbMouse: warnings

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