ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * UsbMouse - USB Human Interface Device Emulation (Mouse).
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2007-2012 Oracle Corporation
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * available from http://www.virtualbox.org. This file is free software;
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * General Public License (GPL) as published by the Free Software
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync* Header Files *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync* Defined Constants And Macros *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @name USB HID string IDs
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @name USB HID specific descriptor types
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** @name USB HID vendor and product IDs
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync* Structures and Typedefs *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * The USB HID request state.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Invalid status. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Ready to receive a new read request. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Have (more) data for the host. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Waiting to supply status information to the host. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The end of the valid states. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * The device reporting mode.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync * @todo Use an interface instead of an enum and switches.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Relative. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Absolute. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Multi-touch. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Endpoint status data.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Pointer to the endpoint status. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * A URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The head pointer. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Where to insert the next entry. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Pointer to a URB queue. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Pointer to a const URB queue. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Mouse movement accumulator.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync#define MT_CONTACT_S_ACTIVE 0x01 /* Contact must be reported to the guest. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync#define MT_CONTACT_S_CANCELLED 0x02 /* Contact loss must be reported to the guest. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync#define MT_CONTACT_S_REUSED 0x04 /* Report contact loss for the oldId and then new contact for the id. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync#define MT_CONTACT_S_DIRTY 0x08 /* Temporary flag used to track already processed elements. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync uint8_t oldId; /* Valid only if MT_CONTACT_S_REUSED is set. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * The USB HID instance data.
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync /** Pointer back to the PDM USB Device instance structure. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Critical section protecting the device state. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The current configuration.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * (0 - default, 1 - the one supported configuration, i.e configured.) */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Endpoint 0 is the default control pipe, 1 is the dev->host interrupt one. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The state of the HID (state machine).*/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Pointer movement accumulator. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Pending to-host queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * The URBs waiting here are waiting for data to become available.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Done queue
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * The URBs stashed here are waiting to be reaped. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * is set. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** Someone is waiting on the done queue. */
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /** If device has pending changes. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /** Is this a relative, absolute or multi-touch pointing device? */
6cd65034f702d9b4122249011835e9639a7bc660vboxsync /** Tablet coordinate shift factor for old and broken operating systems. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Mouse port - LUN#0.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @implements PDMIBASE
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @implements PDMIMOUSEPORT
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The base interface for the mouse port. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The mouse port base interface. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The base interface of the attached mouse driver. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** The mouse interface of the attached mouse driver. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync MTCONTACT aCurrentContactState[MT_CONTACT_MAX_COUNT];
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync MTCONTACT aReportingContactState[MT_CONTACT_MAX_COUNT];
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/** Pointer to the USB HID instance data. */
8112e0942f1128329b99b22a20b395963d4abceavboxsync * The USB HID report structure for relative device.
33f7a1bbfb625f3401368928cd5e9317ca04881dvboxsync * The USB HID report structure for absolute device.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * The combined USB HID report union for relative and absolute
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * The USB HID report structure for the multi-touch device.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync* Global Variables *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic const PDMUSBDESCCACHESTRING g_aUsbHidStrings_en_US[] =
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic const PDMUSBDESCCACHELANG g_aUsbHidLanguages[] =
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync { 0x0409, RT_ELEMENTS(g_aUsbHidStrings_en_US), g_aUsbHidStrings_en_US }
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic const VUSBDESCENDPOINTEX g_aUsbHidMEndpointDescs[] =
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .cbClass = */ 0
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic const VUSBDESCENDPOINTEX g_aUsbHidTEndpointDescs[] =
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .cbClass = */ 0
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsyncstatic const VUSBDESCENDPOINTEX g_aUsbHidMTEndpointDescs[] =
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* .cbClass = */ 0
8112e0942f1128329b99b22a20b395963d4abceavboxsync/* HID report descriptor (mouse). */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
500d759609a43a472c7a29b58f3479ed319a5a76vboxsync /* Report Size */ 0x75, 0x03, /* 3 (padding bits) */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Input */ 0x81, 0x06, /* Data, Value, Relative, Bit field */
8112e0942f1128329b99b22a20b395963d4abceavboxsync/* HID report descriptor (tablet). */
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync/* NB: The layout is far from random. Having the buttons and Z axis grouped
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync * together avoids alignment issues. Also, if X/Y is reported first, followed
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync * by buttons/Z, Windows gets phantom Z movement. That is likely a bug in Windows
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync * as OS X shows no such problem. When X/Y is reported last, Windows behaves
0e3950d85821ff3f0f9191f7bf0efe7b3510a808vboxsync * properly.
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
500d759609a43a472c7a29b58f3479ed319a5a76vboxsync /* Report Size */ 0x75, 0x03, /* 3 (padding bits) */
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync /* Input */ 0x81, 0x06, /* Data, Value, Relative, Bit field */
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync /* Usage Page */ 0x05, 0x0C, /* Consumer Devices */
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync /* Usage */ 0x0A, 0x38, 0x02,/* AC Pan (horizontal wheel) */
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync /* Input */ 0x81, 0x06, /* Data, Value, Relative, Bit field */
4fa6d2a2ac7d62a1815bcb6d6565ae7cdf775cdbvboxsync /* Report Size */ 0x75, 0x08, /* 8 (padding byte) */
4fa6d2a2ac7d62a1815bcb6d6565ae7cdf775cdbvboxsync /* Input */ 0x81, 0x03, /* Constant, Value, Absolute, Bit field */
4fa6d2a2ac7d62a1815bcb6d6565ae7cdf775cdbvboxsync /* Physical Maximum */ 0x46, 0xFF,0x7F,/* 0x7fff */
4fa6d2a2ac7d62a1815bcb6d6565ae7cdf775cdbvboxsync /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * Multi-touch device implementation based on "Windows Pointer Device Data Delivery Protocol"
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * specification.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* MT_CONTACTS_PER_REPORT structs u8TipSwitch, u8ContactIdentifier, u16X, u16Y */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* 1 of 5 */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* 2 of 5 */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* 3 of 5 */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* 4 of 5 */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* 5 of 5 */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* Note: "Scan time" usage is required for all touch devices (in 100microseconds units). */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* Logical Minimum (0) */ 0x17, 0x00, 0x00, 0x00, 0x00,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* Logical Maximum (2147483647) */ 0x27, 0xFF, 0xFF, 0xFF, 0x7F,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* Usage Page (Vendor-Defined 1) */ 0x06, 0x00, 0xFF,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync/* Note: the pointer report is required by specification:
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * "The report descriptor for a multiple input device must include at least
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * one top-level collection for the primary device and a separate top-level
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * collection for the mouse."
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync/** @todo Do these really have to all be duplicated three times? */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/* Additional HID class interface descriptor. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bCountryCode = */ 0,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .wDescriptorLength = */ sizeof(g_UsbHidMReportDesc), 0x00
8112e0942f1128329b99b22a20b395963d4abceavboxsync/* Additional HID class interface descriptor. */
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bCountryCode = */ 0,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .wDescriptorLength = */ sizeof(g_UsbHidTReportDesc), 0x00
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync/* Additional HID class interface descriptor. */
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bCountryCode = */ 0,
dd0f1b7925a57b9976df733c4203f995bdcb170dvboxsync /* .wDescriptorLength = */ (uint8_t)(sizeof(g_UsbHidMTReportDesc) & 0xFF),
dd0f1b7925a57b9976df733c4203f995bdcb170dvboxsync (uint8_t)((sizeof(g_UsbHidMTReportDesc) >> 8) & 0xFF)
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic const VUSBDESCINTERFACEEX g_UsbHidMInterfaceDesc =
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bInterfaceNumber = */ 0,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bAlternateSetting = */ 0,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .iInterface = */ 0
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync /* .cbIAD = */ 0
8112e0942f1128329b99b22a20b395963d4abceavboxsyncstatic const VUSBDESCINTERFACEEX g_UsbHidTInterfaceDesc =
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bInterfaceNumber = */ 0,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bAlternateSetting = */ 0,
1a1433dbc5e55f83cbcde6aa9f045c2dc7eeb9e7vboxsync /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
1a1433dbc5e55f83cbcde6aa9f045c2dc7eeb9e7vboxsync /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .iInterface = */ 0
d28bd01ede12da4a939e81a155d227ee4d6ff634vboxsync /* .cbIAD = */ 0
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsyncstatic const VUSBDESCINTERFACEEX g_UsbHidMTInterfaceDesc =
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bInterfaceNumber = */ 0,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bAlternateSetting = */ 0,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bInterfaceSubClass = */ 0 /* No subclass - no boot interface. */,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bInterfaceProtocol = */ 0 /* No protocol - no boot interface. */,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .iInterface = */ 0
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .cbIAD = */ 0
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsyncstatic const VUSBINTERFACE g_aUsbHidMTInterfaces[] =
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync { &g_UsbHidMTInterfaceDesc, /* .cSettings = */ 1 },
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .wTotalLength = */ 0 /* recalculated on read */,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMInterfaces),
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .iConfiguration = */ 0,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .wTotalLength = */ 0 /* recalculated on read */,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidTInterfaces),
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .iConfiguration = */ 0,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsyncstatic const VUSBDESCCONFIGEX g_UsbHidMTConfigDesc =
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .wTotalLength = */ 0 /* recalculated on read */,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidMTInterfaces),
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .iConfiguration = */ 0,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .iSerialNumber = */ 0,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .iSerialNumber = */ 0,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .iSerialNumber = */ 0,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .fUseCachedDescriptors = */ true,
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* .fUseCachedStringsDescriptors = */ true
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .fUseCachedDescriptors = */ true,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* .fUseCachedStringsDescriptors = */ true
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .fUseCachedDescriptors = */ true,
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync /* .fUseCachedStringsDescriptors = */ true
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync/*******************************************************************************
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync* Internal Functions *
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync*******************************************************************************/
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Initializes an URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pQueue The URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Inserts an URB at the end of the queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pQueue The URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pUrb The URB to insert.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncDECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Unlinks the head of the queue and returns it.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @returns The head entry.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pQueue The URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncDECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Removes an URB from anywhere in the queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @returns true if found, false if not.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pQueue The URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pUrb The URB to remove.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncDECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return false;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return true;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Checks if the queue is empty or not.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @returns true if it is, false if it isn't.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pQueue The URB queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncDECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Links an URB into the done queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pThis The HID instance.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pUrb The URB.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Completes the URB with a stalled state, halting the pipe.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** @todo figure out if the stall is global or pipe-specific or both. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Completes the URB with a OK state.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, size_t cbData)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
eac945b2260779f7c5d44d8015bcc4779498c6f9vboxsync * usbHidHandleDefaultPipe.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @returns VBox status code.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param pThis The HID instance.
eac945b2260779f7c5d44d8015bcc4779498c6f9vboxsync * @param pUrb Set when usbHidHandleDefaultPipe is the
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @param fSetConfig Set when usbHidUsbSetConfiguration is the
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Wait for the any command currently executing to complete before
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * resetting. (We cannot cancel its execution.) How we do this depends
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * on the reset method.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Reset the device state.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync if (!pUrb && !fSetConfig) /* (only device reset) */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Ditch all pending URBs.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync while ((pCurUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync * Create a USB HID report report based on the currently accumulated data.
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsyncstatic size_t usbHidFillReport(PUSBHIDTM_REPORT pReport,
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pReport->t.fButtons = pAccumulated->u.Absolute.fButtons;
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync pReport->t.dz = clamp_i8(pAccumulated->u.Absolute.dz);
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync pReport->t.dw = clamp_i8(pAccumulated->u.Absolute.dw);
02973eaf12e421595fcc3bbee4dd355d495ecfe6vboxsync LogRel3(("Abs event, x=%d, y=%d, fButtons=%02x, report size %d\n",
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pReport->m.fButtons = pAccumulated->u.Relative.fButtons;
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pReport->m.dx = clamp_i8(pAccumulated->u.Relative.dx);
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pReport->m.dy = clamp_i8(pAccumulated->u.Relative.dy);
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pReport->m.dz = clamp_i8(pAccumulated->u.Relative.dz);
7808943002d119e1d00b500cc4228d48dc2976cfvboxsync LogRel3(("Rel event, dx=%d, dy=%d, dz=%d, fButtons=%02x, report size %d\n",
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /* Clear the accumulated movement. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsyncDECLINLINE(MTCONTACT *) usbHidFindMTContact(MTCONTACT *paContacts, size_t cContacts,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < cContacts; i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsyncstatic int usbHidSendMultiTouchReport(PUSBHID pThis, PVUSBURB pUrb)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Number of contacts to be reported. In hybrid mode the first report contains
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * total number of contacts and subsequent reports contain 0.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Update the reporting state with the new current state.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * Also mark all active contacts in reporting state as dirty,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * that is they must be reported to the guest.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < MT_CONTACT_MAX_COUNT; i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Keep x,y. Will report lost contact at this point. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync else if (pThis->aCurrentContactState[i].status & MT_CONTACT_S_CANCELLED)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact->status &= ~(MT_CONTACT_S_CANCELLED | MT_CONTACT_S_ACTIVE);
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Keep x,y. Will report lost contact at this point. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact->status &= ~MT_CONTACT_S_ACTIVE; /* Contact disapeared. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Report current state. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync USBHIDMT_REPORT *p = (USBHIDMT_REPORT *)&pUrb->abData[0];
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (iReportedContact = 0; iReportedContact < MT_CONTACTS_PER_REPORT; iReportedContact++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Find the next not reported contact. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRel3(("usbHid: no more touch contacts to report\n"));
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Do not clear DIRTY flag for contacts which were reused.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * Because two reports must be generated:
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * one for old contact off, and the second for new contact on.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync p->aContacts[iReportedContact].fContact = pRepContact->flags;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync p->aContacts[iReportedContact].cContact = pRepContact->id;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync p->aContacts[iReportedContact].x = pRepContact->x >> pThis->u8CoordShift;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync p->aContacts[iReportedContact].y = pRepContact->y >> pThis->u8CoordShift;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Reset TouchReporting if all contacts reported. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pRepContact = usbHidFindMTContact(pThis->aReportingContactState, RT_ELEMENTS(pThis->aReportingContactState),
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRel3(("usbHid: all touch contacts reported\n"));
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync pThis->fHasPendingChanges = pThis->fTouchStateUpdated;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRel3(("usbHid: reporting touch contact:\n%.*Rhxd\n", sizeof(USBHIDMT_REPORT), p));
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync return usbHidCompleteOk(pThis, pUrb, sizeof(USBHIDMT_REPORT));
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync * Sends a state report to the host if there is a pending URB.
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* This device uses a different reporting method and fHasPendingChanges maintenance. */
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync PUSBHIDTM_REPORT pReport = (PUSBHIDTM_REPORT)&pUrb->abData[0];
bb2f3a7f00e605b890f8a8a74969f551cc9a0477vboxsync cbCopy = usbHidFillReport(pReport, &pThis->PtrDelta, pThis->enmMode);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic DECLCALLBACK(void *) usbHidMouseQueryInterface(PPDMIBASE pInterface, const char *pszIID)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMOUSEPORT, &pThis->Lun0.IPort);
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync * @interface_method_impl{PDMIMOUSEPORT,pfnPutEvent}
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsyncstatic DECLCALLBACK(int) usbHidMousePutEvent(PPDMIMOUSEPORT pInterface,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Accumulate movement - the events from the front end may arrive
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * at a much higher rate than USB can handle.
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pThis->PtrDelta.u.Relative.dz -= dz; /* Inverted! */
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /* Send a report if possible. */
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventAbs}
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsyncstatic DECLCALLBACK(int) usbHidMousePutEventAbs(PPDMIMOUSEPORT pInterface,
8112e0942f1128329b99b22a20b395963d4abceavboxsync PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
8112e0942f1128329b99b22a20b395963d4abceavboxsync /* Accumulate movement - the events from the front end may arrive
8112e0942f1128329b99b22a20b395963d4abceavboxsync * at a much higher rate than USB can handle. Probably not a real issue
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync * when only the Z axis is relative (X/Y movement isn't technically
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync * accumulated and only the last value is used).
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pThis->PtrDelta.u.Absolute.x = x >> pThis->u8CoordShift;
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync pThis->PtrDelta.u.Absolute.y = y >> pThis->u8CoordShift;
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync pThis->PtrDelta.u.Absolute.dz -= dz; /* Inverted! */
0ddb8d1d457c326e713f6afb589fec72df6a7550vboxsync pThis->PtrDelta.u.Absolute.dw -= dw; /* Inverted! */
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync /* Send a report if possible. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * @interface_method_impl{PDMIMOUSEPORT,pfnPutEventMultiTouch}
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsyncstatic DECLCALLBACK(int) usbHidMousePutEventMultiTouch(PPDMIMOUSEPORT pInterface,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Make a copy of new contacts */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync MTCONTACT *paNewContacts = (MTCONTACT *)RTMemTmpAlloc(sizeof(MTCONTACT) * cContacts);
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < cContacts; i++)
dd0f1b7925a57b9976df733c4203f995bdcb170dvboxsync paNewContacts[i].flags = RT_BYTE2(u32Hi) & (MT_CONTACT_F_IN_CONTACT | MT_CONTACT_F_IN_RANGE);
36ff42fdbb32d6d77173b33d25aeb6a4e44ea1bcvboxsync if (paNewContacts[i].flags & MT_CONTACT_F_IN_CONTACT)
aa327535f5ce61d8851bf6495ca1b507f013252bvboxsync PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Maintain a state of all current contacts.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync * Intr URBs will be completed according to the state.
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Mark all existing contacts as dirty. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pThis->aCurrentContactState[i].status |= MT_CONTACT_S_DIRTY;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Update existing contacts and mark new contacts. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < cContacts; i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Find existing contact with the same id. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (j = 0; j < RT_ELEMENTS(pThis->aCurrentContactState); j++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync if ( (pThis->aCurrentContactState[j].status & MT_CONTACT_S_ACTIVE) != 0
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync && pThis->aCurrentContactState[j].id == pNewContact->id)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync if (pCurContact->flags == 0) /* Contact disappeared already. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Append new contacts (the dirty one in the paNewContacts). */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < cContacts; i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* It is a new contact, copy is to one of not ACTIVE or not updated existing contacts. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact->status = MT_CONTACT_S_ACTIVE; /* Reset status. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Dirty existing contacts can be reused. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact = usbHidFindMTContact(pThis->aCurrentContactState, RT_ELEMENTS(pThis->aCurrentContactState),
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync if ((pCurContact->status & MT_CONTACT_S_REUSED) == 0)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pCurContact->status |= MT_CONTACT_S_REUSED; /* Report to the guest that the contact not in touch. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRel3(("usbHid: dropped new contact: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Mark still dirty existing contacts as cancelled, because a new set of contacts does not include them. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRel3(("usbHid: scanTime (ms): %d\n", pThis->u32LastTouchScanTime));
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync for (i = 0; i < RT_ELEMENTS(pThis->aCurrentContactState); i++)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRel3(("usbHid: contact state[%d]: %d,%d id %d flags %RX8 status %RX8 oldId %d\n",
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /* Send a report if possible. */
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnUrbReap
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
d0e467f88aeb4288b409908dbe1b96d07c7133b2vboxsync LogFlowFunc(("pUsbIns=%p cMillies=%u\n", pUsbIns, cMillies));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
d0e467f88aeb4288b409908dbe1b96d07c7133b2vboxsync * @copydoc PDMUSBREG::pfnWakeup
d0e467f88aeb4288b409908dbe1b96d07c7133b2vboxsyncstatic DECLCALLBACK(int) usbHidWakeup(PPDMUSBINS pUsbIns)
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnUrbCancel
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Remove the URB from the to-host queue and move it onto the done queue.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Handles request sent to the inbound (device to host) interrupt pipe. This is
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * rather different from bulk requests because an interrupt read URB may complete
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * after arbitrarily long time.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Stall the request if the pipe is halted.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Deal with the URB according to the state.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * We've data left to transfer to the host.
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Status transfer.
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidHandleIntrDevToHost: Entering READY\n"));
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRelFlow(("usbHidHandleIntrDevToHost: Added %p:%s to the queue\n",
689866c0e5e611f2db46822ae47724b55a27a1a0vboxsync /* If a report is pending, send it right away. */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Bad states, stall.
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsyncstatic int usbHidRequestClass(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync return usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req");
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRelFlow(("usbHid: %s: type %d, ID %d, data\n%.*Rhxd\n",
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pSetup->bRequest == GET_REPORT? "GET_REPORT": "SET_REPORT",
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pUrb->cbData - sizeof(VUSBSETUP), &pUrb->abData[sizeof(VUSBSETUP)]));
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync uint32_t cbData = 0; /* 0 means that the report is unsupported. */
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync if (u8ReportType == 1 && u8ReportID == REPORTID_TOUCH_POINTER)
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync USBHIDMT_REPORT_POINTER *p = (USBHIDMT_REPORT_POINTER *)&pUrb->abData[sizeof(VUSBSETUP)];
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync /* The actual state should be reported here. */
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync else if (u8ReportType == 1 && u8ReportID == REPORTID_TOUCH_EVENT)
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync USBHIDMT_REPORT *p = (USBHIDMT_REPORT *)&pUrb->abData[sizeof(VUSBSETUP)];
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync /* The actual state should be reported here. */
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_MAX_COUNT)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_MAX_COUNT;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pUrb->abData[sizeof(VUSBSETUP) + 1] = MT_CONTACT_MAX_COUNT; /* Contact count maximum. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pUrb->abData[sizeof(VUSBSETUP) + 2] = 0; /* Device identifier */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_QABLOB)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_QABLOB; /* Report Id. */
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync else if (u8ReportType == 3 && u8ReportID == REPORTID_TOUCH_DEVCONFIG)
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync pUrb->abData[sizeof(VUSBSETUP) + 0] = REPORTID_TOUCH_DEVCONFIG;
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync pUrb->abData[sizeof(VUSBSETUP) + 1] = 2; /* Device mode:
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync * "HID touch device supporting contact
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync * identifier and contact count maximum."
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync pUrb->abData[sizeof(VUSBSETUP) + 2] = 0; /* Device identifier */
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync rc = usbHidCompleteOk(pThis, pUrb, sizeof(VUSBSETUP) + cbData);
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported GET_REPORT MT");
2f9ed1ea91dcb6c529fa86c69d38b965b1c70b67vboxsync /* SET_REPORT */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRelFlow(("usbHid: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync rc = usbHidCompleteStall(pThis, pEp, pUrb, "Unsupported class req MT");
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Handles request sent to the default control pipe.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsyncstatic int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync /* Returned data is written after the setup message. */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidMouse: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n",
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
874be5c5b701726b68fa1391022ae2f5c7768894vboxsync return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* Returned data is written after the setup message. */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n",
8112e0942f1128329b99b22a20b395963d4abceavboxsync memcpy(&pUrb->abData[sizeof(*pSetup)], pDesc, cbCopy);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: Bad GET_STATUS req: wLength=%#x\n",
8865816a3d875ec1a036af307fbb484af107f014vboxsync case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
8865816a3d875ec1a036af307fbb484af107f014vboxsync wRet = 0; /* Not self-powered, no remote wakeup. */
8865816a3d875ec1a036af307fbb484af107f014vboxsync memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
8865816a3d875ec1a036af307fbb484af107f014vboxsync return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
8865816a3d875ec1a036af307fbb484af107f014vboxsync case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
8865816a3d875ec1a036af307fbb484af107f014vboxsync memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
8865816a3d875ec1a036af307fbb484af107f014vboxsync return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n",
8865816a3d875ec1a036af307fbb484af107f014vboxsync case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
8865816a3d875ec1a036af307fbb484af107f014vboxsync wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
8865816a3d875ec1a036af307fbb484af107f014vboxsync memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
8865816a3d875ec1a036af307fbb484af107f014vboxsync return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n",
8865816a3d875ec1a036af307fbb484af107f014vboxsync return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /** @todo implement this. */
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync /* Only VUSB_TO_INTERFACE is allowed. */
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync if ((pSetup->bmRequestType & VUSB_RECIP_MASK) == VUSB_TO_INTERFACE)
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync LogRelFlow(("usbHid: invalid recipient of class req: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync return usbHidCompleteStall(pThis, pEp, pUrb, "Invalid recip");
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnUrbQueue
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance,
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Parse on a per end-point basis.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
3fe24a3690526efc4cceece3819d628caadf3140vboxsync * @copydoc PDMUSBREG::pfnUsbSetInterface
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n",
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnUsbSetConfiguration
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * If the same config is applied more than once, it's a kind of reset.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync if (pThis->bConfigurationValue == bConfigurationValue)
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
8112e0942f1128329b99b22a20b395963d4abceavboxsync * Set received event type to absolute or relative.
3fe24a3690526efc4cceece3819d628caadf3140vboxsync * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnUsbReset
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnDestruct
eb02731cc4b3e9d61f26f793a4e27602826b0d52vboxsync LogRelFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync * @copydoc PDMUSBREG::pfnConstruct
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsyncstatic DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Perform the basic structure initialization first so the destructor
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * will not misbehave.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Validate and read the configuration.
81df7e626b7bf4c65b5e3215e6cf83093ee671efvboxsync rc = CFGMR3ValidateConfig(pCfg, "/", "Mode|CoordShift", "Config", "UsbHid", iInstance);
81df7e626b7bf4c65b5e3215e6cf83093ee671efvboxsync rc = CFGMR3QueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "relative");
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
81df7e626b7bf4c65b5e3215e6cf83093ee671efvboxsync return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
4fa6d2a2ac7d62a1815bcb6d6565ae7cdf775cdbvboxsync LogRelFlow(("usbHidConstruct/#%u: mode '%s'\n", iInstance, szMode));
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync pThis->Lun0.IBase.pfnQueryInterface = usbHidMouseQueryInterface;
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync pThis->Lun0.IPort.pfnPutEvent = usbHidMousePutEvent;
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync pThis->Lun0.IPort.pfnPutEventAbs = usbHidMousePutEventAbs;
c9a52d0e2159c4f4bd272a727406e47562ae82b4vboxsync pThis->Lun0.IPort.pfnPutEventMultiTouch = usbHidMousePutEventMultiTouch;
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * Attach the mouse driver.
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Mouse Port");
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach mouse driver"));
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIMOUSECONNECTOR);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query mouse interface"));
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync rc = CFGMR3QueryU8Def(pCfg, "CoordShift", &pThis->u8CoordShift, 1);
0cbaa6b7062076428f638cc5afba9d16200c6076vboxsync return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query shift factor"));
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync * The USB Human Interface Device (HID) Mouse registration record.
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* u32Version */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* szName */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync "HidMouse",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pszDescription */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync "USB HID Mouse.",
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* fFlags */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* cMaxInstances */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* cbInstance */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnConstruct */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnDestruct */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnVMInitComplete */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnVMPowerOn */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnVMReset */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnVMSuspend */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnVMResume */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnVMPowerOff */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnHotPlugged */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnHotUnplugged */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnDriverAttach */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnDriverDetach */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnQueryInterface */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUsbReset */
1256c6853363727c70b1b5075e5a747510858b94vboxsync /* pfnUsbGetDescriptorCache */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUsbSetConfiguration */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUsbSetInterface */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUsbClearHaltedEndpoint */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUrbNew */
1ab072338283b0c700d1ef4958511296a4d0ca41vboxsync /* pfnUrbQueue */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUrbCancel */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* pfnUrbReap */
d0e467f88aeb4288b409908dbe1b96d07c7133b2vboxsync /* pfnWakeup */
ae0f2178b9a5aded928e0245cb830ba1d3d04c57vboxsync /* u32TheEnd */