VirtualBox

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

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

DevPS.cpp: svn:keywords.

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