|
|
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;
86: } PS2KbdState;
87:
88: typedef struct {
89: PS2State common;
90: uint8_t mouse_status;
91: uint8_t mouse_resolution;
92: uint8_t mouse_sample_rate;
93: uint8_t mouse_wrap;
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 */
97: int mouse_dy;
98: int mouse_dz;
99: uint8_t mouse_buttons;
100: } PS2MouseState;
101:
102: void ps2_queue(void *opaque, int b)
103: {
104: PS2State *s = (PS2State *)opaque;
105: PS2Queue *q = &s->queue;
106:
107: if (q->count >= PS2_QUEUE_SIZE)
108: return;
109: q->data[q->wptr] = b;
110: if (++q->wptr == PS2_QUEUE_SIZE)
111: q->wptr = 0;
112: q->count++;
113: s->update_irq(s->update_arg, 1);
114: }
115:
116: static void ps2_put_keycode(void *opaque, int keycode)
117: {
118: PS2MouseState *s = opaque;
119: ps2_queue(&s->common, keycode);
120: }
121:
122: uint32_t ps2_read_data(void *opaque)
123: {
124: PS2State *s = (PS2State *)opaque;
125: PS2Queue *q;
126: int val, index;
127:
128: q = &s->queue;
129: if (q->count == 0) {
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 */
133: index = q->rptr - 1;
134: if (index < 0)
135: index = PS2_QUEUE_SIZE - 1;
136: val = q->data[index];
137: } else {
138: val = q->data[q->rptr];
139: if (++q->rptr == PS2_QUEUE_SIZE)
140: q->rptr = 0;
141: q->count--;
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);
146: }
147: return val;
148: }
149:
150: static void ps2_reset_keyboard(PS2KbdState *s)
151: {
152: s->scan_enabled = 1;
153: }
154:
155: void ps2_write_keyboard(void *opaque, int val)
156: {
157: PS2KbdState *s = (PS2KbdState *)opaque;
158:
159: switch(s->common.write_cmd) {
160: default:
161: case -1:
162: switch(val) {
163: case 0x00:
164: ps2_queue(&s->common, KBD_REPLY_ACK);
165: break;
166: case 0x05:
167: ps2_queue(&s->common, KBD_REPLY_RESEND);
168: break;
169: case KBD_CMD_GET_ID:
170: ps2_queue(&s->common, KBD_REPLY_ACK);
171: ps2_queue(&s->common, 0xab);
172: ps2_queue(&s->common, 0x83);
173: break;
174: case KBD_CMD_ECHO:
175: ps2_queue(&s->common, KBD_CMD_ECHO);
176: break;
177: case KBD_CMD_ENABLE:
178: s->scan_enabled = 1;
179: ps2_queue(&s->common, KBD_REPLY_ACK);
180: break;
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);
185: break;
186: case KBD_CMD_RESET_DISABLE:
187: ps2_reset_keyboard(s);
188: s->scan_enabled = 0;
189: ps2_queue(&s->common, KBD_REPLY_ACK);
190: break;
191: case KBD_CMD_RESET_ENABLE:
192: ps2_reset_keyboard(s);
193: s->scan_enabled = 1;
194: ps2_queue(&s->common, KBD_REPLY_ACK);
195: break;
196: case KBD_CMD_RESET:
197: ps2_reset_keyboard(s);
198: ps2_queue(&s->common, KBD_REPLY_ACK);
199: ps2_queue(&s->common, KBD_REPLY_POR);
200: break;
201: default:
202: ps2_queue(&s->common, KBD_REPLY_ACK);
203: break;
204: }
205: break;
206: case KBD_CMD_SET_LEDS:
207: ps2_queue(&s->common, KBD_REPLY_ACK);
208: s->common.write_cmd = -1;
209: break;
210: case KBD_CMD_SET_RATE:
211: ps2_queue(&s->common, KBD_REPLY_ACK);
212: s->common.write_cmd = -1;
213: break;
214: }
215: }
216:
217: static void ps2_mouse_send_packet(PS2MouseState *s)
218: {
219: unsigned int b;
220: int dx1, dy1, dz1;
221:
222: dx1 = s->mouse_dx;
223: dy1 = s->mouse_dy;
224: dz1 = s->mouse_dz;
225: /* XXX: increase range to 8 bits ? */
226: if (dx1 > 127)
227: dx1 = 127;
228: else if (dx1 < -127)
229: dx1 = -127;
230: if (dy1 > 127)
231: dy1 = 127;
232: else if (dy1 < -127)
233: dy1 = -127;
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) {
240: default:
241: break;
242: case 3:
243: if (dz1 > 127)
244: dz1 = 127;
245: else if (dz1 < -127)
246: dz1 = -127;
247: ps2_queue(&s->common, dz1 & 0xff);
248: break;
249: case 4:
250: if (dz1 > 7)
251: dz1 = 7;
252: else if (dz1 < -7)
253: dz1 = -7;
254: b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
255: ps2_queue(&s->common, b);
256: break;
257: }
258:
259: /* update deltas */
260: s->mouse_dx -= dx1;
261: s->mouse_dy -= dy1;
262: s->mouse_dz -= dz1;
263: }
264:
265: static void ps2_mouse_event(void *opaque,
266: int dx, int dy, int dz, int buttons_state)
267: {
268: PS2MouseState *s = opaque;
269:
270: /* check if deltas are recorded when disabled */
271: if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
272: return;
273:
274: s->mouse_dx += dx;
275: s->mouse_dy -= dy;
276: s->mouse_dz += dz;
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)
280: return;
281: s->mouse_buttons = buttons_state;
282:
283: if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
284: (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
285: for(;;) {
286: /* if not remote, send event. Multiple events are sent if
287: too big deltas */
288: ps2_mouse_send_packet(s);
289: if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
290: break;
291: }
292: }
293: }
294:
295: void ps2_write_mouse(void *opaque, int val)
296: {
297: PS2MouseState *s = (PS2MouseState *)opaque;
298: #ifdef DEBUG_MOUSE
299: printf("kbd: write mouse 0x%02x\n", val);
300: #endif
301: switch(s->common.write_cmd) {
302: default:
303: case -1:
304: /* mouse command */
305: if (s->mouse_wrap) {
306: if (val == AUX_RESET_WRAP) {
307: s->mouse_wrap = 0;
308: ps2_queue(&s->common, AUX_ACK);
309: return;
310: } else if (val != AUX_RESET) {
311: ps2_queue(&s->common, val);
312: return;
313: }
314: }
315: switch(val) {
316: case AUX_SET_SCALE11:
317: s->mouse_status &= ~MOUSE_STATUS_SCALE21;
318: ps2_queue(&s->common, AUX_ACK);
319: break;
320: case AUX_SET_SCALE21:
321: s->mouse_status |= MOUSE_STATUS_SCALE21;
322: ps2_queue(&s->common, AUX_ACK);
323: break;
324: case AUX_SET_STREAM:
325: s->mouse_status &= ~MOUSE_STATUS_REMOTE;
326: ps2_queue(&s->common, AUX_ACK);
327: break;
328: case AUX_SET_WRAP:
329: s->mouse_wrap = 1;
330: ps2_queue(&s->common, AUX_ACK);
331: break;
332: case AUX_SET_REMOTE:
333: s->mouse_status |= MOUSE_STATUS_REMOTE;
334: ps2_queue(&s->common, AUX_ACK);
335: break;
336: case AUX_GET_TYPE:
337: ps2_queue(&s->common, AUX_ACK);
338: ps2_queue(&s->common, s->mouse_type);
339: break;
340: case AUX_SET_RES:
341: case AUX_SET_SAMPLE:
342: s->common.write_cmd = val;
343: ps2_queue(&s->common, AUX_ACK);
344: break;
345: case AUX_GET_SCALE:
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);
350: break;
351: case AUX_POLL:
352: ps2_queue(&s->common, AUX_ACK);
353: ps2_mouse_send_packet(s);
354: break;
355: case AUX_ENABLE_DEV:
356: s->mouse_status |= MOUSE_STATUS_ENABLED;
357: ps2_queue(&s->common, AUX_ACK);
358: break;
359: case AUX_DISABLE_DEV:
360: s->mouse_status &= ~MOUSE_STATUS_ENABLED;
361: ps2_queue(&s->common, AUX_ACK);
362: break;
363: case AUX_SET_DEFAULT:
364: s->mouse_sample_rate = 100;
365: s->mouse_resolution = 2;
366: s->mouse_status = 0;
367: ps2_queue(&s->common, AUX_ACK);
368: break;
369: case AUX_RESET:
370: s->mouse_sample_rate = 100;
371: s->mouse_resolution = 2;
372: s->mouse_status = 0;
373: s->mouse_type = 0;
374: ps2_queue(&s->common, AUX_ACK);
375: ps2_queue(&s->common, 0xaa);
376: ps2_queue(&s->common, s->mouse_type);
377: break;
378: default:
379: break;
380: }
381: break;
382: case AUX_SET_SAMPLE:
383: s->mouse_sample_rate = val;
384: /* detect IMPS/2 or IMEX */
385: switch(s->mouse_detect_state) {
386: default:
387: case 0:
388: if (val == 200)
389: s->mouse_detect_state = 1;
390: break;
391: case 1:
392: if (val == 100)
393: s->mouse_detect_state = 2;
394: else if (val == 200)
395: s->mouse_detect_state = 3;
396: else
397: s->mouse_detect_state = 0;
398: break;
399: case 2:
400: if (val == 80)
401: s->mouse_type = 3; /* IMPS/2 */
402: s->mouse_detect_state = 0;
403: break;
404: case 3:
405: if (val == 80)
406: s->mouse_type = 4; /* IMEX */
407: s->mouse_detect_state = 0;
408: break;
409: }
410: ps2_queue(&s->common, AUX_ACK);
411: s->common.write_cmd = -1;
412: break;
413: case AUX_SET_RES:
414: s->mouse_resolution = val;
415: ps2_queue(&s->common, AUX_ACK);
416: s->common.write_cmd = -1;
417: break;
418: }
419: }
420:
421: static void ps2_reset(void *opaque)
422: {
423: PS2State *s = (PS2State *)opaque;
424: PS2Queue *q;
425: s->write_cmd = -1;
426: q = &s->queue;
427: q->rptr = 0;
428: q->wptr = 0;
429: q->count = 0;
430: }
431:
432: static void ps2_kbd_save(QEMUFile* f, void* opaque)
433: {
434: PS2KbdState *s = (PS2KbdState*)opaque;
435:
436: qemu_put_be32s(f, &s->common.write_cmd);
437: qemu_put_be32s(f, &s->scan_enabled);
438: }
439:
440: static void ps2_mouse_save(QEMUFile* f, void* opaque)
441: {
442: PS2MouseState *s = (PS2MouseState*)opaque;
443:
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);
455: }
456:
457: static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
458: {
459: PS2KbdState *s = (PS2KbdState*)opaque;
460:
461: if (version_id != 1)
462: return -EINVAL;
463: qemu_get_be32s(f, &s->common.write_cmd);
464: qemu_get_be32s(f, &s->scan_enabled);
465: return 0;
466: }
467:
468: static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
469: {
470: PS2MouseState *s = (PS2MouseState*)opaque;
471:
472: if (version_id != 1)
473: return -EINVAL;
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);
485: return 0;
486: }
487:
488: void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
489: {
490: PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
491:
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);
498: return s;
499: }
500:
501: void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
502: {
503: PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
504:
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);
511: return s;
512: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.