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