VirtualBox

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

Last change on this file since 21205 was 21188, checked in by vboxsync, 15 years ago

Add hotplug flag to PDMR3DeviceAttach/Detach

  • Property svn:eol-style set to native
File size: 55.5 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*******************************************************************************/
66RT_C_DECLS_BEGIN
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);
71RT_C_DECLS_END
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#ifndef VBOX
782 /* XXX: SDL sometimes generates nul events: we delete them */
783 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
784 s->mouse_buttons == buttons_state)
785 return;
786#else
787 /* This issue does not affect VBox, and under some circumstances (which?)
788 * we may wish to send null events to make mouse integration work. */
789#endif
790 s->mouse_buttons = buttons_state;
791
792#ifdef VBOX
793 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
794 (s->mouse_event_queue.count < (MOUSE_EVENT_QUEUE_SIZE - 4))) {
795 for(;;) {
796 /* if not remote, send event. Multiple events are sent if
797 too big deltas */
798 kbd_mouse_send_packet(s, false);
799 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
800 break;
801 }
802 }
803#else /* !VBOX */
804 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
805 (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
806 for(;;) {
807 /* if not remote, send event. Multiple events are sent if
808 too big deltas */
809 kbd_mouse_send_packet(s);
810 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
811 break;
812 }
813 }
814#endif /* !VBOX */
815}
816#endif /* IN_RING3 */
817
818static void kbd_write_mouse(KBDState *s, int val)
819{
820#ifdef DEBUG_MOUSE
821 Log(("kbd: write mouse 0x%02x\n", val));
822#endif
823#ifdef VBOX
824 /* Flush the mouse command response queue. */
825 s->mouse_command_queue.count = 0;
826 s->mouse_command_queue.rptr = 0;
827 s->mouse_command_queue.wptr = 0;
828#endif /* VBOX */
829 switch(s->mouse_write_cmd) {
830 default:
831 case -1:
832 /* mouse command */
833 if (s->mouse_wrap) {
834 if (val == AUX_RESET_WRAP) {
835 s->mouse_wrap = 0;
836 kbd_queue(s, AUX_ACK, 1);
837 return;
838 } else if (val != AUX_RESET) {
839 kbd_queue(s, val, 1);
840 return;
841 }
842 }
843 switch(val) {
844 case AUX_SET_SCALE11:
845 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
846 kbd_queue(s, AUX_ACK, 1);
847 break;
848 case AUX_SET_SCALE21:
849 s->mouse_status |= MOUSE_STATUS_SCALE21;
850 kbd_queue(s, AUX_ACK, 1);
851 break;
852 case AUX_SET_STREAM:
853 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
854 kbd_queue(s, AUX_ACK, 1);
855 break;
856 case AUX_SET_WRAP:
857 s->mouse_wrap = 1;
858 kbd_queue(s, AUX_ACK, 1);
859 break;
860 case AUX_SET_REMOTE:
861 s->mouse_status |= MOUSE_STATUS_REMOTE;
862 kbd_queue(s, AUX_ACK, 1);
863 break;
864 case AUX_GET_TYPE:
865 kbd_queue(s, AUX_ACK, 1);
866 kbd_queue(s, s->mouse_type, 1);
867 break;
868 case AUX_SET_RES:
869 case AUX_SET_SAMPLE:
870 s->mouse_write_cmd = val;
871 kbd_queue(s, AUX_ACK, 1);
872 break;
873 case AUX_GET_SCALE:
874 kbd_queue(s, AUX_ACK, 1);
875 kbd_queue(s, s->mouse_status, 1);
876 kbd_queue(s, s->mouse_resolution, 1);
877 kbd_queue(s, s->mouse_sample_rate, 1);
878 break;
879 case AUX_POLL:
880 kbd_queue(s, AUX_ACK, 1);
881#ifdef VBOX
882 kbd_mouse_send_packet(s, true);
883#else /* !VBOX */
884 kbd_mouse_send_packet(s);
885#endif /* !VBOX */
886 break;
887 case AUX_ENABLE_DEV:
888 s->mouse_status |= MOUSE_STATUS_ENABLED;
889 kbd_queue(s, AUX_ACK, 1);
890 break;
891 case AUX_DISABLE_DEV:
892 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
893 kbd_queue(s, AUX_ACK, 1);
894#ifdef VBOX
895 /* Flush the mouse events queue. */
896 s->mouse_event_queue.count = 0;
897 s->mouse_event_queue.rptr = 0;
898 s->mouse_event_queue.wptr = 0;
899#endif /* VBOX */
900 break;
901 case AUX_SET_DEFAULT:
902 s->mouse_sample_rate = 100;
903 s->mouse_resolution = 2;
904 s->mouse_status = 0;
905 kbd_queue(s, AUX_ACK, 1);
906 break;
907 case AUX_RESET:
908 s->mouse_sample_rate = 100;
909 s->mouse_resolution = 2;
910 s->mouse_status = 0;
911 s->mouse_type = 0;
912 kbd_queue(s, AUX_ACK, 1);
913 kbd_queue(s, 0xaa, 1);
914 kbd_queue(s, s->mouse_type, 1);
915#ifdef VBOX
916 /* Flush the mouse events queue. */
917 s->mouse_event_queue.count = 0;
918 s->mouse_event_queue.rptr = 0;
919 s->mouse_event_queue.wptr = 0;
920#endif /* VBOX */
921 break;
922 default:
923#ifdef VBOX
924 /* NACK all commands we don't know.
925
926 The usecase for this is the OS/2 mouse driver which will try
927 read 0xE2 in order to figure out if it's a trackpoint device
928 or not. If it doesn't get a NACK (or ACK) on the command it'll
929 do several hundred thousand status reads before giving up. This
930 is slows down the OS/2 boot up considerably. (It also seems that
931 the code is somehow vulnerable while polling like this and that
932 mouse or keyboard input at this point might screw things up badly.)
933
934 From http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html:
935
936 Every command or data byte sent to the mouse (except for the
937 resend command fe) is ACKed with fa. If the command or data
938 is invalid, it is NACKed with fe. If the next byte is again
939 invalid, the reply is ERROR: fc. */
940 /** @todo send error if we NACKed the previous command? */
941 kbd_queue(s, AUX_NACK, 1);
942#endif
943 break;
944 }
945 break;
946 case AUX_SET_SAMPLE:
947 s->mouse_sample_rate = val;
948 /* detect IMPS/2 or IMEX */
949 switch(s->mouse_detect_state) {
950 default:
951 case 0:
952 if (val == 200)
953 s->mouse_detect_state = 1;
954 break;
955 case 1:
956 if (val == 100)
957 s->mouse_detect_state = 2;
958 else if (val == 200)
959 s->mouse_detect_state = 3;
960 else
961 s->mouse_detect_state = 0;
962 break;
963 case 2:
964 if (val == 80)
965 s->mouse_type = 3; /* IMPS/2 */
966 s->mouse_detect_state = 0;
967 break;
968 case 3:
969 if (val == 80)
970 s->mouse_type = 4; /* IMEX */
971 s->mouse_detect_state = 0;
972 break;
973 }
974 kbd_queue(s, AUX_ACK, 1);
975 s->mouse_write_cmd = -1;
976 break;
977 case AUX_SET_RES:
978 s->mouse_resolution = val;
979 kbd_queue(s, AUX_ACK, 1);
980 s->mouse_write_cmd = -1;
981 break;
982 }
983}
984
985#ifndef VBOX
986static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
987{
988#else /* VBOX */
989static int kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
990{
991 int rc = VINF_SUCCESS;
992#endif /* VBOX */
993 KBDState *s = (KBDState*)opaque;
994
995#ifdef DEBUG_KBD
996 Log(("kbd: write data=0x%02x\n", val));
997#endif
998
999 switch(s->write_cmd) {
1000 case 0:
1001 rc = kbd_write_keyboard(s, val);
1002 break;
1003 case KBD_CCMD_WRITE_MODE:
1004 s->mode = val;
1005 kbd_update_irq(s);
1006 break;
1007 case KBD_CCMD_WRITE_OBUF:
1008 kbd_queue(s, val, 0);
1009 break;
1010 case KBD_CCMD_WRITE_AUX_OBUF:
1011 kbd_queue(s, val, 1);
1012 break;
1013 case KBD_CCMD_WRITE_OUTPORT:
1014#ifdef TARGET_I386
1015# ifndef VBOX
1016 ioport_set_a20((val >> 1) & 1);
1017# else /* VBOX */
1018# ifndef IN_RING3
1019 if (PDMDevHlpA20IsEnabled(s->CTX_SUFF(pDevIns)) != !!(val & 2))
1020 rc = VINF_IOM_HC_IOPORT_WRITE;
1021# else /* IN_RING3 */
1022 PDMDevHlpA20Set(s->CTX_SUFF(pDevIns), !!(val & 2));
1023# endif /* !IN_RING3 */
1024# endif /* VBOX */
1025#endif
1026 if (!(val & 1)) {
1027#ifndef VBOX
1028 qemu_system_reset_request();
1029#else /* VBOX */
1030# ifndef IN_RING3
1031 rc = VINF_IOM_HC_IOPORT_WRITE;
1032# else
1033 rc = PDMDevHlpVMReset(s->CTX_SUFF(pDevIns));
1034# endif
1035#endif /* VBOX */
1036 }
1037 break;
1038 case KBD_CCMD_WRITE_MOUSE:
1039 kbd_write_mouse(s, val);
1040 break;
1041 default:
1042 break;
1043 }
1044 s->write_cmd = 0;
1045
1046#ifdef VBOX
1047 return rc;
1048#endif
1049}
1050
1051#ifdef IN_RING3
1052
1053static void kbd_reset(void *opaque)
1054{
1055 KBDState *s = (KBDState*)opaque;
1056 KBDQueue *q;
1057#ifdef VBOX
1058 MouseCmdQueue *mcq;
1059 MouseEventQueue *meq;
1060#endif /* VBOX */
1061
1062 s->kbd_write_cmd = -1;
1063 s->mouse_write_cmd = -1;
1064 s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
1065 s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
1066#ifdef VBOX /* Resetting everything, keyword was not working right on NT4 reboot. */
1067 s->write_cmd = 0;
1068 s->scan_enabled = 0;
1069 s->mouse_status = 0;
1070 s->mouse_resolution = 0;
1071 s->mouse_sample_rate = 0;
1072 s->mouse_wrap = 0;
1073 s->mouse_type = 0;
1074 s->mouse_detect_state = 0;
1075 s->mouse_dx = 0;
1076 s->mouse_dy = 0;
1077 s->mouse_dz = 0;
1078 s->mouse_buttons = 0;
1079#endif
1080 q = &s->queue;
1081 q->rptr = 0;
1082 q->wptr = 0;
1083 q->count = 0;
1084#ifdef VBOX
1085 mcq = &s->mouse_command_queue;
1086 mcq->rptr = 0;
1087 mcq->wptr = 0;
1088 mcq->count = 0;
1089 meq = &s->mouse_event_queue;
1090 meq->rptr = 0;
1091 meq->wptr = 0;
1092 meq->count = 0;
1093#endif /* VBOX */
1094}
1095
1096static void kbd_save(QEMUFile* f, void* opaque)
1097{
1098#ifdef VBOX
1099 uint32_t cItems;
1100 int i;
1101#endif /* VBOX */
1102 KBDState *s = (KBDState*)opaque;
1103
1104 qemu_put_8s(f, &s->write_cmd);
1105 qemu_put_8s(f, &s->status);
1106 qemu_put_8s(f, &s->mode);
1107 qemu_put_be32s(f, &s->kbd_write_cmd);
1108 qemu_put_be32s(f, &s->scan_enabled);
1109 qemu_put_be32s(f, &s->mouse_write_cmd);
1110 qemu_put_8s(f, &s->mouse_status);
1111 qemu_put_8s(f, &s->mouse_resolution);
1112 qemu_put_8s(f, &s->mouse_sample_rate);
1113 qemu_put_8s(f, &s->mouse_wrap);
1114 qemu_put_8s(f, &s->mouse_type);
1115 qemu_put_8s(f, &s->mouse_detect_state);
1116 qemu_put_be32s(f, &s->mouse_dx);
1117 qemu_put_be32s(f, &s->mouse_dy);
1118 qemu_put_be32s(f, &s->mouse_dz);
1119 qemu_put_8s(f, &s->mouse_buttons);
1120
1121#ifdef VBOX
1122 /*
1123 * We have to save the queues too.
1124 */
1125 cItems = s->queue.count;
1126 SSMR3PutU32(f, cItems);
1127 for (i = s->queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->queue.data))
1128 SSMR3PutU8(f, s->queue.data[i]);
1129 Log(("kbd_save: %d keyboard queue items stored\n", s->queue.count));
1130
1131 cItems = s->mouse_command_queue.count;
1132 SSMR3PutU32(f, cItems);
1133 for (i = s->mouse_command_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_command_queue.data))
1134 SSMR3PutU8(f, s->mouse_command_queue.data[i]);
1135 Log(("kbd_save: %d mouse command queue items stored\n", s->mouse_command_queue.count));
1136
1137 cItems = s->mouse_event_queue.count;
1138 SSMR3PutU32(f, cItems);
1139 for (i = s->mouse_event_queue.rptr; cItems-- > 0; i = (i + 1) % RT_ELEMENTS(s->mouse_event_queue.data))
1140 SSMR3PutU8(f, s->mouse_event_queue.data[i]);
1141 Log(("kbd_save: %d mouse event queue items stored\n", s->mouse_event_queue.count));
1142
1143 /* terminator */
1144 SSMR3PutU32(f, ~0);
1145#endif /* VBOX */
1146}
1147
1148static int kbd_load(QEMUFile* f, void* opaque, int version_id)
1149{
1150#ifdef VBOX
1151 uint32_t u32, i;
1152 int rc;
1153#endif
1154 KBDState *s = (KBDState*)opaque;
1155
1156 if (version_id != PCKBD_SAVED_STATE_VERSION)
1157#ifndef VBOX
1158 return -EINVAL;
1159#else
1160 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1161#endif
1162 qemu_get_8s(f, &s->write_cmd);
1163 qemu_get_8s(f, &s->status);
1164 qemu_get_8s(f, &s->mode);
1165 qemu_get_be32s(f, (uint32_t *)&s->kbd_write_cmd);
1166 qemu_get_be32s(f, (uint32_t *)&s->scan_enabled);
1167 qemu_get_be32s(f, (uint32_t *)&s->mouse_write_cmd);
1168 qemu_get_8s(f, &s->mouse_status);
1169 qemu_get_8s(f, &s->mouse_resolution);
1170 qemu_get_8s(f, &s->mouse_sample_rate);
1171 qemu_get_8s(f, &s->mouse_wrap);
1172 qemu_get_8s(f, &s->mouse_type);
1173 qemu_get_8s(f, &s->mouse_detect_state);
1174 qemu_get_be32s(f, (uint32_t *)&s->mouse_dx);
1175 qemu_get_be32s(f, (uint32_t *)&s->mouse_dy);
1176 qemu_get_be32s(f, (uint32_t *)&s->mouse_dz);
1177 qemu_get_8s(f, &s->mouse_buttons);
1178#ifdef VBOX
1179 s->queue.count = 0;
1180 s->queue.rptr = 0;
1181 s->queue.wptr = 0;
1182 s->mouse_command_queue.count = 0;
1183 s->mouse_command_queue.rptr = 0;
1184 s->mouse_command_queue.wptr = 0;
1185 s->mouse_event_queue.count = 0;
1186 s->mouse_event_queue.rptr = 0;
1187 s->mouse_event_queue.wptr = 0;
1188
1189 /*
1190 * Load the queues
1191 */
1192 rc = SSMR3GetU32(f, &u32);
1193 if (RT_FAILURE(rc))
1194 return rc;
1195 if (u32 > RT_ELEMENTS(s->queue.data))
1196 {
1197 AssertMsgFailed(("u32=%#x\n", u32));
1198 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1199 }
1200 for (i = 0; i < u32; i++)
1201 {
1202 rc = SSMR3GetU8(f, &s->queue.data[i]);
1203 if (RT_FAILURE(rc))
1204 return rc;
1205 }
1206 s->queue.wptr = u32 % RT_ELEMENTS(s->queue.data);
1207 s->queue.count = u32;
1208 Log(("kbd_load: %d keyboard queue items loaded\n", u32));
1209
1210 rc = SSMR3GetU32(f, &u32);
1211 if (RT_FAILURE(rc))
1212 return rc;
1213 if (u32 > RT_ELEMENTS(s->mouse_command_queue.data))
1214 {
1215 AssertMsgFailed(("u32=%#x\n", u32));
1216 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1217 }
1218 for (i = 0; i < u32; i++)
1219 {
1220 rc = SSMR3GetU8(f, &s->mouse_command_queue.data[i]);
1221 if (RT_FAILURE(rc))
1222 return rc;
1223 }
1224 s->mouse_command_queue.wptr = u32 % RT_ELEMENTS(s->mouse_command_queue.data);
1225 s->mouse_command_queue.count = u32;
1226 Log(("kbd_load: %d mouse command queue items loaded\n", u32));
1227
1228 rc = SSMR3GetU32(f, &u32);
1229 if (RT_FAILURE(rc))
1230 return rc;
1231 if (u32 > RT_ELEMENTS(s->mouse_event_queue.data))
1232 {
1233 AssertMsgFailed(("u32=%#x\n", u32));
1234 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1235 }
1236 for (i = 0; i < u32; i++)
1237 {
1238 rc = SSMR3GetU8(f, &s->mouse_event_queue.data[i]);
1239 if (RT_FAILURE(rc))
1240 return rc;
1241 }
1242 s->mouse_event_queue.wptr = u32 % RT_ELEMENTS(s->mouse_event_queue.data);
1243 s->mouse_event_queue.count = u32;
1244 Log(("kbd_load: %d mouse event queue items loaded\n", u32));
1245
1246 /* terminator */
1247 rc = SSMR3GetU32(f, &u32);
1248 if (RT_FAILURE(rc))
1249 return rc;
1250 if (u32 != ~0U)
1251 {
1252 AssertMsgFailed(("u32=%#x\n", u32));
1253 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1254 }
1255#endif /* VBOX */
1256 return 0;
1257}
1258
1259#ifndef VBOX
1260void kbd_init(void)
1261{
1262 KBDState *s = &kbd_state;
1263
1264 kbd_reset(s);
1265 register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
1266 register_ioport_read(0x60, 1, 1, kbd_read_data, s);
1267 register_ioport_write(0x60, 1, 1, kbd_write_data, s);
1268 register_ioport_read(0x64, 1, 1, kbd_read_status, s);
1269 register_ioport_write(0x64, 1, 1, kbd_write_command, s);
1270
1271 qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
1272 qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
1273 qemu_register_reset(kbd_reset, s);
1274}
1275#endif /* !VBOX */
1276
1277#endif /* IN_RING3 */
1278
1279
1280#ifdef VBOX /* VirtualBox code start */
1281
1282/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
1283
1284/**
1285 * Port I/O Handler for keyboard data IN operations.
1286 *
1287 * @returns VBox status code.
1288 *
1289 * @param pDevIns The device instance.
1290 * @param pvUser User argument - ignored.
1291 * @param Port Port number used for the IN operation.
1292 * @param pu32 Where to store the result.
1293 * @param cb Number of bytes read.
1294 */
1295PDMBOTHCBDECL(int) kbdIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1296{
1297 NOREF(pvUser);
1298 if (cb == 1)
1299 {
1300 *pu32 = kbd_read_data(PDMINS_2_DATA(pDevIns, KBDState *), Port);
1301 Log2(("kbdIOPortDataRead: Port=%#x cb=%d *pu32=%#x\n", Port, cb, *pu32));
1302 return VINF_SUCCESS;
1303 }
1304 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1305 return VERR_IOM_IOPORT_UNUSED;
1306}
1307
1308/**
1309 * Port I/O Handler for keyboard data OUT operations.
1310 *
1311 * @returns VBox status code.
1312 *
1313 * @param pDevIns The device instance.
1314 * @param pvUser User argument - ignored.
1315 * @param Port Port number used for the IN operation.
1316 * @param u32 The value to output.
1317 * @param cb The value size in bytes.
1318 */
1319PDMBOTHCBDECL(int) kbdIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1320{
1321 int rc = VINF_SUCCESS;
1322 NOREF(pvUser);
1323 if (cb == 1)
1324 {
1325 rc = kbd_write_data(PDMINS_2_DATA(pDevIns, KBDState *), Port, u32);
1326 Log2(("kbdIOPortDataWrite: Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
1327 }
1328 else
1329 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1330 return rc;
1331}
1332
1333/**
1334 * Port I/O Handler for keyboard status IN operations.
1335 *
1336 * @returns VBox status code.
1337 *
1338 * @param pDevIns The device instance.
1339 * @param pvUser User argument - ignored.
1340 * @param Port Port number used for the IN operation.
1341 * @param pu32 Where to store the result.
1342 * @param cb Number of bytes read.
1343 */
1344PDMBOTHCBDECL(int) kbdIOPortStatusRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1345{
1346 NOREF(pvUser);
1347 if (cb == 1)
1348 {
1349 *pu32 = kbd_read_status(PDMINS_2_DATA(pDevIns, KBDState *), Port);
1350 Log2(("kbdIOPortStatusRead: Port=%#x cb=%d -> *pu32=%#x\n", Port, cb, *pu32));
1351 return VINF_SUCCESS;
1352 }
1353 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1354 return VERR_IOM_IOPORT_UNUSED;
1355}
1356
1357/**
1358 * Port I/O Handler for keyboard command OUT operations.
1359 *
1360 * @returns VBox status code.
1361 *
1362 * @param pDevIns The device instance.
1363 * @param pvUser User argument - ignored.
1364 * @param Port Port number used for the IN operation.
1365 * @param u32 The value to output.
1366 * @param cb The value size in bytes.
1367 */
1368PDMBOTHCBDECL(int) kbdIOPortCommandWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1369{
1370 NOREF(pvUser);
1371 if (cb == 1)
1372 {
1373 int rc = kbd_write_command(PDMINS_2_DATA(pDevIns, KBDState *), Port, u32);
1374 Log2(("kbdIOPortCommandWrite: Port=%#x cb=%d u32=%#x rc=%Rrc\n", Port, cb, u32, rc));
1375 return rc;
1376 }
1377 AssertMsgFailed(("Port=%#x cb=%d\n", Port, cb));
1378 return VINF_SUCCESS;
1379}
1380
1381#ifdef IN_RING3
1382
1383/**
1384 * Saves a state of the keyboard device.
1385 *
1386 * @returns VBox status code.
1387 * @param pDevIns The device instance.
1388 * @param pSSMHandle The handle to save the state to.
1389 */
1390static DECLCALLBACK(int) kbdSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1391{
1392 kbd_save(pSSMHandle, PDMINS_2_DATA(pDevIns, KBDState *));
1393 return VINF_SUCCESS;
1394}
1395
1396
1397/**
1398 * Loads a saved keyboard device state.
1399 *
1400 * @returns VBox status code.
1401 * @param pDevIns The device instance.
1402 * @param pSSMHandle The handle to the saved state.
1403 * @param u32Version The data unit version number.
1404 */
1405static DECLCALLBACK(int) kbdLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1406{
1407 return kbd_load(pSSMHandle, PDMINS_2_DATA(pDevIns, KBDState *), u32Version);
1408}
1409
1410/**
1411 * Reset notification.
1412 *
1413 * @returns VBox status.
1414 * @param pDevIns The device instance data.
1415 */
1416static DECLCALLBACK(void) kbdReset(PPDMDEVINS pDevIns)
1417{
1418 kbd_reset(PDMINS_2_DATA(pDevIns, KBDState *));
1419}
1420
1421
1422/* -=-=-=-=-=- Keyboard: IBase -=-=-=-=-=- */
1423
1424/**
1425 * Queries an interface to the driver.
1426 *
1427 * @returns Pointer to interface.
1428 * @returns NULL if the interface was not supported by the device.
1429 * @param pInterface Pointer to the keyboard port base interface (KBDState::Keyboard.Base).
1430 * @param enmInterface The requested interface identification.
1431 */
1432static DECLCALLBACK(void *) kbdKeyboardQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1433{
1434 KBDState *pThis = (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Keyboard.Base));
1435 switch (enmInterface)
1436 {
1437 case PDMINTERFACE_BASE:
1438 return &pThis->Keyboard.Base;
1439 case PDMINTERFACE_KEYBOARD_PORT:
1440 return &pThis->Keyboard.Port;
1441 default:
1442 return NULL;
1443 }
1444}
1445
1446
1447/* -=-=-=-=-=- Keyboard: IKeyboardPort -=-=-=-=-=- */
1448
1449/** Converts a keyboard port interface pointer to a keyboard state pointer. */
1450#define IKEYBOARDPORT_2_KBDSTATE(pInterface) ( (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Keyboard.Port)) )
1451
1452/**
1453 * Keyboard event handler.
1454 *
1455 * @returns VBox status code.
1456 * @param pInterface Pointer to the keyboard port interface (KBDState::Keyboard.Port).
1457 * @param u8KeyCode The keycode.
1458 */
1459static DECLCALLBACK(int) kbdKeyboardPutEvent(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)
1460{
1461 KBDState *pThis = IKEYBOARDPORT_2_KBDSTATE(pInterface);
1462 pc_kbd_put_keycode(pThis, u8KeyCode);
1463 return VINF_SUCCESS;
1464}
1465
1466
1467/* -=-=-=-=-=- Mouse: IBase -=-=-=-=-=- */
1468
1469/**
1470 * Queries an interface to the driver.
1471 *
1472 * @returns Pointer to interface.
1473 * @returns NULL if the interface was not supported by the device.
1474 * @param pInterface Pointer to the mouse port base interface (KBDState::Mouse.Base).
1475 * @param enmInterface The requested interface identification.
1476 */
1477static DECLCALLBACK(void *) kbdMouseQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1478{
1479 KBDState *pThis = (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Mouse.Base));
1480 switch (enmInterface)
1481 {
1482 case PDMINTERFACE_BASE:
1483 return &pThis->Mouse.Base;
1484 case PDMINTERFACE_MOUSE_PORT:
1485 return &pThis->Mouse.Port;
1486 default:
1487 return NULL;
1488 }
1489}
1490
1491
1492/* -=-=-=-=-=- Mouse: IMousePort -=-=-=-=-=- */
1493
1494/** Converts a mouse port interface pointer to a keyboard state pointer. */
1495#define IMOUSEPORT_2_KBDSTATE(pInterface) ( (KBDState *)((uintptr_t)pInterface - RT_OFFSETOF(KBDState, Mouse.Port)) )
1496
1497/**
1498 * Mouse event handler.
1499 *
1500 * @returns VBox status code.
1501 * @param pInterface Pointer to the mouse port interface (KBDState::Mouse.Port).
1502 * @param i32DeltaX The X delta.
1503 * @param i32DeltaY The Y delta.
1504 * @param i32DeltaZ The Z delta.
1505 * @param fButtonStates The button states.
1506 */
1507static DECLCALLBACK(int) kbdMousePutEvent(PPDMIMOUSEPORT pInterface, int32_t i32DeltaX, int32_t i32DeltaY, int32_t i32DeltaZ, uint32_t fButtonStates)
1508{
1509 KBDState *pThis = IMOUSEPORT_2_KBDSTATE(pInterface);
1510 pc_kbd_mouse_event(pThis, i32DeltaX, i32DeltaY, i32DeltaZ, fButtonStates);
1511 return VINF_SUCCESS;
1512}
1513
1514
1515/* -=-=-=-=-=- real code -=-=-=-=-=- */
1516
1517
1518/**
1519 * Attach command.
1520 *
1521 * This is called to let the device attach to a driver for a specified LUN
1522 * during runtime. This is not called during VM construction, the device
1523 * constructor have to attach to all the available drivers.
1524 *
1525 * This is like plugging in the keyboard or mouse after turning on the PC.
1526 *
1527 * @returns VBox status code.
1528 * @param pDevIns The device instance.
1529 * @param iLUN The logical unit which is being detached.
1530 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1531 * @remark The keyboard controller doesn't support this action, this is just
1532 * implemented to try out the driver<->device structure.
1533 */
1534static DECLCALLBACK(int) kbdAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1535{
1536 int rc;
1537 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1538
1539 AssertMsgReturn(fFlags & PDMDEVATT_FLAGS_NOT_HOT_PLUG,
1540 ("PS/2 device does not support hotplugging\n"),
1541 VERR_INVALID_PARAMETER);
1542
1543 switch (iLUN)
1544 {
1545 /* LUN #0: keyboard */
1546 case 0:
1547 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Keyboard.Base, &pThis->Keyboard.pDrvBase, "Keyboard Port");
1548 if (RT_SUCCESS(rc))
1549 {
1550 pThis->Keyboard.pDrv = (PDMIKEYBOARDCONNECTOR*)(pThis->Keyboard.pDrvBase->pfnQueryInterface(pThis->Keyboard.pDrvBase, PDMINTERFACE_KEYBOARD_CONNECTOR));
1551 if (!pThis->Keyboard.pDrv)
1552 {
1553 AssertLogRelMsgFailed(("LUN #0 doesn't have a keyboard interface! rc=%Rrc\n", rc));
1554 rc = VERR_PDM_MISSING_INTERFACE;
1555 }
1556 }
1557 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1558 {
1559 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1560 rc = VINF_SUCCESS;
1561 }
1562 else
1563 AssertLogRelMsgFailed(("Failed to attach LUN #0! rc=%Rrc\n", rc));
1564 break;
1565
1566 /* LUN #1: aux/mouse */
1567 case 1:
1568 rc = PDMDevHlpDriverAttach(pDevIns, iLUN, &pThis->Mouse.Base, &pThis->Mouse.pDrvBase, "Aux (Mouse) Port");
1569 if (RT_SUCCESS(rc))
1570 {
1571 pThis->Mouse.pDrv = (PDMIMOUSECONNECTOR*)(pThis->Mouse.pDrvBase->pfnQueryInterface(pThis->Mouse.pDrvBase, PDMINTERFACE_MOUSE_CONNECTOR));
1572 if (!pThis->Mouse.pDrv)
1573 {
1574 AssertLogRelMsgFailed(("LUN #1 doesn't have a mouse interface! rc=%Rrc\n", rc));
1575 rc = VERR_PDM_MISSING_INTERFACE;
1576 }
1577 }
1578 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1579 {
1580 Log(("%s/%d: warning: no driver attached to LUN #1!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1581 rc = VINF_SUCCESS;
1582 }
1583 else
1584 AssertLogRelMsgFailed(("Failed to attach LUN #1! rc=%Rrc\n", rc));
1585 break;
1586
1587 default:
1588 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1589 return VERR_PDM_NO_SUCH_LUN;
1590 }
1591
1592 return rc;
1593}
1594
1595
1596/**
1597 * Detach notification.
1598 *
1599 * This is called when a driver is detaching itself from a LUN of the device.
1600 * The device should adjust it's state to reflect this.
1601 *
1602 * This is like unplugging the network cable to use it for the laptop or
1603 * something while the PC is still running.
1604 *
1605 * @param pDevIns The device instance.
1606 * @param iLUN The logical unit which is being detached.
1607 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1608 * @remark The keyboard controller doesn't support this action, this is just
1609 * implemented to try out the driver<->device structure.
1610 */
1611static DECLCALLBACK(void) kbdDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1612{
1613#if 0
1614 /*
1615 * Reset the interfaces and update the controller state.
1616 */
1617 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1618 switch (iLUN)
1619 {
1620 /* LUN #0: keyboard */
1621 case 0:
1622 pThis->Keyboard.pDrv = NULL;
1623 pThis->Keyboard.pDrvBase = NULL;
1624 break;
1625
1626 /* LUN #1: aux/mouse */
1627 case 1:
1628 pThis->Mouse.pDrv = NULL;
1629 pThis->Mouse.pDrvBase = NULL;
1630 break;
1631
1632 default:
1633 AssertMsgFailed(("Invalid LUN #%d\n", iLUN));
1634 break;
1635 }
1636#endif
1637}
1638
1639/**
1640 * @copydoc FNPDMDEVRELOCATE
1641 */
1642static DECLCALLBACK(void) kdbRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1643{
1644 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1645 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1646}
1647
1648
1649/**
1650 * Construct a device instance for a VM.
1651 *
1652 * @returns VBox status.
1653 * @param pDevIns The device instance data.
1654 * If the registration structure is needed, pDevIns->pDevReg points to it.
1655 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1656 * The device number is also found in pDevIns->iInstance, but since it's
1657 * likely to be freqently used PDM passes it as parameter.
1658 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1659 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1660 * iInstance it's expected to be used a bit in this function.
1661 */
1662static DECLCALLBACK(int) kbdConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1663{
1664 KBDState *pThis = PDMINS_2_DATA(pDevIns, KBDState *);
1665 int rc;
1666 bool fGCEnabled;
1667 bool fR0Enabled;
1668 Assert(iInstance == 0);
1669
1670 /*
1671 * Validate and read the configuration.
1672 */
1673 if (!CFGMR3AreValuesValid(pCfgHandle, "GCEnabled\0R0Enabled\0"))
1674 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1675 rc = CFGMR3QueryBoolDef(pCfgHandle, "GCEnabled", &fGCEnabled, true);
1676 if (RT_FAILURE(rc))
1677 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"GCEnabled\" from the config"));
1678 rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &fR0Enabled, true);
1679 if (RT_FAILURE(rc))
1680 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to query \"R0Enabled\" from the config"));
1681 Log(("pckbd: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1682
1683
1684 /*
1685 * Initialize the interfaces.
1686 */
1687 pThis->pDevInsR3 = pDevIns;
1688 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1689 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1690 pThis->Keyboard.Base.pfnQueryInterface = kbdKeyboardQueryInterface;
1691 pThis->Keyboard.Port.pfnPutEvent = kbdKeyboardPutEvent;
1692
1693 pThis->Mouse.Base.pfnQueryInterface = kbdMouseQueryInterface;
1694 pThis->Mouse.Port.pfnPutEvent = kbdMousePutEvent;
1695
1696 /*
1697 * Register I/O ports, save state, keyboard event handler and mouse event handlers.
1698 */
1699 rc = PDMDevHlpIOPortRegister(pDevIns, 0x60, 1, NULL, kbdIOPortDataWrite, kbdIOPortDataRead, NULL, NULL, "PC Keyboard - Data");
1700 if (RT_FAILURE(rc))
1701 return rc;
1702 rc = PDMDevHlpIOPortRegister(pDevIns, 0x64, 1, NULL, kbdIOPortCommandWrite, kbdIOPortStatusRead, NULL, NULL, "PC Keyboard - Command / Status");
1703 if (RT_FAILURE(rc))
1704 return rc;
1705 if (fGCEnabled)
1706 {
1707 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1708 if (RT_FAILURE(rc))
1709 return rc;
1710 rc = PDMDevHlpIOPortRegisterGC(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1711 if (RT_FAILURE(rc))
1712 return rc;
1713 }
1714 if (fR0Enabled)
1715 {
1716 rc = pDevIns->pDevHlpR3->pfnIOPortRegisterR0(pDevIns, 0x60, 1, 0, "kbdIOPortDataWrite", "kbdIOPortDataRead", NULL, NULL, "PC Keyboard - Data");
1717 if (RT_FAILURE(rc))
1718 return rc;
1719 rc = pDevIns->pDevHlpR3->pfnIOPortRegisterR0(pDevIns, 0x64, 1, 0, "kbdIOPortCommandWrite", "kbdIOPortStatusRead", NULL, NULL, "PC Keyboard - Command / Status");
1720 if (RT_FAILURE(rc))
1721 return rc;
1722 }
1723 rc = PDMDevHlpSSMRegister(pDevIns, g_DevicePS2KeyboardMouse.szDeviceName, iInstance, PCKBD_SAVED_STATE_VERSION, sizeof(*pThis),
1724 NULL, kbdSaveExec, NULL,
1725 NULL, kbdLoadExec, NULL);
1726 if (RT_FAILURE(rc))
1727 return rc;
1728
1729 /*
1730 * Attach to the keyboard and mouse drivers.
1731 */
1732 rc = kbdAttach(pDevIns, 0 /* keyboard LUN # */, PDMDEVATT_FLAGS_NOT_HOT_PLUG);
1733 if (RT_FAILURE(rc))
1734 return rc;
1735 rc = kbdAttach(pDevIns, 1 /* aux/mouse LUN # */, PDMDEVATT_FLAGS_NOT_HOT_PLUG);
1736 if (RT_FAILURE(rc))
1737 return rc;
1738
1739 /*
1740 * Initialize the device state.
1741 */
1742 kbdReset(pDevIns);
1743
1744 return VINF_SUCCESS;
1745}
1746
1747
1748/**
1749 * The device registration structure.
1750 */
1751const PDMDEVREG g_DevicePS2KeyboardMouse =
1752{
1753 /* u32Version */
1754 PDM_DEVREG_VERSION,
1755 /* szDeviceName */
1756 "pckbd",
1757 /* szRCMod */
1758 "VBoxDDGC.gc",
1759 /* szR0Mod */
1760 "VBoxDDR0.r0",
1761 /* pszDescription */
1762 "PS/2 Keyboard and Mouse device. Emulates both the keyboard, mouse and the keyboard controller. "
1763 "LUN #0 is the keyboard connector. "
1764 "LUN #1 is the aux/mouse connector.",
1765 /* fFlags */
1766 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,
1767 /* fClass */
1768 PDM_DEVREG_CLASS_INPUT,
1769 /* cMaxInstances */
1770 1,
1771 /* cbInstance */
1772 sizeof(KBDState),
1773 /* pfnConstruct */
1774 kbdConstruct,
1775 /* pfnDestruct */
1776 NULL,
1777 /* pfnRelocate */
1778 kdbRelocate,
1779 /* pfnIOCtl */
1780 NULL,
1781 /* pfnPowerOn */
1782 NULL,
1783 /* pfnReset */
1784 kbdReset,
1785 /* pfnSuspend */
1786 NULL,
1787 /* pfnResume */
1788 NULL,
1789 /* pfnAttach */
1790 kbdAttach,
1791 /* pfnDetach */
1792 kbdDetach,
1793 /* pfnQueryInterface. */
1794 NULL,
1795 /* pfnInitComplete */
1796 NULL,
1797 /* pfnPowerOff */
1798 NULL,
1799 /* pfnSoftReset */
1800 NULL,
1801 /* u32VersionEnd */
1802 PDM_DEVREG_VERSION
1803};
1804
1805#endif /* IN_RING3 */
1806#endif /* VBOX */
1807#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1808
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use