blob: 24228c1539fab514bbb7c45e4e4977c316bf2af5 [file] [log] [blame]
bellard0e43e992005-11-26 10:36:25 +00001/*
2 * QEMU PS/2 keyboard/mouse emulation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard0e43e992005-11-26 10:36:25 +00004 * Copyright (c) 2003 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellard0e43e992005-11-26 10:36:25 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "hw.h"
25#include "ps2.h"
26#include "console.h"
bellard0e43e992005-11-26 10:36:25 +000027
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
aurel32e7d93952008-03-18 06:54:34 +000037#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
bellard0e43e992005-11-26 10:36:25 +000038#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 */
aurel3235c4d672008-04-13 16:08:44 +000047#define KBD_REPLY_ID 0xAB /* Keyboard ID */
bellard0e43e992005-11-26 10:36:25 +000048#define KBD_REPLY_ACK 0xFA /* Command ACK */
49#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
50
51/* Mouse Commands */
52#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
53#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
54#define AUX_SET_RES 0xE8 /* Set resolution */
55#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
56#define AUX_SET_STREAM 0xEA /* Set stream mode */
57#define AUX_POLL 0xEB /* Poll */
58#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
59#define AUX_SET_WRAP 0xEE /* Set wrap mode */
60#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
61#define AUX_GET_TYPE 0xF2 /* Get type */
62#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
63#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
64#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
65#define AUX_SET_DEFAULT 0xF6
66#define AUX_RESET 0xFF /* Reset aux device */
67#define AUX_ACK 0xFA /* Command byte ACK. */
68
69#define MOUSE_STATUS_REMOTE 0x40
70#define MOUSE_STATUS_ENABLED 0x20
71#define MOUSE_STATUS_SCALE21 0x10
72
73#define PS2_QUEUE_SIZE 256
74
75typedef struct {
76 uint8_t data[PS2_QUEUE_SIZE];
77 int rptr, wptr, count;
78} PS2Queue;
79
80typedef struct {
81 PS2Queue queue;
82 int32_t write_cmd;
83 void (*update_irq)(void *, int);
84 void *update_arg;
85} PS2State;
86
87typedef struct {
88 PS2State common;
89 int scan_enabled;
pbrookf94f5d72006-02-08 04:42:17 +000090 /* Qemu uses translated PC scancodes internally. To avoid multiple
91 conversions we do the translation (if any) in the PS/2 emulation
92 not the keyboard controller. */
93 int translate;
aurel32e7d93952008-03-18 06:54:34 +000094 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
bellard0e43e992005-11-26 10:36:25 +000095} PS2KbdState;
96
97typedef struct {
98 PS2State common;
99 uint8_t mouse_status;
100 uint8_t mouse_resolution;
101 uint8_t mouse_sample_rate;
102 uint8_t mouse_wrap;
103 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
104 uint8_t mouse_detect_state;
105 int mouse_dx; /* current values, needed for 'poll' mode */
106 int mouse_dy;
107 int mouse_dz;
108 uint8_t mouse_buttons;
109} PS2MouseState;
110
pbrookf94f5d72006-02-08 04:42:17 +0000111/* Table to convert from PC scancodes to raw scancodes. */
112static const unsigned char ps2_raw_keycode[128] = {
Roy Tam7096a962011-02-21 08:06:32 +0800113 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
114 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
115 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
116 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3,
117 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
118114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63,
119 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
120 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
121};
122static const unsigned char ps2_raw_keycode_set3[128] = {
123 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
124 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27,
125 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42,
126 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39,
127 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
128114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63,
129 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
130 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
pbrookf94f5d72006-02-08 04:42:17 +0000131};
132
bellard0e43e992005-11-26 10:36:25 +0000133void ps2_queue(void *opaque, int b)
134{
135 PS2State *s = (PS2State *)opaque;
136 PS2Queue *q = &s->queue;
137
138 if (q->count >= PS2_QUEUE_SIZE)
139 return;
140 q->data[q->wptr] = b;
141 if (++q->wptr == PS2_QUEUE_SIZE)
142 q->wptr = 0;
143 q->count++;
144 s->update_irq(s->update_arg, 1);
145}
146
aurel3235c4d672008-04-13 16:08:44 +0000147/*
148 keycode is expressed as follow:
149 bit 7 - 0 key pressed, 1 = key released
150 bits 6-0 - translated scancode set 2
151 */
bellard0e43e992005-11-26 10:36:25 +0000152static void ps2_put_keycode(void *opaque, int keycode)
153{
pbrookf94f5d72006-02-08 04:42:17 +0000154 PS2KbdState *s = opaque;
aurel32e7d93952008-03-18 06:54:34 +0000155
Roy Tam7096a962011-02-21 08:06:32 +0800156 /* XXX: add support for scancode set 1 */
157 if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
158 if (keycode & 0x80) {
pbrookf94f5d72006-02-08 04:42:17 +0000159 ps2_queue(&s->common, 0xf0);
Roy Tam7096a962011-02-21 08:06:32 +0800160 }
161 if (s->scancode_set == 2) {
162 keycode = ps2_raw_keycode[keycode & 0x7f];
163 } else if (s->scancode_set == 3) {
164 keycode = ps2_raw_keycode_set3[keycode & 0x7f];
165 }
pbrookf94f5d72006-02-08 04:42:17 +0000166 }
bellard0e43e992005-11-26 10:36:25 +0000167 ps2_queue(&s->common, keycode);
168}
169
170uint32_t ps2_read_data(void *opaque)
171{
172 PS2State *s = (PS2State *)opaque;
173 PS2Queue *q;
174 int val, index;
ths3b46e622007-09-17 08:09:54 +0000175
bellard0e43e992005-11-26 10:36:25 +0000176 q = &s->queue;
177 if (q->count == 0) {
178 /* NOTE: if no data left, we return the last keyboard one
179 (needed for EMM386) */
180 /* XXX: need a timer to do things correctly */
181 index = q->rptr - 1;
182 if (index < 0)
183 index = PS2_QUEUE_SIZE - 1;
184 val = q->data[index];
185 } else {
186 val = q->data[q->rptr];
187 if (++q->rptr == PS2_QUEUE_SIZE)
188 q->rptr = 0;
189 q->count--;
190 /* reading deasserts IRQ */
191 s->update_irq(s->update_arg, 0);
192 /* reassert IRQs if data left */
193 s->update_irq(s->update_arg, q->count != 0);
194 }
195 return val;
196}
197
198static void ps2_reset_keyboard(PS2KbdState *s)
199{
200 s->scan_enabled = 1;
aurel32e7d93952008-03-18 06:54:34 +0000201 s->scancode_set = 2;
Gerd Hoffmann6937b372010-02-26 17:17:37 +0100202 kbd_put_ledstate(0);
bellard0e43e992005-11-26 10:36:25 +0000203}
204
205void ps2_write_keyboard(void *opaque, int val)
206{
207 PS2KbdState *s = (PS2KbdState *)opaque;
208
209 switch(s->common.write_cmd) {
210 default:
211 case -1:
212 switch(val) {
213 case 0x00:
214 ps2_queue(&s->common, KBD_REPLY_ACK);
215 break;
216 case 0x05:
217 ps2_queue(&s->common, KBD_REPLY_RESEND);
218 break;
219 case KBD_CMD_GET_ID:
220 ps2_queue(&s->common, KBD_REPLY_ACK);
aurel32e7d93952008-03-18 06:54:34 +0000221 /* We emulate a MF2 AT keyboard here */
aurel3235c4d672008-04-13 16:08:44 +0000222 ps2_queue(&s->common, KBD_REPLY_ID);
223 if (s->translate)
224 ps2_queue(&s->common, 0x41);
225 else
226 ps2_queue(&s->common, 0x83);
bellard0e43e992005-11-26 10:36:25 +0000227 break;
228 case KBD_CMD_ECHO:
229 ps2_queue(&s->common, KBD_CMD_ECHO);
230 break;
231 case KBD_CMD_ENABLE:
232 s->scan_enabled = 1;
233 ps2_queue(&s->common, KBD_REPLY_ACK);
234 break;
aurel32e7d93952008-03-18 06:54:34 +0000235 case KBD_CMD_SCANCODE:
bellard0e43e992005-11-26 10:36:25 +0000236 case KBD_CMD_SET_LEDS:
237 case KBD_CMD_SET_RATE:
238 s->common.write_cmd = val;
239 ps2_queue(&s->common, KBD_REPLY_ACK);
240 break;
241 case KBD_CMD_RESET_DISABLE:
242 ps2_reset_keyboard(s);
243 s->scan_enabled = 0;
244 ps2_queue(&s->common, KBD_REPLY_ACK);
245 break;
246 case KBD_CMD_RESET_ENABLE:
247 ps2_reset_keyboard(s);
248 s->scan_enabled = 1;
249 ps2_queue(&s->common, KBD_REPLY_ACK);
250 break;
251 case KBD_CMD_RESET:
252 ps2_reset_keyboard(s);
253 ps2_queue(&s->common, KBD_REPLY_ACK);
254 ps2_queue(&s->common, KBD_REPLY_POR);
255 break;
256 default:
257 ps2_queue(&s->common, KBD_REPLY_ACK);
258 break;
259 }
260 break;
aurel32e7d93952008-03-18 06:54:34 +0000261 case KBD_CMD_SCANCODE:
262 if (val == 0) {
263 if (s->scancode_set == 1)
264 ps2_put_keycode(s, 0x43);
265 else if (s->scancode_set == 2)
266 ps2_put_keycode(s, 0x41);
267 else if (s->scancode_set == 3)
268 ps2_put_keycode(s, 0x3f);
269 } else {
270 if (val >= 1 && val <= 3)
271 s->scancode_set = val;
272 ps2_queue(&s->common, KBD_REPLY_ACK);
273 }
274 s->common.write_cmd = -1;
275 break;
bellard0e43e992005-11-26 10:36:25 +0000276 case KBD_CMD_SET_LEDS:
Gerd Hoffmann6937b372010-02-26 17:17:37 +0100277 kbd_put_ledstate(val);
bellard0e43e992005-11-26 10:36:25 +0000278 ps2_queue(&s->common, KBD_REPLY_ACK);
279 s->common.write_cmd = -1;
280 break;
281 case KBD_CMD_SET_RATE:
282 ps2_queue(&s->common, KBD_REPLY_ACK);
283 s->common.write_cmd = -1;
284 break;
285 }
286}
287
pbrookf94f5d72006-02-08 04:42:17 +0000288/* Set the scancode translation mode.
289 0 = raw scancodes.
290 1 = translated scancodes (used by qemu internally). */
291
292void ps2_keyboard_set_translation(void *opaque, int mode)
293{
294 PS2KbdState *s = (PS2KbdState *)opaque;
295 s->translate = mode;
296}
297
bellard0e43e992005-11-26 10:36:25 +0000298static void ps2_mouse_send_packet(PS2MouseState *s)
299{
300 unsigned int b;
301 int dx1, dy1, dz1;
302
303 dx1 = s->mouse_dx;
304 dy1 = s->mouse_dy;
305 dz1 = s->mouse_dz;
306 /* XXX: increase range to 8 bits ? */
307 if (dx1 > 127)
308 dx1 = 127;
309 else if (dx1 < -127)
310 dx1 = -127;
311 if (dy1 > 127)
312 dy1 = 127;
313 else if (dy1 < -127)
314 dy1 = -127;
315 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
316 ps2_queue(&s->common, b);
317 ps2_queue(&s->common, dx1 & 0xff);
318 ps2_queue(&s->common, dy1 & 0xff);
319 /* extra byte for IMPS/2 or IMEX */
320 switch(s->mouse_type) {
321 default:
322 break;
323 case 3:
324 if (dz1 > 127)
325 dz1 = 127;
326 else if (dz1 < -127)
327 dz1 = -127;
328 ps2_queue(&s->common, dz1 & 0xff);
329 break;
330 case 4:
331 if (dz1 > 7)
332 dz1 = 7;
333 else if (dz1 < -7)
334 dz1 = -7;
335 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
336 ps2_queue(&s->common, b);
337 break;
338 }
339
340 /* update deltas */
341 s->mouse_dx -= dx1;
342 s->mouse_dy -= dy1;
343 s->mouse_dz -= dz1;
344}
345
ths5fafdf22007-09-16 21:08:06 +0000346static void ps2_mouse_event(void *opaque,
bellard0e43e992005-11-26 10:36:25 +0000347 int dx, int dy, int dz, int buttons_state)
348{
349 PS2MouseState *s = opaque;
350
351 /* check if deltas are recorded when disabled */
352 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
353 return;
354
355 s->mouse_dx += dx;
356 s->mouse_dy -= dy;
357 s->mouse_dz += dz;
358 /* XXX: SDL sometimes generates nul events: we delete them */
359 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
360 s->mouse_buttons == buttons_state)
361 return;
362 s->mouse_buttons = buttons_state;
ths3b46e622007-09-17 08:09:54 +0000363
bellard0e43e992005-11-26 10:36:25 +0000364 if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
365 (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
366 for(;;) {
367 /* if not remote, send event. Multiple events are sent if
368 too big deltas */
369 ps2_mouse_send_packet(s);
370 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
371 break;
372 }
373 }
374}
375
ths548df2a2007-03-20 16:45:27 +0000376void ps2_mouse_fake_event(void *opaque)
377{
378 ps2_mouse_event(opaque, 1, 0, 0, 0);
379}
380
bellard0e43e992005-11-26 10:36:25 +0000381void ps2_write_mouse(void *opaque, int val)
382{
383 PS2MouseState *s = (PS2MouseState *)opaque;
384#ifdef DEBUG_MOUSE
385 printf("kbd: write mouse 0x%02x\n", val);
386#endif
387 switch(s->common.write_cmd) {
388 default:
389 case -1:
390 /* mouse command */
391 if (s->mouse_wrap) {
392 if (val == AUX_RESET_WRAP) {
393 s->mouse_wrap = 0;
394 ps2_queue(&s->common, AUX_ACK);
395 return;
396 } else if (val != AUX_RESET) {
397 ps2_queue(&s->common, val);
398 return;
399 }
400 }
401 switch(val) {
402 case AUX_SET_SCALE11:
403 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
404 ps2_queue(&s->common, AUX_ACK);
405 break;
406 case AUX_SET_SCALE21:
407 s->mouse_status |= MOUSE_STATUS_SCALE21;
408 ps2_queue(&s->common, AUX_ACK);
409 break;
410 case AUX_SET_STREAM:
411 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
412 ps2_queue(&s->common, AUX_ACK);
413 break;
414 case AUX_SET_WRAP:
415 s->mouse_wrap = 1;
416 ps2_queue(&s->common, AUX_ACK);
417 break;
418 case AUX_SET_REMOTE:
419 s->mouse_status |= MOUSE_STATUS_REMOTE;
420 ps2_queue(&s->common, AUX_ACK);
421 break;
422 case AUX_GET_TYPE:
423 ps2_queue(&s->common, AUX_ACK);
424 ps2_queue(&s->common, s->mouse_type);
425 break;
426 case AUX_SET_RES:
427 case AUX_SET_SAMPLE:
428 s->common.write_cmd = val;
429 ps2_queue(&s->common, AUX_ACK);
430 break;
431 case AUX_GET_SCALE:
432 ps2_queue(&s->common, AUX_ACK);
433 ps2_queue(&s->common, s->mouse_status);
434 ps2_queue(&s->common, s->mouse_resolution);
435 ps2_queue(&s->common, s->mouse_sample_rate);
436 break;
437 case AUX_POLL:
438 ps2_queue(&s->common, AUX_ACK);
439 ps2_mouse_send_packet(s);
440 break;
441 case AUX_ENABLE_DEV:
442 s->mouse_status |= MOUSE_STATUS_ENABLED;
443 ps2_queue(&s->common, AUX_ACK);
444 break;
445 case AUX_DISABLE_DEV:
446 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
447 ps2_queue(&s->common, AUX_ACK);
448 break;
449 case AUX_SET_DEFAULT:
450 s->mouse_sample_rate = 100;
451 s->mouse_resolution = 2;
452 s->mouse_status = 0;
453 ps2_queue(&s->common, AUX_ACK);
454 break;
455 case AUX_RESET:
456 s->mouse_sample_rate = 100;
457 s->mouse_resolution = 2;
458 s->mouse_status = 0;
459 s->mouse_type = 0;
460 ps2_queue(&s->common, AUX_ACK);
461 ps2_queue(&s->common, 0xaa);
462 ps2_queue(&s->common, s->mouse_type);
463 break;
464 default:
465 break;
466 }
467 break;
468 case AUX_SET_SAMPLE:
469 s->mouse_sample_rate = val;
470 /* detect IMPS/2 or IMEX */
471 switch(s->mouse_detect_state) {
472 default:
473 case 0:
474 if (val == 200)
475 s->mouse_detect_state = 1;
476 break;
477 case 1:
478 if (val == 100)
479 s->mouse_detect_state = 2;
480 else if (val == 200)
481 s->mouse_detect_state = 3;
482 else
483 s->mouse_detect_state = 0;
484 break;
485 case 2:
ths5fafdf22007-09-16 21:08:06 +0000486 if (val == 80)
bellard0e43e992005-11-26 10:36:25 +0000487 s->mouse_type = 3; /* IMPS/2 */
488 s->mouse_detect_state = 0;
489 break;
490 case 3:
ths5fafdf22007-09-16 21:08:06 +0000491 if (val == 80)
bellard0e43e992005-11-26 10:36:25 +0000492 s->mouse_type = 4; /* IMEX */
493 s->mouse_detect_state = 0;
494 break;
495 }
496 ps2_queue(&s->common, AUX_ACK);
497 s->common.write_cmd = -1;
498 break;
499 case AUX_SET_RES:
500 s->mouse_resolution = val;
501 ps2_queue(&s->common, AUX_ACK);
502 s->common.write_cmd = -1;
503 break;
504 }
505}
506
Dinesh Subhravetief746792009-07-14 18:30:53 -0700507static void ps2_common_reset(PS2State *s)
bellard0e43e992005-11-26 10:36:25 +0000508{
bellard0e43e992005-11-26 10:36:25 +0000509 PS2Queue *q;
510 s->write_cmd = -1;
511 q = &s->queue;
512 q->rptr = 0;
513 q->wptr = 0;
514 q->count = 0;
aliguorideeccef2009-01-26 15:57:52 +0000515 s->update_irq(s->update_arg, 0);
bellard0e43e992005-11-26 10:36:25 +0000516}
517
Dinesh Subhravetief746792009-07-14 18:30:53 -0700518static void ps2_kbd_reset(void *opaque)
519{
520 PS2KbdState *s = (PS2KbdState *) opaque;
521
522 ps2_common_reset(&s->common);
523 s->scan_enabled = 0;
524 s->translate = 0;
525 s->scancode_set = 0;
526}
527
528static void ps2_mouse_reset(void *opaque)
529{
530 PS2MouseState *s = (PS2MouseState *) opaque;
531
532 ps2_common_reset(&s->common);
533 s->mouse_status = 0;
534 s->mouse_resolution = 0;
535 s->mouse_sample_rate = 0;
536 s->mouse_wrap = 0;
537 s->mouse_type = 0;
538 s->mouse_detect_state = 0;
539 s->mouse_dx = 0;
540 s->mouse_dy = 0;
541 s->mouse_dz = 0;
542 s->mouse_buttons = 0;
543}
544
Juan Quintelab31442c2009-08-20 19:42:36 +0200545static const VMStateDescription vmstate_ps2_common = {
546 .name = "PS2 Common State",
547 .version_id = 3,
548 .minimum_version_id = 2,
549 .minimum_version_id_old = 2,
550 .fields = (VMStateField []) {
551 VMSTATE_INT32(write_cmd, PS2State),
552 VMSTATE_INT32(queue.rptr, PS2State),
553 VMSTATE_INT32(queue.wptr, PS2State),
554 VMSTATE_INT32(queue.count, PS2State),
555 VMSTATE_BUFFER(queue.data, PS2State),
556 VMSTATE_END_OF_LIST()
557 }
558};
pbrook7783e9f2006-04-08 14:12:31 +0000559
Juan Quinteladb596c52009-09-29 22:48:23 +0200560static int ps2_kbd_post_load(void* opaque, int version_id)
bellard0e43e992005-11-26 10:36:25 +0000561{
562 PS2KbdState *s = (PS2KbdState*)opaque;
pbrook7783e9f2006-04-08 14:12:31 +0000563
Juan Quinteladb596c52009-09-29 22:48:23 +0200564 if (version_id == 2)
aurel32e7d93952008-03-18 06:54:34 +0000565 s->scancode_set=2;
bellard0e43e992005-11-26 10:36:25 +0000566 return 0;
567}
568
Juan Quintelab31442c2009-08-20 19:42:36 +0200569static const VMStateDescription vmstate_ps2_keyboard = {
570 .name = "ps2kbd",
571 .version_id = 3,
Juan Quinteladb596c52009-09-29 22:48:23 +0200572 .minimum_version_id = 2,
Juan Quintelab31442c2009-08-20 19:42:36 +0200573 .minimum_version_id_old = 2,
Juan Quinteladb596c52009-09-29 22:48:23 +0200574 .post_load = ps2_kbd_post_load,
Juan Quintelab31442c2009-08-20 19:42:36 +0200575 .fields = (VMStateField []) {
576 VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
577 VMSTATE_INT32(scan_enabled, PS2KbdState),
578 VMSTATE_INT32(translate, PS2KbdState),
579 VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
580 VMSTATE_END_OF_LIST()
581 }
582};
pbrook7783e9f2006-04-08 14:12:31 +0000583
Juan Quintelab31442c2009-08-20 19:42:36 +0200584static const VMStateDescription vmstate_ps2_mouse = {
585 .name = "ps2mouse",
586 .version_id = 2,
587 .minimum_version_id = 2,
588 .minimum_version_id_old = 2,
589 .fields = (VMStateField []) {
590 VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
591 VMSTATE_UINT8(mouse_status, PS2MouseState),
592 VMSTATE_UINT8(mouse_resolution, PS2MouseState),
593 VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
594 VMSTATE_UINT8(mouse_wrap, PS2MouseState),
595 VMSTATE_UINT8(mouse_type, PS2MouseState),
596 VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
597 VMSTATE_INT32(mouse_dx, PS2MouseState),
598 VMSTATE_INT32(mouse_dy, PS2MouseState),
599 VMSTATE_INT32(mouse_dz, PS2MouseState),
600 VMSTATE_UINT8(mouse_buttons, PS2MouseState),
601 VMSTATE_END_OF_LIST()
602 }
603};
bellard0e43e992005-11-26 10:36:25 +0000604
605void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
606{
Anthony Liguori7267c092011-08-20 22:09:37 -0500607 PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
bellard0e43e992005-11-26 10:36:25 +0000608
609 s->common.update_irq = update_irq;
610 s->common.update_arg = update_arg;
aurel32e7d93952008-03-18 06:54:34 +0000611 s->scancode_set = 2;
Alex Williamson0be71e32010-06-25 11:09:07 -0600612 vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
bellard0e43e992005-11-26 10:36:25 +0000613 qemu_add_kbd_event_handler(ps2_put_keycode, s);
Dinesh Subhravetief746792009-07-14 18:30:53 -0700614 qemu_register_reset(ps2_kbd_reset, s);
bellard0e43e992005-11-26 10:36:25 +0000615 return s;
616}
617
618void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
619{
Anthony Liguori7267c092011-08-20 22:09:37 -0500620 PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
bellard0e43e992005-11-26 10:36:25 +0000621
622 s->common.update_irq = update_irq;
623 s->common.update_arg = update_arg;
Alex Williamson0be71e32010-06-25 11:09:07 -0600624 vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
ths455204e2007-01-05 16:42:13 +0000625 qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
Dinesh Subhravetief746792009-07-14 18:30:53 -0700626 qemu_register_reset(ps2_mouse_reset, s);
bellard0e43e992005-11-26 10:36:25 +0000627 return s;
628}