VirtualBox

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

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

Eliminated HCPTRTYPE and replaced with R3R0PTRTYPE where necessary.

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