VirtualBox

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

Last change on this file since 35025 was 34371, checked in by vboxsync, 14 years ago

DevPS2: Removed code identified as incorrect in comment. I canot see where it helps, only what it breaks.

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