~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/Main/KeyboardImpl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 *
 
3
 * VirtualBox COM class implementation
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2007 innotek GmbH
 
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 as published by the Free Software Foundation,
 
13
 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
 
14
 * distribution. VirtualBox OSE is distributed in the hope that it will
 
15
 * be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
#include "KeyboardImpl.h"
 
19
#include "ConsoleImpl.h"
 
20
 
 
21
#include "Logging.h"
 
22
 
 
23
#include <VBox/pdmdrv.h>
 
24
#include <iprt/asm.h>
 
25
 
 
26
// defines
 
27
////////////////////////////////////////////////////////////////////////////////
 
28
 
 
29
// globals
 
30
////////////////////////////////////////////////////////////////////////////////
 
31
 
 
32
/**
 
33
 * Keyboard driver instance data.
 
34
 */
 
35
typedef struct DRVMAINKEYBOARD
 
36
{
 
37
    /** Pointer to the keyboard object. */
 
38
    Keyboard                   *pKeyboard;
 
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
    /** Our mouse connector interface. */
 
44
    PDMIKEYBOARDCONNECTOR       Connector;
 
45
} DRVMAINKEYBOARD, *PDRVMAINKEYBOARD;
 
46
 
 
47
/** Converts PDMIVMMDEVCONNECTOR pointer to a DRVMAINVMMDEV pointer. */
 
48
#define PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface) ( (PDRVMAINKEYBOARD) ((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINKEYBOARD, Connector)) )
 
49
 
 
50
 
 
51
// constructor / destructor
 
52
////////////////////////////////////////////////////////////////////////////////
 
53
 
 
54
HRESULT Keyboard::FinalConstruct()
 
55
{
 
56
    mParent = NULL;
 
57
    mpDrv = NULL;
 
58
    mpVMMDev = NULL;
 
59
    mfVMMDevInited = false;
 
60
    return S_OK;
 
61
}
 
62
 
 
63
void Keyboard::FinalRelease()
 
64
{
 
65
    if (isReady())
 
66
        uninit();
 
67
}
 
68
 
 
69
// public methods
 
70
////////////////////////////////////////////////////////////////////////////////
 
71
 
 
72
/**
 
73
 * Initializes the keyboard object.
 
74
 *
 
75
 * @returns COM result indicator
 
76
 * @param parent handle of our parent object
 
77
 */
 
78
HRESULT Keyboard::init (Console *parent)
 
79
{
 
80
    LogFlow(("Keyboard::init(): isReady=%d\n", isReady()));
 
81
 
 
82
    ComAssertRet (parent, E_INVALIDARG);
 
83
 
 
84
    AutoLock alock (this);
 
85
    ComAssertRet (!isReady(), E_UNEXPECTED);
 
86
 
 
87
    mParent = parent;
 
88
 
 
89
    setReady (true);
 
90
    return S_OK;
 
91
}
 
92
 
 
93
/**
 
94
 *  Uninitializes the instance and sets the ready flag to FALSE.
 
95
 *  Called either from FinalRelease() or by the parent when it gets destroyed.
 
96
 */
 
97
void Keyboard::uninit()
 
98
{
 
99
    LogFlow(("Keyboard::uninit(): isReady=%d\n", isReady()));
 
100
 
 
101
    AutoLock alock (this);
 
102
    AssertReturn (isReady(), (void) 0);
 
103
 
 
104
    if (mpDrv)
 
105
        mpDrv->pKeyboard = NULL;
 
106
    mpDrv = NULL;
 
107
    mpVMMDev = NULL;
 
108
    mfVMMDevInited = true;
 
109
 
 
110
    setReady (false);
 
111
}
 
112
 
 
113
/**
 
114
 * Sends a scancode to the keyboard.
 
115
 *
 
116
 * @returns COM status code
 
117
 * @param scancode The scancode to send
 
118
 */
 
119
STDMETHODIMP Keyboard::PutScancode(LONG scancode)
 
120
{
 
121
    AutoLock alock (this);
 
122
    CHECK_READY();
 
123
 
 
124
    CHECK_CONSOLE_DRV (mpDrv);
 
125
 
 
126
    int rcVBox = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, (uint8_t)scancode);
 
127
 
 
128
    if (VBOX_FAILURE (rcVBox))
 
129
        return setError (E_FAIL,
 
130
            tr ("Could not send scan code 0x%08X to the virtual keyboard (%Vrc)"),
 
131
                scancode, rcVBox);
 
132
 
 
133
    return S_OK;
 
134
}
 
