VirtualBox

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

Last change on this file since 49469 was 49451, checked in by vboxsync, 11 years ago

DrvKeyboardQueue: activate on resume (from saved state).

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