VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp@ 29945

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

Route input to PS/2 keyboard unless USB keyboard was explicitly activated.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: DrvKeyboardQueue.cpp 28909 2010-04-29 16:34:17Z vboxsync $ */
2/** @file
3 * VBox input devices: Keyboard queue driver
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_KBD_QUEUE
23#include <VBox/pdmdrv.h>
24#include <iprt/assert.h>
25#include <iprt/uuid.h>
26
27#include "Builtins.h"
28
29
30
31/*******************************************************************************
32* Structures and Typedefs *
33*******************************************************************************/
34/**
35 * Keyboard queue driver instance data.
36 *
37 * @implements PDMIKEYBOARDCONNECTOR
38 * @implements PDMIKEYBOARDPORT
39 */
40typedef struct DRVKBDQUEUE
41{
42 /** Pointer to the driver instance structure. */
43 PPDMDRVINS pDrvIns;
44 /** Pointer to the keyboard port interface of the driver/device above us. */
45 PPDMIKEYBOARDPORT pUpPort;
46 /** Pointer to the keyboard port interface of the driver/device below us. */
47 PPDMIKEYBOARDCONNECTOR pDownConnector;
48 /** Our keyboard connector interface. */
49 PDMIKEYBOARDCONNECTOR IConnector;
50 /** Our keyboard port interface. */
51 PDMIKEYBOARDPORT IPort;
52 /** The queue handle. */
53 PPDMQUEUE pQueue;
54 /** Discard input when this flag is set.
55 * We only accept input when the VM is running. */
56 bool fInactive;
57} DRVKBDQUEUE, *PDRVKBDQUEUE;
58
59
60/**
61 * Keyboard queue item.
62 */
63typedef struct DRVKBDQUEUEITEM
64{
65 /** The core part owned by the queue manager. */
66 PDMQUEUEITEMCORE Core;
67 /** The keycode. */
68 uint8_t u8KeyCode;
69} DRVKBDQUEUEITEM, *PDRVKBDQUEUEITEM;
70
71
72
73/* -=-=-=-=- IBase -=-=-=-=- */
74
75/**
76 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
77 */
78static DECLCALLBACK(void *) drvKbdQueueQueryInterface(PPDMIBASE pInterface, const char *pszIID)
79{
80 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
81 PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
82
83 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
84 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDCONNECTOR, &pThis->IConnector);
85 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIKEYBOARDPORT, &pThis->IPort);
86 return NULL;
87}
88
89
90/* -=-=-=-=- IKeyboardPort -=-=-=-=- */
91
92/** Converts a pointer to DRVKBDQUEUE::IPort to a DRVKBDQUEUE pointer. */
93#define IKEYBOARDPORT_2_DRVKBDQUEUE(pInterface) ( (PDRVKBDQUEUE)((char *)(pInterface) - RT_OFFSETOF(DRVKBDQUEUE, IPort)) )
94
95
96/**
97 * Queues a keyboard event.
98 * Because of the event queueing the EMT context requirement is lifted.
99 *
100 * @returns VBox status code.
101 * @param pInterface Pointer to this interface structure.
102 * @param u8KeyCode The keycode to queue.
103 * @thread Any thread.
104 */
105static DECLCALLBACK(int) drvKbdQueuePutEvent(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)
106{
107 PDRVKBDQUEUE pDrv = IKEYBOARDPORT_2_DRVKBDQUEUE(pInterface);
108 if (pDrv->fInactive)
109 return VINF_SUCCESS;
110
111 PDRVKBDQUEUEITEM pItem = (PDRVKBDQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
112 if (pItem)
113 {
114 pItem->u8KeyCode = u8KeyCode;
115 PDMQueueInsert(pDrv->pQueue, &pItem->Core);
116 return VINF_SUCCESS;
117 }
118 AssertMsgFailed(("drvKbdQueuePutEvent: Queue is full!!!!\n"));
119 return VERR_PDM_NO_QUEUE_ITEMS;
120}
121
122
123/* -=-=-=-=- IConnector -=-=-=-=- */
124
125#define PPDMIKEYBOARDCONNECTOR_2_DRVKBDQUEUE(pInterface) ( (PDRVKBDQUEUE)((char *)(pInterface) - RT_OFFSETOF(DRVKBDQUEUE, IConnector)) )
126
127
128/**
129 * Pass LED status changes from the guest thru to the frontent driver.
130 *
131 * @param pInterface Pointer to the keyboard connector interface structure.
132 * @param enmLeds The new LED mask.
133 */
134static DECLCALLBACK(void) drvKbdPassThruLedsChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)
135{
136 PDRVKBDQUEUE pDrv = PPDMIKEYBOARDCONNECTOR_2_DRVKBDQUEUE(pInterface);
137 pDrv->pDownConnector->pfnLedStatusChange(pDrv->pDownConnector, enmLeds);
138}
139
140/**
141 * Pass keyboard state changes from the guest thru to the frontent driver.
142 *
143 * @param pInterface Pointer to the keyboard connector interface structure.
144 * @param fActive The new active/inactive state.
145 */
146static DECLCALLBACK(void) drvKbdPassThruSetActive(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)
147{
148 PDRVKBDQUEUE pDrv = PPDMIKEYBOARDCONNECTOR_2_DRVKBDQUEUE(pInterface);
149 pDrv->pDownConnector->pfnSetActive(pDrv->pDownConnector, fActive);
150}
151
152
153/* -=-=-=-=- queue -=-=-=-=- */
154
155/**
156 * Queue callback for processing a queued item.
157 *
158 * @returns Success indicator.
159 * If false the item will not be removed and the flushing will stop.
160 * @param pDrvIns The driver instance.
161 * @param pItemCore Pointer to the queue item to process.
162 */
163static DECLCALLBACK(bool) drvKbdQueueConsumer(PPDMDRVINS pDrvIns, PPDMQUEUEITEMCORE pItemCore)
164{
165 PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
166 PDRVKBDQUEUEITEM pItem = (PDRVKBDQUEUEITEM)pItemCore;
167 int rc = pThis->pUpPort->pfnPutEvent(pThis->pUpPort, pItem->u8KeyCode);
168 return RT_SUCCESS(rc);
169}
170
171
172/* -=-=-=-=- driver interface -=-=-=-=- */
173
174/**
175 * Power On notification.
176 *
177 * @returns VBox status.
178 * @param pDrvIns The drive instance data.
179 */
180static DECLCALLBACK(void) drvKbdQueuePowerOn(PPDMDRVINS pDrvIns)
181{
182 PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
183 pThis->fInactive = false;
184}
185
186
187/**
188 * Reset notification.
189 *
190 * @returns VBox status.
191 * @param pDrvIns The drive instance data.
192 */
193static DECLCALLBACK(void) drvKbdQueueReset(PPDMDRVINS pDrvIns)
194{
195 //PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
196 /** @todo purge the queue on reset. */
197}
198
199
200/**
201 * Suspend notification.
202 *
203 * @returns VBox status.
204 * @param pDrvIns The drive instance data.
205 */
206static DECLCALLBACK(void) drvKbdQueueSuspend(PPDMDRVINS pDrvIns)
207{
208 PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
209 pThis->fInactive = true;
210}
211
212
213/**
214 * Resume notification.
215 *
216 * @returns VBox status.
217 * @param pDrvIns The drive instance data.
218 */
219static DECLCALLBACK(void) drvKbdQueueResume(PPDMDRVINS pDrvIns)
220{
221 PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
222 pThis->fInactive = false;
223}
224
225
226/**
227 * Power Off notification.
228 *
229 * @param pDrvIns The drive instance data.
230 */
231static DECLCALLBACK(void) drvKbdQueuePowerOff(PPDMDRVINS pDrvIns)
232{
233 PDRVKBDQUEUE pThis = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
234 pThis->fInactive = true;
235}
236
237
238/**
239 * Construct a keyboard driver instance.
240 *
241 * @copydoc FNPDMDRVCONSTRUCT
242 */
243static DECLCALLBACK(int) drvKbdQueueConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
244{
245 PDRVKBDQUEUE pDrv = PDMINS_2_DATA(pDrvIns, PDRVKBDQUEUE);
246 LogFlow(("drvKbdQueueConstruct: iInstance=%d\n", pDrvIns->iInstance));
247 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
248
249 /*
250 * Validate configuration.
251 */
252 if (!CFGMR3AreValuesValid(pCfg, "QueueSize\0Interval\0"))
253 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
254
255 /*
256 * Init basic data members and interfaces.
257 */
258 pDrv->fInactive = true;
259 /* IBase. */
260 pDrvIns->IBase.pfnQueryInterface = drvKbdQueueQueryInterface;
261 /* IKeyboardConnector. */
262 pDrv->IConnector.pfnLedStatusChange = drvKbdPassThruLedsChange;
263 pDrv->IConnector.pfnSetActive = drvKbdPassThruSetActive;
264 /* IKeyboardPort. */
265 pDrv->IPort.pfnPutEvent = drvKbdQueuePutEvent;
266
267 /*
268 * Get the IKeyboardPort interface of the above driver/device.
269 */
270 pDrv->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIKEYBOARDPORT);
271 if (!pDrv->pUpPort)
272 {
273 AssertMsgFailed(("Configuration error: No keyboard port interface above!\n"));
274 return VERR_PDM_MISSING_INTERFACE_ABOVE;
275 }
276
277 /*
278 * Attach driver below and query it's connector interface.
279 */
280 PPDMIBASE pDownBase;
281 int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pDownBase);
282 if (RT_FAILURE(rc))
283 {
284 AssertMsgFailed(("Failed to attach driver below us! rc=%Rra\n", rc));
285 return rc;
286 }
287 pDrv->pDownConnector = PDMIBASE_QUERY_INTERFACE(pDownBase, PDMIKEYBOARDCONNECTOR);
288 if (!pDrv->pDownConnector)
289 {
290 AssertMsgFailed(("Configuration error: No keyboard connector interface below!\n"));
291 return VERR_PDM_MISSING_INTERFACE_BELOW;
292 }
293
294 /*
295 * Create the queue.
296 */
297 uint32_t cMilliesInterval = 0;
298 rc = CFGMR3QueryU32(pCfg, "Interval", &cMilliesInterval);
299 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
300 cMilliesInterval = 0;
301 else if (RT_FAILURE(rc))
302 {
303 AssertMsgFailed(("Configuration error: 32-bit \"Interval\" -> rc=%Rrc\n", rc));
304 return rc;
305 }
306
307 uint32_t cItems = 0;
308 rc = CFGMR3QueryU32(pCfg, "QueueSize", &cItems);
309 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
310 cItems = 128;
311 else if (RT_FAILURE(rc))
312 {
313 AssertMsgFailed(("Configuration error: 32-bit \"QueueSize\" -> rc=%Rrc\n", rc));
314 return rc;
315 }
316
317 rc = PDMDrvHlpQueueCreate(pDrvIns, sizeof(DRVKBDQUEUEITEM), cItems, cMilliesInterval, drvKbdQueueConsumer, "Keyboard", &pDrv->pQueue);
318 if (RT_FAILURE(rc))
319 {
320 AssertMsgFailed(("Failed to create driver: cItems=%d cMilliesInterval=%d rc=%Rrc\n", cItems, cMilliesInterval, rc));
321 return rc;
322 }
323
324 return VINF_SUCCESS;
325}
326
327
328/**
329 * Keyboard queue driver registration record.
330 */
331const PDMDRVREG g_DrvKeyboardQueue =
332{
333 /* u32Version */
334 PDM_DRVREG_VERSION,
335 /* szName */
336 "KeyboardQueue",
337 /* szRCMod */
338 "",
339 /* szR0Mod */
340 "",
341 /* pszDescription */
342 "Keyboard queue driver to plug in between the key source and the device to do queueing and inter-thread transport.",
343 /* fFlags */
344 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
345 /* fClass. */
346 PDM_DRVREG_CLASS_KEYBOARD,
347 /* cMaxInstances */
348 ~0,
349 /* cbInstance */
350 sizeof(DRVKBDQUEUE),
351 /* pfnConstruct */
352 drvKbdQueueConstruct,
353 /* pfnRelocate */
354 NULL,
355 /* pfnDestruct */
356 NULL,
357 /* pfnIOCtl */
358 NULL,
359 /* pfnPowerOn */
360 drvKbdQueuePowerOn,
361 /* pfnReset */
362 drvKbdQueueReset,
363 /* pfnSuspend */
364 drvKbdQueueSuspend,
365 /* pfnResume */
366 drvKbdQueueResume,
367 /* pfnAttach */
368 NULL,
369 /* pfnDetach */
370 NULL,
371 /* pfnPowerOff */
372 drvKbdQueuePowerOff,
373 /* pfnSoftReset */
374 NULL,
375 /* u32EndVersion */
376 PDM_DRVREG_VERSION
377};
378
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