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