2 * QEMU PS/2 keyboard/mouse emulation
4 * Copyright (c) 2003 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 /* debug PC keyboard */
29 /* debug PC keyboard : only mouse */
32 /* Keyboard Commands */
33 #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
34 #define KBD_CMD_ECHO 0xEE
35 #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
36 #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
37 #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
38 #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
39 #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
40 #define KBD_CMD_RESET 0xFF /* Reset */
42 /* Keyboard Replies */
43 #define KBD_REPLY_POR 0xAA /* Power on reset */
44 #define KBD_REPLY_ACK 0xFA /* Command ACK */
45 #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
48 #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
49 #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
50 #define AUX_SET_RES 0xE8 /* Set resolution */
51 #define AUX_GET_SCALE 0xE9 /* Get scaling factor */
52 #define AUX_SET_STREAM 0xEA /* Set stream mode */
53 #define AUX_POLL 0xEB /* Poll */
54 #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
55 #define AUX_SET_WRAP 0xEE /* Set wrap mode */
56 #define AUX_SET_REMOTE 0xF0 /* Set remote mode */
57 #define AUX_GET_TYPE 0xF2 /* Get type */
58 #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
59 #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
60 #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
61 #define AUX_SET_DEFAULT 0xF6
62 #define AUX_RESET 0xFF /* Reset aux device */
63 #define AUX_ACK 0xFA /* Command byte ACK. */
65 #define MOUSE_STATUS_REMOTE 0x40
66 #define MOUSE_STATUS_ENABLED 0x20
67 #define MOUSE_STATUS_SCALE21 0x10
69 #define PS2_QUEUE_SIZE 256
72 uint8_t data[PS2_QUEUE_SIZE];
73 int rptr, wptr, count;
79 void (*update_irq)(void *, int);
91 uint8_t mouse_resolution;
92 uint8_t mouse_sample_rate;
94 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
95 uint8_t mouse_detect_state;
96 int mouse_dx; /* current values, needed for 'poll' mode */
99 uint8_t mouse_buttons;
102 void ps2_queue(void *opaque, int b)
104 PS2State *s = (PS2State *)opaque;
105 PS2Queue *q = &s->queue;
107 if (q->count >= PS2_QUEUE_SIZE)
109 q->data[q->wptr] = b;
110 if (++q->wptr == PS2_QUEUE_SIZE)
113 s->update_irq(s->update_arg, 1);
116 static void ps2_put_keycode(void *opaque, int keycode)
118 PS2MouseState *s = opaque;
119 ps2_queue(&s->common, keycode);
122 uint32_t ps2_read_data(void *opaque)
124 PS2State *s = (PS2State *)opaque;
130 /* NOTE: if no data left, we return the last keyboard one
131 (needed for EMM386) */
132 /* XXX: need a timer to do things correctly */
135 index = PS2_QUEUE_SIZE - 1;
136 val = q->data[index];
138 val = q->data[q->rptr];
139 if (++q->rptr == PS2_QUEUE_SIZE)
142 /* reading deasserts IRQ */
143 s->update_irq(s->update_arg, 0);
144 /* reassert IRQs if data left */
145 s->update_irq(s->update_arg, q->count != 0);
150 static void ps2_reset_keyboard(PS2KbdState *s)
155 void ps2_write_keyboard(void *opaque, int val)
157 PS2KbdState *s = (PS2KbdState *)opaque;
159 switch(s->common.write_cmd) {
164 ps2_queue(&s->common, KBD_REPLY_ACK);
167 ps2_queue(&s->common, KBD_REPLY_RESEND);
170 ps2_queue(&s->common, KBD_REPLY_ACK);
171 ps2_queue(&s->common, 0xab);
172 ps2_queue(&s->common, 0x83);
175 ps2_queue(&s->common, KBD_CMD_ECHO);
179 ps2_queue(&s->common, KBD_REPLY_ACK);
181 case KBD_CMD_SET_LEDS:
182 case KBD_CMD_SET_RATE:
183 s->common.write_cmd = val;
184 ps2_queue(&s->common, KBD_REPLY_ACK);
186 case KBD_CMD_RESET_DISABLE:
187 ps2_reset_keyboard(s);
189 ps2_queue(&s->common, KBD_REPLY_ACK);
191 case KBD_CMD_RESET_ENABLE:
192 ps2_reset_keyboard(s);
194 ps2_queue(&s->common, KBD_REPLY_ACK);
197 ps2_reset_keyboard(s);
198 ps2_queue(&s->common, KBD_REPLY_ACK);
199 ps2_queue(&s->common, KBD_REPLY_POR);
202 ps2_queue(&s->common, KBD_REPLY_ACK);
206 case KBD_CMD_SET_LEDS:
207 ps2_queue(&s->common, KBD_REPLY_ACK);
208 s->common.write_cmd = -1;
210 case KBD_CMD_SET_RATE:
211 ps2_queue(&s->common, KBD_REPLY_ACK);
212 s->common.write_cmd = -1;
217 static void ps2_mouse_send_packet(PS2MouseState *s)
225 /* XXX: increase range to 8 bits ? */
234 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
235 ps2_queue(&s->common, b);
236 ps2_queue(&s->common, dx1 & 0xff);
237 ps2_queue(&s->common, dy1 & 0xff);
238 /* extra byte for IMPS/2 or IMEX */
239 switch(s->mouse_type) {
247 ps2_queue(&s->common, dz1 & 0xff);
254 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
255 ps2_queue(&s->common, b);
265 static void ps2_mouse_event(void *opaque,
266 int dx, int dy, int dz, int buttons_state)
268 PS2MouseState *s = opaque;
270 /* check if deltas are recorded when disabled */
271 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
277 /* XXX: SDL sometimes generates nul events: we delete them */
278 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
279 s->mouse_buttons == buttons_state)
281 s->mouse_buttons = buttons_state;
283 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
284 (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
286 /* if not remote, send event. Multiple events are sent if
288 ps2_mouse_send_packet(s);
289 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
295 void ps2_write_mouse(void *opaque, int val)
297 PS2MouseState *s = (PS2MouseState *)opaque;
299 printf("kbd: write mouse 0x%02x\n", val);
301 switch(s->common.write_cmd) {
306 if (val == AUX_RESET_WRAP) {
308 ps2_queue(&s->common, AUX_ACK);
310 } else if (val != AUX_RESET) {
311 ps2_queue(&s->common, val);
316 case AUX_SET_SCALE11:
317 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
318 ps2_queue(&s->common, AUX_ACK);
320 case AUX_SET_SCALE21:
321 s->mouse_status |= MOUSE_STATUS_SCALE21;
322 ps2_queue(&s->common, AUX_ACK);
325 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
326 ps2_queue(&s->common, AUX_ACK);
330 ps2_queue(&s->common, AUX_ACK);
333 s->mouse_status |= MOUSE_STATUS_REMOTE;
334 ps2_queue(&s->common, AUX_ACK);
337 ps2_queue(&s->common, AUX_ACK);
338 ps2_queue(&s->common, s->mouse_type);
342 s->common.write_cmd = val;
343 ps2_queue(&s->common, AUX_ACK);
346 ps2_queue(&s->common, AUX_ACK);
347 ps2_queue(&s->common, s->mouse_status);
348 ps2_queue(&s->common, s->mouse_resolution);
349 ps2_queue(&s->common, s->mouse_sample_rate);
352 ps2_queue(&s->common, AUX_ACK);
353 ps2_mouse_send_packet(s);
356 s->mouse_status |= MOUSE_STATUS_ENABLED;
357 ps2_queue(&s->common, AUX_ACK);
359 case AUX_DISABLE_DEV:
360 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
361 ps2_queue(&s->common, AUX_ACK);
363 case AUX_SET_DEFAULT:
364 s->mouse_sample_rate = 100;
365 s->mouse_resolution = 2;
367 ps2_queue(&s->common, AUX_ACK);
370 s->mouse_sample_rate = 100;
371 s->mouse_resolution = 2;
374 ps2_queue(&s->common, AUX_ACK);
375 ps2_queue(&s->common, 0xaa);
376 ps2_queue(&s->common, s->mouse_type);
383 s->mouse_sample_rate = val;
384 /* detect IMPS/2 or IMEX */
385 switch(s->mouse_detect_state) {
389 s->mouse_detect_state = 1;
393 s->mouse_detect_state = 2;
395 s->mouse_detect_state = 3;
397 s->mouse_detect_state = 0;
401 s->mouse_type = 3; /* IMPS/2 */
402 s->mouse_detect_state = 0;
406 s->mouse_type = 4; /* IMEX */
407 s->mouse_detect_state = 0;
410 ps2_queue(&s->common, AUX_ACK);
411 s->common.write_cmd = -1;
414 s->mouse_resolution = val;
415 ps2_queue(&s->common, AUX_ACK);
416 s->common.write_cmd = -1;
421 static void ps2_reset(void *opaque)
423 PS2State *s = (PS2State *)opaque;
432 static void ps2_kbd_save(QEMUFile* f, void* opaque)
434 PS2KbdState *s = (PS2KbdState*)opaque;
436 qemu_put_be32s(f, &s->common.write_cmd);
437 qemu_put_be32s(f, &s->scan_enabled);
440 static void ps2_mouse_save(QEMUFile* f, void* opaque)
442 PS2MouseState *s = (PS2MouseState*)opaque;
444 qemu_put_be32s(f, &s->common.write_cmd);
445 qemu_put_8s(f, &s->mouse_status);
446 qemu_put_8s(f, &s->mouse_resolution);
447 qemu_put_8s(f, &s->mouse_sample_rate);
448 qemu_put_8s(f, &s->mouse_wrap);
449 qemu_put_8s(f, &s->mouse_type);
450 qemu_put_8s(f, &s->mouse_detect_state);
451 qemu_put_be32s(f, &s->mouse_dx);
452 qemu_put_be32s(f, &s->mouse_dy);
453 qemu_put_be32s(f, &s->mouse_dz);
454 qemu_put_8s(f, &s->mouse_buttons);
457 static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
459 PS2KbdState *s = (PS2KbdState*)opaque;
463 qemu_get_be32s(f, &s->common.write_cmd);
464 qemu_get_be32s(f, &s->scan_enabled);
468 static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
470 PS2MouseState *s = (PS2MouseState*)opaque;
474 qemu_get_be32s(f, &s->common.write_cmd);
475 qemu_get_8s(f, &s->mouse_status);
476 qemu_get_8s(f, &s->mouse_resolution);
477 qemu_get_8s(f, &s->mouse_sample_rate);
478 qemu_get_8s(f, &s->mouse_wrap);
479 qemu_get_8s(f, &s->mouse_type);
480 qemu_get_8s(f, &s->mouse_detect_state);
481 qemu_get_be32s(f, &s->mouse_dx);
482 qemu_get_be32s(f, &s->mouse_dy);
483 qemu_get_be32s(f, &s->mouse_dz);
484 qemu_get_8s(f, &s->mouse_buttons);
488 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
490 PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
492 s->common.update_irq = update_irq;
493 s->common.update_arg = update_arg;
494 ps2_reset(&s->common);
495 register_savevm("ps2kbd", 0, 1, ps2_kbd_save, ps2_kbd_load, s);
496 qemu_add_kbd_event_handler(ps2_put_keycode, s);
497 qemu_register_reset(ps2_reset, &s->common);
501 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
503 PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
505 s->common.update_irq = update_irq;
506 s->common.update_arg = update_arg;
507 ps2_reset(&s->common);
508 register_savevm("ps2mouse", 0, 1, ps2_mouse_save, ps2_mouse_load, s);
509 qemu_add_mouse_event_handler(ps2_mouse_event, s);
510 qemu_register_reset(ps2_reset, &s->common);