VirtualBox

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

Last change on this file since 7558 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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