VirtualBox

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

Last change on this file since 7086 was 6102, checked in by vboxsync, 17 years ago

Implemented 8042 command E0h, read test inputs.

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