VirtualBox

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

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

Frontend,Devices: touch input updates

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