|
|
1.1 root 1: /*
2: * QEMU PS/2 keyboard/mouse emulation
1.1.1.4 ! root 3: *
1.1 root 4: * Copyright (c) 2003 Fabrice Bellard
1.1.1.4 ! root 5: *
1.1 root 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: */
1.1.1.4 ! root 24: #include "hw.h"
! 25: #include "ps2.h"
! 26: #include "console.h"
1.1 root 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_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 */
43:
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 */
48:
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. */
66:
67: #define MOUSE_STATUS_REMOTE 0x40
68: #define MOUSE_STATUS_ENABLED 0x20
69: #define MOUSE_STATUS_SCALE21 0x10
70:
71: #define PS2_QUEUE_SIZE 256
72:
73: typedef struct {
74: uint8_t data[PS2_QUEUE_SIZE];
75: int rptr, wptr, count;
76: } PS2Queue;
77:
78: typedef struct {
79: PS2Queue queue;
80: int32_t write_cmd;
81: void (*update_irq)(void *, int);
82: void *update_arg;
83: } PS2State;
84:
85: typedef struct {
86: PS2State common;
87: int scan_enabled;
1.1.1.2 root 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;
1.1 root 92: } PS2KbdState;
93:
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;
107:
1.1.1.2 root 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
118: };
119:
1.1 root 120: void ps2_queue(void *opaque, int b)
121: {
122: PS2State *s = (PS2State *)opaque;
123: PS2Queue *q = &s->queue;
124:
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);
132: }
133:
134: static void ps2_put_keycode(void *opaque, int keycode)
135: {
1.1.1.2 root 136: PS2KbdState *s = opaque;
137: if (!s->translate && keycode < 0xe0)
138: {
139: if (keycode & 0x80)
140: ps2_queue(&s->common, 0xf0);
141: keycode = ps2_raw_keycode[keycode & 0x7f];
142: }
1.1 root 143: ps2_queue(&s->common, keycode);
144: }
145:
146: uint32_t ps2_read_data(void *opaque)
147: {
148: PS2State *s = (PS2State *)opaque;
149: PS2Queue *q;
150: int val, index;
1.1.1.4 ! root 151:
1.1 root 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);
170: }
171: return val;
172: }
173:
174: static void ps2_reset_keyboard(PS2KbdState *s)
175: {
176: s->scan_enabled = 1;
177: }
178:
179: void ps2_write_keyboard(void *opaque, int val)
180: {
181: PS2KbdState *s = (PS2KbdState *)opaque;
182:
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;
228: }
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;
238: }
239: }
240:
1.1.1.2 root 241: /* Set the scancode translation mode.
242: 0 = raw scancodes.
243: 1 = translated scancodes (used by qemu internally). */
244:
245: void ps2_keyboard_set_translation(void *opaque, int mode)
246: {
247: PS2KbdState *s = (PS2KbdState *)opaque;
248: s->translate = mode;
249: }
250:
1.1 root 251: static void ps2_mouse_send_packet(PS2MouseState *s)
252: {
253: unsigned int b;
254: int dx1, dy1, dz1;
255:
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;
291: }
292:
293: /* update deltas */
294: s->mouse_dx -= dx1;
295: s->mouse_dy -= dy1;
296: s->mouse_dz -= dz1;
297: }
298:
1.1.1.4 ! root 299: static void ps2_mouse_event(void *opaque,
1.1 root 300: int dx, int dy, int dz, int buttons_state)
301: {
302: PS2MouseState *s = opaque;
303:
304: /* check if deltas are recorded when disabled */
305: if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
306: return;
307:
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;
1.1.1.4 ! root 316:
1.1 root 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;
325: }
326: }
327: }
328:
1.1.1.4 ! root 329: void ps2_mouse_fake_event(void *opaque)
! 330: {
! 331: ps2_mouse_event(opaque, 1, 0, 0, 0);
! 332: }
! 333:
1.1 root 334: void ps2_write_mouse(void *opaque, int val)
335: {
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;
352: }
353: }
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;
419: }
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:
1.1.1.4 ! root 439: if (val == 80)
1.1 root 440: s->mouse_type = 3; /* IMPS/2 */
441: s->mouse_detect_state = 0;
442: break;
443: case 3:
1.1.1.4 ! root 444: if (val == 80)
1.1 root 445: s->mouse_type = 4; /* IMEX */
446: s->mouse_detect_state = 0;
447: break;
448: }
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;
457: }
458: }
459:
460: static void ps2_reset(void *opaque)
461: {
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;
469: }
470:
1.1.1.2 root 471: static void ps2_common_save (QEMUFile *f, PS2State *s)
472: {
1.1.1.4 ! root 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);
1.1.1.2 root 477: qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data));
478: }
479:
480: static void ps2_common_load (QEMUFile *f, PS2State *s)
481: {
1.1.1.4 ! root 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);
1.1.1.2 root 486: qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data));
487: }
488:
1.1 root 489: static void ps2_kbd_save(QEMUFile* f, void* opaque)
490: {
491: PS2KbdState *s = (PS2KbdState*)opaque;
1.1.1.2 root 492:
493: ps2_common_save (f, &s->common);
1.1.1.4 ! root 494: qemu_put_be32(f, s->scan_enabled);
! 495: qemu_put_be32(f, s->translate);
1.1 root 496: }
497:
498: static void ps2_mouse_save(QEMUFile* f, void* opaque)
499: {
500: PS2MouseState *s = (PS2MouseState*)opaque;
1.1.1.2 root 501:
502: ps2_common_save (f, &s->common);
1.1 root 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);
1.1.1.4 ! root 509: qemu_put_be32(f, s->mouse_dx);
! 510: qemu_put_be32(f, s->mouse_dy);
! 511: qemu_put_be32(f, s->mouse_dz);
1.1 root 512: qemu_put_8s(f, &s->mouse_buttons);
513: }
514:
515: static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
516: {
517: PS2KbdState *s = (PS2KbdState*)opaque;
1.1.1.2 root 518:
519: if (version_id != 2)
1.1 root 520: return -EINVAL;
1.1.1.2 root 521:
522: ps2_common_load (f, &s->common);
1.1.1.4 ! root 523: s->scan_enabled=qemu_get_be32(f);
! 524: s->translate=qemu_get_be32(f);
1.1 root 525: return 0;
526: }
527:
528: static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
529: {
530: PS2MouseState *s = (PS2MouseState*)opaque;
1.1.1.2 root 531:
532: if (version_id != 2)
1.1 root 533: return -EINVAL;
1.1.1.2 root 534:
535: ps2_common_load (f, &s->common);
1.1 root 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);
1.1.1.4 ! root 542: s->mouse_dx=qemu_get_be32(f);
! 543: s->mouse_dy=qemu_get_be32(f);
! 544: s->mouse_dz=qemu_get_be32(f);
1.1 root 545: qemu_get_8s(f, &s->mouse_buttons);
546: return 0;
547: }
548:
549: void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
550: {
551: PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
552:
553: s->common.update_irq = update_irq;
554: s->common.update_arg = update_arg;
555: ps2_reset(&s->common);
1.1.1.2 root 556: register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s);
1.1 root 557: qemu_add_kbd_event_handler(ps2_put_keycode, s);
558: qemu_register_reset(ps2_reset, &s->common);
559: return s;
560: }
561:
562: void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
563: {
564: PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
565:
566: s->common.update_irq = update_irq;
567: s->common.update_arg = update_arg;
568: ps2_reset(&s->common);
1.1.1.2 root 569: register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
1.1.1.3 root 570: qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
1.1 root 571: qemu_register_reset(ps2_reset, &s->common);
572: return s;
573: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.