VirtualBox

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

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

OSE header fixes

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