VirtualBox

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

Last change on this file since 3481 was 3265, checked in by vboxsync, 17 years ago

NACK mouse commands we don't implement (not doing so slows down OS/2 boot up by 10+ seconds). Return 0 if anyone tries to read non-standard 8042 RAM (commands 0x21 thru 0x3f).

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