VirtualBox

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

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

DevPS2: Added qemu code to emulate turning off scancode translation in controller (S8 keyboard fix); from http://git.savannah.gnu.org/cgit/qemu.git/tree/hw/ps2.c#n502

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