VirtualBox

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

Last change on this file since 22621 was 22584, checked in by vboxsync, 15 years ago

Devices: tab

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