VirtualBox

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

Last change on this file since 27838 was 27838, checked in by vboxsync, 15 years ago

USB keyboard: avoid loosing keypresses due to missed URBs

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