VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/UsbKbd.cpp

Last change on this file was 99558, checked in by vboxsync, 13 months ago

DevPS2K/UsbKbd: Improved range checks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 65.2 KB
Line 
1/* $Id: UsbKbd.cpp 99558 2023-04-28 13:54:03Z vboxsync $ */
2/** @file
3 * UsbKbd - USB Human Interface Device Emulation, Keyboard.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_usb_kbd USB Keyboard Device Emulation.
29 *
30 * This module implements a standard USB keyboard which uses the boot
31 * interface. The keyboard sends reports which have room for up to six
32 * normal keys and all standard modifier keys. A report always reflects the
33 * current state of the keyboard and indicates which keys are held down.
34 *
35 * Software normally utilizes the keyboard's interrupt endpoint to request
36 * reports to be sent whenever a state change occurs. However, reports can
37 * also be sent whenever an interrupt transfer is initiated (the keyboard is
38 * not "idle") or requested via the control endpoint (polling).
39 *
40 * Because turnaround on USB is relatively slow, the keyboard often ends up
41 * in a situation where new input arrived but there is no URB available
42 * where a report could be written to. The PDM queue maintained by the
43 * keyboard driver is utilized to provide buffering and hold incoming events
44 * until they can be passed along. The USB keyboard can effectively buffer
45 * up to one event.
46 *
47 * If there is a pending event and a new URB becomes available, a report is
48 * built and the keyboard queue is flushed. This ensures that queued events
49 * are processed as quickly as possible.
50 *
51 * A second interface with its own interrupt endpoint is used to deliver
52 * additional key events for media and system control keys. This adds
53 * considerable complexity to the emulated device, but unfortunately the
54 * keyboard boot interface is fixed and fairly limited.
55 *
56 * The second interface is only exposed if the device is configured in
57 * "extended" mode, with a different USB product ID and different
58 * descriptors. The "basic" mode should be indistinguishable from the original
59 * implementation.
60 *
61 * There are various options available for reporting media keys. We chose
62 * a very basic approach which reports system control keys as a bit-field
63 * (since there are only 3 keys defined) and consumer control keys as just
64 * a single 16-bit value.
65 *
66 * As a consequence, only one consumer control key can be reported as
67 * pressed at any one time. While this may seem limiting, the usefulness of
68 * being able to report e.g. volume-up at the same time as volume-down or
69 * mute is highly questionable.
70 *
71 * System control and consumer control keys are reported in a single
72 * 4-byte report in order to avoid sending multiple separate report types.
73 *
74 * There is a slight complication in that both interfaces are configured
75 * together, but a guest does not necessarily "listen" on both (e.g. EFI).
76 * Since all events come through a single queue, we can't just push back
77 * events for the secondary interface because the entire keyboard would be
78 * blocked. After the device is reset/configured, we drop any events destined
79 * for the secondary interface until a URB is actually queued on the second
80 * interrupt endpoint. Once that happens, we assume the guest will be
81 * receiving data on the second endpoint until the next reset/reconfig.
82 *
83 * References:
84 *
85 * Device Class Definition for Human Interface Devices (HID), Version 1.11
86 *
87 */
88
89
90/*********************************************************************************************************************************
91* Header Files *
92*********************************************************************************************************************************/
93#define LOG_GROUP LOG_GROUP_USB_KBD
94#include <VBox/vmm/pdmusb.h>
95#include <VBox/log.h>
96#include <VBox/err.h>
97#include <iprt/assert.h>
98#include <iprt/critsect.h>
99#include <iprt/mem.h>
100#include <iprt/semaphore.h>
101#include <iprt/string.h>
102#include <iprt/uuid.h>
103#include "VBoxDD.h"
104
105
106/*********************************************************************************************************************************
107* Defined Constants And Macros *
108*********************************************************************************************************************************/
109/** @name USB HID string IDs
110 * @{ */
111#define USBHID_STR_ID_MANUFACTURER 1
112#define USBHID_STR_ID_PRODUCT 2
113#define USBHID_STR_ID_IF_KBD 3
114#define USBHID_STR_ID_IF_EXT 4
115/** @} */
116
117/** @name USB HID specific descriptor types
118 * @{ */
119#define DT_IF_HID_DESCRIPTOR 0x21
120#define DT_IF_HID_REPORT 0x22
121/** @} */
122
123/** @name USB HID vendor and product IDs
124 * @{ */
125#define VBOX_USB_VENDOR 0x80EE
126#define USBHID_PID_BAS_KEYBOARD 0x0010
127#define USBHID_PID_EXT_KEYBOARD 0x0011
128/** @} */
129
130/** @name USB HID class specific requests
131 * @{ */
132#define HID_REQ_GET_REPORT 0x01
133#define HID_REQ_GET_IDLE 0x02
134#define HID_REQ_SET_REPORT 0x09
135#define HID_REQ_SET_IDLE 0x0A
136/** @} */
137
138/** @name USB HID additional constants
139 * @{ */
140/** The highest USB usage code reported by the VBox emulated keyboard */
141#define VBOX_USB_MAX_USAGE_CODE 0xE7
142/** The size of an array needed to store all USB usage codes */
143#define VBOX_USB_USAGE_ARRAY_SIZE (VBOX_USB_MAX_USAGE_CODE + 1)
144#define USBHID_USAGE_ROLL_OVER 1
145/** The usage code of the first modifier key. */
146#define USBHID_MODIFIER_FIRST 0xE0
147/** The usage code of the last modifier key. */
148#define USBHID_MODIFIER_LAST 0xE7
149/** @} */
150
151
152/*********************************************************************************************************************************
153* Structures and Typedefs *
154*********************************************************************************************************************************/
155
156/**
157 * The device mode.
158 */
159typedef enum USBKBDMODE
160{
161 /** Basic keyboard only, backward compatible. */
162 USBKBDMODE_BASIC = 0,
163 /** Extended 2nd interface for consumer control and power. */
164 USBKBDMODE_EXTENDED,
165} USBKBDMODE;
166
167
168/**
169 * The USB HID request state.
170 */
171typedef enum USBHIDREQSTATE
172{
173 /** Invalid status. */
174 USBHIDREQSTATE_INVALID = 0,
175 /** Ready to receive a new read request. */
176 USBHIDREQSTATE_READY,
177 /** Have (more) data for the host. */
178 USBHIDREQSTATE_DATA_TO_HOST,
179 /** Waiting to supply status information to the host. */
180 USBHIDREQSTATE_STATUS,
181 /** The end of the valid states. */
182 USBHIDREQSTATE_END
183} USBHIDREQSTATE;
184
185
186/**
187 * A URB queue.
188 */
189typedef struct USBHIDURBQUEUE
190{
191 /** The head pointer. */
192 PVUSBURB pHead;
193 /** Where to insert the next entry. */
194 PVUSBURB *ppTail;
195} USBHIDURBQUEUE;
196/** Pointer to a URB queue. */
197typedef USBHIDURBQUEUE *PUSBHIDURBQUEUE;
198/** Pointer to a const URB queue. */
199typedef USBHIDURBQUEUE const *PCUSBHIDURBQUEUE;
200
201
202/**
203 * Endpoint state.
204 */
205typedef struct USBHIDEP
206{
207 /** Endpoint halt flag.*/
208 bool fHalted;
209} USBHIDEP;
210/** Pointer to the endpoint status. */
211typedef USBHIDEP *PUSBHIDEP;
212
213
214/**
215 * Interface state.
216 */
217typedef struct USBHIDIF
218{
219 /** If interface has pending changes. */
220 bool fHasPendingChanges;
221 /** The state of the HID (state machine).*/
222 USBHIDREQSTATE enmState;
223 /** Pending to-host queue.
224 * The URBs waiting here are waiting for data to become available.
225 */
226 USBHIDURBQUEUE ToHostQueue;
227} USBHIDIF;
228/** Pointer to the endpoint status. */
229typedef USBHIDIF *PUSBHIDIF;
230
231
232/**
233 * The USB HID report structure for regular keys.
234 */
235typedef struct USBHIDK_REPORT
236{
237 uint8_t ShiftState; /**< Modifier keys bitfield */
238 uint8_t Reserved; /**< Currently unused */
239 uint8_t aKeys[6]; /**< Normal keys */
240} USBHIDK_REPORT, *PUSBHIDK_REPORT;
241
242/* Must match 8-byte packet size. */
243AssertCompile(sizeof(USBHIDK_REPORT) == 8);
244
245
246/**
247 * The USB HID report structure for extra keys.
248 */
249typedef struct USBHIDX_REPORT
250{
251 uint16_t uKeyCC; /**< Consumer Control key code */
252 uint8_t uSCKeys; /**< System Control keys bit map */
253 uint8_t Reserved; /**< Unused */
254} USBHIDX_REPORT, *PUSBHIDX_REPORT;
255
256/* Must match 4-byte packet size. */
257AssertCompile(sizeof(USBHIDX_REPORT) == 4);
258
259
260/**
261 * The USB HID instance data.
262 */
263typedef struct USBHID
264{
265 /** Pointer back to the PDM USB Device instance structure. */
266 PPDMUSBINS pUsbIns;
267 /** Critical section protecting the device state. */
268 RTCRITSECT CritSect;
269
270 /** The current configuration.
271 * (0 - default, 1 - the one supported configuration, i.e configured.) */
272 uint8_t bConfigurationValue;
273 /** USB HID Idle value.
274 * (0 - only report state change, !=0 - report in bIdle * 4ms intervals.) */
275 uint8_t bIdle;
276 /** Is this a relative, absolute or multi-touch pointing device? */
277 USBKBDMODE enmMode;
278 /** Endpoint 0 is the default control pipe, 1 is the dev->host interrupt one
279 * for standard keys, 1 is the interrupt EP for extra keys. */
280 USBHIDEP aEps[3];
281 /** Interface 0 is the standard keyboard interface, 1 is the additional
282 * control/media key interface. */
283 USBHIDIF aIfs[2];
284
285 /** Done queue
286 * The URBs stashed here are waiting to be reaped. */
287 USBHIDURBQUEUE DoneQueue;
288 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
289 * is set. */
290 RTSEMEVENT hEvtDoneQueue;
291 /** Someone is waiting on the done queue. */
292 bool fHaveDoneQueueWaiter;
293 /** The guest expects data coming over second endpoint/pipe. */
294 bool fExtPipeActive;
295 /** Currently depressed keys */
296 uint8_t abDepressedKeys[VBOX_USB_USAGE_ARRAY_SIZE];
297
298 /**
299 * Keyboard port - LUN#0.
300 *
301 * @implements PDMIBASE
302 * @implements PDMIKEYBOARDPORT
303 */
304 struct
305 {
306 /** The base interface for the keyboard port. */
307 PDMIBASE IBase;
308 /** The keyboard port base interface. */
309 PDMIKEYBOARDPORT IPort;
310
311 /** The base interface of the attached keyboard driver. */
312 R3PTRTYPE(PPDMIBASE) pDrvBase;
313 /** The keyboard interface of the attached keyboard driver. */
314 R3PTRTYPE(PPDMIKEYBOARDCONNECTOR) pDrv;
315 } Lun0;
316} USBHID;
317/** Pointer to the USB HID instance data. */
318typedef USBHID *PUSBHID;
319
320
321/*********************************************************************************************************************************
322* Global Variables *
323*********************************************************************************************************************************/
324static const PDMUSBDESCCACHESTRING g_aUsbHidStrings_en_US[] =
325{
326 { USBHID_STR_ID_MANUFACTURER, "VirtualBox" },
327 { USBHID_STR_ID_PRODUCT, "USB Keyboard" },
328 { USBHID_STR_ID_IF_KBD, "Keyboard" },
329 { USBHID_STR_ID_IF_EXT, "System Control"},
330};
331
332static const PDMUSBDESCCACHELANG g_aUsbHidLanguages[] =
333{
334 { 0x0409, RT_ELEMENTS(g_aUsbHidStrings_en_US), g_aUsbHidStrings_en_US }
335};
336
337static const VUSBDESCENDPOINTEX g_aUsbHidEndpointDescsKbd[] =
338{
339 {
340 {
341 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
342 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
343 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
344 /* .bmAttributes = */ 3 /* interrupt */,
345 /* .wMaxPacketSize = */ 8,
346 /* .bInterval = */ 10,
347 },
348 /* .pvMore = */ NULL,
349 /* .pvClass = */ NULL,
350 /* .cbClass = */ 0
351 },
352};
353
354static const VUSBDESCENDPOINTEX g_aUsbHidEndpointDescsExt[] =
355{
356 {
357 {
358 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
359 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
360 /* .bEndpointAddress = */ 0x82 /* ep=2, in */,
361 /* .bmAttributes = */ 3 /* interrupt */,
362 /* .wMaxPacketSize = */ 4,
363 /* .bInterval = */ 10,
364 },
365 /* .pvMore = */ NULL,
366 /* .pvClass = */ NULL,
367 /* .cbClass = */ 0
368 },
369};
370
371/** HID report descriptor for standard keys. */
372static const uint8_t g_UsbHidReportDescKbd[] =
373{
374 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
375 /* Usage */ 0x09, 0x06, /* Keyboard */
376 /* Collection */ 0xA1, 0x01, /* Application */
377 /* Usage Page */ 0x05, 0x07, /* Keyboard */
378 /* Usage Minimum */ 0x19, 0xE0, /* Left Ctrl Key */
379 /* Usage Maximum */ 0x29, 0xE7, /* Right GUI Key */
380 /* Logical Minimum */ 0x15, 0x00, /* 0 */
381 /* Logical Maximum */ 0x25, 0x01, /* 1 */
382 /* Report Count */ 0x95, 0x08, /* 8 */
383 /* Report Size */ 0x75, 0x01, /* 1 */
384 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
385 /* Report Count */ 0x95, 0x01, /* 1 */
386 /* Report Size */ 0x75, 0x08, /* 8 (padding bits) */
387 /* Input */ 0x81, 0x01, /* Constant, Array, Absolute, Bit field */
388 /* Report Count */ 0x95, 0x05, /* 5 */
389 /* Report Size */ 0x75, 0x01, /* 1 */
390 /* Usage Page */ 0x05, 0x08, /* LEDs */
391 /* Usage Minimum */ 0x19, 0x01, /* Num Lock */
392 /* Usage Maximum */ 0x29, 0x05, /* Kana */
393 /* Output */ 0x91, 0x02, /* Data, Value, Absolute, Non-volatile, Bit field */
394 /* Report Count */ 0x95, 0x01, /* 1 */
395 /* Report Size */ 0x75, 0x03, /* 3 */
396 /* Output */ 0x91, 0x01, /* Constant, Value, Absolute, Non-volatile, Bit field */
397 /* Report Count */ 0x95, 0x06, /* 6 */
398 /* Report Size */ 0x75, 0x08, /* 8 */
399 /* Logical Minimum */ 0x15, 0x00, /* 0 */
400 /* Logical Maximum */ 0x26, 0xFF,0x00,/* 255 */
401 /* Usage Page */ 0x05, 0x07, /* Keyboard */
402 /* Usage Minimum */ 0x19, 0x00, /* 0 */
403 /* Usage Maximum */ 0x29, 0xFF, /* 255 */
404 /* Input */ 0x81, 0x00, /* Data, Array, Absolute, Bit field */
405 /* End Collection */ 0xC0,
406};
407
408/** HID report descriptor for extra multimedia/system keys. */
409static const uint8_t g_UsbHidReportDescExt[] =
410{
411 /* Usage Page */ 0x05, 0x0C, /* Consumer */
412 /* Usage */ 0x09, 0x01, /* Consumer Control */
413 /* Collection */ 0xA1, 0x01, /* Application */
414
415 /* Usage Page */ 0x05, 0x0C, /* Consumer */
416 /* Usage Minimum */ 0x19, 0x00, /* 0 */
417 /* Usage Maximum */ 0x2A, 0x3C, 0x02, /* 572 */
418 /* Logical Minimum */ 0x15, 0x00, /* 0 */
419 /* Logical Maximum */ 0x26, 0x3C, 0x02, /* 572 */
420 /* Report Count */ 0x95, 0x01, /* 1 */
421 /* Report Size */ 0x75, 0x10, /* 16 */
422 /* Input */ 0x81, 0x80, /* Data, Array, Absolute, Bytes */
423
424 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
425 /* Usage Minimum */ 0x19, 0x81, /* 129 */
426 /* Usage Maximum */ 0x29, 0x83, /* 131 */
427 /* Logical Minimum */ 0x15, 0x00, /* 0 */
428 /* Logical Maximum */ 0x25, 0x01, /* 1 */
429 /* Report Size */ 0x75, 0x01, /* 1 */
430 /* Report Count */ 0x95, 0x03, /* 3 */
431 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
432 /* Report Count */ 0x95, 0x05, /* 5 */
433 /* Input */ 0x81, 0x01, /* Constant, Array, Absolute, Bit field */
434 /* Report Count */ 0x95, 0x01, /* 1 */
435 /* Report Size */ 0x75, 0x08, /* 8 (padding bits) */
436 /* Input */ 0x81, 0x01, /* Constant, Array, Absolute, Bit field */
437
438 /* End Collection */ 0xC0,
439};
440
441/** Additional HID class interface descriptor for standard keys. */
442static const uint8_t g_UsbHidIfHidDescKbd[] =
443{
444 /* .bLength = */ 0x09,
445 /* .bDescriptorType = */ 0x21, /* HID */
446 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
447 /* .bCountryCode = */ 0x0D, /* International (ISO) */
448 /* .bNumDescriptors = */ 1,
449 /* .bDescriptorType = */ 0x22, /* Report */
450 /* .wDescriptorLength = */ sizeof(g_UsbHidReportDescKbd), 0x00
451};
452
453/** Additional HID class interface descriptor for extra keys. */
454static const uint8_t g_UsbHidIfHidDescExt[] =
455{
456 /* .bLength = */ 0x09,
457 /* .bDescriptorType = */ 0x21, /* HID */
458 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
459 /* .bCountryCode = */ 0,
460 /* .bNumDescriptors = */ 1,
461 /* .bDescriptorType = */ 0x22, /* Report */
462 /* .wDescriptorLength = */ sizeof(g_UsbHidReportDescExt), 0x00
463};
464
465/** Standard keyboard interface. */
466static const VUSBDESCINTERFACEEX g_UsbHidInterfaceDescKbd =
467{
468 {
469 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
470 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
471 /* .bInterfaceNumber = */ 0,
472 /* .bAlternateSetting = */ 0,
473 /* .bNumEndpoints = */ 1,
474 /* .bInterfaceClass = */ 3 /* HID */,
475 /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
476 /* .bInterfaceProtocol = */ 1 /* Keyboard */,
477 /* .iInterface = */ USBHID_STR_ID_IF_KBD
478 },
479 /* .pvMore = */ NULL,
480 /* .pvClass = */ &g_UsbHidIfHidDescKbd,
481 /* .cbClass = */ sizeof(g_UsbHidIfHidDescKbd),
482 &g_aUsbHidEndpointDescsKbd[0],
483 /* .pIAD = */ NULL,
484 /* .cbIAD = */ 0
485};
486
487/** Extra keys (multimedia/system) interface. */
488static const VUSBDESCINTERFACEEX g_UsbHidInterfaceDescExt =
489{
490 {
491 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
492 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
493 /* .bInterfaceNumber = */ 1,
494 /* .bAlternateSetting = */ 0,
495 /* .bNumEndpoints = */ 1,
496 /* .bInterfaceClass = */ 3 /* HID */,
497 /* .bInterfaceSubClass = */ 0 /* None */,
498 /* .bInterfaceProtocol = */ 0 /* Unspecified */,
499 /* .iInterface = */ USBHID_STR_ID_IF_EXT
500 },
501 /* .pvMore = */ NULL,
502 /* .pvClass = */ &g_UsbHidIfHidDescExt,
503 /* .cbClass = */ sizeof(g_UsbHidIfHidDescExt),
504 &g_aUsbHidEndpointDescsExt[0],
505 /* .pIAD = */ NULL,
506 /* .cbIAD = */ 0
507};
508
509static const VUSBINTERFACE g_aUsbHidBasInterfaces[] =
510{
511 { &g_UsbHidInterfaceDescKbd, /* .cSettings = */ 1 },
512};
513
514static const VUSBINTERFACE g_aUsbHidExtInterfaces[] =
515{
516 { &g_UsbHidInterfaceDescKbd, /* .cSettings = */ 1 },
517 { &g_UsbHidInterfaceDescExt, /* .cSettings = */ 1 },
518};
519
520static const VUSBDESCCONFIGEX g_UsbHidBasConfigDesc =
521{
522 {
523 /* .bLength = */ sizeof(VUSBDESCCONFIG),
524 /* .bDescriptorType = */ VUSB_DT_CONFIG,
525 /* .wTotalLength = */ 0 /* recalculated on read */,
526 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidBasInterfaces),
527 /* .bConfigurationValue =*/ 1,
528 /* .iConfiguration = */ 0,
529 /* .bmAttributes = */ RT_BIT(7), /* bus-powered */
530 /* .MaxPower = */ 50 /* 100mA */
531 },
532 NULL, /* pvMore */
533 NULL, /* pvClass */
534 0, /* cbClass */
535 &g_aUsbHidBasInterfaces[0],
536 NULL /* pvOriginal */
537};
538
539static const VUSBDESCCONFIGEX g_UsbHidExtConfigDesc =
540{
541 {
542 /* .bLength = */ sizeof(VUSBDESCCONFIG),
543 /* .bDescriptorType = */ VUSB_DT_CONFIG,
544 /* .wTotalLength = */ 0 /* recalculated on read */,
545 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidExtInterfaces),
546 /* .bConfigurationValue =*/ 1,
547 /* .iConfiguration = */ 0,
548 /* .bmAttributes = */ RT_BIT(7), /* bus-powered */
549 /* .MaxPower = */ 50 /* 100mA */
550 },
551 NULL, /* pvMore */
552 NULL, /* pvClass */
553 0, /* cbClass */
554 &g_aUsbHidExtInterfaces[0],
555 NULL /* pvOriginal */
556};
557
558static const VUSBDESCDEVICE g_UsbHidBasDeviceDesc =
559{
560 /* .bLength = */ sizeof(g_UsbHidBasDeviceDesc),
561 /* .bDescriptorType = */ VUSB_DT_DEVICE,
562 /* .bcdUsb = */ 0x110, /* 1.1 */
563 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
564 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
565 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
566 /* .bMaxPacketSize0 = */ 8,
567 /* .idVendor = */ VBOX_USB_VENDOR,
568 /* .idProduct = */ USBHID_PID_BAS_KEYBOARD,
569 /* .bcdDevice = */ 0x0100, /* 1.0 */
570 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
571 /* .iProduct = */ USBHID_STR_ID_PRODUCT,
572 /* .iSerialNumber = */ 0,
573 /* .bNumConfigurations = */ 1
574};
575
576static const VUSBDESCDEVICE g_UsbHidExtDeviceDesc =
577{
578 /* .bLength = */ sizeof(g_UsbHidExtDeviceDesc),
579 /* .bDescriptorType = */ VUSB_DT_DEVICE,
580 /* .bcdUsb = */ 0x110, /* 1.1 */
581 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
582 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
583 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
584 /* .bMaxPacketSize0 = */ 8,
585 /* .idVendor = */ VBOX_USB_VENDOR,
586 /* .idProduct = */ USBHID_PID_EXT_KEYBOARD,
587 /* .bcdDevice = */ 0x0100, /* 1.0 */
588 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
589 /* .iProduct = */ USBHID_STR_ID_PRODUCT,
590 /* .iSerialNumber = */ 0,
591 /* .bNumConfigurations = */ 1
592};
593
594static const PDMUSBDESCCACHE g_UsbHidBasDescCache =
595{
596 /* .pDevice = */ &g_UsbHidBasDeviceDesc,
597 /* .paConfigs = */ &g_UsbHidBasConfigDesc,
598 /* .paLanguages = */ g_aUsbHidLanguages,
599 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
600 /* .fUseCachedDescriptors = */ true,
601 /* .fUseCachedStringsDescriptors = */ true
602};
603
604static const PDMUSBDESCCACHE g_UsbHidExtDescCache =
605{
606 /* .pDevice = */ &g_UsbHidExtDeviceDesc,
607 /* .paConfigs = */ &g_UsbHidExtConfigDesc,
608 /* .paLanguages = */ g_aUsbHidLanguages,
609 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
610 /* .fUseCachedDescriptors = */ true,
611 /* .fUseCachedStringsDescriptors = */ true
612};
613
614/**
615 * Conversion table for consumer control keys (HID Usage Page 12).
616 * Used to 'compress' the USB HID usage code into a single 8-bit
617 * value. See also PS2CCKeys in the PS/2 keyboard emulation.
618 */
619static const uint16_t aHidCCKeys[] = {
620 0x00B5, /* Scan Next Track */
621 0x00B6, /* Scan Previous Track */
622 0x00B7, /* Stop */
623 0x00CD, /* Play/Pause */
624 0x00E2, /* Mute */
625 0x00E5, /* Bass Boost */
626 0x00E7, /* Loudness */
627 0x00E9, /* Volume Up */
628 0x00EA, /* Volume Down */
629 0x0152, /* Bass Up */
630 0x0153, /* Bass Down */
631 0x0154, /* Treble Up */
632 0x0155, /* Treble Down */
633 0x0183, /* Media Select */
634 0x018A, /* Mail */
635 0x0192, /* Calculator */
636 0x0194, /* My Computer */
637 0x0221, /* WWW Search */
638 0x0223, /* WWW Home */
639 0x0224, /* WWW Back */
640 0x0225, /* WWW Forward */
641 0x0226, /* WWW Stop */
642 0x0227, /* WWW Refresh */
643 0x022A, /* WWW Favorites */
644};
645
646/**
647 * Conversion table for generic desktop control keys (HID Usage Page 1).
648 * Used to 'compress' the USB HID usage code into a single 8-bit
649 * value. See also PS2DCKeys in the PS/2 keyboard emulation.
650 */
651static const uint16_t aHidDCKeys[] = {
652 0x81, /* System Power */
653 0x82, /* System Sleep */
654 0x83, /* System Wake */
655};
656
657#define USBHID_PAGE_DC_START 0xb0
658#define USBHID_PAGE_DC_END (USBHID_PAGE_DC_START + RT_ELEMENTS(aHidDCKeys) - 1)
659#define USBHID_PAGE_CC_START 0xc0
660#define USBHID_PAGE_CC_END (USBHID_PAGE_CC_START + RT_ELEMENTS(aHidCCKeys) - 1)
661
662AssertCompile(RT_ELEMENTS(aHidCCKeys) <= 0x20); /* Must fit between 0xC0-0xDF. */
663AssertCompile(RT_ELEMENTS(aHidDCKeys) <= 0x10); /* Must fit between 0xB0-0xBF. */
664
665
666/*********************************************************************************************************************************
667* Internal Functions *
668*********************************************************************************************************************************/
669
670
671/**
672 * Converts a 32-bit USB HID code to an internal 8-bit value.
673 *
674 * @returns 8-bit internal key code/index. -1 if not found.
675 * @param u32HidCode 32-bit USB HID code.
676 */
677static int usbHidToInternalCode(uint32_t u32HidCode)
678{
679 uint8_t u8HidPage;
680 uint16_t u16HidUsage;
681 int iKeyIndex = -1;
682
683 u8HidPage = RT_LOBYTE(RT_HIWORD(u32HidCode));
684 u16HidUsage = RT_LOWORD(u32HidCode);
685
686 if (u8HidPage == USB_HID_KB_PAGE)
687 {
688 if (u16HidUsage <= VBOX_USB_MAX_USAGE_CODE)
689 iKeyIndex = u16HidUsage; /* Direct mapping. */
690 else
691 AssertMsgFailed(("u16HidUsage out of range! (%04X)\n", u16HidUsage));
692 }
693 else if (u8HidPage == USB_HID_CC_PAGE)
694 {
695 for (unsigned i = 0; i < RT_ELEMENTS(aHidCCKeys); ++i)
696 if (aHidCCKeys[i] == u16HidUsage)
697 {
698 iKeyIndex = USBHID_PAGE_CC_START + i;
699 break;
700 }
701 AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_CC_PAGE! (%04X)\n", u16HidUsage));
702 }
703 else if (u8HidPage == USB_HID_DC_PAGE)
704 {
705 for (unsigned i = 0; i < RT_ELEMENTS(aHidDCKeys); ++i)
706 if (aHidDCKeys[i] == u16HidUsage)
707 {
708 iKeyIndex = USBHID_PAGE_DC_START + i;
709 break;
710 }
711 AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_DC_PAGE! (%04X)\n", u16HidUsage));
712 }
713 else
714 {
715 AssertMsgFailed(("Unsupported u8HidPage! (%02X)\n", u8HidPage));
716 }
717
718 return iKeyIndex;
719}
720
721
722/**
723 * Converts an internal 8-bit key index back to a 32-bit USB HID code.
724 *
725 * @returns 32-bit USB HID code. Zero if not found.
726 * @param uKeyCode Internal key code/index.
727 */
728static uint32_t usbInternalCodeToHid(unsigned uKeyCode)
729{
730 uint16_t u16HidUsage;
731 uint32_t u32HidCode = 0;
732
733 if ((uKeyCode >= USBHID_PAGE_DC_START) && (uKeyCode <= USBHID_PAGE_DC_END))
734 {
735 u16HidUsage = aHidDCKeys[uKeyCode - USBHID_PAGE_DC_START];
736 u32HidCode = RT_MAKE_U32(u16HidUsage, USB_HID_DC_PAGE);
737 }
738 else if ((uKeyCode >= USBHID_PAGE_CC_START) && (uKeyCode <= USBHID_PAGE_CC_END))
739 {
740 u16HidUsage = aHidCCKeys[uKeyCode - USBHID_PAGE_CC_START];
741 u32HidCode = RT_MAKE_U32(u16HidUsage, USB_HID_CC_PAGE);
742 }
743 else /* Must be the keyboard usage page. */
744 {
745 if (uKeyCode <= VBOX_USB_MAX_USAGE_CODE)
746 u32HidCode = RT_MAKE_U32(uKeyCode, USB_HID_KB_PAGE);
747 else
748 AssertMsgFailed(("uKeyCode out of range! (%u)\n", uKeyCode));
749 }
750
751 return u32HidCode;
752}
753
754
755/**
756 * Initializes an URB queue.
757 *
758 * @param pQueue The URB queue.
759 */
760static void usbHidQueueInit(PUSBHIDURBQUEUE pQueue)
761{
762 pQueue->pHead = NULL;
763 pQueue->ppTail = &pQueue->pHead;
764}
765
766/**
767 * Inserts an URB at the end of the queue.
768 *
769 * @param pQueue The URB queue.
770 * @param pUrb The URB to insert.
771 */
772DECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
773{
774 pUrb->Dev.pNext = NULL;
775 *pQueue->ppTail = pUrb;
776 pQueue->ppTail = &pUrb->Dev.pNext;
777}
778
779
780/**
781 * Unlinks the head of the queue and returns it.
782 *
783 * @returns The head entry.
784 * @param pQueue The URB queue.
785 */
786DECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
787{
788 PVUSBURB pUrb = pQueue->pHead;
789 if (pUrb)
790 {
791 PVUSBURB pNext = pUrb->Dev.pNext;
792 pQueue->pHead = pNext;
793 if (!pNext)
794 pQueue->ppTail = &pQueue->pHead;
795 else
796 pUrb->Dev.pNext = NULL;
797 }
798 return pUrb;
799}
800
801
802/**
803 * Removes an URB from anywhere in the queue.
804 *
805 * @returns true if found, false if not.
806 * @param pQueue The URB queue.
807 * @param pUrb The URB to remove.
808 */
809DECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
810{
811 PVUSBURB pCur = pQueue->pHead;
812 if (pCur == pUrb)
813 {
814 pQueue->pHead = pUrb->Dev.pNext;
815 if (!pUrb->Dev.pNext)
816 pQueue->ppTail = &pQueue->pHead;
817 }
818 else
819 {
820 while (pCur)
821 {
822 if (pCur->Dev.pNext == pUrb)
823 {
824 pCur->Dev.pNext = pUrb->Dev.pNext;
825 break;
826 }
827 pCur = pCur->Dev.pNext;
828 }
829 if (!pCur)
830 return false;
831 if (!pUrb->Dev.pNext)
832 pQueue->ppTail = &pCur->Dev.pNext;
833 }
834 pUrb->Dev.pNext = NULL;
835 return true;
836}
837
838
839#if 0 /* unused */
840/**
841 * Checks if the queue is empty or not.
842 *
843 * @returns true if it is, false if it isn't.
844 * @param pQueue The URB queue.
845 */
846DECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
847{
848 return pQueue->pHead == NULL;
849}
850#endif /* unused */
851
852
853/**
854 * Links an URB into the done queue.
855 *
856 * @param pThis The HID instance.
857 * @param pUrb The URB.
858 */
859static void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
860{
861 usbHidQueueAddTail(&pThis->DoneQueue, pUrb);
862
863 if (pThis->fHaveDoneQueueWaiter)
864 {
865 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
866 AssertRC(rc);
867 }
868}
869
870
871/**
872 * Completes the URB with a stalled state, halting the pipe.
873 */
874static int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
875{
876 RT_NOREF1(pszWhy);
877 Log(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
878
879 pUrb->enmStatus = VUSBSTATUS_STALL;
880
881 /** @todo figure out if the stall is global or pipe-specific or both. */
882 if (pEp)
883 pEp->fHalted = true;
884 else
885 {
886 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
887 pThis->aEps[i].fHalted = true;
888 }
889
890 usbHidLinkDone(pThis, pUrb);
891 return VINF_SUCCESS;
892}
893
894
895/**
896 * Completes the URB after device successfully processed it. Optionally copies data
897 * into the URB. May still generate an error if the URB is not big enough.
898 */
899static int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, const void *pSrc, size_t cbSrc)
900{
901 Log(("usbHidCompleteOk/#%u: pUrb=%p:%s (cbData=%#x) cbSrc=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->cbData, cbSrc));
902
903 pUrb->enmStatus = VUSBSTATUS_OK;
904 size_t cbCopy = 0;
905 size_t cbSetup = 0;
906
907 if (pSrc) /* Can be NULL if not copying anything. */
908 {
909 Assert(cbSrc);
910 uint8_t *pDst = pUrb->abData;
911
912 /* Returned data is written after the setup message in control URBs. */
913 if (pUrb->enmType == VUSBXFERTYPE_MSG)
914 cbSetup = sizeof(VUSBSETUP);
915
916 Assert(pUrb->cbData >= cbSetup); /* Only triggers if URB is corrupted. */
917
918 if (pUrb->cbData > cbSetup)
919 {
920 /* There is at least one byte of room in the URB. */
921 cbCopy = RT_MIN(pUrb->cbData - cbSetup, cbSrc);
922 memcpy(pDst + cbSetup, pSrc, cbCopy);
923 pUrb->cbData = (uint32_t)(cbCopy + cbSetup);
924 Log(("Copied %zu bytes to pUrb->abData[%zu], source had %zu bytes\n", cbCopy, cbSetup, cbSrc));
925 }
926
927 /* Need to check length differences. If cbSrc is less than what
928 * the URB has space for, it'll be resolved as a short packet. But
929 * if cbSrc is bigger, there is a real problem and the host needs
930 * to see an overrun/babble error.
931 */
932 if (RT_UNLIKELY(cbSrc > cbCopy))
933 pUrb->enmStatus = VUSBSTATUS_DATA_OVERRUN;
934 }
935 else
936 Assert(cbSrc == 0); /* Make up your mind, caller! */
937
938 usbHidLinkDone(pThis, pUrb);
939 return VINF_SUCCESS;
940}
941
942
943/**
944 * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
945 * usbHidHandleDefaultPipe.
946 *
947 * @returns VBox status code.
948 * @param pThis The HID instance.
949 * @param pUrb Set when usbHidHandleDefaultPipe is the
950 * caller.
951 * @param fSetConfig Set when usbHidUsbSetConfiguration is the
952 * caller.
953 */
954static int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
955{
956 /*
957 * Deactivate the keyboard.
958 */
959 pThis->Lun0.pDrv->pfnSetActive(pThis->Lun0.pDrv, false);
960
961 /*
962 * Reset the device state.
963 */
964 pThis->bIdle = 0;
965 pThis->fExtPipeActive = false;
966
967 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
968 pThis->aEps[i].fHalted = false;
969
970 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aIfs); i++)
971 {
972 pThis->aIfs[i].fHasPendingChanges = false;
973 pThis->aIfs[i].enmState = USBHIDREQSTATE_READY;
974 }
975
976 if (!pUrb && !fSetConfig) /* (only device reset) */
977 pThis->bConfigurationValue = 0; /* default */
978
979 /*
980 * Ditch all pending URBs.
981 */
982 PVUSBURB pCurUrb;
983 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aIfs); i++)
984 while ((pCurUrb = usbHidQueueRemoveHead(&pThis->aIfs[i].ToHostQueue)) != NULL)
985 {
986 pCurUrb->enmStatus = VUSBSTATUS_CRC;
987 usbHidLinkDone(pThis, pCurUrb);
988 }
989
990 if (pUrb)
991 return usbHidCompleteOk(pThis, pUrb, NULL, 0);
992 return VINF_SUCCESS;
993}
994
995/**
996 * Returns true if the usage code corresponds to a keyboard modifier key
997 * (left or right ctrl, shift, alt or GUI). The usage codes for these keys
998 * are the range 0xe0 to 0xe7.
999 */
1000static bool usbHidUsageCodeIsModifier(uint8_t u8Usage)
1001{
1002 return u8Usage >= USBHID_MODIFIER_FIRST && u8Usage <= USBHID_MODIFIER_LAST;
1003}
1004
1005/**
1006 * Convert a USB HID usage code to a keyboard modifier flag. The arithmetic
1007 * is simple: the modifier keys have usage codes from 0xe0 to 0xe7, and the
1008 * lower nibble is the bit number of the flag.
1009 */
1010static uint8_t usbHidModifierToFlag(uint8_t u8Usage)
1011{
1012 Assert(usbHidUsageCodeIsModifier(u8Usage));
1013 return RT_BIT(u8Usage & 0xf);
1014}
1015
1016/**
1017 * Returns true if the usage code corresponds to a System Control key.
1018 * The usage codes for these keys are the range 0x81 to 0x83.
1019 */
1020static bool usbHidUsageCodeIsSCKey(uint16_t u16Usage)
1021{
1022 return u16Usage >= 0x81 && u16Usage <= 0x83;
1023}
1024
1025/**
1026 * Convert a USB HID usage code to a system control key mask. The system control
1027 * keys have usage codes from 0x81 to 0x83, and the lower nibble is the bit
1028 * position plus one.
1029 */
1030static uint8_t usbHidSCKeyToMask(uint16_t u16Usage)
1031{
1032 Assert(usbHidUsageCodeIsSCKey(u16Usage));
1033 return RT_BIT((u16Usage & 0xf) - 1);
1034}
1035
1036/**
1037 * Create a USB HID keyboard report reflecting the current state of the
1038 * standard keyboard (up/down keys).
1039 */
1040static void usbHidBuildReportKbd(PUSBHIDK_REPORT pReport, uint8_t *pabDepressedKeys)
1041{
1042 unsigned iBuf = 0;
1043 RT_ZERO(*pReport);
1044 for (unsigned iKey = 0; iKey < VBOX_USB_USAGE_ARRAY_SIZE; ++iKey)
1045 {
1046 Assert(iBuf <= RT_ELEMENTS(pReport->aKeys));
1047 if (pabDepressedKeys[iKey])
1048 {
1049 if (usbHidUsageCodeIsModifier(iKey))
1050 pReport->ShiftState |= usbHidModifierToFlag(iKey);
1051 else if (iBuf == RT_ELEMENTS(pReport->aKeys))
1052 {
1053 /* The USB HID spec says that the entire vector should be
1054 * set to ErrorRollOver on overflow. We don't mind if this
1055 * path is taken several times for one report. */
1056 for (unsigned iBuf2 = 0;
1057 iBuf2 < RT_ELEMENTS(pReport->aKeys); ++iBuf2)
1058 pReport->aKeys[iBuf2] = USBHID_USAGE_ROLL_OVER;
1059 }
1060 else
1061 {
1062 /* Key index back to 32-bit HID code. */
1063 uint32_t u32HidCode = usbInternalCodeToHid(iKey);
1064 uint8_t u8HidPage = RT_LOBYTE(RT_HIWORD(u32HidCode));
1065 uint16_t u16HidUsage = RT_LOWORD(u32HidCode);
1066
1067 if (u8HidPage == USB_HID_KB_PAGE)
1068 {
1069 pReport->aKeys[iBuf] = (uint8_t)u16HidUsage;
1070 ++iBuf;
1071 }
1072 }
1073 }
1074 }
1075}
1076
1077/**
1078 * Create a USB HID keyboard report reflecting the current state of the
1079 * consumer control keys. This is very easy as we have a bit mask that fully
1080 * reflects the state of all defined system control keys.
1081 */
1082static void usbHidBuildReportExt(PUSBHIDX_REPORT pReport, uint8_t *pabDepressedKeys)
1083{
1084 RT_ZERO(*pReport);
1085
1086 for (unsigned iKey = 0; iKey < VBOX_USB_USAGE_ARRAY_SIZE; ++iKey)
1087 {
1088 if (pabDepressedKeys[iKey])
1089 {
1090 /* Key index back to 32-bit HID code. */
1091 uint32_t u32HidCode = usbInternalCodeToHid(iKey);
1092 uint8_t u8HidPage = RT_LOBYTE(RT_HIWORD(u32HidCode));
1093 uint16_t u16HidUsage = RT_LOWORD(u32HidCode);
1094
1095 if (u8HidPage == USB_HID_CC_PAGE)
1096 pReport->uKeyCC = u16HidUsage;
1097 else if (u8HidPage == USB_HID_DC_PAGE)
1098 if (usbHidUsageCodeIsSCKey(u16HidUsage))
1099 pReport->uSCKeys |= usbHidSCKeyToMask(u16HidUsage);
1100 }
1101 }
1102}
1103
1104/**
1105 * Handles a SET_REPORT request sent to the default control pipe. Note
1106 * that unrecognized requests are ignored without reporting an error.
1107 */
1108static void usbHidSetReport(PUSBHID pThis, PVUSBURB pUrb)
1109{
1110 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1111 Assert(pSetup->bRequest == HID_REQ_SET_REPORT);
1112
1113 /* The LED report is the 3rd report, ID 0 (-> wValue 0x200). */
1114 if (pSetup->wIndex == 0 && pSetup->wLength == 1 && pSetup->wValue == 0x200)
1115 {
1116 PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE;
1117 uint8_t u8LEDs = pUrb->abData[sizeof(*pSetup)];
1118 LogFlowFunc(("Setting keybooard LEDs to u8LEDs=%02X\n", u8LEDs));
1119
1120 /* Translate LED state to PDM format and send upstream. */
1121 if (u8LEDs & 0x01)
1122 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
1123 if (u8LEDs & 0x02)
1124 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
1125 if (u8LEDs & 0x04)
1126 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
1127
1128 pThis->Lun0.pDrv->pfnLedStatusChange(pThis->Lun0.pDrv, enmLeds);
1129 }
1130}
1131
1132/**
1133 * Sends a state report to the guest if there is a URB available.
1134 */
1135static void usbHidSendReport(PUSBHID pThis, PUSBHIDIF pIf)
1136{
1137 PVUSBURB pUrb = usbHidQueueRemoveHead(&pIf->ToHostQueue);
1138 if (pUrb)
1139 {
1140 pIf->fHasPendingChanges = false;
1141 if (pIf == &pThis->aIfs[0])
1142 {
1143 USBHIDK_REPORT ReportKbd;
1144
1145 usbHidBuildReportKbd(&ReportKbd, pThis->abDepressedKeys);
1146 usbHidCompleteOk(pThis, pUrb, &ReportKbd, sizeof(ReportKbd));
1147 }
1148 else
1149 {
1150 Assert(pIf == &pThis->aIfs[1]);
1151 USBHIDX_REPORT ReportExt;
1152
1153 usbHidBuildReportExt(&ReportExt, pThis->abDepressedKeys);
1154 usbHidCompleteOk(pThis, pUrb, &ReportExt, sizeof(ReportExt));
1155 }
1156 }
1157 else
1158 {
1159 Log2(("No available URB for USB kbd\n"));
1160 pIf->fHasPendingChanges = true;
1161 }
1162}
1163
1164/**
1165 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1166 */
1167static DECLCALLBACK(void *) usbHidKeyboardQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1168{
1169 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
1170 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
1171 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDPORT, &pThis->Lun0.IPort);
1172 return NULL;
1173}
1174
1175/**
1176 * @interface_method_impl{PDMIKEYBOARDPORT,pfnPutEventHid}
1177 */
1178static DECLCALLBACK(int) usbHidKeyboardPutEvent(PPDMIKEYBOARDPORT pInterface, uint32_t idUsage)
1179{
1180 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
1181 PUSBHIDIF pIf;
1182 bool fKeyDown;
1183 bool fHaveEvent = true;
1184 int rc = VINF_SUCCESS;
1185 int iKeyCode;
1186 uint8_t u8HidPage = RT_LOBYTE(RT_HIWORD(idUsage));
1187
1188 /* Let's see what we got... */
1189 fKeyDown = !(idUsage & PDMIKBDPORT_KEY_UP);
1190
1191 /* Always respond to USB_HID_KB_PAGE, but quietly drop USB_HID_CC_PAGE/USB_HID_DC_PAGE
1192 * events unless the device is in the extended mode. And drop anything else, too.
1193 */
1194 if (u8HidPage == USB_HID_KB_PAGE)
1195 pIf = &pThis->aIfs[0];
1196 else
1197 {
1198 if ( pThis->fExtPipeActive
1199 && ((u8HidPage == USB_HID_CC_PAGE) || (u8HidPage == USB_HID_DC_PAGE)))
1200 pIf = &pThis->aIfs[1];
1201 else
1202 return VINF_SUCCESS; /* Must consume data to avoid blockage. */
1203 }
1204
1205 iKeyCode = usbHidToInternalCode(idUsage);
1206 AssertReturn((iKeyCode > 0 && iKeyCode <= VBOX_USB_MAX_USAGE_CODE) || (idUsage & PDMIKBDPORT_RELEASE_KEYS), VERR_INTERNAL_ERROR);
1207
1208 RTCritSectEnter(&pThis->CritSect);
1209
1210 if (RT_LIKELY(!(idUsage & PDMIKBDPORT_RELEASE_KEYS)))
1211 {
1212 LogFlowFunc(("key %s: %08X (iKeyCode 0x%x)\n", fKeyDown ? "down" : "up", idUsage, iKeyCode));
1213
1214 /*
1215 * Due to host key repeat, we can get key events for keys which are
1216 * already depressed. Drop those right here.
1217 */
1218 if (fKeyDown && pThis->abDepressedKeys[iKeyCode])
1219 fHaveEvent = false;
1220
1221 /* If there is already a pending event, we won't accept a new one yet. */
1222 if (pIf->fHasPendingChanges && fHaveEvent)
1223 {
1224 rc = VERR_TRY_AGAIN;
1225 }
1226 else if (fHaveEvent)
1227 {
1228 /* Regular key event - update keyboard state. */
1229 if (fKeyDown)
1230 pThis->abDepressedKeys[iKeyCode] = 1;
1231 else
1232 pThis->abDepressedKeys[iKeyCode] = 0;
1233
1234 /*
1235 * Try sending a report. Note that we already decided to consume the
1236 * event regardless of whether a URB is available or not. If it's not,
1237 * we will simply not accept any further events.
1238 */
1239 usbHidSendReport(pThis, pIf);
1240 }
1241 }
1242 else
1243 {
1244 LogFlowFunc(("Release all keys.\n"));
1245
1246 /* Clear all currently depressed keys. */
1247 RT_ZERO(pThis->abDepressedKeys);
1248 }
1249
1250 RTCritSectLeave(&pThis->CritSect);
1251
1252 return rc;
1253}
1254
1255/**
1256 * @interface_method_impl{PDMUSBREG,pfnUrbReap}
1257 */
1258static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
1259{
1260 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1261 //LogFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
1262
1263 RTCritSectEnter(&pThis->CritSect);
1264
1265 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1266 if (!pUrb && cMillies)
1267 {
1268 /* Wait */
1269 pThis->fHaveDoneQueueWaiter = true;
1270 RTCritSectLeave(&pThis->CritSect);
1271
1272 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
1273
1274 RTCritSectEnter(&pThis->CritSect);
1275 pThis->fHaveDoneQueueWaiter = false;
1276
1277 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
1278 }
1279
1280 RTCritSectLeave(&pThis->CritSect);
1281
1282 if (pUrb)
1283 Log(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1284 return pUrb;
1285}
1286
1287
1288/**
1289 * @interface_method_impl{PDMUSBREG,pfnWakeup}
1290 */
1291static DECLCALLBACK(int) usbHidWakeup(PPDMUSBINS pUsbIns)
1292{
1293 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1294
1295 return RTSemEventSignal(pThis->hEvtDoneQueue);
1296}
1297
1298
1299/**
1300 * @interface_method_impl{PDMUSBREG,pfnUrbCancel}
1301 */
1302static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1303{
1304 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1305 LogFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
1306 RTCritSectEnter(&pThis->CritSect);
1307
1308 /*
1309 * Remove the URB from its to-host queue and move it onto the done queue.
1310 */
1311 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aIfs); i++)
1312 if (usbHidQueueRemove(&pThis->aIfs[i].ToHostQueue, pUrb))
1313 usbHidLinkDone(pThis, pUrb);
1314
1315 RTCritSectLeave(&pThis->CritSect);
1316 return VINF_SUCCESS;
1317}
1318
1319
1320/**
1321 * Handles request sent to the inbound (device to host) interrupt pipe. This is
1322 * rather different from bulk requests because an interrupt read URB may complete
1323 * after arbitrarily long time.
1324 */
1325static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PUSBHIDIF pIf, PVUSBURB pUrb)
1326{
1327 /*
1328 * Stall the request if the pipe is halted.
1329 */
1330 if (RT_UNLIKELY(pEp->fHalted))
1331 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
1332
1333 /*
1334 * Deal with the URB according to the endpoint/interface state.
1335 */
1336 switch (pIf->enmState)
1337 {
1338 /*
1339 * We've data left to transfer to the host.
1340 */
1341 case USBHIDREQSTATE_DATA_TO_HOST:
1342 {
1343 AssertFailed();
1344 Log(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
1345 return usbHidCompleteOk(pThis, pUrb, NULL, 0);
1346 }
1347
1348 /*
1349 * Status transfer.
1350 */
1351 case USBHIDREQSTATE_STATUS:
1352 {
1353 AssertFailed();
1354 Log(("usbHidHandleIntrDevToHost: Entering READY\n"));
1355 pIf->enmState = USBHIDREQSTATE_READY;
1356 return usbHidCompleteOk(pThis, pUrb, NULL, 0);
1357 }
1358
1359 case USBHIDREQSTATE_READY:
1360 usbHidQueueAddTail(&pIf->ToHostQueue, pUrb);
1361 /* If device was not set idle, send the current report right away. */
1362 if (pThis->bIdle != 0 || pIf->fHasPendingChanges)
1363 {
1364 usbHidSendReport(pThis, pIf);
1365 LogFlow(("usbHidHandleIntrDevToHost: Sent report via %p:%s\n", pUrb, pUrb->pszDesc));
1366 Assert(!pIf->fHasPendingChanges); /* Since we just got a URB... */
1367 /* There may be more input queued up. Ask for it now. */
1368 pThis->Lun0.pDrv->pfnFlushQueue(pThis->Lun0.pDrv);
1369 }
1370 return VINF_SUCCESS;
1371
1372 /*
1373 * Bad states, stall.
1374 */
1375 default:
1376 Log(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n", pIf->enmState, pUrb->cbData));
1377 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
1378 }
1379}
1380
1381
1382/**
1383 * Handles request sent to the default control pipe.
1384 */
1385static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
1386{
1387 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1388 LogFlow(("usbHidHandleDefaultPipe: cbData=%d\n", pUrb->cbData));
1389
1390 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
1391
1392 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
1393 {
1394 switch (pSetup->bRequest)
1395 {
1396 case VUSB_REQ_GET_DESCRIPTOR:
1397 {
1398 switch (pSetup->bmRequestType)
1399 {
1400 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1401 {
1402 switch (pSetup->wValue >> 8)
1403 {
1404 case VUSB_DT_STRING:
1405 Log(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1406 break;
1407 default:
1408 Log(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1409 break;
1410 }
1411 break;
1412 }
1413
1414 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1415 {
1416 switch (pSetup->wValue >> 8)
1417 {
1418 case DT_IF_HID_DESCRIPTOR:
1419 {
1420 uint32_t cbSrc;
1421 const void *pSrc;
1422
1423 if (pSetup->wIndex == 0)
1424 {
1425 cbSrc = RT_MIN(pSetup->wLength, sizeof(g_UsbHidIfHidDescKbd));
1426 pSrc = &g_UsbHidIfHidDescKbd;
1427 }
1428 else
1429 {
1430 cbSrc = RT_MIN(pSetup->wLength, sizeof(g_UsbHidIfHidDescExt));
1431 pSrc = &g_UsbHidIfHidDescExt;
1432 }
1433 Log(("usbHidKbd: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbSrc=%#x\n", pSetup->wValue, pSetup->wIndex, cbSrc));
1434 return usbHidCompleteOk(pThis, pUrb, pSrc, cbSrc);
1435 }
1436
1437 case DT_IF_HID_REPORT:
1438 {
1439 uint32_t cbSrc;
1440 const void *pSrc;
1441
1442 /* Returned data is written after the setup message. */
1443 if (pSetup->wIndex == 0)
1444 {
1445 cbSrc = RT_MIN(pSetup->wLength, sizeof(g_UsbHidReportDescKbd));
1446 pSrc = &g_UsbHidReportDescKbd;
1447 }
1448 else
1449 {
1450 cbSrc = RT_MIN(pSetup->wLength, sizeof(g_UsbHidReportDescExt));
1451 pSrc = &g_UsbHidReportDescExt;
1452 }
1453
1454 Log(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbSrc=%#x\n", pSetup->wValue, pSetup->wIndex, cbSrc));
1455 return usbHidCompleteOk(pThis, pUrb, pSrc, cbSrc);
1456 }
1457
1458 default:
1459 Log(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1460 break;
1461 }
1462 break;
1463 }
1464
1465 default:
1466 Log(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
1467 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
1468 }
1469 break;
1470 }
1471
1472 case VUSB_REQ_GET_STATUS:
1473 {
1474 uint16_t wRet = 0;
1475
1476 if (pSetup->wLength != 2)
1477 {
1478 Log(("usbHid: Bad GET_STATUS req: wLength=%#x\n", pSetup->wLength));
1479 break;
1480 }
1481 Assert(pSetup->wValue == 0);
1482 switch (pSetup->bmRequestType)
1483 {
1484 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1485 {
1486 Assert(pSetup->wIndex == 0);
1487 Log(("usbHid: GET_STATUS (device)\n"));
1488 wRet = 0; /* Not self-powered, no remote wakeup. */
1489 return usbHidCompleteOk(pThis, pUrb, &wRet, sizeof(wRet));
1490 }
1491
1492 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1493 {
1494 if (pSetup->wIndex == 0)
1495 {
1496 return usbHidCompleteOk(pThis, pUrb, &wRet, sizeof(wRet));
1497 }
1498 Log(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n", pSetup->wIndex));
1499 break;
1500 }
1501
1502 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
1503 {
1504 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
1505 {
1506 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
1507 return usbHidCompleteOk(pThis, pUrb, &wRet, sizeof(wRet));
1508 }
1509 Log(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n", pSetup->wIndex));
1510 break;
1511 }
1512
1513 default:
1514 Log(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n", pSetup->bmRequestType));
1515 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
1516 }
1517 break;
1518 }
1519
1520 case VUSB_REQ_CLEAR_FEATURE:
1521 break;
1522 }
1523
1524 /** @todo implement this. */
1525 Log(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1526 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1527
1528 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1529 }
1530 else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
1531 {
1532 switch (pSetup->bRequest)
1533 {
1534 case HID_REQ_SET_IDLE:
1535 {
1536 switch (pSetup->bmRequestType)
1537 {
1538 case VUSB_TO_INTERFACE | VUSB_REQ_CLASS | VUSB_DIR_TO_DEVICE:
1539 {
1540 Log(("usbHid: SET_IDLE wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1541 pThis->bIdle = pSetup->wValue >> 8;
1542 /* Consider 24ms to mean zero for keyboards (see IOUSBHIDDriver) */
1543 if (pThis->bIdle == 6) pThis->bIdle = 0;
1544 return usbHidCompleteOk(pThis, pUrb, NULL, 0);
1545 }
1546 break;
1547 }
1548 break;
1549 }
1550 case HID_REQ_GET_IDLE:
1551 {
1552 switch (pSetup->bmRequestType)
1553 {
1554 case VUSB_TO_INTERFACE | VUSB_REQ_CLASS | VUSB_DIR_TO_HOST:
1555 {
1556 Log(("usbHid: GET_IDLE wValue=%#x wIndex=%#x, returning %#x\n", pSetup->wValue, pSetup->wIndex, pThis->bIdle));
1557 return usbHidCompleteOk(pThis, pUrb, &pThis->bIdle, sizeof(pThis->bIdle));
1558 }
1559 break;
1560 }
1561 break;
1562 }
1563 case HID_REQ_SET_REPORT:
1564 {
1565 switch (pSetup->bmRequestType)
1566 {
1567 case VUSB_TO_INTERFACE | VUSB_REQ_CLASS | VUSB_DIR_TO_DEVICE:
1568 {
1569 Log(("usbHid: SET_REPORT wValue=%#x wIndex=%#x wLength=%#x\n", pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1570 usbHidSetReport(pThis, pUrb);
1571 return usbHidCompleteOk(pThis, pUrb, NULL, 0);
1572 }
1573 break;
1574 }
1575 break;
1576 }
1577 }
1578 Log(("usbHid: Unimplemented class request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1579 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1580
1581 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: class request stuff");
1582 }
1583 else
1584 {
1585 Log(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1586 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1587 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1588 }
1589
1590 return VINF_SUCCESS;
1591}
1592
1593
1594/**
1595 * @interface_method_impl{PDMUSBREG,pfnUrbQueue}
1596 */
1597static DECLCALLBACK(int) usbHidQueueUrb(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1598{
1599 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1600 LogFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
1601 RTCritSectEnter(&pThis->CritSect);
1602
1603 /*
1604 * Parse on a per-endpoint basis.
1605 */
1606 int rc;
1607 switch (pUrb->EndPt)
1608 {
1609 case 0:
1610 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1611 break;
1612
1613 /* Standard keyboard interface. */
1614 case 0x81:
1615 AssertFailed();
1616 RT_FALL_THRU();
1617 case 0x01:
1618 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], &pThis->aIfs[0], pUrb);
1619 break;
1620
1621 /* Extended multimedia/control keys interface. */
1622 case 0x82:
1623 AssertFailed();
1624 RT_FALL_THRU();
1625 case 0x02:
1626 if (pThis->enmMode == USBKBDMODE_EXTENDED)
1627 {
1628 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[2], &pThis->aIfs[1], pUrb);
1629 pThis->fExtPipeActive = true;
1630 break;
1631 }
1632 RT_FALL_THRU();
1633 default:
1634 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1635 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1636 break;
1637 }
1638
1639 RTCritSectLeave(&pThis->CritSect);
1640 return rc;
1641}
1642
1643
1644/**
1645 * @interface_method_impl{PDMUSBREG,pfnUsbClearHaltedEndpoint}
1646 */
1647static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1648{
1649 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1650 LogFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
1651
1652 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1653 {
1654 RTCritSectEnter(&pThis->CritSect);
1655 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1656 RTCritSectLeave(&pThis->CritSect);
1657 }
1658
1659 return VINF_SUCCESS;
1660}
1661
1662
1663/**
1664 * @interface_method_impl{PDMUSBREG,pfnUsbSetInterface}
1665 */
1666static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1667{
1668 RT_NOREF3(pUsbIns, bInterfaceNumber, bAlternateSetting);
1669 LogFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1670 Assert(bAlternateSetting == 0);
1671 return VINF_SUCCESS;
1672}
1673
1674
1675/**
1676 * @interface_method_impl{PDMUSBREG,pfnUsbSetConfiguration}
1677 */
1678static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1679 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1680{
1681 RT_NOREF3(pvOldCfgDesc, pvOldIfState, pvNewCfgDesc);
1682 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1683 LogFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
1684 Assert(bConfigurationValue == 1);
1685 RTCritSectEnter(&pThis->CritSect);
1686
1687 /*
1688 * If the same config is applied more than once, it's a kind of reset.
1689 */
1690 if (pThis->bConfigurationValue == bConfigurationValue)
1691 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1692 pThis->bConfigurationValue = bConfigurationValue;
1693
1694 /*
1695 * Tell the other end that the keyboard is now enabled and wants
1696 * to receive keystrokes.
1697 */
1698 pThis->Lun0.pDrv->pfnSetActive(pThis->Lun0.pDrv, true);
1699
1700 RTCritSectLeave(&pThis->CritSect);
1701 return VINF_SUCCESS;
1702}
1703
1704
1705/**
1706 * @interface_method_impl{PDMUSBREG,pfnUsbGetDescriptorCache}
1707 */
1708static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1709{
1710 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1711 LogRelFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1712 switch (pThis->enmMode)
1713 {
1714 case USBKBDMODE_BASIC:
1715 return &g_UsbHidBasDescCache;
1716 case USBKBDMODE_EXTENDED:
1717 return &g_UsbHidExtDescCache;
1718 default:
1719 return NULL;
1720 }
1721}
1722
1723
1724/**
1725 * @interface_method_impl{PDMUSBREG,pfnUsbReset}
1726 */
1727static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1728{
1729 RT_NOREF1(fResetOnLinux);
1730 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1731 LogFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
1732 RTCritSectEnter(&pThis->CritSect);
1733
1734 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
1735
1736 RTCritSectLeave(&pThis->CritSect);
1737 return rc;
1738}
1739
1740
1741/**
1742 * @interface_method_impl{PDMUSBREG,pfnDestruct}
1743 */
1744static DECLCALLBACK(void) usbHidDestruct(PPDMUSBINS pUsbIns)
1745{
1746 PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns);
1747 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1748 LogFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
1749
1750 if (RTCritSectIsInitialized(&pThis->CritSect))
1751 {
1752 /* Let whoever runs in this critical section complete. */
1753 RTCritSectEnter(&pThis->CritSect);
1754 RTCritSectLeave(&pThis->CritSect);
1755 RTCritSectDelete(&pThis->CritSect);
1756 }
1757
1758 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1759 {
1760 RTSemEventDestroy(pThis->hEvtDoneQueue);
1761 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1762 }
1763}
1764
1765
1766/**
1767 * @interface_method_impl{PDMUSBREG,pfnConstruct}
1768 */
1769static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1770{
1771 RT_NOREF1(pCfgGlobal);
1772 PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns);
1773 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1774 PCPDMUSBHLP pHlp = pUsbIns->pHlpR3;
1775 Log(("usbHidConstruct/#%u:\n", iInstance));
1776
1777 /*
1778 * Perform the basic structure initialization first so the destructor
1779 * will not misbehave.
1780 */
1781 pThis->pUsbIns = pUsbIns;
1782 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1783 usbHidQueueInit(&pThis->DoneQueue);
1784 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aIfs); i++)
1785 usbHidQueueInit(&pThis->aIfs[i].ToHostQueue);
1786
1787 int rc = RTCritSectInit(&pThis->CritSect);
1788 AssertRCReturn(rc, rc);
1789
1790 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1791 AssertRCReturn(rc, rc);
1792
1793 /*
1794 * Validate and read the configuration.
1795 */
1796 rc = pHlp->pfnCFGMValidateConfig(pCfg, "/", "Mode", "Config", "UsbHid", iInstance);
1797 if (RT_FAILURE(rc))
1798 return rc;
1799 char szMode[64];
1800 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "Mode", szMode, sizeof(szMode), "basic");
1801 if (RT_FAILURE(rc))
1802 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to query settings"));
1803 if (!RTStrCmp(szMode, "basic"))
1804 pThis->enmMode = USBKBDMODE_BASIC;
1805 else if (!RTStrCmp(szMode, "extended"))
1806 pThis->enmMode = USBKBDMODE_EXTENDED;
1807 else
1808 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS,
1809 N_("Invalid HID mode"));
1810
1811 pThis->Lun0.IBase.pfnQueryInterface = usbHidKeyboardQueryInterface;
1812 pThis->Lun0.IPort.pfnPutEventHid = usbHidKeyboardPutEvent;
1813
1814 /*
1815 * Attach the keyboard driver.
1816 */
1817 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Keyboard Port");
1818 if (RT_FAILURE(rc))
1819 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach keyboard driver"));
1820
1821 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIKEYBOARDCONNECTOR);
1822 if (!pThis->Lun0.pDrv)
1823 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query keyboard interface"));
1824
1825 return VINF_SUCCESS;
1826}
1827
1828
1829/**
1830 * The USB Human Interface Device (HID) Keyboard registration record.
1831 */
1832const PDMUSBREG g_UsbHidKbd =
1833{
1834 /* u32Version */
1835 PDM_USBREG_VERSION,
1836 /* szName */
1837 "HidKeyboard",
1838 /* pszDescription */
1839 "USB HID Keyboard.",
1840 /* fFlags */
1841 0,
1842 /* cMaxInstances */
1843 ~0U,
1844 /* cbInstance */
1845 sizeof(USBHID),
1846 /* pfnConstruct */
1847 usbHidConstruct,
1848 /* pfnDestruct */
1849 usbHidDestruct,
1850 /* pfnVMInitComplete */
1851 NULL,
1852 /* pfnVMPowerOn */
1853 NULL,
1854 /* pfnVMReset */
1855 NULL,
1856 /* pfnVMSuspend */
1857 NULL,
1858 /* pfnVMResume */
1859 NULL,
1860 /* pfnVMPowerOff */
1861 NULL,
1862 /* pfnHotPlugged */
1863 NULL,
1864 /* pfnHotUnplugged */
1865 NULL,
1866 /* pfnDriverAttach */
1867 NULL,
1868 /* pfnDriverDetach */
1869 NULL,
1870 /* pfnQueryInterface */
1871 NULL,
1872 /* pfnUsbReset */
1873 usbHidUsbReset,
1874 /* pfnUsbGetDescriptorCache */
1875 usbHidUsbGetDescriptorCache,
1876 /* pfnUsbSetConfiguration */
1877 usbHidUsbSetConfiguration,
1878 /* pfnUsbSetInterface */
1879 usbHidUsbSetInterface,
1880 /* pfnUsbClearHaltedEndpoint */
1881 usbHidUsbClearHaltedEndpoint,
1882 /* pfnUrbNew */
1883 NULL/*usbHidUrbNew*/,
1884 /* pfnUrbQueue */
1885 usbHidQueueUrb,
1886 /* pfnUrbCancel */
1887 usbHidUrbCancel,
1888 /* pfnUrbReap */
1889 usbHidUrbReap,
1890 /* pfnWakeup */
1891 usbHidWakeup,
1892 /* u32TheEnd */
1893 PDM_USBREG_VERSION
1894};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use