]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/input/ps2.c
hw: Clean up includes
[thirdparty/qemu.git] / hw / input / ps2.c
CommitLineData
0e43e99c
FB
1/*
2 * QEMU PS/2 keyboard/mouse emulation
5fafdf24 3 *
0e43e99c 4 * Copyright (c) 2003 Fabrice Bellard
5fafdf24 5 *
0e43e99c
FB
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 */
0430891c 24#include "qemu/osdep.h"
83c9f4ca 25#include "hw/hw.h"
0d09e41a 26#include "hw/input/ps2.h"
28ecbaee 27#include "ui/console.h"
66e6536e 28#include "ui/input.h"
9c17d615 29#include "sysemu/sysemu.h"
0e43e99c 30
5edab03d
DK
31#include "trace.h"
32
0e43e99c
FB
33/* debug PC keyboard */
34//#define DEBUG_KBD
35
36/* debug PC keyboard : only mouse */
37//#define DEBUG_MOUSE
38
39/* Keyboard Commands */
40#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
41#define KBD_CMD_ECHO 0xEE
e7d93956 42#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
0e43e99c
FB
43#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
44#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
45#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
46#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
47#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
48#define KBD_CMD_RESET 0xFF /* Reset */
49
50/* Keyboard Replies */
51#define KBD_REPLY_POR 0xAA /* Power on reset */
35c4d671 52#define KBD_REPLY_ID 0xAB /* Keyboard ID */
0e43e99c
FB
53#define KBD_REPLY_ACK 0xFA /* Command ACK */
54#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
55
56/* Mouse Commands */
57#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
58#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
59#define AUX_SET_RES 0xE8 /* Set resolution */
60#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
61#define AUX_SET_STREAM 0xEA /* Set stream mode */
62#define AUX_POLL 0xEB /* Poll */
63#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
64#define AUX_SET_WRAP 0xEE /* Set wrap mode */
65#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
66#define AUX_GET_TYPE 0xF2 /* Get type */
67#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
68#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
69#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
70#define AUX_SET_DEFAULT 0xF6
71#define AUX_RESET 0xFF /* Reset aux device */
72#define AUX_ACK 0xFA /* Command byte ACK. */
73
74#define MOUSE_STATUS_REMOTE 0x40
75#define MOUSE_STATUS_ENABLED 0x20
76#define MOUSE_STATUS_SCALE21 0x10
77
2858ab09 78#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */
0e43e99c
FB
79
80typedef struct {
2858ab09
GA
81 /* Keep the data array 256 bytes long, which compatibility
82 with older qemu versions. */
83 uint8_t data[256];
0e43e99c
FB
84 int rptr, wptr, count;
85} PS2Queue;
86
87typedef struct {
88 PS2Queue queue;
89 int32_t write_cmd;
90 void (*update_irq)(void *, int);
91 void *update_arg;
92} PS2State;
93
94typedef struct {
95 PS2State common;
96 int scan_enabled;
5cbdb3a3 97 /* QEMU uses translated PC scancodes internally. To avoid multiple
f94f5d71
PB
98 conversions we do the translation (if any) in the PS/2 emulation
99 not the keyboard controller. */
100 int translate;
e7d93956 101 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
7f540ab5 102 int ledstate;
0e43e99c
FB
103} PS2KbdState;
104
105typedef struct {
106 PS2State common;
107 uint8_t mouse_status;
108 uint8_t mouse_resolution;
109 uint8_t mouse_sample_rate;
110 uint8_t mouse_wrap;
111 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
112 uint8_t mouse_detect_state;
113 int mouse_dx; /* current values, needed for 'poll' mode */
114 int mouse_dy;
115 int mouse_dz;
116 uint8_t mouse_buttons;
117} PS2MouseState;
118
f94f5d71
PB
119/* Table to convert from PC scancodes to raw scancodes. */
120static const unsigned char ps2_raw_keycode[128] = {
7096a96d
RT
121 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
122 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
123 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
124 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3,
125 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
126114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63,
127 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
128 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
129};
130static const unsigned char ps2_raw_keycode_set3[128] = {
131 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
132 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27,
133 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42,
134 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39,
135 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
136114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63,
137 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
138 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
f94f5d71
PB
139};
140
0e43e99c
FB
141void ps2_queue(void *opaque, int b)
142{
143 PS2State *s = (PS2State *)opaque;
144 PS2Queue *q = &s->queue;
145
2858ab09 146 if (q->count >= PS2_QUEUE_SIZE - 1)
0e43e99c
FB
147 return;
148 q->data[q->wptr] = b;
149 if (++q->wptr == PS2_QUEUE_SIZE)
150 q->wptr = 0;
151 q->count++;
152 s->update_irq(s->update_arg, 1);
153}
154
35c4d671
AJ
155/*
156 keycode is expressed as follow:
157 bit 7 - 0 key pressed, 1 = key released
158 bits 6-0 - translated scancode set 2
159 */
0e43e99c
FB
160static void ps2_put_keycode(void *opaque, int keycode)
161{
f94f5d71 162 PS2KbdState *s = opaque;
e7d93956 163
5edab03d 164 trace_ps2_put_keycode(opaque, keycode);
fd214d18 165 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
7096a96d
RT
166 /* XXX: add support for scancode set 1 */
167 if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
168 if (keycode & 0x80) {
f94f5d71 169 ps2_queue(&s->common, 0xf0);
7096a96d
RT
170 }
171 if (s->scancode_set == 2) {
172 keycode = ps2_raw_keycode[keycode & 0x7f];
173 } else if (s->scancode_set == 3) {
174 keycode = ps2_raw_keycode_set3[keycode & 0x7f];
175 }
f94f5d71 176 }
0e43e99c
FB
177 ps2_queue(&s->common, keycode);
178}
179
66e6536e
GH
180static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
181 InputEvent *evt)
182{
183 PS2KbdState *s = (PS2KbdState *)dev;
184 int scancodes[3], i, count;
185
186 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
568c73a4
EB
187 count = qemu_input_key_value_to_scancode(evt->u.key->key,
188 evt->u.key->down,
66e6536e
GH
189 scancodes);
190 for (i = 0; i < count; i++) {
191 ps2_put_keycode(s, scancodes[i]);
192 }
193}
194
0e43e99c
FB
195uint32_t ps2_read_data(void *opaque)
196{
197 PS2State *s = (PS2State *)opaque;
198 PS2Queue *q;
199 int val, index;
3b46e624 200
5edab03d 201 trace_ps2_read_data(opaque);
0e43e99c
FB
202 q = &s->queue;
203 if (q->count == 0) {
204 /* NOTE: if no data left, we return the last keyboard one
205 (needed for EMM386) */
206 /* XXX: need a timer to do things correctly */
207 index = q->rptr - 1;
208 if (index < 0)
209 index = PS2_QUEUE_SIZE - 1;
210 val = q->data[index];
211 } else {
212 val = q->data[q->rptr];
213 if (++q->rptr == PS2_QUEUE_SIZE)
214 q->rptr = 0;
215 q->count--;
216 /* reading deasserts IRQ */
217 s->update_irq(s->update_arg, 0);
218 /* reassert IRQs if data left */
219 s->update_irq(s->update_arg, q->count != 0);
220 }
221 return val;
222}
223
7f540ab5
CF
224static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
225{
5edab03d 226 trace_ps2_set_ledstate(s, ledstate);
7f540ab5
CF
227 s->ledstate = ledstate;
228 kbd_put_ledstate(ledstate);
229}
230
0e43e99c
FB
231static void ps2_reset_keyboard(PS2KbdState *s)
232{
5edab03d 233 trace_ps2_reset_keyboard(s);
0e43e99c 234 s->scan_enabled = 1;
e7d93956 235 s->scancode_set = 2;
7f540ab5 236 ps2_set_ledstate(s, 0);
0e43e99c
FB
237}
238
239void ps2_write_keyboard(void *opaque, int val)
240{
241 PS2KbdState *s = (PS2KbdState *)opaque;
242
5edab03d 243 trace_ps2_write_keyboard(opaque, val);
0e43e99c
FB
244 switch(s->common.write_cmd) {
245 default:
246 case -1:
247 switch(val) {
248 case 0x00:
249 ps2_queue(&s->common, KBD_REPLY_ACK);
250 break;
251 case 0x05:
252 ps2_queue(&s->common, KBD_REPLY_RESEND);
253 break;
254 case KBD_CMD_GET_ID:
255 ps2_queue(&s->common, KBD_REPLY_ACK);
e7d93956 256 /* We emulate a MF2 AT keyboard here */
35c4d671
AJ
257 ps2_queue(&s->common, KBD_REPLY_ID);
258 if (s->translate)
259 ps2_queue(&s->common, 0x41);
260 else
261 ps2_queue(&s->common, 0x83);
0e43e99c
FB
262 break;
263 case KBD_CMD_ECHO:
264 ps2_queue(&s->common, KBD_CMD_ECHO);
265 break;
266 case KBD_CMD_ENABLE:
267 s->scan_enabled = 1;
268 ps2_queue(&s->common, KBD_REPLY_ACK);
269 break;
e7d93956 270 case KBD_CMD_SCANCODE:
0e43e99c
FB
271 case KBD_CMD_SET_LEDS:
272 case KBD_CMD_SET_RATE:
273 s->common.write_cmd = val;
274 ps2_queue(&s->common, KBD_REPLY_ACK);
275 break;
276 case KBD_CMD_RESET_DISABLE:
277 ps2_reset_keyboard(s);
278 s->scan_enabled = 0;
279 ps2_queue(&s->common, KBD_REPLY_ACK);
280 break;
281 case KBD_CMD_RESET_ENABLE:
282 ps2_reset_keyboard(s);
283 s->scan_enabled = 1;
284 ps2_queue(&s->common, KBD_REPLY_ACK);
285 break;
286 case KBD_CMD_RESET:
287 ps2_reset_keyboard(s);
288 ps2_queue(&s->common, KBD_REPLY_ACK);
289 ps2_queue(&s->common, KBD_REPLY_POR);
290 break;
291 default:
292 ps2_queue(&s->common, KBD_REPLY_ACK);
293 break;
294 }
295 break;
e7d93956
AJ
296 case KBD_CMD_SCANCODE:
297 if (val == 0) {
298 if (s->scancode_set == 1)
299 ps2_put_keycode(s, 0x43);
300 else if (s->scancode_set == 2)
301 ps2_put_keycode(s, 0x41);
302 else if (s->scancode_set == 3)
303 ps2_put_keycode(s, 0x3f);
304 } else {
305 if (val >= 1 && val <= 3)
306 s->scancode_set = val;
307 ps2_queue(&s->common, KBD_REPLY_ACK);
308 }
309 s->common.write_cmd = -1;
310 break;
0e43e99c 311 case KBD_CMD_SET_LEDS:
7f540ab5 312 ps2_set_ledstate(s, val);
0e43e99c
FB
313 ps2_queue(&s->common, KBD_REPLY_ACK);
314 s->common.write_cmd = -1;
315 break;
316 case KBD_CMD_SET_RATE:
317 ps2_queue(&s->common, KBD_REPLY_ACK);
318 s->common.write_cmd = -1;
319 break;
320 }
321}
322
f94f5d71
PB
323/* Set the scancode translation mode.
324 0 = raw scancodes.
325 1 = translated scancodes (used by qemu internally). */
326
327void ps2_keyboard_set_translation(void *opaque, int mode)
328{
329 PS2KbdState *s = (PS2KbdState *)opaque;
5edab03d 330 trace_ps2_keyboard_set_translation(opaque, mode);
f94f5d71
PB
331 s->translate = mode;
332}
333
0e43e99c
FB
334static void ps2_mouse_send_packet(PS2MouseState *s)
335{
336 unsigned int b;
337 int dx1, dy1, dz1;
338
339 dx1 = s->mouse_dx;
340 dy1 = s->mouse_dy;
341 dz1 = s->mouse_dz;
342 /* XXX: increase range to 8 bits ? */
343 if (dx1 > 127)
344 dx1 = 127;
345 else if (dx1 < -127)
346 dx1 = -127;
347 if (dy1 > 127)
348 dy1 = 127;
349 else if (dy1 < -127)
350 dy1 = -127;
351 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
352 ps2_queue(&s->common, b);
353 ps2_queue(&s->common, dx1 & 0xff);
354 ps2_queue(&s->common, dy1 & 0xff);
355 /* extra byte for IMPS/2 or IMEX */
356 switch(s->mouse_type) {
357 default:
358 break;
359 case 3:
360 if (dz1 > 127)
361 dz1 = 127;
362 else if (dz1 < -127)
363 dz1 = -127;
364 ps2_queue(&s->common, dz1 & 0xff);
365 break;
366 case 4:
367 if (dz1 > 7)
368 dz1 = 7;
369 else if (dz1 < -7)
370 dz1 = -7;
371 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
372 ps2_queue(&s->common, b);
373 break;
374 }
375
5edab03d 376 trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
0e43e99c
FB
377 /* update deltas */
378 s->mouse_dx -= dx1;
379 s->mouse_dy -= dy1;
380 s->mouse_dz -= dz1;
381}
382
2a766d29
GH
383static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
384 InputEvent *evt)
0e43e99c 385{
7fb1cf16 386 static const int bmap[INPUT_BUTTON__MAX] = {
2a766d29
GH
387 [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
388 [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
389 [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
390 };
391 PS2MouseState *s = (PS2MouseState *)dev;
0e43e99c
FB
392
393 /* check if deltas are recorded when disabled */
394 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
395 return;
396
568c73a4 397 switch (evt->type) {
2a766d29 398 case INPUT_EVENT_KIND_REL:
568c73a4
EB
399 if (evt->u.rel->axis == INPUT_AXIS_X) {
400 s->mouse_dx += evt->u.rel->value;
401 } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
402 s->mouse_dy -= evt->u.rel->value;
2a766d29
GH
403 }
404 break;
3b46e624 405
2a766d29 406 case INPUT_EVENT_KIND_BTN:
568c73a4
EB
407 if (evt->u.btn->down) {
408 s->mouse_buttons |= bmap[evt->u.btn->button];
d20a580b 409 if (evt->u.btn->button == INPUT_BUTTON_WHEELUP) {
2a766d29 410 s->mouse_dz--;
d20a580b 411 } else if (evt->u.btn->button == INPUT_BUTTON_WHEELDOWN) {
2a766d29
GH
412 s->mouse_dz++;
413 }
414 } else {
568c73a4 415 s->mouse_buttons &= ~bmap[evt->u.btn->button];
2a766d29
GH
416 }
417 break;
418
419 default:
420 /* keep gcc happy */
421 break;
fd214d18 422 }
2a766d29 423}
fd214d18 424
2a766d29
GH
425static void ps2_mouse_sync(DeviceState *dev)
426{
427 PS2MouseState *s = (PS2MouseState *)dev;
428
429 if (s->mouse_buttons) {
430 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
431 }
2858ab09
GA
432 if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
433 while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
0e43e99c
FB
434 /* if not remote, send event. Multiple events are sent if
435 too big deltas */
436 ps2_mouse_send_packet(s);
437 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
438 break;
439 }
440 }
441}
442
548df2ac
TS
443void ps2_mouse_fake_event(void *opaque)
444{
2a766d29 445 PS2MouseState *s = opaque;
5edab03d 446 trace_ps2_mouse_fake_event(opaque);
2a766d29
GH
447 s->mouse_dx++;
448 ps2_mouse_sync(opaque);
548df2ac
TS
449}
450
0e43e99c
FB
451void ps2_write_mouse(void *opaque, int val)
452{
453 PS2MouseState *s = (PS2MouseState *)opaque;
5edab03d
DK
454
455 trace_ps2_write_mouse(opaque, val);
0e43e99c
FB
456#ifdef DEBUG_MOUSE
457 printf("kbd: write mouse 0x%02x\n", val);
458#endif
459 switch(s->common.write_cmd) {
460 default:
461 case -1:
462 /* mouse command */
463 if (s->mouse_wrap) {
464 if (val == AUX_RESET_WRAP) {
465 s->mouse_wrap = 0;
466 ps2_queue(&s->common, AUX_ACK);
467 return;
468 } else if (val != AUX_RESET) {
469 ps2_queue(&s->common, val);
470 return;
471 }
472 }
473 switch(val) {
474 case AUX_SET_SCALE11:
475 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
476 ps2_queue(&s->common, AUX_ACK);
477 break;
478 case AUX_SET_SCALE21:
479 s->mouse_status |= MOUSE_STATUS_SCALE21;
480 ps2_queue(&s->common, AUX_ACK);
481 break;
482 case AUX_SET_STREAM:
483 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
484 ps2_queue(&s->common, AUX_ACK);
485 break;
486 case AUX_SET_WRAP:
487 s->mouse_wrap = 1;
488 ps2_queue(&s->common, AUX_ACK);
489 break;
490 case AUX_SET_REMOTE:
491 s->mouse_status |= MOUSE_STATUS_REMOTE;
492 ps2_queue(&s->common, AUX_ACK);
493 break;
494 case AUX_GET_TYPE:
495 ps2_queue(&s->common, AUX_ACK);
496 ps2_queue(&s->common, s->mouse_type);
497 break;
498 case AUX_SET_RES:
499 case AUX_SET_SAMPLE:
500 s->common.write_cmd = val;
501 ps2_queue(&s->common, AUX_ACK);
502 break;
503 case AUX_GET_SCALE:
504 ps2_queue(&s->common, AUX_ACK);
505 ps2_queue(&s->common, s->mouse_status);
506 ps2_queue(&s->common, s->mouse_resolution);
507 ps2_queue(&s->common, s->mouse_sample_rate);
508 break;
509 case AUX_POLL:
510 ps2_queue(&s->common, AUX_ACK);
511 ps2_mouse_send_packet(s);
512 break;
513 case AUX_ENABLE_DEV:
514 s->mouse_status |= MOUSE_STATUS_ENABLED;
515 ps2_queue(&s->common, AUX_ACK);
516 break;
517 case AUX_DISABLE_DEV:
518 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
519 ps2_queue(&s->common, AUX_ACK);
520 break;
521 case AUX_SET_DEFAULT:
522 s->mouse_sample_rate = 100;
523 s->mouse_resolution = 2;
524 s->mouse_status = 0;
525 ps2_queue(&s->common, AUX_ACK);
526 break;
527 case AUX_RESET:
528 s->mouse_sample_rate = 100;
529 s->mouse_resolution = 2;
530 s->mouse_status = 0;
531 s->mouse_type = 0;
532 ps2_queue(&s->common, AUX_ACK);
533 ps2_queue(&s->common, 0xaa);
534 ps2_queue(&s->common, s->mouse_type);
535 break;
536 default:
537 break;
538 }
539 break;
540 case AUX_SET_SAMPLE:
541 s->mouse_sample_rate = val;
542 /* detect IMPS/2 or IMEX */
543 switch(s->mouse_detect_state) {
544 default:
545 case 0:
546 if (val == 200)
547 s->mouse_detect_state = 1;
548 break;
549 case 1:
550 if (val == 100)
551 s->mouse_detect_state = 2;
552 else if (val == 200)
553 s->mouse_detect_state = 3;
554 else
555 s->mouse_detect_state = 0;
556 break;
557 case 2:
5fafdf24 558 if (val == 80)
0e43e99c
FB
559 s->mouse_type = 3; /* IMPS/2 */
560 s->mouse_detect_state = 0;
561 break;
562 case 3:
5fafdf24 563 if (val == 80)
0e43e99c
FB
564 s->mouse_type = 4; /* IMEX */
565 s->mouse_detect_state = 0;
566 break;
567 }
568 ps2_queue(&s->common, AUX_ACK);
569 s->common.write_cmd = -1;
570 break;
571 case AUX_SET_RES:
572 s->mouse_resolution = val;
573 ps2_queue(&s->common, AUX_ACK);
574 s->common.write_cmd = -1;
575 break;
576 }
577}
578
ef74679a 579static void ps2_common_reset(PS2State *s)
0e43e99c 580{
0e43e99c
FB
581 PS2Queue *q;
582 s->write_cmd = -1;
583 q = &s->queue;
584 q->rptr = 0;
585 q->wptr = 0;
586 q->count = 0;
deeccef3 587 s->update_irq(s->update_arg, 0);
0e43e99c
FB
588}
589
2858ab09
GA
590static void ps2_common_post_load(PS2State *s)
591{
592 PS2Queue *q = &s->queue;
593 int size;
594 int i;
595 int tmp_data[PS2_QUEUE_SIZE];
596
597 /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
598 size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
599
600 /* move the queue elements to the start of data array */
601 if (size > 0) {
602 for (i = 0; i < size; i++) {
603 /* move the queue elements to the temporary buffer */
604 tmp_data[i] = q->data[q->rptr];
605 if (++q->rptr == 256) {
606 q->rptr = 0;
607 }
608 }
609 memcpy(q->data, tmp_data, size);
610 }
611 /* reset rptr/wptr/count */
612 q->rptr = 0;
613 q->wptr = size;
614 q->count = size;
615 s->update_irq(s->update_arg, q->count != 0);
616}
617
ef74679a
DS
618static void ps2_kbd_reset(void *opaque)
619{
620 PS2KbdState *s = (PS2KbdState *) opaque;
621
5edab03d 622 trace_ps2_kbd_reset(opaque);
ef74679a
DS
623 ps2_common_reset(&s->common);
624 s->scan_enabled = 0;
625 s->translate = 0;
626 s->scancode_set = 0;
627}
628
629static void ps2_mouse_reset(void *opaque)
630{
631 PS2MouseState *s = (PS2MouseState *) opaque;
632
5edab03d 633 trace_ps2_mouse_reset(opaque);
ef74679a
DS
634 ps2_common_reset(&s->common);
635 s->mouse_status = 0;
636 s->mouse_resolution = 0;
637 s->mouse_sample_rate = 0;
638 s->mouse_wrap = 0;
639 s->mouse_type = 0;
640 s->mouse_detect_state = 0;
641 s->mouse_dx = 0;
642 s->mouse_dy = 0;
643 s->mouse_dz = 0;
644 s->mouse_buttons = 0;
645}
646
b31442c3
JQ
647static const VMStateDescription vmstate_ps2_common = {
648 .name = "PS2 Common State",
649 .version_id = 3,
650 .minimum_version_id = 2,
d49805ae 651 .fields = (VMStateField[]) {
b31442c3
JQ
652 VMSTATE_INT32(write_cmd, PS2State),
653 VMSTATE_INT32(queue.rptr, PS2State),
654 VMSTATE_INT32(queue.wptr, PS2State),
655 VMSTATE_INT32(queue.count, PS2State),
656 VMSTATE_BUFFER(queue.data, PS2State),
657 VMSTATE_END_OF_LIST()
658 }
659};
0e43e99c 660
7f540ab5
CF
661static bool ps2_keyboard_ledstate_needed(void *opaque)
662{
663 PS2KbdState *s = opaque;
664
665 return s->ledstate != 0; /* 0 is default state */
666}
667
668static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
669{
670 PS2KbdState *s = opaque;
671
672 kbd_put_ledstate(s->ledstate);
673 return 0;
674}
675
676static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
677 .name = "ps2kbd/ledstate",
678 .version_id = 3,
679 .minimum_version_id = 2,
7f540ab5 680 .post_load = ps2_kbd_ledstate_post_load,
5cd8cada 681 .needed = ps2_keyboard_ledstate_needed,
d49805ae 682 .fields = (VMStateField[]) {
7f540ab5
CF
683 VMSTATE_INT32(ledstate, PS2KbdState),
684 VMSTATE_END_OF_LIST()
685 }
686};
687
db596c53 688static int ps2_kbd_post_load(void* opaque, int version_id)
0e43e99c
FB
689{
690 PS2KbdState *s = (PS2KbdState*)opaque;
2858ab09 691 PS2State *ps2 = &s->common;
7783e9f0 692
db596c53 693 if (version_id == 2)
e7d93956 694 s->scancode_set=2;
2858ab09
GA
695
696 ps2_common_post_load(ps2);
697
0e43e99c
FB
698 return 0;
699}
700
2858ab09
GA
701static void ps2_kbd_pre_save(void *opaque)
702{
703 PS2KbdState *s = (PS2KbdState *)opaque;
704 PS2State *ps2 = &s->common;
705
706 ps2_common_post_load(ps2);
707}
708
b31442c3
JQ
709static const VMStateDescription vmstate_ps2_keyboard = {
710 .name = "ps2kbd",
711 .version_id = 3,
db596c53 712 .minimum_version_id = 2,
db596c53 713 .post_load = ps2_kbd_post_load,
2858ab09 714 .pre_save = ps2_kbd_pre_save,
d49805ae 715 .fields = (VMStateField[]) {
b31442c3
JQ
716 VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
717 VMSTATE_INT32(scan_enabled, PS2KbdState),
718 VMSTATE_INT32(translate, PS2KbdState),
719 VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
720 VMSTATE_END_OF_LIST()
7f540ab5 721 },
5cd8cada
JQ
722 .subsections = (const VMStateDescription*[]) {
723 &vmstate_ps2_keyboard_ledstate,
724 NULL
b31442c3
JQ
725 }
726};
7783e9f0 727
2858ab09
GA
728static int ps2_mouse_post_load(void *opaque, int version_id)
729{
730 PS2MouseState *s = (PS2MouseState *)opaque;
731 PS2State *ps2 = &s->common;
732
733 ps2_common_post_load(ps2);
734
735 return 0;
736}
737
738static void ps2_mouse_pre_save(void *opaque)
739{
740 PS2MouseState *s = (PS2MouseState *)opaque;
741 PS2State *ps2 = &s->common;
742
743 ps2_common_post_load(ps2);
744}
745
b31442c3
JQ
746static const VMStateDescription vmstate_ps2_mouse = {
747 .name = "ps2mouse",
748 .version_id = 2,
749 .minimum_version_id = 2,
2858ab09
GA
750 .post_load = ps2_mouse_post_load,
751 .pre_save = ps2_mouse_pre_save,
d49805ae 752 .fields = (VMStateField[]) {
b31442c3
JQ
753 VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
754 VMSTATE_UINT8(mouse_status, PS2MouseState),
755 VMSTATE_UINT8(mouse_resolution, PS2MouseState),
756 VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
757 VMSTATE_UINT8(mouse_wrap, PS2MouseState),
758 VMSTATE_UINT8(mouse_type, PS2MouseState),
759 VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
760 VMSTATE_INT32(mouse_dx, PS2MouseState),
761 VMSTATE_INT32(mouse_dy, PS2MouseState),
762 VMSTATE_INT32(mouse_dz, PS2MouseState),
763 VMSTATE_UINT8(mouse_buttons, PS2MouseState),
764 VMSTATE_END_OF_LIST()
765 }
766};
0e43e99c 767
66e6536e
GH
768static QemuInputHandler ps2_keyboard_handler = {
769 .name = "QEMU PS/2 Keyboard",
770 .mask = INPUT_EVENT_MASK_KEY,
771 .event = ps2_keyboard_event,
772};
773
0e43e99c
FB
774void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
775{
7267c094 776 PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
0e43e99c 777
5edab03d 778 trace_ps2_kbd_init(s);
0e43e99c
FB
779 s->common.update_irq = update_irq;
780 s->common.update_arg = update_arg;
e7d93956 781 s->scancode_set = 2;
0be71e32 782 vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
66e6536e
GH
783 qemu_input_handler_register((DeviceState *)s,
784 &ps2_keyboard_handler);
ef74679a 785 qemu_register_reset(ps2_kbd_reset, s);
0e43e99c
FB
786 return s;
787}
788
2a766d29
GH
789static QemuInputHandler ps2_mouse_handler = {
790 .name = "QEMU PS/2 Mouse",
791 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
792 .event = ps2_mouse_event,
793 .sync = ps2_mouse_sync,
794};
795
0e43e99c
FB
796void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
797{
7267c094 798 PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
0e43e99c 799
5edab03d 800 trace_ps2_mouse_init(s);
0e43e99c
FB
801 s->common.update_irq = update_irq;
802 s->common.update_arg = update_arg;
0be71e32 803 vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
2a766d29
GH
804 qemu_input_handler_register((DeviceState *)s,
805 &ps2_mouse_handler);
ef74679a 806 qemu_register_reset(ps2_mouse_reset, s);
0e43e99c
FB
807 return s;
808}