VirtualBox

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

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

PDM critsects for drivers. Fixed critsect cleanup in failure path. Started on new transmit locking scheme (required for intnet buffer serialization).

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