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