VirtualBox

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

Last change on this file since 54030 was 51546, checked in by vboxsync, 10 years ago

UsbKbd: Added a brief theory of operation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.2 KB
Line 
1/* $Id: UsbKbd.cpp 51546 2014-06-05 09:56:45Z vboxsync $ */
2/** @file
3 * UsbKbd - USB Human Interface Device Emulation, Keyboard.
4 */
5
6/*
7 * Copyright (C) 2007-2012 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 *
42 * References:
43 *
44 * Device Class Definition for Human Interface Devices (HID), Version 1.11
45 *
46 */
47
48/*******************************************************************************
49* Header Files *
50*******************************************************************************/
51#define LOG_GROUP LOG_GROUP_USB_KBD
52#include <VBox/vmm/pdmusb.h>
53#include <VBox/log.h>
54#include <VBox/err.h>
55#include <iprt/assert.h>
56#include <iprt/critsect.h>
57#include <iprt/mem.h>
58#include <iprt/semaphore.h>
59#include <iprt/string.h>
60#include <iprt/uuid.h>
61#include "VBoxDD.h"
62
63
64/*******************************************************************************
65* Defined Constants And Macros *
66*******************************************************************************/
67/** @name USB HID string IDs
68 * @{ */
69#define USBHID_STR_ID_MANUFACTURER 1
70#define USBHID_STR_ID_PRODUCT 2
71/** @} */
72
73/** @name USB HID specific descriptor types
74 * @{ */
75#define DT_IF_HID_DESCRIPTOR 0x21
76#define DT_IF_HID_REPORT 0x22
77/** @} */
78
79/** @name USB HID vendor and product IDs
80 * @{ */
81#define VBOX_USB_VENDOR 0x80EE
82#define USBHID_PID_KEYBOARD 0x0010
83/** @} */
84
85/** @name USB HID class specific requests
86 * @{ */
87#define HID_REQ_GET_REPORT 0x01
88#define HID_REQ_GET_IDLE 0x02
89#define HID_REQ_SET_REPORT 0x09
90#define HID_REQ_SET_IDLE 0x0A
91/** @} */
92
93/** @name USB HID additional constants
94 * @{ */
95/** The highest USB usage code reported by the VBox emulated keyboard */
96#define VBOX_USB_MAX_USAGE_CODE 0xE7
97/** The size of an array needed to store all USB usage codes */
98#define VBOX_USB_USAGE_ARRAY_SIZE (VBOX_USB_MAX_USAGE_CODE + 1)
99#define USBHID_USAGE_ROLL_OVER 1
100/** The usage code of the first modifier key. */
101#define USBHID_MODIFIER_FIRST 0xE0
102/** The usage code of the last modifier key. */
103#define USBHID_MODIFIER_LAST 0xE7
104/** @} */
105
106/*******************************************************************************
107* Structures and Typedefs *
108*******************************************************************************/
109
110/**
111 * The USB HID request state.
112 */
113typedef enum USBHIDREQSTATE
114{
115 /** Invalid status. */
116 USBHIDREQSTATE_INVALID = 0,
117 /** Ready to receive a new read request. */
118 USBHIDREQSTATE_READY,
119 /** Have (more) data for the host. */
120 USBHIDREQSTATE_DATA_TO_HOST,
121 /** Waiting to supply status information to the host. */
122 USBHIDREQSTATE_STATUS,
123 /** The end of the valid states. */
124 USBHIDREQSTATE_END
125} USBHIDREQSTATE;
126
127
128/**
129 * Endpoint status data.
130 */
131typedef struct USBHIDEP
132{
133 bool fHalted;
134} USBHIDEP;
135/** Pointer to the endpoint status. */
136typedef USBHIDEP *PUSBHIDEP;
137
138
139/**
140 * A URB queue.
141 */
142typedef struct USBHIDURBQUEUE
143{
144 /** The head pointer. */
145 PVUSBURB pHead;
146 /** Where to insert the next entry. */
147 PVUSBURB *ppTail;
148} USBHIDURBQUEUE;
149/** Pointer to a URB queue. */
150typedef USBHIDURBQUEUE *PUSBHIDURBQUEUE;
151/** Pointer to a const URB queue. */
152typedef USBHIDURBQUEUE const *PCUSBHIDURBQUEUE;
153
154
155/**
156 * The USB HID report structure for regular keys.
157 */
158typedef struct USBHIDK_REPORT
159{
160 uint8_t ShiftState; /**< Modifier keys bitfield */
161 uint8_t Reserved; /**< Currently unused */
162 uint8_t aKeys[6]; /**< Normal keys */
163} USBHIDK_REPORT, *PUSBHIDK_REPORT;
164
165/**
166 * The USB HID instance data.
167 */
168typedef struct USBHID
169{
170 /** Pointer back to the PDM USB Device instance structure. */
171 PPDMUSBINS pUsbIns;
172 /** Critical section protecting the device state. */
173 RTCRITSECT CritSect;
174
175 /** The current configuration.
176 * (0 - default, 1 - the one supported configuration, i.e configured.) */
177 uint8_t bConfigurationValue;
178 /** USB HID Idle value..
179 * (0 - only report state change, !=0 - report in bIdle * 4ms intervals.) */
180 uint8_t bIdle;
181 /** Endpoint 0 is the default control pipe, 1 is the dev->host interrupt one. */
182 USBHIDEP aEps[2];
183 /** The state of the HID (state machine).*/
184 USBHIDREQSTATE enmState;
185
186 /** Pending to-host queue.
187 * The URBs waiting here are waiting for data to become available.
188 */
189 USBHIDURBQUEUE ToHostQueue;
190
191 /** Done queue
192 * The URBs stashed here are waiting to be reaped. */
193 USBHIDURBQUEUE DoneQueue;
194 /** Signalled when adding an URB to the done queue and fHaveDoneQueueWaiter
195 * is set. */
196 RTSEMEVENT hEvtDoneQueue;
197 /** Someone is waiting on the done queue. */
198 bool fHaveDoneQueueWaiter;
199 /** If device has pending changes. */
200 bool fHasPendingChanges;
201 /** Currently depressed keys */
202 uint8_t abDepressedKeys[VBOX_USB_USAGE_ARRAY_SIZE];
203
204 /**
205 * Keyboard port - LUN#0.
206 *
207 * @implements PDMIBASE
208 * @implements PDMIKEYBOARDPORT
209 */
210 struct
211 {
212 /** The base interface for the keyboard port. */
213 PDMIBASE IBase;
214 /** The keyboard port base interface. */
215 PDMIKEYBOARDPORT IPort;
216
217 /** The base interface of the attached keyboard driver. */
218 R3PTRTYPE(PPDMIBASE) pDrvBase;
219 /** The keyboard interface of the attached keyboard driver. */
220 R3PTRTYPE(PPDMIKEYBOARDCONNECTOR) pDrv;
221 } Lun0;
222} USBHID;
223/** Pointer to the USB HID instance data. */
224typedef USBHID *PUSBHID;
225
226/*******************************************************************************
227* Global Variables *
228*******************************************************************************/
229static const PDMUSBDESCCACHESTRING g_aUsbHidStrings_en_US[] =
230{
231 { USBHID_STR_ID_MANUFACTURER, "VirtualBox" },
232 { USBHID_STR_ID_PRODUCT, "USB Keyboard" },
233};
234
235static const PDMUSBDESCCACHELANG g_aUsbHidLanguages[] =
236{
237 { 0x0409, RT_ELEMENTS(g_aUsbHidStrings_en_US), g_aUsbHidStrings_en_US }
238};
239
240static const VUSBDESCENDPOINTEX g_aUsbHidEndpointDescs[] =
241{
242 {
243 {
244 /* .bLength = */ sizeof(VUSBDESCENDPOINT),
245 /* .bDescriptorType = */ VUSB_DT_ENDPOINT,
246 /* .bEndpointAddress = */ 0x81 /* ep=1, in */,
247 /* .bmAttributes = */ 3 /* interrupt */,
248 /* .wMaxPacketSize = */ 8,
249 /* .bInterval = */ 10,
250 },
251 /* .pvMore = */ NULL,
252 /* .pvClass = */ NULL,
253 /* .cbClass = */ 0
254 },
255};
256
257/** HID report descriptor. */
258static const uint8_t g_UsbHidReportDesc[] =
259{
260 /* Usage Page */ 0x05, 0x01, /* Generic Desktop */
261 /* Usage */ 0x09, 0x06, /* Keyboard */
262 /* Collection */ 0xA1, 0x01, /* Application */
263 /* Usage Page */ 0x05, 0x07, /* Keyboard */
264 /* Usage Minimum */ 0x19, 0xE0, /* Left Ctrl Key */
265 /* Usage Maximum */ 0x29, 0xE7, /* Right GUI Key */
266 /* Logical Minimum */ 0x15, 0x00, /* 0 */
267 /* Logical Maximum */ 0x25, 0x01, /* 1 */
268 /* Report Count */ 0x95, 0x08, /* 8 */
269 /* Report Size */ 0x75, 0x01, /* 1 */
270 /* Input */ 0x81, 0x02, /* Data, Value, Absolute, Bit field */
271 /* Report Count */ 0x95, 0x01, /* 1 */
272 /* Report Size */ 0x75, 0x08, /* 8 (padding bits) */
273 /* Input */ 0x81, 0x01, /* Constant, Array, Absolute, Bit field */
274 /* Report Count */ 0x95, 0x05, /* 5 */
275 /* Report Size */ 0x75, 0x01, /* 1 */
276 /* Usage Page */ 0x05, 0x08, /* LEDs */
277 /* Usage Minimum */ 0x19, 0x01, /* Num Lock */
278 /* Usage Maximum */ 0x29, 0x05, /* Kana */
279 /* Output */ 0x91, 0x02, /* Data, Value, Absolute, Non-volatile,Bit field */
280 /* Report Count */ 0x95, 0x01, /* 1 */
281 /* Report Size */ 0x75, 0x03, /* 3 */
282 /* Output */ 0x91, 0x01, /* Constant, Value, Absolute, Non-volatile, Bit field */
283 /* Report Count */ 0x95, 0x06, /* 6 */
284 /* Report Size */ 0x75, 0x08, /* 8 */
285 /* Logical Minimum */ 0x15, 0x00, /* 0 */
286 /* Logical Maximum */ 0x26, 0xFF,0x00,/* 255 */
287 /* Usage Page */ 0x05, 0x07, /* Keyboard */
288 /* Usage Minimum */ 0x19, 0x00, /* 0 */
289 /* Usage Maximum */ 0x29, 0xFF, /* 255 */
290 /* Input */ 0x81, 0x00, /* Data, Array, Absolute, Bit field */
291 /* End Collection */ 0xC0,
292};
293
294/** Additional HID class interface descriptor. */
295static const uint8_t g_UsbHidIfHidDesc[] =
296{
297 /* .bLength = */ 0x09,
298 /* .bDescriptorType = */ 0x21, /* HID */
299 /* .bcdHID = */ 0x10, 0x01, /* 1.1 */
300 /* .bCountryCode = */ 0x0D, /* International (ISO) */
301 /* .bNumDescriptors = */ 1,
302 /* .bDescriptorType = */ 0x22, /* Report */
303 /* .wDescriptorLength = */ sizeof(g_UsbHidReportDesc), 0x00
304};
305
306static const VUSBDESCINTERFACEEX g_UsbHidInterfaceDesc =
307{
308 {
309 /* .bLength = */ sizeof(VUSBDESCINTERFACE),
310 /* .bDescriptorType = */ VUSB_DT_INTERFACE,
311 /* .bInterfaceNumber = */ 0,
312 /* .bAlternateSetting = */ 0,
313 /* .bNumEndpoints = */ 1,
314 /* .bInterfaceClass = */ 3 /* HID */,
315 /* .bInterfaceSubClass = */ 1 /* Boot Interface */,
316 /* .bInterfaceProtocol = */ 1 /* Keyboard */,
317 /* .iInterface = */ 0
318 },
319 /* .pvMore = */ NULL,
320 /* .pvClass = */ &g_UsbHidIfHidDesc,
321 /* .cbClass = */ sizeof(g_UsbHidIfHidDesc),
322 &g_aUsbHidEndpointDescs[0],
323 /* .pIAD = */ NULL,
324 /* .cbIAD = */ 0
325};
326
327static const VUSBINTERFACE g_aUsbHidInterfaces[] =
328{
329 { &g_UsbHidInterfaceDesc, /* .cSettings = */ 1 },
330};
331
332static const VUSBDESCCONFIGEX g_UsbHidConfigDesc =
333{
334 {
335 /* .bLength = */ sizeof(VUSBDESCCONFIG),
336 /* .bDescriptorType = */ VUSB_DT_CONFIG,
337 /* .wTotalLength = */ 0 /* recalculated on read */,
338 /* .bNumInterfaces = */ RT_ELEMENTS(g_aUsbHidInterfaces),
339 /* .bConfigurationValue =*/ 1,
340 /* .iConfiguration = */ 0,
341 /* .bmAttributes = */ RT_BIT(7),
342 /* .MaxPower = */ 50 /* 100mA */
343 },
344 NULL, /* pvMore */
345 &g_aUsbHidInterfaces[0],
346 NULL /* pvOriginal */
347};
348
349static const VUSBDESCDEVICE g_UsbHidDeviceDesc =
350{
351 /* .bLength = */ sizeof(g_UsbHidDeviceDesc),
352 /* .bDescriptorType = */ VUSB_DT_DEVICE,
353 /* .bcdUsb = */ 0x110, /* 1.1 */
354 /* .bDeviceClass = */ 0 /* Class specified in the interface desc. */,
355 /* .bDeviceSubClass = */ 0 /* Subclass specified in the interface desc. */,
356 /* .bDeviceProtocol = */ 0 /* Protocol specified in the interface desc. */,
357 /* .bMaxPacketSize0 = */ 8,
358 /* .idVendor = */ VBOX_USB_VENDOR,
359 /* .idProduct = */ USBHID_PID_KEYBOARD,
360 /* .bcdDevice = */ 0x0100, /* 1.0 */
361 /* .iManufacturer = */ USBHID_STR_ID_MANUFACTURER,
362 /* .iProduct = */ USBHID_STR_ID_PRODUCT,
363 /* .iSerialNumber = */ 0,
364 /* .bNumConfigurations = */ 1
365};
366
367static const PDMUSBDESCCACHE g_UsbHidDescCache =
368{
369 /* .pDevice = */ &g_UsbHidDeviceDesc,
370 /* .paConfigs = */ &g_UsbHidConfigDesc,
371 /* .paLanguages = */ g_aUsbHidLanguages,
372 /* .cLanguages = */ RT_ELEMENTS(g_aUsbHidLanguages),
373 /* .fUseCachedDescriptors = */ true,
374 /* .fUseCachedStringsDescriptors = */ true
375};
376
377
378/*******************************************************************************
379* Internal Functions *
380*******************************************************************************/
381
382
383/**
384 * Initializes an URB queue.
385 *
386 * @param pQueue The URB queue.
387 */
388static void usbHidQueueInit(PUSBHIDURBQUEUE pQueue)
389{
390 pQueue->pHead = NULL;
391 pQueue->ppTail = &pQueue->pHead;
392}
393
394/**
395 * Inserts an URB at the end of the queue.
396 *
397 * @param pQueue The URB queue.
398 * @param pUrb The URB to insert.
399 */
400DECLINLINE(void) usbHidQueueAddTail(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
401{
402 pUrb->Dev.pNext = NULL;
403 *pQueue->ppTail = pUrb;
404 pQueue->ppTail = &pUrb->Dev.pNext;
405}
406
407
408/**
409 * Unlinks the head of the queue and returns it.
410 *
411 * @returns The head entry.
412 * @param pQueue The URB queue.
413 */
414DECLINLINE(PVUSBURB) usbHidQueueRemoveHead(PUSBHIDURBQUEUE pQueue)
415{
416 PVUSBURB pUrb = pQueue->pHead;
417 if (pUrb)
418 {
419 PVUSBURB pNext = pUrb->Dev.pNext;
420 pQueue->pHead = pNext;
421 if (!pNext)
422 pQueue->ppTail = &pQueue->pHead;
423 else
424 pUrb->Dev.pNext = NULL;
425 }
426 return pUrb;
427}
428
429
430/**
431 * Removes an URB from anywhere in the queue.
432 *
433 * @returns true if found, false if not.
434 * @param pQueue The URB queue.
435 * @param pUrb The URB to remove.
436 */
437DECLINLINE(bool) usbHidQueueRemove(PUSBHIDURBQUEUE pQueue, PVUSBURB pUrb)
438{
439 PVUSBURB pCur = pQueue->pHead;
440 if (pCur == pUrb)
441 pQueue->pHead = pUrb->Dev.pNext;
442 else
443 {
444 while (pCur)
445 {
446 if (pCur->Dev.pNext == pUrb)
447 {
448 pCur->Dev.pNext = pUrb->Dev.pNext;
449 break;
450 }
451 pCur = pCur->Dev.pNext;
452 }
453 if (!pCur)
454 return false;
455 }
456 if (!pUrb->Dev.pNext)
457 pQueue->ppTail = &pQueue->pHead;
458 return true;
459}
460
461
462/**
463 * Checks if the queue is empty or not.
464 *
465 * @returns true if it is, false if it isn't.
466 * @param pQueue The URB queue.
467 */
468DECLINLINE(bool) usbHidQueueIsEmpty(PCUSBHIDURBQUEUE pQueue)
469{
470 return pQueue->pHead == NULL;
471}
472
473
474/**
475 * Links an URB into the done queue.
476 *
477 * @param pThis The HID instance.
478 * @param pUrb The URB.
479 */
480static void usbHidLinkDone(PUSBHID pThis, PVUSBURB pUrb)
481{
482 usbHidQueueAddTail(&pThis->DoneQueue, pUrb);
483
484 if (pThis->fHaveDoneQueueWaiter)
485 {
486 int rc = RTSemEventSignal(pThis->hEvtDoneQueue);
487 AssertRC(rc);
488 }
489}
490
491
492/**
493 * Completes the URB with a stalled state, halting the pipe.
494 */
495static int usbHidCompleteStall(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb, const char *pszWhy)
496{
497 Log(("usbHidCompleteStall/#%u: pUrb=%p:%s: %s\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, pszWhy));
498
499 pUrb->enmStatus = VUSBSTATUS_STALL;
500
501 /** @todo figure out if the stall is global or pipe-specific or both. */
502 if (pEp)
503 pEp->fHalted = true;
504 else
505 {
506 pThis->aEps[0].fHalted = true;
507 pThis->aEps[1].fHalted = true;
508 }
509
510 usbHidLinkDone(pThis, pUrb);
511 return VINF_SUCCESS;
512}
513
514
515/**
516 * Completes the URB with a OK state.
517 */
518static int usbHidCompleteOk(PUSBHID pThis, PVUSBURB pUrb, size_t cbData)
519{
520 Log(("usbHidCompleteOk/#%u: pUrb=%p:%s cbData=%#zx\n", pThis->pUsbIns->iInstance, pUrb, pUrb->pszDesc, cbData));
521
522 pUrb->enmStatus = VUSBSTATUS_OK;
523 pUrb->cbData = (uint32_t)cbData;
524
525 usbHidLinkDone(pThis, pUrb);
526 return VINF_SUCCESS;
527}
528
529
530/**
531 * Reset worker for usbHidUsbReset, usbHidUsbSetConfiguration and
532 * usbHidHandleDefaultPipe.
533 *
534 * @returns VBox status code.
535 * @param pThis The HID instance.
536 * @param pUrb Set when usbHidHandleDefaultPipe is the
537 * caller.
538 * @param fSetConfig Set when usbHidUsbSetConfiguration is the
539 * caller.
540 */
541static int usbHidResetWorker(PUSBHID pThis, PVUSBURB pUrb, bool fSetConfig)
542{
543 /*
544 * Deactivate the keyboard.
545 */
546 pThis->Lun0.pDrv->pfnSetActive(pThis->Lun0.pDrv, false);
547
548 /*
549 * Reset the device state.
550 */
551 pThis->enmState = USBHIDREQSTATE_READY;
552 pThis->bIdle = 0;
553 pThis->fHasPendingChanges = false;
554
555 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
556 pThis->aEps[i].fHalted = false;
557
558 if (!pUrb && !fSetConfig) /* (only device reset) */
559 pThis->bConfigurationValue = 0; /* default */
560
561 /*
562 * Ditch all pending URBs.
563 */
564 PVUSBURB pCurUrb;
565 while ((pCurUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue)) != NULL)
566 {
567 pCurUrb->enmStatus = VUSBSTATUS_CRC;
568 usbHidLinkDone(pThis, pCurUrb);
569 }
570
571 if (pUrb)
572 return usbHidCompleteOk(pThis, pUrb, 0);
573 return VINF_SUCCESS;
574}
575
576/**
577 * Returns true if the usage code corresponds to a keyboard modifier key
578 * (left or right ctrl, shift, alt or GUI). The usage codes for these keys
579 * are the range 0xe0 to 0xe7.
580 */
581static bool usbHidUsageCodeIsModifier(uint8_t u8Usage)
582{
583 return u8Usage >= USBHID_MODIFIER_FIRST && u8Usage <= USBHID_MODIFIER_LAST;
584}
585
586/**
587 * Convert a USB HID usage code to a keyboard modifier flag. The arithmetic
588 * is simple: the modifier keys have usage codes from 0xe0 to 0xe7, and the
589 * lower nibble is the bit number of the flag.
590 */
591static uint8_t usbHidModifierToFlag(uint8_t u8Usage)
592{
593 Assert(usbHidUsageCodeIsModifier(u8Usage));
594 return RT_BIT(u8Usage & 0xf);
595}
596
597/**
598 * Create a USB HID keyboard report reflecting the current state of the
599 * keyboard (up/down keys).
600 */
601static void usbHidBuildReport(PUSBHIDK_REPORT pReport, uint8_t *pabDepressedKeys)
602{
603 unsigned iBuf = 0;
604 RT_ZERO(*pReport);
605 for (unsigned iKey = 0; iKey < VBOX_USB_USAGE_ARRAY_SIZE; ++iKey)
606 {
607 Assert(iBuf <= RT_ELEMENTS(pReport->aKeys));
608 if (pabDepressedKeys[iKey])
609 {
610 if (usbHidUsageCodeIsModifier(iKey))
611 pReport->ShiftState |= usbHidModifierToFlag(iKey);
612 else if (iBuf == RT_ELEMENTS(pReport->aKeys))
613 {
614 /* The USB HID spec says that the entire vector should be
615 * set to ErrorRollOver on overflow. We don't mind if this
616 * path is taken several times for one report. */
617 for (unsigned iBuf2 = 0;
618 iBuf2 < RT_ELEMENTS(pReport->aKeys); ++iBuf2)
619 pReport->aKeys[iBuf2] = USBHID_USAGE_ROLL_OVER;
620 }
621 else
622 {
623 pReport->aKeys[iBuf] = iKey;
624 ++iBuf;
625 }
626 }
627 }
628}
629
630/**
631 * Handles a SET_REPORT request sent to the default control pipe. Note
632 * that unrecognized requests are ignored without reporting an error.
633 */
634static void usbHidSetReport(PUSBHID pThis, PVUSBURB pUrb)
635{
636 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
637 Assert(pSetup->bRequest == HID_REQ_SET_REPORT);
638
639 /* The LED report is the 3rd report, ID 0 (-> wValue 0x200). */
640 if (pSetup->wIndex == 0 && pSetup->wLength == 1 && pSetup->wValue == 0x200)
641 {
642 PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE;
643 uint8_t u8LEDs = pUrb->abData[sizeof(*pSetup)];
644 LogFlowFunc(("Setting keybooard LEDs to u8LEDs=%02X\n", u8LEDs));
645
646 /* Translate LED state to PDM format and send upstream. */
647 if (u8LEDs & 0x01)
648 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
649 if (u8LEDs & 0x02)
650 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
651 if (u8LEDs & 0x04)
652 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
653
654 pThis->Lun0.pDrv->pfnLedStatusChange(pThis->Lun0.pDrv, enmLeds);
655 }
656}
657
658/**
659 * Sends a state report to the guest if there is a URB available.
660 */
661static void usbHidSendReport(PUSBHID pThis)
662{
663 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->ToHostQueue);
664 if (pUrb)
665 {
666 PUSBHIDK_REPORT pReport = (PUSBHIDK_REPORT)&pUrb->abData[0];
667
668 usbHidBuildReport(pReport, pThis->abDepressedKeys);
669 pThis->fHasPendingChanges = false;
670 usbHidCompleteOk(pThis, pUrb, sizeof(*pReport));
671 }
672 else
673 {
674 Log2(("No available URB for USB kbd\n"));
675 pThis->fHasPendingChanges = true;
676 }
677}
678
679/**
680 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
681 */
682static DECLCALLBACK(void *) usbHidKeyboardQueryInterface(PPDMIBASE pInterface, const char *pszIID)
683{
684 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IBase);
685 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
686 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDPORT, &pThis->Lun0.IPort);
687 return NULL;
688}
689
690/* See the PS2K device. */
691#define KRSP_BAT_FAIL 0xFC /* Also a 'release keys' signal. */
692
693/**
694 * Keyboard event handler.
695 *
696 * @returns VBox status code.
697 * @param pInterface Pointer to the keyboard port interface (KBDState::Keyboard.IPort).
698 * @param u32UsageCode The key usage ID.
699 */
700static DECLCALLBACK(int) usbHidKeyboardPutEvent(PPDMIKEYBOARDPORT pInterface, uint32_t u32UsageCode)
701{
702 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
703 uint8_t u8HidCode;
704 bool fKeyDown;
705 bool fHaveEvent = true;
706 int rc = VINF_SUCCESS;
707
708 RTCritSectEnter(&pThis->CritSect);
709
710 /* Let's see what we got... */
711 fKeyDown = !(u32UsageCode & 0x80000000);
712 u8HidCode = u32UsageCode & 0xFF;
713 AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
714
715 LogFlowFunc(("key %s: 0x%x\n", fKeyDown ? "down" : "up", u8HidCode));
716
717 /*
718 * Due to host key repeat, we can get key events for keys which are
719 * already depressed. Drop those right here.
720 */
721 if (fKeyDown && pThis->abDepressedKeys[u8HidCode])
722 fHaveEvent = false;
723
724 /* If there is already a pending event, we won't accept a new one yet. */
725 if (pThis->fHasPendingChanges && fHaveEvent)
726 {
727 rc = VERR_TRY_AGAIN;
728 }
729 else if (fHaveEvent)
730 {
731 if (RT_UNLIKELY(u32UsageCode == KRSP_BAT_FAIL))
732 {
733 /* Clear all currently depressed and unreported keys. */
734 RT_ZERO(pThis->abDepressedKeys);
735 }
736 else
737 {
738 /* Regular key event - update keyboard state. */
739 if (fKeyDown)
740 pThis->abDepressedKeys[u8HidCode] = 1;
741 else
742 pThis->abDepressedKeys[u8HidCode] = 0;
743 }
744
745 /*
746 * Try sending a report. Note that we already decided to consume the
747 * event regardless of whether a URB is available or not. If it's not,
748 * we will simply not accept any further events.
749 */
750 usbHidSendReport(pThis);
751 }
752
753 RTCritSectLeave(&pThis->CritSect);
754
755 return rc;
756}
757
758/**
759 * @copydoc PDMUSBREG::pfnUrbReap
760 */
761static DECLCALLBACK(PVUSBURB) usbHidUrbReap(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)
762{
763 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
764 //LogFlow(("usbHidUrbReap/#%u: cMillies=%u\n", pUsbIns->iInstance, cMillies));
765
766 RTCritSectEnter(&pThis->CritSect);
767
768 PVUSBURB pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
769 if (!pUrb && cMillies)
770 {
771 /* Wait */
772 pThis->fHaveDoneQueueWaiter = true;
773 RTCritSectLeave(&pThis->CritSect);
774
775 RTSemEventWait(pThis->hEvtDoneQueue, cMillies);
776
777 RTCritSectEnter(&pThis->CritSect);
778 pThis->fHaveDoneQueueWaiter = false;
779
780 pUrb = usbHidQueueRemoveHead(&pThis->DoneQueue);
781 }
782
783 RTCritSectLeave(&pThis->CritSect);
784
785 if (pUrb)
786 Log(("usbHidUrbReap/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
787 return pUrb;
788}
789
790
791/**
792 * @copydoc PDMUSBREG::pfnWakeup
793 */
794static DECLCALLBACK(int) usbHidWakeup(PPDMUSBINS pUsbIns)
795{
796 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
797
798 return RTSemEventSignal(pThis->hEvtDoneQueue);
799}
800
801
802/**
803 * @copydoc PDMUSBREG::pfnUrbCancel
804 */
805static DECLCALLBACK(int) usbHidUrbCancel(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
806{
807 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
808 LogFlow(("usbHidUrbCancel/#%u: pUrb=%p:%s\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc));
809 RTCritSectEnter(&pThis->CritSect);
810
811 /*
812 * Remove the URB from the to-host queue and move it onto the done queue.
813 */
814 if (usbHidQueueRemove(&pThis->ToHostQueue, pUrb))
815 usbHidLinkDone(pThis, pUrb);
816
817 RTCritSectLeave(&pThis->CritSect);
818 return VINF_SUCCESS;
819}
820
821
822/**
823 * Handles request sent to the inbound (device to host) interrupt pipe. This is
824 * rather different from bulk requests because an interrupt read URB may complete
825 * after arbitrarily long time.
826 */
827static int usbHidHandleIntrDevToHost(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
828{
829 /*
830 * Stall the request if the pipe is halted.
831 */
832 if (RT_UNLIKELY(pEp->fHalted))
833 return usbHidCompleteStall(pThis, NULL, pUrb, "Halted pipe");
834
835 /*
836 * Deal with the URB according to the state.
837 */
838 switch (pThis->enmState)
839 {
840 /*
841 * We've data left to transfer to the host.
842 */
843 case USBHIDREQSTATE_DATA_TO_HOST:
844 {
845 AssertFailed();
846 Log(("usbHidHandleIntrDevToHost: Entering STATUS\n"));
847 return usbHidCompleteOk(pThis, pUrb, 0);
848 }
849
850 /*
851 * Status transfer.
852 */
853 case USBHIDREQSTATE_STATUS:
854 {
855 AssertFailed();
856 Log(("usbHidHandleIntrDevToHost: Entering READY\n"));
857 pThis->enmState = USBHIDREQSTATE_READY;
858 return usbHidCompleteOk(pThis, pUrb, 0);
859 }
860
861 case USBHIDREQSTATE_READY:
862 usbHidQueueAddTail(&pThis->ToHostQueue, pUrb);
863 /* If device was not set idle, send the current report right away. */
864 if (pThis->bIdle != 0 || pThis->fHasPendingChanges)
865 {
866 usbHidSendReport(pThis);
867 LogFlow(("usbHidHandleIntrDevToHost: Sent report via %p:%s\n", pUrb, pUrb->pszDesc));
868 Assert(!pThis->fHasPendingChanges); /* Since we just got a URB... */
869 /* There may be more input queued up. Ask for it now. */
870 pThis->Lun0.pDrv->pfnFlushQueue(pThis->Lun0.pDrv);
871 }
872 return VINF_SUCCESS;
873
874 /*
875 * Bad states, stall.
876 */
877 default:
878 Log(("usbHidHandleIntrDevToHost: enmState=%d cbData=%#x\n", pThis->enmState, pUrb->cbData));
879 return usbHidCompleteStall(pThis, NULL, pUrb, "Really bad state (D2H)!");
880 }
881}
882
883
884/**
885 * Handles request sent to the default control pipe.
886 */
887static int usbHidHandleDefaultPipe(PUSBHID pThis, PUSBHIDEP pEp, PVUSBURB pUrb)
888{
889 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
890 LogFlow(("usbHidHandleDefaultPipe: cbData=%d\n", pUrb->cbData));
891
892 AssertReturn(pUrb->cbData >= sizeof(*pSetup), VERR_VUSB_FAILED_TO_QUEUE_URB);
893
894 if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_STANDARD)
895 {
896 switch (pSetup->bRequest)
897 {
898 case VUSB_REQ_GET_DESCRIPTOR:
899 {
900 switch (pSetup->bmRequestType)
901 {
902 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
903 {
904 switch (pSetup->wValue >> 8)
905 {
906 case VUSB_DT_STRING:
907 Log(("usbHid: GET_DESCRIPTOR DT_STRING wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
908 break;
909 default:
910 Log(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
911 break;
912 }
913 break;
914 }
915
916 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
917 {
918 switch (pSetup->wValue >> 8)
919 {
920 case DT_IF_HID_DESCRIPTOR:
921 {
922 uint32_t cbCopy;
923
924 /* Returned data is written after the setup message. */
925 cbCopy = pUrb->cbData - sizeof(*pSetup);
926 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbHidIfHidDesc));
927 Log(("usbHidKbd: GET_DESCRIPTOR DT_IF_HID_DESCRIPTOR wValue=%#x wIndex=%#x cbCopy=%#x\n", pSetup->wValue, pSetup->wIndex, cbCopy));
928 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbHidIfHidDesc, cbCopy);
929 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
930 }
931
932 case DT_IF_HID_REPORT:
933 {
934 uint32_t cbCopy;
935
936 /* Returned data is written after the setup message. */
937 cbCopy = pUrb->cbData - sizeof(*pSetup);
938 cbCopy = RT_MIN(cbCopy, sizeof(g_UsbHidReportDesc));
939 Log(("usbHid: GET_DESCRIPTOR DT_IF_HID_REPORT wValue=%#x wIndex=%#x cbCopy=%#x\n", pSetup->wValue, pSetup->wIndex, cbCopy));
940 memcpy(&pUrb->abData[sizeof(*pSetup)], &g_UsbHidReportDesc, cbCopy);
941 return usbHidCompleteOk(pThis, pUrb, cbCopy + sizeof(*pSetup));
942 }
943
944 default:
945 Log(("usbHid: GET_DESCRIPTOR, huh? wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
946 break;
947 }
948 break;
949 }
950
951 default:
952 Log(("usbHid: Bad GET_DESCRIPTOR req: bmRequestType=%#x\n", pSetup->bmRequestType));
953 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_DESCRIPTOR");
954 }
955 break;
956 }
957
958 case VUSB_REQ_GET_STATUS:
959 {
960 uint16_t wRet = 0;
961
962 if (pSetup->wLength != 2)
963 {
964 Log(("usbHid: Bad GET_STATUS req: wLength=%#x\n", pSetup->wLength));
965 break;
966 }
967 Assert(pSetup->wValue == 0);
968 switch (pSetup->bmRequestType)
969 {
970 case VUSB_TO_DEVICE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
971 {
972 Assert(pSetup->wIndex == 0);
973 Log(("usbHid: GET_STATUS (device)\n"));
974 wRet = 0; /* Not self-powered, no remote wakeup. */
975 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
976 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
977 }
978
979 case VUSB_TO_INTERFACE | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
980 {
981 if (pSetup->wIndex == 0)
982 {
983 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
984 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
985 }
986 else
987 {
988 Log(("usbHid: GET_STATUS (interface) invalid, wIndex=%#x\n", pSetup->wIndex));
989 }
990 break;
991 }
992
993 case VUSB_TO_ENDPOINT | VUSB_REQ_STANDARD | VUSB_DIR_TO_HOST:
994 {
995 if (pSetup->wIndex < RT_ELEMENTS(pThis->aEps))
996 {
997 wRet = pThis->aEps[pSetup->wIndex].fHalted ? 1 : 0;
998 memcpy(&pUrb->abData[sizeof(*pSetup)], &wRet, sizeof(wRet));
999 return usbHidCompleteOk(pThis, pUrb, sizeof(wRet) + sizeof(*pSetup));
1000 }
1001 else
1002 {
1003 Log(("usbHid: GET_STATUS (endpoint) invalid, wIndex=%#x\n", pSetup->wIndex));
1004 }
1005 break;
1006 }
1007
1008 default:
1009 Log(("usbHid: Bad GET_STATUS req: bmRequestType=%#x\n", pSetup->bmRequestType));
1010 return usbHidCompleteStall(pThis, pEp, pUrb, "Bad GET_STATUS");
1011 }
1012 break;
1013 }
1014
1015 case VUSB_REQ_CLEAR_FEATURE:
1016 break;
1017 }
1018
1019 /** @todo implement this. */
1020 Log(("usbHid: Implement standard request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1021 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1022
1023 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: standard request stuff");
1024 }
1025 else if ((pSetup->bmRequestType & VUSB_REQ_MASK) == VUSB_REQ_CLASS)
1026 {
1027 switch (pSetup->bRequest)
1028 {
1029 case HID_REQ_SET_IDLE:
1030 {
1031 switch (pSetup->bmRequestType)
1032 {
1033 case VUSB_TO_INTERFACE | VUSB_REQ_CLASS | VUSB_DIR_TO_DEVICE:
1034 {
1035 Log(("usbHid: SET_IDLE wValue=%#x wIndex=%#x\n", pSetup->wValue, pSetup->wIndex));
1036 pThis->bIdle = pSetup->wValue >> 8;
1037 /* Consider 24ms to mean zero for keyboards (see IOUSBHIDDriver) */
1038 if (pThis->bIdle == 6) pThis->bIdle = 0;
1039 return usbHidCompleteOk(pThis, pUrb, 0);
1040 }
1041 break;
1042 }
1043 break;
1044 }
1045 case HID_REQ_GET_IDLE:
1046 {
1047 switch (pSetup->bmRequestType)
1048 {
1049 case VUSB_TO_INTERFACE | VUSB_REQ_CLASS | VUSB_DIR_TO_HOST:
1050 {
1051 Log(("usbHid: GET_IDLE wValue=%#x wIndex=%#x, returning %#x\n", pSetup->wValue, pSetup->wIndex, pThis->bIdle));
1052 pUrb->abData[sizeof(*pSetup)] = pThis->bIdle;
1053 return usbHidCompleteOk(pThis, pUrb, 1);
1054 }
1055 break;
1056 }
1057 break;
1058 }
1059 case HID_REQ_SET_REPORT:
1060 {
1061 switch (pSetup->bmRequestType)
1062 {
1063 case VUSB_TO_INTERFACE | VUSB_REQ_CLASS | VUSB_DIR_TO_DEVICE:
1064 {
1065 Log(("usbHid: SET_REPORT wValue=%#x wIndex=%#x wLength=%#x\n", pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1066 usbHidSetReport(pThis, pUrb);
1067 return usbHidCompleteOk(pThis, pUrb, 0);
1068 }
1069 break;
1070 }
1071 break;
1072 }
1073 }
1074 Log(("usbHid: Unimplemented class request: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1075 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1076
1077 usbHidCompleteStall(pThis, pEp, pUrb, "TODO: class request stuff");
1078 }
1079 else
1080 {
1081 Log(("usbHid: Unknown control msg: bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
1082 pSetup->bmRequestType, pSetup->bRequest, pSetup->wValue, pSetup->wIndex, pSetup->wLength));
1083 return usbHidCompleteStall(pThis, pEp, pUrb, "Unknown control msg");
1084 }
1085
1086 return VINF_SUCCESS;
1087}
1088
1089
1090/**
1091 * @copydoc PDMUSBREG::pfnUrbQueue
1092 */
1093static DECLCALLBACK(int) usbHidQueue(PPDMUSBINS pUsbIns, PVUSBURB pUrb)
1094{
1095 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1096 LogFlow(("usbHidQueue/#%u: pUrb=%p:%s EndPt=%#x\n", pUsbIns->iInstance, pUrb, pUrb->pszDesc, pUrb->EndPt));
1097 RTCritSectEnter(&pThis->CritSect);
1098
1099 /*
1100 * Parse on a per end-point basis.
1101 */
1102 int rc;
1103 switch (pUrb->EndPt)
1104 {
1105 case 0:
1106 rc = usbHidHandleDefaultPipe(pThis, &pThis->aEps[0], pUrb);
1107 break;
1108
1109 case 0x81:
1110 AssertFailed();
1111 case 0x01:
1112 rc = usbHidHandleIntrDevToHost(pThis, &pThis->aEps[1], pUrb);
1113 break;
1114
1115 default:
1116 AssertMsgFailed(("EndPt=%d\n", pUrb->EndPt));
1117 rc = VERR_VUSB_FAILED_TO_QUEUE_URB;
1118 break;
1119 }
1120
1121 RTCritSectLeave(&pThis->CritSect);
1122 return rc;
1123}
1124
1125
1126/**
1127 * @copydoc PDMUSBREG::pfnUsbClearHaltedEndpoint
1128 */
1129static DECLCALLBACK(int) usbHidUsbClearHaltedEndpoint(PPDMUSBINS pUsbIns, unsigned uEndpoint)
1130{
1131 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1132 LogFlow(("usbHidUsbClearHaltedEndpoint/#%u: uEndpoint=%#x\n", pUsbIns->iInstance, uEndpoint));
1133
1134 if ((uEndpoint & ~0x80) < RT_ELEMENTS(pThis->aEps))
1135 {
1136 RTCritSectEnter(&pThis->CritSect);
1137 pThis->aEps[(uEndpoint & ~0x80)].fHalted = false;
1138 RTCritSectLeave(&pThis->CritSect);
1139 }
1140
1141 return VINF_SUCCESS;
1142}
1143
1144
1145/**
1146 * @copydoc PDMUSBREG::pfnUsbSetInterface
1147 */
1148static DECLCALLBACK(int) usbHidUsbSetInterface(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1149{
1150 LogFlow(("usbHidUsbSetInterface/#%u: bInterfaceNumber=%u bAlternateSetting=%u\n", pUsbIns->iInstance, bInterfaceNumber, bAlternateSetting));
1151 Assert(bAlternateSetting == 0);
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * @copydoc PDMUSBREG::pfnUsbSetConfiguration
1158 */
1159static DECLCALLBACK(int) usbHidUsbSetConfiguration(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue,
1160 const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)
1161{
1162 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1163 LogFlow(("usbHidUsbSetConfiguration/#%u: bConfigurationValue=%u\n", pUsbIns->iInstance, bConfigurationValue));
1164 Assert(bConfigurationValue == 1);
1165 RTCritSectEnter(&pThis->CritSect);
1166
1167 /*
1168 * If the same config is applied more than once, it's a kind of reset.
1169 */
1170 if (pThis->bConfigurationValue == bConfigurationValue)
1171 usbHidResetWorker(pThis, NULL, true /*fSetConfig*/); /** @todo figure out the exact difference */
1172 pThis->bConfigurationValue = bConfigurationValue;
1173
1174 /*
1175 * Tell the other end that the keyboard is now enabled and wants
1176 * to receive keystrokes.
1177 */
1178 pThis->Lun0.pDrv->pfnSetActive(pThis->Lun0.pDrv, true);
1179
1180 RTCritSectLeave(&pThis->CritSect);
1181 return VINF_SUCCESS;
1182}
1183
1184
1185/**
1186 * @copydoc PDMUSBREG::pfnUsbGetDescriptorCache
1187 */
1188static DECLCALLBACK(PCPDMUSBDESCCACHE) usbHidUsbGetDescriptorCache(PPDMUSBINS pUsbIns)
1189{
1190 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1191 LogFlow(("usbHidUsbGetDescriptorCache/#%u:\n", pUsbIns->iInstance));
1192 return &g_UsbHidDescCache;
1193}
1194
1195
1196/**
1197 * @copydoc PDMUSBREG::pfnUsbReset
1198 */
1199static DECLCALLBACK(int) usbHidUsbReset(PPDMUSBINS pUsbIns, bool fResetOnLinux)
1200{
1201 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1202 LogFlow(("usbHidUsbReset/#%u:\n", pUsbIns->iInstance));
1203 RTCritSectEnter(&pThis->CritSect);
1204
1205 int rc = usbHidResetWorker(pThis, NULL, false /*fSetConfig*/);
1206
1207 RTCritSectLeave(&pThis->CritSect);
1208 return rc;
1209}
1210
1211
1212/**
1213 * @copydoc PDMUSBREG::pfnDestruct
1214 */
1215static void usbHidDestruct(PPDMUSBINS pUsbIns)
1216{
1217 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1218 LogFlow(("usbHidDestruct/#%u:\n", pUsbIns->iInstance));
1219
1220 if (RTCritSectIsInitialized(&pThis->CritSect))
1221 {
1222 /* Let whoever runs in this critical section complete. */
1223 RTCritSectEnter(&pThis->CritSect);
1224 RTCritSectLeave(&pThis->CritSect);
1225 RTCritSectDelete(&pThis->CritSect);
1226 }
1227
1228 if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
1229 {
1230 RTSemEventDestroy(pThis->hEvtDoneQueue);
1231 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1232 }
1233}
1234
1235
1236/**
1237 * @copydoc PDMUSBREG::pfnConstruct
1238 */
1239static DECLCALLBACK(int) usbHidConstruct(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)
1240{
1241 PUSBHID pThis = PDMINS_2_DATA(pUsbIns, PUSBHID);
1242 Log(("usbHidConstruct/#%u:\n", iInstance));
1243
1244 /*
1245 * Perform the basic structure initialization first so the destructor
1246 * will not misbehave.
1247 */
1248 pThis->pUsbIns = pUsbIns;
1249 pThis->hEvtDoneQueue = NIL_RTSEMEVENT;
1250 usbHidQueueInit(&pThis->ToHostQueue);
1251 usbHidQueueInit(&pThis->DoneQueue);
1252
1253 int rc = RTCritSectInit(&pThis->CritSect);
1254 AssertRCReturn(rc, rc);
1255
1256 rc = RTSemEventCreate(&pThis->hEvtDoneQueue);
1257 AssertRCReturn(rc, rc);
1258
1259 /*
1260 * Validate and read the configuration.
1261 */
1262 rc = CFGMR3ValidateConfig(pCfg, "/", "", "", "UsbHid", iInstance);
1263 if (RT_FAILURE(rc))
1264 return rc;
1265
1266 pThis->Lun0.IBase.pfnQueryInterface = usbHidKeyboardQueryInterface;
1267 pThis->Lun0.IPort.pfnPutEventHid = usbHidKeyboardPutEvent;
1268
1269 /*
1270 * Attach the keyboard driver.
1271 */
1272 rc = PDMUsbHlpDriverAttach(pUsbIns, 0 /*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Keyboard Port");
1273 if (RT_FAILURE(rc))
1274 return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("HID failed to attach keyboard driver"));
1275
1276 pThis->Lun0.pDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIKEYBOARDCONNECTOR);
1277 if (!pThis->Lun0.pDrv)
1278 return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("HID failed to query keyboard interface"));
1279
1280 return VINF_SUCCESS;
1281}
1282
1283
1284/**
1285 * The USB Human Interface Device (HID) Keyboard registration record.
1286 */
1287const PDMUSBREG g_UsbHidKbd =
1288{
1289 /* u32Version */
1290 PDM_USBREG_VERSION,
1291 /* szName */
1292 "HidKeyboard",
1293 /* pszDescription */
1294 "USB HID Keyboard.",
1295 /* fFlags */
1296 0,
1297 /* cMaxInstances */
1298 ~0U,
1299 /* cbInstance */
1300 sizeof(USBHID),
1301 /* pfnConstruct */
1302 usbHidConstruct,
1303 /* pfnDestruct */
1304 usbHidDestruct,
1305 /* pfnVMInitComplete */
1306 NULL,
1307 /* pfnVMPowerOn */
1308 NULL,
1309 /* pfnVMReset */
1310 NULL,
1311 /* pfnVMSuspend */
1312 NULL,
1313 /* pfnVMResume */
1314 NULL,
1315 /* pfnVMPowerOff */
1316 NULL,
1317 /* pfnHotPlugged */
1318 NULL,
1319 /* pfnHotUnplugged */
1320 NULL,
1321 /* pfnDriverAttach */
1322 NULL,
1323 /* pfnDriverDetach */
1324 NULL,
1325 /* pfnQueryInterface */
1326 NULL,
1327 /* pfnUsbReset */
1328 usbHidUsbReset,
1329 /* pfnUsbGetDescriptorCache */
1330 usbHidUsbGetDescriptorCache,
1331 /* pfnUsbSetConfiguration */
1332 usbHidUsbSetConfiguration,
1333 /* pfnUsbSetInterface */
1334 usbHidUsbSetInterface,
1335 /* pfnUsbClearHaltedEndpoint */
1336 usbHidUsbClearHaltedEndpoint,
1337 /* pfnUrbNew */
1338 NULL/*usbHidUrbNew*/,
1339 /* pfnUrbQueue */
1340 usbHidQueue,
1341 /* pfnUrbCancel */
1342 usbHidUrbCancel,
1343 /* pfnUrbReap */
1344 usbHidUrbReap,
1345 /* pfnWakeup */
1346 usbHidWakeup,
1347 /* u32TheEnd */
1348 PDM_USBREG_VERSION
1349};
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