VirtualBox

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

Last change on this file since 16954 was 12977, checked in by vboxsync, 16 years ago

#1865: Updated PDMDEVREG with pfnSoftReset, u32VersionEnd and some flag/name cleanups.

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