VirtualBox

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

Last change on this file since 95294 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette