Convert udivx and sdivx to TCG
[qemu/malc.git] / hw / ps2.c
blob130e894784aabc8f8d300b655b1fb6e2f8e13218
1 /*
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
22 * THE SOFTWARE.
24 #include "hw.h"
25 #include "ps2.h"
26 #include "console.h"
28 /* debug PC keyboard */
29 //#define DEBUG_KBD
31 /* debug PC keyboard : only mouse */
32 //#define DEBUG_MOUSE
34 /* Keyboard Commands */
35 #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
36 #define KBD_CMD_ECHO 0xEE
37 #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
38 #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
39 #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
40 #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
41 #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
42 #define KBD_CMD_RESET 0xFF /* Reset */
44 /* Keyboard Replies */
45 #define KBD_REPLY_POR 0xAA /* Power on reset */
46 #define KBD_REPLY_ACK 0xFA /* Command ACK */
47 #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
49 /* Mouse Commands */
50 #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
51 #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
52 #define AUX_SET_RES 0xE8 /* Set resolution */
53 #define AUX_GET_SCALE 0xE9 /* Get scaling factor */
54 #define AUX_SET_STREAM 0xEA /* Set stream mode */
55 #define AUX_POLL 0xEB /* Poll */
56 #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
57 #define AUX_SET_WRAP 0xEE /* Set wrap mode */
58 #define AUX_SET_REMOTE 0xF0 /* Set remote mode */
59 #define AUX_GET_TYPE 0xF2 /* Get type */
60 #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
61 #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
62 #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
63 #define AUX_SET_DEFAULT 0xF6
64 #define AUX_RESET 0xFF /* Reset aux device */
65 #define AUX_ACK 0xFA /* Command byte ACK. */
67 #define MOUSE_STATUS_REMOTE 0x40
68 #define MOUSE_STATUS_ENABLED 0x20
69 #define MOUSE_STATUS_SCALE21 0x10
71 #define PS2_QUEUE_SIZE 256
73 typedef struct {
74 uint8_t data[PS2_QUEUE_SIZE];
75 int rptr, wptr, count;
76 } PS2Queue;
78 typedef struct {
79 PS2Queue queue;
80 int32_t write_cmd;
81 void (*update_irq)(void *, int);
82 void *update_arg;
83 } PS2State;
85 typedef struct {
86 PS2State common;
87 int scan_enabled;
88 /* Qemu uses translated PC scancodes internally. To avoid multiple
89 conversions we do the translation (if any) in the PS/2 emulation
90 not the keyboard controller. */
91 int translate;
92 } PS2KbdState;
94 typedef struct {
95 PS2State common;
96 uint8_t mouse_status;
97 uint8_t mouse_resolution;
98 uint8_t mouse_sample_rate;
99 uint8_t mouse_wrap;
100 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
101 uint8_t mouse_detect_state;
102 int mouse_dx; /* current values, needed for 'poll' mode */
103 int mouse_dy;
104 int mouse_dz;
105 uint8_t mouse_buttons;
106 } PS2MouseState;
108 /* Table to convert from PC scancodes to raw scancodes. */
109 static const unsigned char ps2_raw_keycode[128] = {
110 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
111 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
112 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
113 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
114 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
115 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
116 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
117 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
120 void ps2_queue(void *opaque, int b)
122 PS2State *s = (PS2State *)opaque;
123 PS2Queue *q = &s->queue;
125 if (q->count >= PS2_QUEUE_SIZE)
126 return;
127 q->data[q->wptr] = b;
128 if (++q->wptr == PS2_QUEUE_SIZE)
129 q->wptr = 0;
130 q->count++;
131 s->update_irq(s->update_arg, 1);
134 static void ps2_put_keycode(void *opaque, int keycode)
136 PS2KbdState *s = opaque;
137 if (!s->translate && keycode < 0xe0)
139 if (keycode & 0x80)
140 ps2_queue(&s->common, 0xf0);
141 keycode = ps2_raw_keycode[keycode & 0x7f];
143 ps2_queue(&s->common, keycode);
146 uint32_t ps2_read_data(void *opaque)
148 PS2State *s = (PS2State *)opaque;
149 PS2Queue *q;
150 int val, index;
152 q = &s->queue;
153 if (q->count == 0) {
154 /* NOTE: if no data left, we return the last keyboard one
155 (needed for EMM386) */
156 /* XXX: need a timer to do things correctly */
157 index = q->rptr - 1;
158 if (index < 0)
159 index = PS2_QUEUE_SIZE - 1;
160 val = q->data[index];
161 } else {
162 val = q->data[q->rptr];
163 if (++q->rptr == PS2_QUEUE_SIZE)
164 q->rptr = 0;
165 q->count--;
166 /* reading deasserts IRQ */
167 s->update_irq(s->update_arg, 0);
168 /* reassert IRQs if data left */
169 s->update_irq(s->update_arg, q->count != 0);
171 return val;
174 static void ps2_reset_keyboard(PS2KbdState *s)
176 s->scan_enabled = 1;
179 void ps2_write_keyboard(void *opaque, int val)
181 PS2KbdState *s = (PS2KbdState *)opaque;
183 switch(s->common.write_cmd) {
184 default:
185 case -1:
186 switch(val) {
187 case 0x00:
188 ps2_queue(&s->common, KBD_REPLY_ACK);
189 break;
190 case 0x05:
191 ps2_queue(&s->common, KBD_REPLY_RESEND);
192 break;
193 case KBD_CMD_GET_ID:
194 ps2_queue(&s->common, KBD_REPLY_ACK);
195 ps2_queue(&s->common, 0xab);
196 ps2_queue(&s->common, 0x83);
197 break;
198 case KBD_CMD_ECHO:
199 ps2_queue(&s->common, KBD_CMD_ECHO);
200 break;
201 case KBD_CMD_ENABLE:
202 s->scan_enabled = 1;
203 ps2_queue(&s->common, KBD_REPLY_ACK);
204 break;
205 case KBD_CMD_SET_LEDS:
206 case KBD_CMD_SET_RATE:
207 s->common.write_cmd = val;
208 ps2_queue(&s->common, KBD_REPLY_ACK);
209 break;
210 case KBD_CMD_RESET_DISABLE:
211 ps2_reset_keyboard(s);
212 s->scan_enabled = 0;
213 ps2_queue(&s->common, KBD_REPLY_ACK);
214 break;
215 case KBD_CMD_RESET_ENABLE:
216 ps2_reset_keyboard(s);
217 s->scan_enabled = 1;
218 ps2_queue(&s->common, KBD_REPLY_ACK);
219 break;
220 case KBD_CMD_RESET:
221 ps2_reset_keyboard(s);
222 ps2_queue(&s->common, KBD_REPLY_ACK);
223 ps2_queue(&s->common, KBD_REPLY_POR);
224 break;
225 default:
226 ps2_queue(&s->common, KBD_REPLY_ACK);
227 break;
229 break;
230 case KBD_CMD_SET_LEDS:
231 ps2_queue(&s->common, KBD_REPLY_ACK);
232 s->common.write_cmd = -1;
233 break;
234 case KBD_CMD_SET_RATE:
235 ps2_queue(&s->common, KBD_REPLY_ACK);
236 s->common.write_cmd = -1;
237 break;
241 /* Set the scancode translation mode.
242 0 = raw scancodes.
243 1 = translated scancodes (used by qemu internally). */
245 void ps2_keyboard_set_translation(void *opaque, int mode)
247 PS2KbdState *s = (PS2KbdState *)opaque;
248 s->translate = mode;
251 static void ps2_mouse_send_packet(PS2MouseState *s)
253 unsigned int b;
254 int dx1, dy1, dz1;
256 dx1 = s->mouse_dx;
257 dy1 = s->mouse_dy;
258 dz1 = s->mouse_dz;
259 /* XXX: increase range to 8 bits ? */
260 if (dx1 > 127)
261 dx1 = 127;
262 else if (dx1 < -127)
263 dx1 = -127;
264 if (dy1 > 127)
265 dy1 = 127;
266 else if (dy1 < -127)
267 dy1 = -127;
268 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
269 ps2_queue(&s->common, b);
270 ps2_queue(&s->common, dx1 & 0xff);
271 ps2_queue(&s->common, dy1 & 0xff);
272 /* extra byte for IMPS/2 or IMEX */
273 switch(s->mouse_type) {
274 default:
275 break;
276 case 3:
277 if (dz1 > 127)
278 dz1 = 127;
279 else if (dz1 < -127)
280 dz1 = -127;
281 ps2_queue(&s->common, dz1 & 0xff);
282 break;
283 case 4:
284 if (dz1 > 7)
285 dz1 = 7;
286 else if (dz1 < -7)
287 dz1 = -7;
288 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
289 ps2_queue(&s->common, b);
290 break;
293 /* update deltas */
294 s->mouse_dx -= dx1;
295 s->mouse_dy -= dy1;
296 s->mouse_dz -= dz1;
299 static void ps2_mouse_event(void *opaque,
300 int dx, int dy, int dz, int buttons_state)
302 PS2MouseState *s = opaque;
304 /* check if deltas are recorded when disabled */
305 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
306 return;
308 s->mouse_dx += dx;
309 s->mouse_dy -= dy;
310 s->mouse_dz += dz;
311 /* XXX: SDL sometimes generates nul events: we delete them */
312 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
313 s->mouse_buttons == buttons_state)
314 return;
315 s->mouse_buttons = buttons_state;
317 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
318 (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
319 for(;;) {
320 /* if not remote, send event. Multiple events are sent if
321 too big deltas */
322 ps2_mouse_send_packet(s);
323 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
324 break;
329 void ps2_mouse_fake_event(void *opaque)
331 ps2_mouse_event(opaque, 1, 0, 0, 0);
334 void ps2_write_mouse(void *opaque, int val)
336 PS2MouseState *s = (PS2MouseState *)opaque;
337 #ifdef DEBUG_MOUSE
338 printf("kbd: write mouse 0x%02x\n", val);
339 #endif
340 switch(s->common.write_cmd) {
341 default:
342 case -1:
343 /* mouse command */
344 if (s->mouse_wrap) {
345 if (val == AUX_RESET_WRAP) {
346 s->mouse_wrap = 0;
347 ps2_queue(&s->common, AUX_ACK);
348 return;
349 } else if (val != AUX_RESET) {
350 ps2_queue(&s->common, val);
351 return;
354 switch(val) {
355 case AUX_SET_SCALE11:
356 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
357 ps2_queue(&s->common, AUX_ACK);
358 break;
359 case AUX_SET_SCALE21:
360 s->mouse_status |= MOUSE_STATUS_SCALE21;
361 ps2_queue(&s->common, AUX_ACK);
362 break;
363 case AUX_SET_STREAM:
364 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
365 ps2_queue(&s->common, AUX_ACK);
366 break;
367 case AUX_SET_WRAP:
368 s->mouse_wrap = 1;
369 ps2_queue(&s->common, AUX_ACK);
370 break;
371 case AUX_SET_REMOTE:
372 s->mouse_status |= MOUSE_STATUS_REMOTE;
373 ps2_queue(&s->common, AUX_ACK);
374 break;
375 case AUX_GET_TYPE:
376 ps2_queue(&s->common, AUX_ACK);
377 ps2_queue(&s->common, s->mouse_type);
378 break;
379 case AUX_SET_RES:
380 case AUX_SET_SAMPLE:
381 s->common.write_cmd = val;
382 ps2_queue(&s->common, AUX_ACK);
383 break;
384 case AUX_GET_SCALE:
385 ps2_queue(&s->common, AUX_ACK);
386 ps2_queue(&s->common, s->mouse_status);
387 ps2_queue(&s->common, s->mouse_resolution);
388 ps2_queue(&s->common, s->mouse_sample_rate);
389 break;
390 case AUX_POLL:
391 ps2_queue(&s->common, AUX_ACK);
392 ps2_mouse_send_packet(s);
393 break;
394 case AUX_ENABLE_DEV:
395 s->mouse_status |= MOUSE_STATUS_ENABLED;
396 ps2_queue(&s->common, AUX_ACK);
397 break;
398 case AUX_DISABLE_DEV:
399 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
400 ps2_queue(&s->common, AUX_ACK);
401 break;
402 case AUX_SET_DEFAULT:
403 s->mouse_sample_rate = 100;
404 s->mouse_resolution = 2;
405 s->mouse_status = 0;
406 ps2_queue(&s->common, AUX_ACK);
407 break;
408 case AUX_RESET:
409 s->mouse_sample_rate = 100;
410 s->mouse_resolution = 2;
411 s->mouse_status = 0;
412 s->mouse_type = 0;
413 ps2_queue(&s->common, AUX_ACK);
414 ps2_queue(&s->common, 0xaa);
415 ps2_queue(&s->common, s->mouse_type);
416 break;
417 default:
418 break;
420 break;
421 case AUX_SET_SAMPLE:
422 s->mouse_sample_rate = val;
423 /* detect IMPS/2 or IMEX */
424 switch(s->mouse_detect_state) {
425 default:
426 case 0:
427 if (val == 200)
428 s->mouse_detect_state = 1;
429 break;
430 case 1:
431 if (val == 100)
432 s->mouse_detect_state = 2;
433 else if (val == 200)
434 s->mouse_detect_state = 3;
435 else
436 s->mouse_detect_state = 0;
437 break;
438 case 2:
439 if (val == 80)
440 s->mouse_type = 3; /* IMPS/2 */
441 s->mouse_detect_state = 0;
442 break;
443 case 3:
444 if (val == 80)
445 s->mouse_type = 4; /* IMEX */
446 s->mouse_detect_state = 0;
447 break;
449 ps2_queue(&s->common, AUX_ACK);
450 s->common.write_cmd = -1;
451 break;
452 case AUX_SET_RES:
453 s->mouse_resolution = val;
454 ps2_queue(&s->common, AUX_ACK);
455 s->common.write_cmd = -1;
456 break;
460 static void ps2_reset(void *opaque)
462 PS2State *s = (PS2State *)opaque;
463 PS2Queue *q;
464 s->write_cmd = -1;
465 q = &s->queue;
466 q->rptr = 0;
467 q->wptr = 0;
468 q->count = 0;
471 static void ps2_common_save (QEMUFile *f, PS2State *s)
473 qemu_put_be32 (f, s->write_cmd);
474 qemu_put_be32 (f, s->queue.rptr);
475 qemu_put_be32 (f, s->queue.wptr);
476 qemu_put_be32 (f, s->queue.count);
477 qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data));
480 static void ps2_common_load (QEMUFile *f, PS2State *s)
482 s->write_cmd=qemu_get_be32 (f);
483 s->queue.rptr=qemu_get_be32 (f);
484 s->queue.wptr=qemu_get_be32 (f);
485 s->queue.count=qemu_get_be32 (f);
486 qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data));
489 static void ps2_kbd_save(QEMUFile* f, void* opaque)
491 PS2KbdState *s = (PS2KbdState*)opaque;
493 ps2_common_save (f, &s->common);
494 qemu_put_be32(f, s->scan_enabled);
495 qemu_put_be32(f, s->translate);
498 static void ps2_mouse_save(QEMUFile* f, void* opaque)
500 PS2MouseState *s = (PS2MouseState*)opaque;
502 ps2_common_save (f, &s->common);
503 qemu_put_8s(f, &s->mouse_status);
504 qemu_put_8s(f, &s->mouse_resolution);
505 qemu_put_8s(f, &s->mouse_sample_rate);
506 qemu_put_8s(f, &s->mouse_wrap);
507 qemu_put_8s(f, &s->mouse_type);
508 qemu_put_8s(f, &s->mouse_detect_state);
509 qemu_put_be32(f, s->mouse_dx);
510 qemu_put_be32(f, s->mouse_dy);
511 qemu_put_be32(f, s->mouse_dz);
512 qemu_put_8s(f, &s->mouse_buttons);
515 static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
517 PS2KbdState *s = (PS2KbdState*)opaque;
519 if (version_id != 2)
520 return -EINVAL;
522 ps2_common_load (f, &s->common);
523 s->scan_enabled=qemu_get_be32(f);
524 s->translate=qemu_get_be32(f);
525 return 0;
528 static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
530 PS2MouseState *s = (PS2MouseState*)opaque;
532 if (version_id != 2)
533 return -EINVAL;
535 ps2_common_load (f, &s->common);
536 qemu_get_8s(f, &s->mouse_status);
537 qemu_get_8s(f, &s->mouse_resolution);
538 qemu_get_8s(f, &s->mouse_sample_rate);
539 qemu_get_8s(f, &s->mouse_wrap);
540 qemu_get_8s(f, &s->mouse_type);
541 qemu_get_8s(f, &s->mouse_detect_state);
542 s->mouse_dx=qemu_get_be32(f);
543 s->mouse_dy=qemu_get_be32(f);
544 s->mouse_dz=qemu_get_be32(f);
545 qemu_get_8s(f, &s->mouse_buttons);
546 return 0;
549 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
551 PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
553 s->common.update_irq = update_irq;
554 s->common.update_arg = update_arg;
555 ps2_reset(&s->common);
556 register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s);
557 qemu_add_kbd_event_handler(ps2_put_keycode, s);
558 qemu_register_reset(ps2_reset, &s->common);
559 return s;
562 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
564 PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
566 s->common.update_irq = update_irq;
567 s->common.update_arg = update_arg;
568 ps2_reset(&s->common);
569 register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
570 qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
571 qemu_register_reset(ps2_reset, &s->common);
572 return s;