VirtualBox

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

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

Keyboard: Reworked the release-all-keys mechanism, made sure it's used before switching active keyboard, avoided potential mix-ups when tracking depressed keys (see bugref:10045).

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