VirtualBox

source: vbox/trunk/src/VBox/Devices/Input/DevPS2.cpp@ 23875

Last change on this file since 23875 was 23690, checked in by vboxsync, 15 years ago

Devices/DevPS2: we only send an additional packet in ImEX mode, so don't wait forever for it to be sent in other modes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.4 KB
Line 
1/* $Id: DevPS2.cpp 23690 2009-10-12 13:16:43Z vboxsync $ */
2/** @file
3 * DevPS2 - PS/2 keyboard & mouse controller device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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 * This code is based on:
23 *
24 * QEMU PC keyboard emulation (revision 1.12)
25 *
26 * Copyright (c) 2003 Fabrice Bellard
27 *
28 * Permission is hereby granted, free of charge, to any person obtaining a copy
29 * of this software and associated documentation files (the "Software"), to deal
30 * in the Software without restriction, including without limitation the rights
31 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 * copies of the Software, and to permit persons to whom the Software is
33 * furnished to do so, subject to the following conditions:
34 *
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 * THE SOFTWARE.
45 *
46 */
47
48/*******************************************************************************
49* Header Files *
50*******************************************************************************/
51#define LOG_GROUP LOG_GROUP_DEV_KBD
52#include "vl_vbox.h"
53#include <VBox/pdmdev.h>
54#include <iprt/assert.h>
55
56#include "../Builtins.h"
57
58#define PCKBD_SAVED_STATE_VERSION 3
59
60
61#ifndef VBOX_DEVICE_STRUCT_TESTCASE
62/*******************************************************************************
63* Internal Functions *
64*******************************************************************************/
65RT_C_DECLS_BEGIN
66PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
67PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
68PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
69PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
70RT_C_DECLS_END
71#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
72
73/* debug PC keyboard */
74#define DEBUG_KBD
75
76/* debug PC keyboard : only mouse */
77#define DEBUG_MOUSE
78
79/* Keyboard Controller Commands */
80#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
81#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
82#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
83#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
84#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
85#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
86#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
87#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
88#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
89#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
90#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
91#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
92#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
93#define KBD_CCMD_WRITE_OBUF 0xD2
94#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
95 initiated by the auxiliary device */
96#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
97#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
98#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
99#define KBD_CCMD_READ_TSTINP 0xE0 /* Read test inputs T0, T1 */
100#define KBD_CCMD_RESET 0xFE
101
102/* Keyboard Commands */
103#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
104#define KBD_CMD_ECHO 0xEE
105#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
106#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
107#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
108#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
109#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
110#define KBD_CMD_RESET 0xFF /* Reset */
111
112/* Keyboard Replies */
113#define KBD_REPLY_POR 0xAA /* Power on reset */
114#define KBD_REPLY_ACK 0xFA /* Command ACK */
115#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
116
117/* Status Register Bits */
118#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
119#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
120#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
121#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
122#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
123#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
124#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
125#define KBD_STAT_PERR 0x80 /* Parity error */
126
127/* Controller Mode Register Bits */
128#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
129#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
130#define KBD_MODE_SYS 0x04 /* The system flag (?) */
131#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
132#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
133#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
134#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
135#define KBD_MODE_RFU 0x80
136
137/* Mouse Commands */
138#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
139#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
140#define AUX_SET_RES 0xE8 /* Set resolution */
141#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
142#define AUX_SET_STREAM 0xEA /* Set stream mode */
143#define AUX_POLL 0xEB /* Poll */
144#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
145#define AUX_SET_WRAP 0xEE /* Set wrap mode */
146#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
147#define AUX_GET_TYPE 0xF2 /* Get type */
148#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
149#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
150#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
151#define AUX_SET_DEFAULT 0xF6
152#define AUX_RESET 0xFF /* Reset aux device */
153#define AUX_ACK 0xFA /* Command byte ACK. */
154#define AUX_NACK 0xFE /* Command byte NACK. */
155
156#define MOUSE_STATUS_REMOTE 0x40
157#define MOUSE_STATUS_ENABLED 0x20
158#define MOUSE_STATUS_SCALE21 0x10
159
160#define KBD_QUEUE_SIZE 256
161
162# define MOUSE_REPORT_HORIZONTAL 0x01
163# define MOUSE_OUTSTANDING_CLICK 0x02
164
165typedef struct {
166 uint8_t data[KBD_QUEUE_SIZE];
167 int rptr, wptr, count;
168} KBDQueue;
169
170#define MOUSE_CMD_QUEUE_SIZE 8
171
172typedef struct {
173 uint8_t data[MOUSE_CMD_QUEUE_SIZE];
174 int rptr, wptr, count;
175} MouseCmdQueue;
176
177
178#define MOUSE_EVENT_QUEUE_SIZE 256
179
180typedef struct {
181 uint8_t data[MOUSE_EVENT_QUEUE_SIZE];
182 int rptr, wptr, count;
183} MouseEventQueue;
184
185typedef struct KBDState {
186 KBDQueue queue;
187 MouseCmdQueue mouse_command_queue;
188 MouseEventQueue mouse_event_queue;
189 uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
190 uint8_t status;
191 uint8_t mode;
192 /* keyboard state */
193 int32_t kbd_write_cmd;
194 int32_t scan_enabled;
195 /* mouse state */
196 int32_t mouse_write_cmd;
197 uint8_t mouse_status;
198 uint8_t mouse_resolution;
199 uint8_t mouse_sample_rate;
200 uint8_t mouse_wrap;
201 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
202 uint8_t mouse_detect_state;
203 int32_t mouse_dx; /* current values, needed for 'poll' mode */
204 int32_t mouse_dy;
205 int32_t mouse_dz;
206 int32_t mouse_dw;
207 int32_t mouse_flags;
208 uint8_t mouse_buttons;
209
210 /** Pointer to the device instance - RC. */
211 PPDMDEVINSRC pDevInsRC;
212 /** Pointer to the device instance - R3 . */
213 PPDMDEVINSR3 pDevInsR3;
214 /** Pointer to the device instance. */
215 PPDMDEVINSR0 pDevInsR0;
216 /** Critical section protecting the state. */
217 PDMCRITSECT CritSect;
218 /**
219 * Keyboard port - LUN#0.
220 */
221 struct
222 {
223 /** The base interface for the keyboard port. */
224 PDMIBASE Base;
225 /** The keyboard port base interface. */
226 PDMIKEYBOARDPORT Port;
227
228 /** The base interface of the attached keyboard driver. */
229 R3PTRTYPE(PPDMIBASE) pDrvBase;
230 /** The keyboard interface of the attached keyboard driver. */
231 R3PTRTYPE(PPDMIKEYBOARDCONNECTOR) pDrv;
232 } Keyboard;
233
234 /**
235 * Mouse port - LUN#1.
236 */
237 struct
238 {
239 /** The base interface for the mouse port. */
240 PDMIBASE Base;
241 /** The mouse port base interface. */
242 PDMIMOUSEPORT Port;
243
244 /** The base interface of the attached mouse driver. */
245 R3PTRTYPE(PPDMIBASE) pDrvBase;
246 /** The mouse interface of the attached mouse driver. */
247 R3PTRTYPE(PPDMIMOUSECONNECTOR) pDrv;
248 } Mouse;
249} KBDState;
250
251#ifndef VBOX_DEVICE_STRUCT_TESTCASE
252
253/* update irq and KBD_STAT_[MOUSE_]OBF */
254/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
255 incorrect, but it avoids having to simulate exact delays */
256static void kbd_update_irq(KBDState *s)
257{
258 KBDQueue *q = &s->queue;
259 MouseCmdQueue *mcq = &s->mouse_command_queue;
260 MouseEventQueue *meq = &s->mouse_event_queue;
261 int irq12_level, irq1_level;
262
263 irq1_level = 0;
264 irq12_level = 0;
265 s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
266 if (q->count != 0)
267 {
268 s->status |= KBD_STAT_OBF;
269 if ((s->mode & KBD_MODE_KBD_INT) && !(s->mode & KBD_MODE_DISABLE_KBD))
270 irq1_level = 1;
271 }
272 else if (mcq->count != 0 || meq->count != 0)
273 {
274 s->status |= KBD_STAT_OBF | KBD_STAT_MOUSE_OBF;
275 if (s->mode & KBD_MODE_MOUSE_INT)
276 irq12_level = 1;
277 }
278 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, irq1_level);
279 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, irq12_level);
280}
281
282static void kbd_queue(KBDState *s, int b, int aux)
283{
284 KBDQueue *q = &s->queue;
285 MouseCmdQueue *mcq = &s->mouse_command_queue;
286 MouseEventQueue *meq = &s->mouse_event_queue;
287
288#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
289 if (aux == 1)
290 LogRel3(("%s: mouse command response: 0x%02x\n", __PRETTY_FUNCTION__, b));
291 else if (aux == 2)
292 LogRel3(("%s: mouse event data: 0x%02x\n", __PRETTY_FUNCTION__, b));
293#ifdef DEBUG_KBD
294 else
295 LogRel3(("%s: kbd event: 0x%02x\n", __PRETTY_FUNCTION__, b));
296#endif
297#endif
298 switch (aux)
299 {
300 case 0: /* keyboard */
301 if (q->count >= KBD_QUEUE_SIZE)
302 return;
303 q->data[q->wptr] = b;
304 if (++q->wptr == KBD_QUEUE_SIZE)
305 q->wptr = 0;
306 q->count++;
307 break;
308 case 1: /* mouse command response */
309 if (mcq->count >= MOUSE_CMD_QUEUE_SIZE)
310 return;
311 mcq->data[mcq->wptr] = b;
312 if (++mcq->wptr == MOUSE_CMD_QUEUE_SIZE)
313 mcq->wptr = 0;
314 mcq->count++;
315 break;
316 case 2: /* mouse event data */
317 if (meq->count >= MOUSE_EVENT_QUEUE_SIZE)
318 return;
319 meq->data[meq->wptr] = b;
320 if (++meq->wptr == MOUSE_EVENT_QUEUE_SIZE)
321 meq->wptr = 0;
322 meq->count++;
323 break;
324 default:
325 AssertMsgFailed(("aux=%d\n", aux));
326 }
327 kbd_update_irq(s);
328}
329
330#ifdef IN_RING3
331static void pc_kbd_put_keycode(void *opaque, int keycode)
332{
333 KBDState *s = (KBDState*)opaque;
334 kbd_queue(s, keycode, 0);
335}
336#endif /* IN_RING3 */
337
338static uint32_t kbd_read_status(void *opaque, uint32_t addr)
339{
340 KBDState *s = (KBDState*)opaque;
341 int val;
342 val = s->status;
343#if defined(DEBUG_KBD)
344 Log(("kbd: read status=0x%02x\n", val));
345#endif
346 return val;
347}
348
349static int kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
350{
351 int rc = VINF_SUCCESS;
352 KBDState *s = (KBDState*)opaque;
353
354#ifdef DEBUG_KBD
355 Log(("kbd: write cmd=0x%02x\n", val));
356#endif
357 switch(val) {
358 case KBD_CCMD_READ_MODE:
359 kbd_queue(s, s->mode, 0);
360 break;
361 case KBD_CCMD_WRITE_MODE:
362 case KBD_CCMD_WRITE_OBUF:
363 case KBD_CCMD_WRITE_AUX_OBUF:
364 case KBD_CCMD_WRITE_MOUSE:
365 case KBD_CCMD_WRITE_OUTPORT:
366 s->write_cmd = val;
367 break;
368 case KBD_CCMD_MOUSE_DISABLE:
369 s->mode |= KBD_MODE_DISABLE_MOUSE;
370 break;
371 case KBD_CCMD_MOUSE_ENABLE:
372 s->mode &= ~KBD_MODE_DISABLE_MOUSE;
373 break;
374 case KBD_CCMD_TEST_MOUSE:
375 kbd_queue(s, 0x00, 0);
376 break;
377 case KBD_CCMD_SELF_TEST:
378 s->status |= KBD_STAT_SELFTEST;
379 kbd_queue(s, 0x55, 0);
380 break;
381 case KBD_CCMD_KBD_TEST:
382 kbd_queue(s, 0x00, 0);
383 break;
384 case KBD_CCMD_KBD_DISABLE:
385 s->mode |= KBD_MODE_DISABLE_KBD;
386 kbd_update_irq(s);
387 break;
388 case KBD_CCMD_KBD_ENABLE:
389 s->mode &= ~KBD_MODE_DISABLE_KBD;
390 kbd_update_irq(s);
391 break;
392 case KBD_CCMD_READ_INPORT:
393 kbd_queue(s, 0x00, 0);
394 break;
395 case KBD_CCMD_READ_OUTPORT:
396 /* XXX: check that */
397#ifdef TARGET_I386
398 val = 0x01 | (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) << 1);
399#else
400 val = 0x01;
401#endif
402 if (s->status & KBD_STAT_OBF)
403 val |= 0x10;
404 if (s->status & KBD_STAT_MOUSE_OBF)
405 val |= 0x20;
406 kbd_queue(s, val, 0);
407 break;
408#ifdef TARGET_I386
409 case KBD_CCMD_ENABLE_A20:
410# ifndef IN_RING3
411 if (!PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
412 rc = VINF_IOM_HC_IOPORT_WRITE;
413# else /* IN_RING3 */
414 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), true);
415# endif /* IN_RING3 */
416 break;
417 case KBD_CCMD_DISABLE_A20:
418# ifndef IN_RING3
419 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)))
420 rc = VINF_IOM_HC_IOPORT_WRITE;
421# else /* IN_RING3 */
422 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), false);
423# endif /* !IN_RING3 */
424 break;
425#endif
426 case KBD_CCMD_READ_TSTINP:
427 /* Keyboard clock line is zero IFF keyboard is disabled */
428 val = (s->mode & KBD_MODE_DISABLE_KBD) ? 0 : 1;
429 kbd_queue(s, val, 0);
430 break;
431 case KBD_CCMD_RESET:
432#ifndef IN_RING3
433 rc = VINF_IOM_HC_IOPORT_WRITE;
434#else /* IN_RING3 */
435 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
436#endif /* !IN_RING3 */
437 break;
438 case 0xff:
439 /* ignore that - I don't know what is its use */
440 break;
441 /* Make OS/2 happy. */
442 /* The 8042 RAM is readble using commands 0x20 thru 0x3f, and writable
443 by 0x60 thru 0x7f. Now days only the firs byte, the mode, is used.
444 We'll ignore the writes (0x61..7f) and return 0 for all the reads
445 just to make some OS/2 debug stuff a bit happier. */
446 case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
447 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
448 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
449 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
450 kbd_queue(s, 0, 0);
451 Log(("kbd: reading non-standard RAM addr %#x\n", val & 0x1f));
452 break;
453 default:
454 Log(("kbd: unsupported keyboard cmd=0x%02x\n", val));
455 break;
456 }
457 return rc;
458}
459
460static uint32_t kbd_read_data(void *opaque, uint32_t addr)
461{
462 KBDState *s = (KBDState*)opaque;
463 KBDQueue *q;
464 MouseCmdQueue *mcq;
465 MouseEventQueue *meq;
466 int val, index, aux;
467
468 q = &s->queue;
469 mcq = &s->mouse_command_queue;
470 meq = &s->mouse_event_queue;
471 if (q->count == 0 && mcq->count == 0 && meq->count == 0) {
472 /* NOTE: if no data left, we return the last keyboard one
473 (needed for EMM386) */
474 /* XXX: need a timer to do things correctly */
475 index = q->rptr - 1;
476 if (index < 0)
477 index = KBD_QUEUE_SIZE - 1;
478 val = q->data[index];
479 } else {
480 aux = (s->status & KBD_STAT_MOUSE_OBF);
481 if (!aux)
482 {
483 val = q->data[q->rptr];
484 if (++q->rptr == KBD_QUEUE_SIZE)
485 q->rptr = 0;
486 q->count--;
487 }
488 else
489 {
490 if (mcq->count)
491 {
492 val = mcq->data[mcq->rptr];
493 if (++mcq->rptr == MOUSE_CMD_QUEUE_SIZE)
494 mcq->rptr = 0;
495 mcq->count--;
496 }
497 else
498 {
499 val = meq->data[meq->rptr];
500 if (++meq->rptr == MOUSE_EVENT_QUEUE_SIZE)
501 meq->rptr = 0;
502 meq->count--;
503 }
504 }
505 /* reading deasserts IRQ */
506 if (aux)
507 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 12, 0);
508 else
509 PDMDevHlpISASetIrq(s->CTX_SUFF(pDevIns), 1, 0);
510 }
511 /* reassert IRQs if data left */
512 kbd_update_irq(s);
513#ifdef DEBUG_KBD
514 Log(("kbd: read data=0x%02x\n", val));
515#endif
516 return val;
517}
518
519static void kbd_reset_keyboard(KBDState *s)
520{
521 s->scan_enabled = 1;
522}
523
524static int kbd_write_keyboard(KBDState *s, int val)
525{
526 switch(s->kbd_write_cmd) {
527 default:
528 case -1:
529 switch(val) {
530 case 0x00:
531 kbd_queue(s, KBD_REPLY_ACK, 0);
532 break;
533 case 0x05:
534 kbd_queue(s, KBD_REPLY_RESEND, 0);
535 break;
536 case KBD_CMD_GET_ID:
537 kbd_queue(s, KBD_REPLY_ACK, 0);
538 kbd_queue(s, 0xab, 0);
539 kbd_queue(s, 0x83, 0);
540 break;
541 case KBD_CMD_ECHO:
542 kbd_queue(s, KBD_CMD_ECHO, 0);
543 break;
544 case KBD_CMD_ENABLE:
545 s->scan_enabled = 1;
546 kbd_queue(s, KBD_REPLY_ACK, 0);
547 break;
548 case KBD_CMD_SET_LEDS:
549 case KBD_CMD_SET_RATE:
550 s->kbd_write_cmd = val;
551 kbd_queue(s, KBD_REPLY_ACK, 0);
552 break;
553 case KBD_CMD_RESET_DISABLE:
554 kbd_reset_keyboard(s);
555 s->scan_enabled = 0;
556 kbd_queue(s, KBD_REPLY_ACK, 0);
557 break;
558 case KBD_CMD_RESET_ENABLE:
559 kbd_reset_keyboard(s);
560 s->scan_enabled = 1;
561 kbd_queue(s, KBD_REPLY_ACK, 0);
562 break;
563 case KBD_CMD_RESET:
564 kbd_reset_keyboard(s);
565 kbd_queue(s, KBD_REPLY_ACK, 0);
566 kbd_queue(s, KBD_REPLY_POR, 0);
567 break;
568 default:
569 kbd_queue(s, KBD_REPLY_ACK, 0);
570 break;
571 }
572 break;
573 case KBD_CMD_SET_LEDS:
574 {
575#ifdef IN_RING3
576 PDMKEYBLEDS enmLeds = PDMKEYBLEDS_NONE;
577 if (val & 0x01)
578 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_SCROLLLOCK);
579 if (val & 0x02)
580 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_NUMLOCK);
581 if (val & 0x04)
582 enmLeds = (PDMKEYBLEDS)(enmLeds | PDMKEYBLEDS_CAPSLOCK);
583 s->Keyboard.pDrv->pfnLedStatusChange(s->Keyboard.pDrv, enmLeds);
584#else
585 return VINF_IOM_HC_IOPORT_WRITE;
586#endif
587 kbd_queue(s, KBD_REPLY_ACK, 0);
588 s->kbd_write_cmd = -1;
589 }
590 break;
591 case KBD_CMD_SET_RATE:
592 kbd_queue(s, KBD_REPLY_ACK, 0);
593 s->kbd_write_cmd = -1;
594 break;
595 }
596
597 return VINF_SUCCESS;
598}
599
600static void kbd_mouse_send_packet(KBDState *s, bool fToCmdQueue)
601{
602 int aux = fToCmdQueue ? 1 : 2;
603 unsigned int b;
604 int dx1, dy1, dz1, dw1;
605
606 dx1 = s->mouse_dx;
607 dy1 = s->mouse_dy;
608 dz1 = s->mouse_dz;
609 dw1 = s->mouse_dw;
610 LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
611 dx1, dy1, dz1, dw1));
612 /* XXX: increase range to 8 bits ? */
613 if (dx1 > 127)
614 dx1 = 127;
615 else if (dx1 < -127)
616 dx1 = -127;
617 if (dy1 > 127)
618 dy1 = 127;
619 else if (dy1 < -127)
620 dy1 = -127;
621 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
622 kbd_queue(s, b, aux);
623 kbd_queue(s, dx1 & 0xff, aux);
624 kbd_queue(s, dy1 & 0xff, aux);
625 /* extra byte for IMPS/2 or IMEX */
626 switch(s->mouse_type) {
627 default:
628 break;
629 case 3:
630 if (dz1 > 127)
631 dz1 = 127;
632 else if (dz1 < -127)
633 dz1 = -127;
634 kbd_queue(s, dz1 & 0xff, aux);
635 break;
636 case 4:
637 if (dz1 > 1)
638 dz1 = 1;
639 else if (dz1 < -1)
640 dz1 = -1;
641 else if (dw1 > 1)
642 dw1 = 1;
643 else if (dw1 < -1)
644 dw1 = -1;
645 if (dz1)
646 dw1 = 0;
647 if ((s->mouse_flags & MOUSE_REPORT_HORIZONTAL) && dw1)
648 b = 0x40 | (dw1 & 0x3f);
649 else
650 {
651 b = (dz1 & 0x0f) | ((dw1 << 1) & 0x0f)
652 | ((s->mouse_buttons & 0x18) << 1);
653 s->mouse_flags &= ~MOUSE_OUTSTANDING_CLICK;
654 }
655 kbd_queue(s, b, aux);
656 break;
657 }
658
659 /* update deltas */
660 s->mouse_dx -= dx1;
661 s->mouse_dy -= dy1;
662 s->mouse_dz -= dz1;
663 s->mouse_dw -= dw1;
664}
665
666#ifdef IN_RING3
667static void pc_kbd_mouse_event(void *opaque,
668 int dx, int dy, int dz, int dw, int buttons_state)
669{
670 KBDState *s = (KBDState*)opaque;
671
672 /* check if deltas are recorded when disabled */
673 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
674 return;
675
676 s->mouse_dx += dx;
677 s->mouse_dy -= dy;
678 s->mouse_dz += dz;
679 s->mouse_dw += dw;
680 /* In horizontal reporting mode, we may need to send an additional packet
681 * for the forth and fifth buttons, as they can't share a packet with a
682 * horizontal scroll delta. */
683 if ( s->mouse_type == 4
684 && (s->mouse_buttons & 0x18) != (buttons_state & 0x18))
685 s->mouse_flags |= MOUSE_OUTSTANDING_CLICK;
686 s->mouse_buttons = buttons_state;
687
688 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
689 (s->mouse_event_queue.count < (MOUSE_EVENT_QUEUE_SIZE - 4))) {
690 for(;;) {
691 /* if not remote, send event. Multiple events are sent if
692 too big deltas */
693 kbd_mouse_send_packet(s, false);
694 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && s->mouse_dw == 0 && !(s->mouse_flags & MOUSE_OUTSTANDING_CLICK))
695 break;
696 }
697 }
698}
699#endif /* IN_RING3 */
700
701static void kbd_write_mouse(KBDState *s, int val)
702{
703#ifdef DEBUG_MOUSE
704 LogRelFlowFunc(("kbd: write mouse 0x%02x\n", val));
705#endif
706 /* Flush the mouse command response queue. */
707 s->mouse_command_queue.count = 0;
708 s->mouse_command_queue.rptr = 0;
709 s->mouse_command_queue.wptr = 0;
710 switch(s->mouse_write_cmd) {
711 default:
712 case -1:
713 /* mouse command */
714 if (s->mouse_wrap) {
715 if (val == AUX_RESET_WRAP) {
716 s->mouse_wrap = 0;
717 kbd_queue(s, AUX_ACK, 1);
718 return;
719 } else if (val != AUX_RESET) {
720 kbd_queue(s, val, 1);
721 return;
722 }
723 }
724 switch(val) {
725 case AUX_SET_SCALE11:
726 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
727 kbd_queue(s, AUX_ACK, 1);
728 break;
729 case AUX_SET_SCALE21:
730 s->mouse_status |= MOUSE_STATUS_SCALE21;
731 kbd_queue(s, AUX_ACK, 1);
732 break;
733 case AUX_SET_STREAM:
734 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
735 kbd_queue(s, AUX_ACK, 1);
736 break;
737 case AUX_SET_WRAP:
738 s->mouse_wrap = 1;
739 kbd_queue(s, AUX_ACK, 1);
740 break;
741 case AUX_SET_REMOTE:
742 s->mouse_status |= MOUSE_STATUS_REMOTE;
743 kbd_queue(s, AUX_ACK, 1);
744 break;
745 case AUX_GET_TYPE:
746 kbd_queue(s, AUX_ACK, 1);
747 kbd_queue(s, s->mouse_type, 1);
748 break;
749 case AUX_SET_RES:
750 case AUX_SET_SAMPLE:
751 s->mouse_write_cmd = val;
752 kbd_queue(s, AUX_ACK, 1);
753 break;
754 case AUX_GET_SCALE:
755 kbd_queue(s, AUX_ACK, 1);
756 kbd_queue(s, s->mouse_status, 1);
757 kbd_queue(s, s->mouse_resolution, 1);
758 kbd_queue(s, s->mouse_sample_rate, 1);
759 break;
760 case AUX_POLL:
761 kbd_queue(s, AUX_ACK, 1);
762 kbd_mouse_send_packet(s, true);
763 break;
764 case AUX_ENABLE_DEV:
765 s->mouse_status |= MOUSE_STATUS_ENABLED;
766 kbd_queue(s, AUX_ACK, 1);
767 break;
768 case AUX_DISABLE_DEV:
769 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
770 kbd_queue(s, AUX_ACK, 1);
771 /* Flush the mouse events queue. */
772 s->mouse_event_queue.count = 0;
773 s->mouse_event_queue.rptr = 0;
774 s->mouse_event_queue.wptr = 0;
775 break;
776 case AUX_SET_DEFAULT:
777 s->mouse_sample_rate = 100;
778 s->mouse_resolution = 2;
779 s->mouse_status = 0;
780 kbd_queue(s, AUX_ACK, 1);
781 break;
782 case AUX_RESET:
783 s->mouse_sample_rate = 100;
784 s->mouse_resolution = 2;
785 s->mouse_status = 0;
786 s->mouse_type = 0;
787 kbd_queue(s, AUX_ACK, 1);
788 kbd_queue(s, 0xaa, 1);
789 kbd_queue(s, s->mouse_type, 1);
790 /* Flush the mouse events queue. */
791 s->mouse_event_queue.count = 0;
792 s->mouse_event_queue.rptr = 0;
793 s->mouse_event_queue.wptr = 0;
794 break;
795 default:
796 /* NACK all commands we don't know.
797
798 The usecase for this is the OS/2 mouse driver which will try
799 read 0xE2 in order to figure out if it's a trackpoint device
800 or not. If it doesn't get a NACK (or ACK) on the command it'll
801 do several hundred thousand status reads before giving up. This
802 is slows down the OS/2 boot up considerably. (It also seems that
803 the code is somehow vulnerable while polling like this and that
804 mouse or keyboard input at this point might screw things up badly.)
805
806 From http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html:
807
808 Every command or data byte sent to the mouse (except for the
809 resend command fe) is ACKed with fa. If the command or data
810 is invalid, it is NACKed with fe. If the next byte is again
811 invalid, the reply is ERROR: fc. */
812 /** @todo send error if we NACKed the previous command? */
813 kbd_queue(s, AUX_NACK, 1);
814 break;
815 }
816 break;
817 case AUX_SET_SAMPLE:
818 s->mouse_sample_rate = val;
819 /* detect IMPS/2 or IMEX */
820 /* And enable horizontal scrolling reporting when requested */
821 switch(s->mouse_detect_state) {
822 default:
823 case 0:
824 if (val == 200)
825 s->mouse_detect_state = 1;
826 break;
827 case 1:
828 if (val == 100)
829 s->mouse_detect_state = 2;
830 else if (val == 200)
831 s->mouse_detect_state = 3;
832 else if ((val == 80) && s->mouse_type == 4 /* IMEX */)
833 /* enable horizontal scrolling, byte two */
834 s->mouse_detect_state = 4;
835 else
836 s->mouse_detect_state = 0;
837 break;
838 case 2:
839 if (val == 80)
840 {
841 LogRelFlowFunc(("switching mouse device to IMPS/2 mode\n"));
842 s->mouse_type = 3; /* IMPS/2 */
843 }
844 s->mouse_detect_state = 0;
845 break;
846 case 3:
847 if (val == 80)
848 {
849 LogRelFlowFunc(("switching mouse device to IMEX mode\n"));
850 s->mouse_type = 4; /* IMEX */
851 }
852 s->mouse_detect_state = 0;
853 break;
854 case 4:
855 if (val == 40)
856 {
857 LogFlowFunc(("enabling IMEX horizontal scrolling reporting\n"));
858 s->mouse_flags |= MOUSE_REPORT_HORIZONTAL;
859 }
860 s->mouse_detect_state = 0;
861 break;
862 }
863 kbd_queue(s, AUX_ACK, 1);
864 s->mouse_write_cmd = -1;
865 break;
866 case AUX_SET_RES:
867 s->mouse_resolution = val;
868 kbd_queue(s, AUX_ACK, 1);
869 s->mouse_write_cmd = -1;
870 break;
871 }
872}
873
874static int kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
875{
876 int rc = VINF_SUCCESS;
877 KBDState *s = (KBDState*)opaque;
878
879#ifdef DEBUG_KBD
880 Log(("kbd: write data=0x%02x\n", val));
881#endif
882
883 switch(s->write_cmd) {
884 case 0:
885 rc = kbd_write_keyboard(s, val);
886 break;
887 case KBD_CCMD_WRITE_MODE:
888 s->mode = val;
889 kbd_update_irq(s);
890 break;
891 case KBD_CCMD_WRITE_OBUF:
892 kbd_queue(s, val, 0);
893 break;
894 case KBD_CCMD_WRITE_AUX_OBUF:
895 kbd_queue(s, val, 1);
896 break;
897 case KBD_CCMD_WRITE_OUTPORT:
898#ifdef TARGET_I386
899# ifndef IN_RING3
900 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) != !!(val & 2))
901 rc = VINF_IOM_HC_IOPORT_WRITE;
902# else /* IN_RING3 */
903 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), !!(val & 2));
904# endif /* !IN_RING3 */
905#endif
906 if (!(val & 1)) {
907# ifndef IN_RING3
908 rc = VINF_IOM_HC_IOPORT_WRITE;
909# else
910 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
911# endif
912 }
913 break;
914 case KBD_CCMD_WRITE_MOUSE:
915 kbd_write_mouse(s, val);
916 break;
917 default:
918 break;
919 }
920 s->write_cmd = 0;
921 return rc;
922}
923
924#ifdef IN_RING3
925
926static void kbd_reset(void *opaque)
927{
928 KBDState *s = (KBDState*)opaque;
929 KBDQueue *q;
930 MouseCmdQueue *mcq;
931 MouseEventQueue *meq;
932
933 s->kbd_write_cmd = -1;
934 s->mouse_write_cmd = -1;
935 s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
936 s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
937 /* Resetting everything, keyword was not working right on NT4 reboot. */
938 s->write_cmd = 0;
939 s->scan_enabled = 0;
940 s->mouse_status = 0;
941 s->mouse_resolution = 0;
942 s->mouse_sample_rate = 0;
943 s->mouse_wrap = 0;
944 s->mouse_type = 0;
945 s->mouse_detect_state = 0;
946 s->mouse_dx = 0;
947 s->mouse_dy = 0;
948 s->mouse_dz = 0;
949 s->mouse_dw = 0;
950 s->mouse_flags = 0;
951 s->mouse_buttons = 0;
952 q = &s->queue;
953 q->rptr = 0;
954 q->wptr = 0;
955 q->count = 0;
956 mcq = &s->mouse_command_queue;
957 mcq->rptr = 0;
958 mcq->wptr = 0;
959 mcq->count = 0;
960 meq = &s->mouse_event_queue;
961 meq->rptr = 0;
962 meq->wptr = 0;
963 meq->count = 0;
964}
965
966static void kbd_save(QEMUFile* f, void* opaque)
967{
968 uint32_t cItems;
969 int i;
970 KBDState *s = (KBDState*)opaque;
971
972 qemu_put_8s(f, &s->write_cmd);
973 qemu_put_8s(f, &s->status);
974 qemu_put_8s(f, &s->mode);
975 qemu_put_be32s(f, &s->kbd_write_cmd);
976 qemu_put_be32s(f, &s->scan_enabled);
977 qemu_put_be32s(f, &s->mouse_write_cmd);
978 qemu_put_8s(f, &s->mouse_status);
979 qemu_put_8s(f, &s->mouse_resolution);
980 qemu_put_8s(f, &s->mouse_sample_rate);
981 qemu_put_8s(f, &s->mouse_wrap);
982 qemu_put_8s(f, &s->mouse_type);
983 qemu_put_8s(f, &s->mouse_detect_state);
984 qemu_put_be32s(f, &s->mouse_dx);
985 qemu_put_be32s(f, &s->mouse_dy);
986 qemu_put_be32s(f, &s->mouse_dz);
987 qemu_put_be32s(f, &s->mouse_dw);
988 qemu_put_be32s(f, &s->mouse_flags);
989 qemu_put_8s(f, &s->mouse_buttons);
990
991 /*
992 * We have to save the queues too.
993 */
994 cItems = s->queue.count;
995 SSMR3PutU32(f, cItems);
996 for (i = s->queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->queue.data))
997 SSMR3PutU8(f, s->queue.data[i]);
998 Log(("kbd_save: %d keyboard queue items stored\n", s->queue.count));
999
1000 cItems = s->mouse_command_queue.count;
1001 SSMR3PutU32(f, cItems);
1002 for (i = s->mouse_command_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_command_queue.data))
1003 SSMR3PutU8(f, s->mouse_command_queue.data[i]);
1004 Log(("kbd_save: %d mouse command queue items stored\n", s->mouse_command_queue.count));
1005
1006 cItems = s->mouse_event_queue.count;
1007 SSMR3PutU32(f, cItems);
1008 for (i = s->mouse_event_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_event_queue.data))
1009 SSMR3PutU8(f, s->mouse_event_queue.data[i]);
1010 Log(("kbd_save: %d mouse event queue items stored\n", s->mouse_event_queue.count));
1011
1012 /* terminator */
1013 SSMR3PutU32(f, ~0);
1014}
1015
1016static int kbd_load(QEMUFile* f, void* opaque, int version_id)
1017{
1018 uint32_t u32, i;
1019 int rc;
1020 KBDState *s = (KBDState*)opaque;
1021
1022 if (version_id < 2 || version_id > PCKBD_SAVED_STATE_VERSION)
1023 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1024 qemu_get_8s(f, &s->write_cmd);
1025 qemu_get_8s(f, &s->status);
1026 qemu_get_8s(f, &s->mode);
1027 qemu_get_be32s(f, (uint32_t *)&s->kbd_write_cmd);
1028 qemu_get_be32s(f, (uint32_t *)&s->scan_enabled);
1029 qemu_get_be32s(f, (uint32_t *)&s->mouse_write_cmd);
1030 qemu_get_8s(f, &s->mouse_status);
1031 qemu_get_8s(f, &s->mouse_resolution);
1032 qemu_get_8s(f, &s->mouse_sample_rate);
1033 qemu_get_8s(f, &s->mouse_wrap);
1034 qemu_get_8s(f, &s->mouse_type);
1035 qemu_get_8s(f, &s->mouse_detect_state);
1036 qemu_get_be32s(f, (uint32_t *)&s->mouse_dx);
1037 qemu_get_be32s(f, (uint32_t *)&s->mouse_dy);
1038 qemu_get_be32s(f, (uint32_t *)&s->mouse_dz);
1039 if (version_id > 2)
1040 {
1041 SSMR3GetS32(f, &s->mouse_dw);
1042 SSMR3GetS32(f, &s->mouse_flags);
1043 }
1044 qemu_get_8s(f, &s->mouse_buttons);
1045 s->queue.count = 0;
1046 s->queue.rptr = 0;
1047 s->queue.wptr = 0;
1048 s->mouse_command_queue.count = 0;
1049 s->mouse_command_queue.rptr = 0;
1050 s->mouse_command_queue.wptr = 0;
1051 s->mouse_event_queue.count = 0;
1052 s->mouse_event_queue.rptr = 0;
1053 s->mouse_event_queue.wptr = 0;
1054
1055 /*
1056 * Load the queues
1057 */
1058 rc = SSMR3GetU32(f, &u32);
1059 if (RT_FAILURE(rc))
1060 return rc;
1061 if (u32 > RT_ELEMENTS(s->queue.data))
1062 {
1063 AssertMsgFailed(("u32=%#x\n", u32));
1064 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1065 }
1066 for (i = 0; i < u32; i++)
1067 {
1068 rc = SSMR3GetU8(f, &s->queue.data[i]);
1069 if (RT_FAILURE(rc))
1070 return rc;
1071 }
1072 s->queue.wptr = u32 % RT_ELEMENTS(s->queue.data);
1073 s->queue.count = u32;
1074 Log(("kbd_load: %d keyboard queue items loaded\n", u32));
1075
1076 rc = SSMR3GetU32(f, &u32);
1077 if (RT_FAILURE(rc))
1078 return rc;
1079 if (u32 > RT_ELEMENTS(s->mouse_command_queue.data))
1080 {
1081 AssertMsgFailed(("u32=%#x\n", u32));
1082 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1083 }
1084 for (i = 0; i < u32; i++)
1085 {
1086 rc = SSMR3GetU8(f, &s->mouse_command_queue.data[i]);
1087 if (RT_FAILURE(rc))
1088 return rc;
1089 }
1090 s->mouse_command_queue.wptr = u32 % RT_ELEMENTS(s->mouse_command_queue.data);
1091 s->mouse_command_queue.count = u32;
1092 Log(("kbd_load: %d mouse command queue items loaded\n", u32));
1093
1094 rc = SSMR3GetU32(f, &u32);
1095 if (RT_FAILURE(rc))
1096 return rc;
1097 if (u32 > RT_ELEMENTS(s->mouse_event_queue.data))
1098 {
1099 AssertMsgFailed(("u32=%#x\n", u32));
1100 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1101 }
1102 for (i = 0; i < u32; i++)
1103 {
1104 rc = SSMR3GetU8(f, &s->mouse_event_queue.data[i]);
1105 if (RT_FAILURE(rc))
1106 return rc;
1107 }
1108 s->mouse_event_queue.wptr = u32 % RT_ELEMENTS(s->mouse_event_queue.data);
1109 s->mouse_event_queue.count = u32;
1110 Log(("kbd_load: %d mouse event queue items loaded\n", u32));
1111
1112 /* terminator */
1113 rc = SSMR3GetU32(f, &u32);
1114 if (RT_FAILURE(rc))
1115 return rc;
1116 if (u32 != ~0U)
1117 {
1118 AssertMsgFailed(("u32=%#x\n", u32));
1119 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1120 }
1121 return 0;
1122}
1123#endif /* IN_RING3 */
1124
1125
1126/* VirtualBox code start */
1127
1128/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
1129
1130/**
1131 * Port I/O Handler for keyboard data IN operations.
1132 *
1133 * @returns VBox status code.
1134 *
1135 * @param pDevIns The device instance.
1136 * @param pvUser User argument - ignored.
1137 * @param Port Port number used for the IN operation.
1138 * @param pu32 Where to store the result.
1139 * @param cb Number of bytes read.
1140 */
1141PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1142{
1143 NOREF(pvUser);
1144 if (cb == 1)
1145 {
1146 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1147 int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
1148 if (RT_LIKELY(rc == VINF_SUCCESS))
1149 {
1150 *pu32 = kbd_read_data(pThis, Port);
1151 PDMCritSectLeave(&pThis->CritSect);
1152 Log2(("kbdIOPortDataRead: Port=%#x cb=%d *pu32=%#x\n", Port, cb, *pu32));
1153 }
1154 return rc;
1155 }
1156 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1157 return VERR_IOM_IOPORT_UNUSED;
1158}
1159
1160/**
1161 * Port I/O Handler for keyboard data OUT operations.
1162 *
1163 * @returns VBox status code.
1164 *
1165 * @param pDevIns The device instance.
1166 * @param pvUser User argument - ignored.
1167 * @param Port Port number used for the IN operation.
1168 * @param u32 The value to output.
1169 * @param cb The value size in bytes.
1170 */
1171PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1172{
1173 int rc = VINF_SUCCESS;
1174 NOREF(pvUser);
1175 if (cb == 1)
1176 {
1177 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1178 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
1179 if (RT_LIKELY(rc == VINF_SUCCESS))
1180 {
1181 rc = kbd_write_data(pThis, Port, u32);
1182 PDMCritSectLeave(&pThis->CritSect);
1183 Log2(("kbdIOPortDataWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1184 }
1185 }
1186 else
1187 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1188 return rc;
1189}
1190
1191/**
1192 * Port I/O Handler for keyboard status IN operations.
1193 *
1194 * @returns VBox status code.
1195 *
1196 * @param pDevIns The device instance.
1197 * @param pvUser User argument - ignored.
1198 * @param Port Port number used for the IN operation.
1199 * @param pu32 Where to store the result.
1200 * @param cb Number of bytes read.
1201 */
1202PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1203{
1204 NOREF(pvUser);
1205 if (cb == 1)
1206 {
1207 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1208 int rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_READ);
1209 if (RT_LIKELY(rc == VINF_SUCCESS))
1210 {
1211 *pu32 = kbd_read_status(pThis, Port);
1212 PDMCritSectLeave(&pThis->CritSect);
1213 Log2(("kbdIOPortStatusRead: Port=%#x cb=%d -> *pu32=%#x\n", Port, cb, *pu32));
1214 }
1215 return rc;
1216 }
1217 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1218 return VERR_IOM_IOPORT_UNUSED;
1219}
1220
1221/**
1222 * Port I/O Handler for keyboard command OUT operations.
1223 *
1224 * @returns VBox status code.
1225 *
1226 * @param pDevIns The device instance.
1227 * @param pvUser User argument - ignored.
1228 * @param Port Port number used for the IN operation.
1229 * @param u32 The value to output.
1230 * @param cb The value size in bytes.
1231 */
1232PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1233{
1234 int rc = VINF_SUCCESS;
1235 NOREF(pvUser);
1236 if (cb == 1)
1237 {
1238 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1239 rc = PDMCritSectEnter(&pThis->CritSect, VINF_IOM_HC_IOPORT_WRITE);
1240 if (RT_LIKELY(rc == VINF_SUCCESS))
1241 {
1242 rc = kbd_write_command(pThis, Port, u32);
1243 PDMCritSectLeave(&pThis->CritSect);
1244 Log2(("kbdIOPortCommandWrite: Port=%#x cb=%d u32=%#x rc=%Rrc\n", Port, cb, u32, rc));
1245 }
1246 }
1247 else
1248 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1249 return rc;
1250}
1251
1252#ifdef IN_RING3
1253
1254/**
1255 * Saves a state of the keyboard device.
1256 *
1257 * @returns VBox status code.
1258 * @param pDevIns The device instance.
1259 * @param pSSMHandle The handle to save the state to.
1260 */
1261static DECLCALLBACK(int) kbdSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1262{
1263 kbd_save(pSSMHandle, PDMINS_2_DATA(pDevIns, KBDState *));
1264 return VINF_SUCCESS;
1265}
1266
1267
1268/**
1269 * Loads a saved keyboard device state.
1270 *
1271 * @returns VBox status code.
1272 * @param pDevIns The device instance.
1273 * @param pSSMHandle The handle to the saved state.
1274 * @param uVersion The data unit version number.
1275 * @param uPass The data pass.
1276 */
1277static DECLCALLBACK(int) kbdLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t uVersion, uint32_t uPass)
1278{
1279 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1280 return kbd_load(pSSMHandle, PDMINS_2_DATA(pDevIns, KBDState *), uVersion);
1281}
1282
1283/**
1284 * Reset notification.
1285 *
1286 * @returns VBox status.
1287 * @param pDevIns The device instance data.
1288 */
1289static DECLCALLBACK(void) kbdReset(PPDMDEVINS pDevIns)
1290{
1291 kbd_reset(PDMINS_2_DATA(pDevIns, KBDState *));
1292}
1293
1294
1295/* -=-=-=-=-=- Keyboard: IBase -=-=-=-=-=- */
1296
1297/**
1298 * Queries an interface to the driver.
1299 *
1300 * @returns Pointer to interface.
1301 * @returns NULL if the interface was not supported by the device.
1302 * @param pInterface Pointer to the keyboard port base interface (KBDState::Keyboard.Base).
1303 * @param enmInterface The requested interface identification.
1304 */
1305static DECLCALLBACK(void *) kbdKeyboardQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1306{
1307 KBDState *pThis = (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Keyboard.Base));
1308 switch (enmInterface)
1309 {
1310 case PDMINTERFACE_BASE:
1311 return &pThis->Keyboard.Base;
1312 case PDMINTERFACE_KEYBOARD_PORT:
1313 return &pThis->Keyboard.Port;
1314 default:
1315 return NULL;
1316 }
1317}
1318
1319
1320/* -=-=-=-=-=- Keyboard: IKeyboardPort -=-=-=-=-=- */
1321
1322/** Converts a keyboard port interface pointer to a keyboard state pointer. */
1323#define IKEYBOARDPORT_2_KBDSTATE(pInterface) ( (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Keyboard.Port)) )
1324
1325/**
1326 * Keyboard event handler.
1327 *
1328 * @returns VBox status code.
1329 * @param pInterface Pointer to the keyboard port interface (KBDState::Keyboard.Port).
1330 * @param u8KeyCode The keycode.
1331 */
1332static DECLCALLBACK(int) kbdKeyboardPutEvent(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)
1333{
1334 KBDState *pThis = IKEYBOARDPORT_2_KBDSTATE(pInterface);
1335 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1336 AssertReleaseRC(rc);
1337 pc_kbd_put_keycode(pThis, u8KeyCode);
1338 PDMCritSectLeave(&pThis->CritSect);
1339 return VINF_SUCCESS;
1340}
1341
1342
1343/* -=-=-=-=-=- Mouse: IBase -=-=-=-=-=- */
1344
1345/**
1346 * Queries an interface to the driver.
1347 *
1348 * @returns Pointer to interface.
1349 * @returns NULL if the interface was not supported by the device.
1350 * @param pInterface Pointer to the mouse port base interface (KBDState::Mouse.Base).
1351 * @param enmInterface The requested interface identification.
1352 */
1353static DECLCALLBACK(void *) kbdMouseQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1354{
1355 KBDState *pThis = (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Mouse.Base));
1356 switch (enmInterface)
1357 {
1358 case PDMINTERFACE_BASE:
1359 return &pThis->Mouse.Base;
1360 case PDMINTERFACE_MOUSE_PORT:
1361 return &pThis->Mouse.Port;
1362 default:
1363 return NULL;
1364 }
1365}
1366
1367
1368/* -=-=-=-=-=- Mouse: IMousePort -=-=-=-=-=- */
1369
1370/** Converts a mouse port interface pointer to a keyboard state pointer. */
1371#define IMOUSEPORT_2_KBDSTATE(pInterface) ( (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Mouse.Port)) )
1372
1373/**
1374 * Mouse event handler.
1375 *
1376 * @returns VBox status code.
1377 * @param pInterface Pointer to the mouse port interface (KBDState::Mouse.Port).
1378 * @param i32DeltaX The X delta.
1379 * @param i32DeltaY The Y delta.
1380 * @param i32DeltaZ The Z delta.
1381 * @param fButtonStates The button states.
1382 */
1383static DECLCALLBACK(int) kbdMousePutEvent(PPDMIMOUSEPORT pInterface, int32_t i32DeltaX, int32_t i32DeltaY, int32_t i32DeltaZ, int32_t i32DeltaW, uint32_t fButtonStates)
1384{
1385 KBDState *pThis = IMOUSEPORT_2_KBDSTATE(pInterface);
1386 int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
1387 AssertReleaseRC(rc);
1388 pc_kbd_mouse_event(pThis, i32DeltaX, i32DeltaY, i32DeltaZ, i32DeltaW, fButtonStates);
1389 PDMCritSectLeave(&pThis->CritSect);
1390 return VINF_SUCCESS;
1391}
1392
1393
1394/* -=-=-=-=-=- real code -=-=-=-=-=- */
1395
1396
1397/**
1398 * Attach command.
1399 *
1400 * This is called to let the device attach to a driver for a specified LUN
1401 * during runtime. This is not called during VM construction, the device
1402 * constructor have to attach to all the available drivers.
1403 *
1404 * This is like plugging in the keyboard or mouse after turning on the PC.
1405 *
1406 * @returns VBox status code.
1407 * @param pDevIns The device instance.
1408 * @param iLUN The logical unit which is being detached.
1409 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1410 * @remark The keyboard controller doesn't support this action, this is just
1411 * implemented to try out the driver<->device structure.
1412 */
1413static DECLCALLBACK(int) kbdAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1414{
1415 int rc;
1416 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1417
1418 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
1419 ("PS/2 device does not support hotplugging\n"),
1420 VERR_INVALID_PARAMETER);
1421
1422 switch (iLUN)
1423 {
1424 /* LUN #0: keyboard */
1425 case 0:
1426 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Keyboard.Base, &pThis->Keyboard.pDrvBase, "Keyboard Port");
1427 if (RT_SUCCESS(rc))
1428 {
1429 pThis->Keyboard.pDrv = (PDMIKEYBOARDCONNECTOR*)(pThis->Keyboard.pDrvBase->pfnQueryInterface(pThis->Keyboard.pDrvBase, PDMINTERFACE_KEYBOARD_CONNECTOR));
1430 if (!pThis->Keyboard.pDrv)
1431 {
1432 AssertLogRelMsgFailed(("LUN #0 doesn't have a keyboard interface! rc=%Rrc\n", rc));
1433 rc = VERR_PDM_MISSING_INTERFACE;
1434 }
1435 }
1436 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1437 {
1438 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1439 rc = VINF_SUCCESS;
1440 }
1441 else
1442 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
1443 break;
1444
1445 /* LUN #1: aux/mouse */
1446 case 1:
1447 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Mouse.Base, &pThis->Mouse.pDrvBase, "Aux (Mouse) Port");
1448 if (RT_SUCCESS(rc))
1449 {
1450 pThis->Mouse.pDrv = (PDMIMOUSECONNECTOR*)(pThis->Mouse.pDrvBase->pfnQueryInterface(pThis->Mouse.pDrvBase, PDMINTERFACE_MOUSE_CONNECTOR));
1451 if (!pThis->Mouse.pDrv)
1452 {
1453 AssertLogRelMsgFailed(("LUN #1 doesn't have a mouse interface! rc=%Rrc\n", rc));
1454 rc = VERR_PDM_MISSING_INTERFACE;
1455 }
1456 }
1457 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1458 {
1459 Log(("%s/%d: warning: no driver attached to LUN #1!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1460 rc = VINF_SUCCESS;
1461 }
1462 else
1463 AssertLogRelMsgFailed(("Failed to attach LUN #1! rc=%Rrc\n", rc));
1464 break;
1465
1466 default:
1467 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1468 return VERR_PDM_NO_SUCH_LUN;
1469 }
1470
1471 return rc;
1472}
1473
1474
1475/**
1476 * Detach notification.
1477 *
1478 * This is called when a driver is detaching itself from a LUN of the device.
1479 * The device should adjust it's state to reflect this.
1480 *
1481 * This is like unplugging the network cable to use it for the laptop or
1482 * something while the PC is still running.
1483 *
1484 * @param pDevIns The device instance.
1485 * @param iLUN The logical unit which is being detached.
1486 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1487 * @remark The keyboard controller doesn't support this action, this is just
1488 * implemented to try out the driver<->device structure.
1489 */
1490static DECLCALLBACK(void) kbdDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1491{
1492#if 0
1493 /*
1494 * Reset the interfaces and update the controller state.
1495 */
1496 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1497 switch (iLUN)
1498 {
1499 /* LUN #0: keyboard */
1500 case 0:
1501 pThis->Keyboard.pDrv = NULL;
1502 pThis->Keyboard.pDrvBase = NULL;
1503 break;
1504
1505 /* LUN #1: aux/mouse */
1506 case 1:
1507 pThis->Mouse.pDrv = NULL;
1508 pThis->Mouse.pDrvBase = NULL;
1509 break;
1510
1511 default:
1512 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1513 break;
1514 }
1515#endif
1516}
1517
1518
1519/**
1520 * @copydoc FNPDMDEVRELOCATE
1521 */
1522static DECLCALLBACK(void) kdbRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1523{
1524 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1525 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1526}
1527
1528
1529/**
1530 * Destruct a device instance for a VM.
1531 *
1532 * @returns VBox status.
1533 * @param pDevIns The device instance data.
1534 */
1535static DECLCALLBACK(int) kbdDestruct(PPDMDEVINS pDevIns)
1536{
1537 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1538 PDMR3CritSectDelete(&pThis->CritSect);
1539
1540 return VINF_SUCCESS;
1541}
1542
1543
1544/**
1545 * Construct a device instance for a VM.
1546 *
1547 * @returns VBox status.
1548 * @param pDevIns The device instance data.
1549 * If the registration structure is needed, pDevIns->pDevReg points to it.
1550 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1551 * The device number is also found in pDevIns->iInstance, but since it's
1552 * likely to be freqently used PDM passes it as parameter.
1553 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1554 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1555 * iInstance it's expected to be used a bit in this function.
1556 */
1557static DECLCALLBACK(int) kbdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1558{
1559 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1560 int rc;
1561 bool fGCEnabled;
1562 bool fR0Enabled;
1563 Assert(iInstance == 0);
1564
1565 /*
1566 * Validate and read the configuration.
1567 */
1568 if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0R0Enabled\0"))
1569 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1570 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
1571 if (RT_FAILURE(rc))
1572 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"GCEnabled\" from the config"));
1573 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
1574 if (RT_FAILURE(rc))
1575 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"R0Enabled\" from the config"));
1576 Log(("pckbd: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1577
1578
1579 /*
1580 * Initialize the interfaces.
1581 */
1582 pThis->pDevInsR3 = pDevIns;
1583 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1584 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1585 pThis->Keyboard.Base.pfnQueryInterface = kbdKeyboardQueryInterface;
1586 pThis->Keyboard.Port.pfnPutEvent = kbdKeyboardPutEvent;
1587
1588 pThis->Mouse.Base.pfnQueryInterface = kbdMouseQueryInterface;
1589 pThis->Mouse.Port.pfnPutEvent = kbdMousePutEvent;
1590
1591 /*
1592 * Initialize the critical section.
1593 */
1594 char szName[24];
1595 RTStrPrintf(szName, sizeof(szName), "PS2KM#%d", iInstance);
1596 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, szName);
1597 if (RT_FAILURE(rc))
1598 return rc;
1599
1600 /*
1601 * Register I/O ports, save state, keyboard event handler and mouse event handlers.
1602 */
1603 rc = PDMDevHlpIOPortRegister(pDevIns, 0x60, 1, NULL, kbdIOPortDataWrite, kbdIOPortDataRead, NULL, NULL, "PC Keyboard - Data");
1604 if (RT_FAILURE(rc))
1605 return rc;
1606 rc = PDMDevHlpIOPortRegister(pDevIns, 0x64, 1, NULL, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL, NULL, "PC Keyboard - Command / Status");
1607 if (RT_FAILURE(rc))
1608 return rc;
1609 if (fGCEnabled)
1610 {
1611 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1612 if (RT_FAILURE(rc))
1613 return rc;
1614 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1615 if (RT_FAILURE(rc))
1616 return rc;
1617 }
1618 if (fR0Enabled)
1619 {
1620 rc = pDevIns->pDevHlpR3->pfnIOPortRegisterR0(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1621 if (RT_FAILURE(rc))
1622 return rc;
1623 rc = pDevIns->pDevHlpR3->pfnIOPortRegisterR0(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1624 if (RT_FAILURE(rc))
1625 return rc;
1626 }
1627 rc = PDMDevHlpSSMRegister(pDevIns, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis), kbdSaveExec, kbdLoadExec);
1628 if (RT_FAILURE(rc))
1629 return rc;
1630
1631 /*
1632 * Attach to the keyboard and mouse drivers.
1633 */
1634 rc = kbdAttach(pDevIns, 0 /* keyboard LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1635 if (RT_FAILURE(rc))
1636 return rc;
1637 rc = kbdAttach(pDevIns, 1 /* aux/mouse LUN # */, PDM_TACH_FLAGS_NOT_HOT_PLUG);
1638 if (RT_FAILURE(rc))
1639 return rc;
1640
1641 /*
1642 * Initialize the device state.
1643 */
1644 kbdReset(pDevIns);
1645
1646 return VINF_SUCCESS;
1647}
1648
1649
1650/**
1651 * The device registration structure.
1652 */
1653const PDMDEVREG g_DevicePS2KeyboardMouse =
1654{
1655 /* u32Version */
1656 PDM_DEVREG_VERSION,
1657 /* szDeviceName */
1658 "pckbd",
1659 /* szRCMod */
1660 "VBoxDDGC.gc",
1661 /* szR0Mod */
1662 "VBoxDDR0.r0",
1663 /* pszDescription */
1664 "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller. "
1665 "LUN #0 is the keyboard connector. "
1666 "LUN #1 is the aux/mouse connector.",
1667 /* fFlags */
1668 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1669 /* fClass */
1670 PDM_DEVREG_CLASS_INPUT,
1671 /* cMaxInstances */
1672 1,
1673 /* cbInstance */
1674 sizeof(KBDState),
1675 /* pfnConstruct */
1676 kbdConstruct,
1677 /* pfnDestruct */
1678 kbdDestruct,
1679 /* pfnRelocate */
1680 kdbRelocate,
1681 /* pfnIOCtl */
1682 NULL,
1683 /* pfnPowerOn */
1684 NULL,
1685 /* pfnReset */
1686 kbdReset,
1687 /* pfnSuspend */
1688 NULL,
1689 /* pfnResume */
1690 NULL,
1691 /* pfnAttach */
1692 kbdAttach,
1693 /* pfnDetach */
1694 kbdDetach,
1695 /* pfnQueryInterface. */
1696 NULL,
1697 /* pfnInitComplete */
1698 NULL,
1699 /* pfnPowerOff */
1700 NULL,
1701 /* pfnSoftReset */
1702 NULL,
1703 /* u32VersionEnd */
1704 PDM_DEVREG_VERSION
1705};
1706
1707#endif /* IN_RING3 */
1708#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1709
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