VirtualBox

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

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

USB keyboard: state machine refinements, locking, Caps Lock scancode bug

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

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