VirtualBox

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

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

PDM: s/szDeviceName/szName/g - PDMDEVREG & PDMUSBREG.

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