135
 
 
136
/**
 
137
 * Sends a list of scancodes to the keyboard.
 
138
 *
 
139
 * @returns COM status code
 
140
 * @param scancodes   Pointer to the first scancode
 
141
 * @param count       Number of scancodes
 
142
 * @param codesStored Address of variable to store the number
 
143
 *                    of scancodes that were sent to the keyboard.
 
144
                      This value can be NULL.
 
145
 */
 
146
STDMETHODIMP Keyboard::PutScancodes(LONG *scancodes,
 
147
                                    ULONG count,
 
148
                                    ULONG *codesStored)
 
149
{
 
150
    if (!scancodes)
 
151
        return E_INVALIDARG;
 
152
 
 
153
    AutoLock alock (this);
 
154
    CHECK_READY();
 
155
 
 
156
    CHECK_CONSOLE_DRV (mpDrv);
 
157
 
 
158
    LONG *currentScancode = scancodes;
 
159
    int rcVBox = VINF_SUCCESS;
 
160
 
 
161
    for (uint32_t i = 0; (i < count) && VBOX_SUCCESS(rcVBox); i++, currentScancode++)
 
162
    {
 
163
        rcVBox = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, *(uint8_t*)currentScancode);
 
164
    }
 
165
 
 
166
    if (VBOX_FAILURE (rcVBox))
 
167
        return setError (E_FAIL,
 
168
            tr ("Could not send all scan codes to the virtual keyboard (%Vrc)"), rcVBox);
 
169
 
 
170
    /// @todo is it actually possible that not all scancodes can be transmitted?
 
171
    if (codesStored)
 
172
        *codesStored = count;
 
173
 
 
174
    return S_OK;
 
175
}
 
176
 
 
177
/**
 
178
 * Sends Control-Alt-Delete to the keyboard. This could be done otherwise
 
179
 * but it's so common that we'll be nice and supply a convenience API.
 
180
 *
 
181
 * @returns COM status code
 
182
 *
 
183
 */
 
184
STDMETHODIMP Keyboard::PutCAD()
 
185
{
 
186
    static LONG cadSequence[] = {
 
187
        0x1d, // Ctrl down
 
188
        0x38, // Alt down
 
189
        0x53, // Del down
 
190
        0xd3, // Del up
 
191
        0xb8, // Alt up
 
192
        0x9d  // Ctrl up
 
193
    };
 
194
 
 
195
    return PutScancodes (cadSequence, ELEMENTS (cadSequence), NULL);
 
196
}
 
197
 
 
198
//
 
199
// private methods
 
200
//
 
201
 
 
202
/**
 
203
 * Queries an interface to the driver.
 
204
 *
 
205
 * @returns Pointer to interface.
 
206
 * @returns NULL if the interface was not supported by the driver.
 
207
 * @param   pInterface          Pointer to this interface structure.
 
208
 * @param   enmInterface        The requested interface identification.
 
209
 */
 
210
DECLCALLBACK(void *)  Keyboard::drvQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
 
211
{
 
212
    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
 
213
    PDRVMAINKEYBOARD pDrv = PDMINS2DATA(pDrvIns, PDRVMAINKEYBOARD);
 
214
    switch (enmInterface)
 
215
    {
 
216
        case PDMINTERFACE_BASE:
 
217
            return &pDrvIns->IBase;
 
218
        case PDMINTERFACE_KEYBOARD_CONNECTOR:
 
219
            return &pDrv->Connector;
 
220
        default:
 
221
            return NULL;
 
222
    }
 
223
}
 
224
 
 
225
 
 
226
/**
 
227
 * Destruct a keyboard driver instance.
 
228
 *
 
229
 * @returns VBox status.
 
230
 * @param   pDrvIns     The driver instance data.
 
231
 */
 
232
DECLCALLBACK(void) Keyboard::drvDestruct(PPDMDRVINS pDrvIns)
 
