VirtualBox

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

最後變更 在這個檔案從39972是 39972,由 vboxsync 提交於 13 年 前

Updated struct testcase to see what breaks.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette