VirtualBox

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

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

scm cleaned up some whitespace.

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