233
{
 
234
    PDRVMAINKEYBOARD pData = PDMINS2DATA(pDrvIns, PDRVMAINKEYBOARD);
 
235
    LogFlow(("Keyboard::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
 
236
    if (pData->pKeyboard)
 
237
    {
 
238
        AutoLock kbdLock (pData->pKeyboard);
 
239
        pData->pKeyboard->mpDrv = NULL;
 
240
        pData->pKeyboard->mpVMMDev = NULL;
 
241
    }
 
242
}
 
243
 
 
244
DECLCALLBACK(void) keyboardLedStatusChange(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)
 
245
{
 
246
    PDRVMAINKEYBOARD pDrv = PPDMIKEYBOARDCONNECTOR_2_MAINKEYBOARD(pInterface);
 
247
    pDrv->pKeyboard->getParent()->onKeyboardLedsChange(!!(enmLeds & PDMKEYBLEDS_NUMLOCK),
 
248
                                                       !!(enmLeds & PDMKEYBLEDS_CAPSLOCK),
 
249
                                                       !!(enmLeds & PDMKEYBLEDS_SCROLLLOCK));
 
250
}
 
251
 
 
252
/**
 
253
 * Construct a keyboard driver instance.
 
254
 *
 
255
 * @returns VBox status.
 
256
 * @param   pDrvIns     The driver instance data.
 
257
 *                      If the registration structure is needed, pDrvIns->pDrvReg points to it.
 
258
 * @param   pCfgHandle  Configuration node handle for the driver. Use this to obtain the configuration
 
259
 *                      of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
 
260
 *                      iInstance it's expected to be used a bit in this function.
 
261
 */
 
262
DECLCALLBACK(int) Keyboard::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
 
263
{
 
264
    PDRVMAINKEYBOARD pData = PDMINS2DATA(pDrvIns, PDRVMAINKEYBOARD);
 
265
    LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
 
266
 
 
267
    /*
 
268
     * Validate configuration.
 
269
     */
 
270
    if (!CFGMR3AreValuesValid(pCfgHandle, "Object\0"))
 
271
        return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
 
272
    PPDMIBASE pBaseIgnore;
 
273
    int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseIgnore);
 
274
    if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
 
275
    {
 
276
        AssertMsgFailed(("Configuration error: Not possible to attach anything to this driver!\n"));
 
277
        return VERR_PDM_DRVINS_NO_ATTACH;
 
278
    }
 
279
 
 
280
    /*
 
281
     * IBase.
 
282
     */
 
283
    pDrvIns->IBase.pfnQueryInterface        = Keyboard::drvQueryInterface;
 
284
 
 
285
    pData->Connector.pfnLedStatusChange     = keyboardLedStatusChange;
 
286
 
 
287
    /*
 
288
     * Get the IKeyboardPort interface of the above driver/device.
 
289
     */
 
290
    pData->pUpPort = (PPDMIKEYBOARDPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_KEYBOARD_PORT);
 
291
    if (!pData->pUpPort)
 
292
    {
 
293
        AssertMsgFailed(("Configuration error: No keyboard port interface above!\n"));
 
294
        return VERR_PDM_MISSING_INTERFACE_ABOVE;
 
295
    }
 
296
 
 
297
    /*
 
298
     * Get the Keyboard object pointer and update the mpDrv member.
 
299
     */
 
300
    void *pv;
 
301
    rc = CFGMR3QueryPtr(pCfgHandle, "Object", &pv);
 
302
    if (VBOX_FAILURE(rc))
 
303
    {
 
304
        AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Vrc\n", rc));
 
305
        return rc;
 
306
    }
 
307
    pData->pKeyboard = (Keyboard *)pv;        /** @todo Check this cast! */
 
308
    pData->pKeyboard->mpDrv = pData;
 
309
 
 
310
    return VINF_SUCCESS;
 
311
}
 
312
 
 
313
 
 
314
/**
 
315
 * Keyboard driver registration record.
 
316
 */
 
317
const PDMDRVREG Keyboard::DrvReg =
 
318
{
 
319
    /* u32Version */
 
320
    PDM_DRVREG_VERSION,
 
321
    /* szDriverName */
 
322
    "MainKeyboard",
 
323
    /* pszDescription */
 
324
    "Main keyboard driver (Main as in the API).",
 
325
    /* fFlags */
 
326
    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
 
327
    /* fClass. */
 
328
    PDM_DRVREG_CLASS_KEYBOARD,
 
329
    /* cMaxInstances */
 
330
    ~0,
 
331
    /* cbInstance */
 
332
    sizeof(DRVMAINKEYBOARD),
 
333
    /* pfnConstruct */
 
334
    Keyboard::drvConstruct,
 
335
    /* pfnDestruct */
 
336
    Keyboard::drvDestruct,
 
337
    /* pfnIOCtl */
 
338
    NULL,
 
339
    /* pfnPowerOn */
 
340
    NULL,
 
341
    /* pfnReset */
 
342
    NULL,
 
343
    /* pfnSuspend */
 
344
    NULL,
 
345
    /* pfnResume */
 
346
    NULL,
 
347
    /* pfnDetach */
 
348
    NULL
 
349
};