VirtualBox

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

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

USB: Added a virtual USB mouse and keyboard. Not yet enabled.

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