]> git.proxmox.com Git - mirror_qemu.git/blame - hw/input/ps2.c
sysemu: Split sysemu/runstate.h off sysemu/sysemu.h
[mirror_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 */
71e8a915 24
0430891c 25#include "qemu/osdep.h"
ec044a80 26#include "qemu/log.h"
0d09e41a 27#include "hw/input/ps2.h"
d6454270 28#include "migration/vmstate.h"
28ecbaee 29#include "ui/console.h"
66e6536e 30#include "ui/input.h"
71e8a915 31#include "sysemu/reset.h"
54d31236 32#include "sysemu/runstate.h"
0e43e99c 33
5edab03d
DK
34#include "trace.h"
35
0e43e99c
FB
36/* debug PC keyboard */
37//#define DEBUG_KBD
38
39/* debug PC keyboard : only mouse */
40//#define DEBUG_MOUSE
41
42/* Keyboard Commands */
43#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
44#define KBD_CMD_ECHO 0xEE
e7d93956 45#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
0e43e99c
FB
46#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
47#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
48#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
49#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
50#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
51#define KBD_CMD_RESET 0xFF /* Reset */
52
53/* Keyboard Replies */
54#define KBD_REPLY_POR 0xAA /* Power on reset */
35c4d671 55#define KBD_REPLY_ID 0xAB /* Keyboard ID */
0e43e99c
FB
56#define KBD_REPLY_ACK 0xFA /* Command ACK */
57#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
58
59/* Mouse Commands */
60#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
61#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
62#define AUX_SET_RES 0xE8 /* Set resolution */
63#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
64#define AUX_SET_STREAM 0xEA /* Set stream mode */
65#define AUX_POLL 0xEB /* Poll */
66#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
67#define AUX_SET_WRAP 0xEE /* Set wrap mode */
68#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
69#define AUX_GET_TYPE 0xF2 /* Get type */
70#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
71#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
72#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
73#define AUX_SET_DEFAULT 0xF6
74#define AUX_RESET 0xFF /* Reset aux device */
75#define AUX_ACK 0xFA /* Command byte ACK. */
76
77#define MOUSE_STATUS_REMOTE 0x40
78#define MOUSE_STATUS_ENABLED 0x20
79#define MOUSE_STATUS_SCALE21 0x10
80
2858ab09 81#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */
0e43e99c 82
620775d1
DB
83/* Bits for 'modifiers' field in PS2KbdState */
84#define MOD_CTRL_L (1 << 0)
85#define MOD_SHIFT_L (1 << 1)
86#define MOD_ALT_L (1 << 2)
87#define MOD_CTRL_R (1 << 3)
88#define MOD_SHIFT_R (1 << 4)
89#define MOD_ALT_R (1 << 5)
90
0e43e99c 91typedef struct {
2858ab09
GA
92 /* Keep the data array 256 bytes long, which compatibility
93 with older qemu versions. */
94 uint8_t data[256];
0e43e99c
FB
95 int rptr, wptr, count;
96} PS2Queue;
97
8498bb8d 98struct PS2State {
0e43e99c
FB
99 PS2Queue queue;
100 int32_t write_cmd;
101 void (*update_irq)(void *, int);
102 void *update_arg;
8498bb8d 103};
0e43e99c
FB
104
105typedef struct {
106 PS2State common;
107 int scan_enabled;
f94f5d71 108 int translate;
e7d93956 109 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
7f540ab5 110 int ledstate;
57d5c005 111 bool need_high_bit;
620775d1 112 unsigned int modifiers; /* bitmask of MOD_* constants above */
0e43e99c
FB
113} PS2KbdState;
114
115typedef struct {
116 PS2State common;
117 uint8_t mouse_status;
118 uint8_t mouse_resolution;
119 uint8_t mouse_sample_rate;
120 uint8_t mouse_wrap;
121 uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
122 uint8_t mouse_detect_state;
123 int mouse_dx; /* current values, needed for 'poll' mode */
124 int mouse_dy;
125 int mouse_dz;
126 uint8_t mouse_buttons;
127} PS2MouseState;
128
57d5c005
HP
129static uint8_t translate_table[256] = {
130 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
131 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
132 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
133 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
134 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
135 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
136 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
137 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
138 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
139 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
140 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
141 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
142 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
143 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
144 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
145 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
146 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
147 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
148 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
149 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
150 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
151 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
152 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
153 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
154 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
155 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
156 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
157 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
158 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
159 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
160 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
161 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
162};
163
620775d1
DB
164static unsigned int ps2_modifier_bit(QKeyCode key)
165{
166 switch (key) {
167 case Q_KEY_CODE_CTRL:
168 return MOD_CTRL_L;
169 case Q_KEY_CODE_CTRL_R:
170 return MOD_CTRL_R;
171 case Q_KEY_CODE_SHIFT:
172 return MOD_SHIFT_L;
173 case Q_KEY_CODE_SHIFT_R:
174 return MOD_SHIFT_R;
175 case Q_KEY_CODE_ALT:
176 return MOD_ALT_L;
177 case Q_KEY_CODE_ALT_R:
178 return MOD_ALT_R;
179 default:
180 return 0;
181 }
182}
183
954ee55b
GH
184static void ps2_reset_queue(PS2State *s)
185{
186 PS2Queue *q = &s->queue;
187
188 q->rptr = 0;
189 q->wptr = 0;
190 q->count = 0;
191}
192
7abe7eb2 193void ps2_queue_noirq(PS2State *s, int b)
0e43e99c 194{
0e43e99c
FB
195 PS2Queue *q = &s->queue;
196
7abe7eb2 197 if (q->count == PS2_QUEUE_SIZE) {
0e43e99c 198 return;
7abe7eb2
GM
199 }
200
0e43e99c
FB
201 q->data[q->wptr] = b;
202 if (++q->wptr == PS2_QUEUE_SIZE)
203 q->wptr = 0;
204 q->count++;
7abe7eb2
GM
205}
206
207void ps2_raise_irq(PS2State *s)
208{
209 s->update_irq(s->update_arg, 1);
210}
211
212void ps2_queue(PS2State *s, int b)
213{
214 ps2_queue_noirq(s, b);
215 s->update_irq(s->update_arg, 1);
216}
217
218void ps2_queue_2(PS2State *s, int b1, int b2)
219{
220 if (PS2_QUEUE_SIZE - s->queue.count < 2) {
221 return;
222 }
223
224 ps2_queue_noirq(s, b1);
225 ps2_queue_noirq(s, b2);
226 s->update_irq(s->update_arg, 1);
227}
228
229void ps2_queue_3(PS2State *s, int b1, int b2, int b3)
230{
231 if (PS2_QUEUE_SIZE - s->queue.count < 3) {
232 return;
233 }
234
235 ps2_queue_noirq(s, b1);
236 ps2_queue_noirq(s, b2);
237 ps2_queue_noirq(s, b3);
238 s->update_irq(s->update_arg, 1);
239}
240
241void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4)
242{
243 if (PS2_QUEUE_SIZE - s->queue.count < 4) {
244 return;
245 }
246
247 ps2_queue_noirq(s, b1);
248 ps2_queue_noirq(s, b2);
249 ps2_queue_noirq(s, b3);
250 ps2_queue_noirq(s, b4);
0e43e99c
FB
251 s->update_irq(s->update_arg, 1);
252}
253
57d5c005 254/* keycode is the untranslated scancode in the current scancode set. */
0e43e99c
FB
255static void ps2_put_keycode(void *opaque, int keycode)
256{
f94f5d71 257 PS2KbdState *s = opaque;
e7d93956 258
5edab03d 259 trace_ps2_put_keycode(opaque, keycode);
fb064112 260 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
57d5c005
HP
261
262 if (s->translate) {
263 if (keycode == 0xf0) {
264 s->need_high_bit = true;
265 } else if (s->need_high_bit) {
266 ps2_queue(&s->common, translate_table[keycode] | 0x80);
267 s->need_high_bit = false;
268 } else {
269 ps2_queue(&s->common, translate_table[keycode]);
7096a96d 270 }
57d5c005
HP
271 } else {
272 ps2_queue(&s->common, keycode);
273 }
0e43e99c
FB
274}
275
66e6536e
GH
276static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
277 InputEvent *evt)
278{
279 PS2KbdState *s = (PS2KbdState *)dev;
32bafa8f 280 InputKeyEvent *key = evt->u.key.data;
8c10e0ba 281 int qcode;
ab8f9d49 282 uint16_t keycode = 0;
620775d1 283 int mod;
66e6536e 284
143c04c7
GM
285 /* do not process events while disabled to prevent stream corruption */
286 if (!s->scan_enabled) {
287 return;
288 }
289
fb064112 290 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
8c10e0ba
HP
291 assert(evt->type == INPUT_EVENT_KIND_KEY);
292 qcode = qemu_input_key_value_to_qcode(key->key);
57d5c005 293
620775d1
DB
294 mod = ps2_modifier_bit(qcode);
295 trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers);
296 if (key->down) {
297 s->modifiers |= mod;
298 } else {
299 s->modifiers &= ~mod;
300 }
301
8c10e0ba
HP
302 if (s->scancode_set == 1) {
303 if (qcode == Q_KEY_CODE_PAUSE) {
29fd23a5
DB
304 if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
305 if (key->down) {
306 ps2_put_keycode(s, 0xe0);
307 ps2_put_keycode(s, 0x46);
308 ps2_put_keycode(s, 0xe0);
309 ps2_put_keycode(s, 0xc6);
310 }
311 } else {
312 if (key->down) {
313 ps2_put_keycode(s, 0xe1);
314 ps2_put_keycode(s, 0x1d);
315 ps2_put_keycode(s, 0x45);
316 ps2_put_keycode(s, 0xe1);
317 ps2_put_keycode(s, 0x9d);
318 ps2_put_keycode(s, 0xc5);
319 }
8c10e0ba
HP
320 }
321 } else if (qcode == Q_KEY_CODE_PRINT) {
620775d1
DB
322 if (s->modifiers & MOD_ALT_L) {
323 if (key->down) {
324 ps2_put_keycode(s, 0xb8);
325 ps2_put_keycode(s, 0x38);
326 ps2_put_keycode(s, 0x54);
327 } else {
328 ps2_put_keycode(s, 0xd4);
329 ps2_put_keycode(s, 0xb8);
330 ps2_put_keycode(s, 0x38);
331 }
332 } else if (s->modifiers & MOD_ALT_R) {
333 if (key->down) {
334 ps2_put_keycode(s, 0xe0);
335 ps2_put_keycode(s, 0xb8);
336 ps2_put_keycode(s, 0xe0);
337 ps2_put_keycode(s, 0x38);
338 ps2_put_keycode(s, 0x54);
339 } else {
340 ps2_put_keycode(s, 0xd4);
341 ps2_put_keycode(s, 0xe0);
342 ps2_put_keycode(s, 0xb8);
343 ps2_put_keycode(s, 0xe0);
344 ps2_put_keycode(s, 0x38);
345 }
8f63458f
DB
346 } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
347 MOD_SHIFT_R | MOD_CTRL_R)) {
348 if (key->down) {
349 ps2_put_keycode(s, 0xe0);
350 ps2_put_keycode(s, 0x37);
351 } else {
352 ps2_put_keycode(s, 0xe0);
353 ps2_put_keycode(s, 0xb7);
354 }
8c10e0ba 355 } else {
620775d1
DB
356 if (key->down) {
357 ps2_put_keycode(s, 0xe0);
358 ps2_put_keycode(s, 0x2a);
359 ps2_put_keycode(s, 0xe0);
360 ps2_put_keycode(s, 0x37);
361 } else {
362 ps2_put_keycode(s, 0xe0);
363 ps2_put_keycode(s, 0xb7);
364 ps2_put_keycode(s, 0xe0);
365 ps2_put_keycode(s, 0xaa);
366 }
8c10e0ba 367 }
57d5c005 368 } else {
ab8f9d49
DB
369 if (qcode < qemu_input_map_qcode_to_atset1_len)
370 keycode = qemu_input_map_qcode_to_atset1[qcode];
8c10e0ba
HP
371 if (keycode) {
372 if (keycode & 0xff00) {
373 ps2_put_keycode(s, keycode >> 8);
374 }
375 if (!key->down) {
376 keycode |= 0x80;
377 }
378 ps2_put_keycode(s, keycode & 0xff);
379 } else {
ec044a80
HP
380 qemu_log_mask(LOG_UNIMP,
381 "ps2: ignoring key with qcode %d\n", qcode);
8c10e0ba 382 }
57d5c005 383 }
8c10e0ba
HP
384 } else if (s->scancode_set == 2) {
385 if (qcode == Q_KEY_CODE_PAUSE) {
29fd23a5
DB
386 if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
387 if (key->down) {
388 ps2_put_keycode(s, 0xe0);
389 ps2_put_keycode(s, 0x7e);
390 ps2_put_keycode(s, 0xe0);
391 ps2_put_keycode(s, 0xf0);
392 ps2_put_keycode(s, 0x7e);
393 }
394 } else {
395 if (key->down) {
396 ps2_put_keycode(s, 0xe1);
397 ps2_put_keycode(s, 0x14);
398 ps2_put_keycode(s, 0x77);
399 ps2_put_keycode(s, 0xe1);
400 ps2_put_keycode(s, 0xf0);
401 ps2_put_keycode(s, 0x14);
402 ps2_put_keycode(s, 0xf0);
403 ps2_put_keycode(s, 0x77);
404 }
57d5c005 405 }
8c10e0ba 406 } else if (qcode == Q_KEY_CODE_PRINT) {
620775d1
DB
407 if (s->modifiers & MOD_ALT_L) {
408 if (key->down) {
409 ps2_put_keycode(s, 0xf0);
410 ps2_put_keycode(s, 0x11);
411 ps2_put_keycode(s, 0x11);
412 ps2_put_keycode(s, 0x84);
413 } else {
414 ps2_put_keycode(s, 0xf0);
415 ps2_put_keycode(s, 0x84);
416 ps2_put_keycode(s, 0xf0);
417 ps2_put_keycode(s, 0x11);
418 ps2_put_keycode(s, 0x11);
419 }
420 } else if (s->modifiers & MOD_ALT_R) {
421 if (key->down) {
422 ps2_put_keycode(s, 0xe0);
423 ps2_put_keycode(s, 0xf0);
424 ps2_put_keycode(s, 0x11);
425 ps2_put_keycode(s, 0xe0);
426 ps2_put_keycode(s, 0x11);
427 ps2_put_keycode(s, 0x84);
428 } else {
429 ps2_put_keycode(s, 0xf0);
430 ps2_put_keycode(s, 0x84);
431 ps2_put_keycode(s, 0xe0);
432 ps2_put_keycode(s, 0xf0);
433 ps2_put_keycode(s, 0x11);
434 ps2_put_keycode(s, 0xe0);
435 ps2_put_keycode(s, 0x11);
436 }
8f63458f
DB
437 } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
438 MOD_SHIFT_R | MOD_CTRL_R)) {
439 if (key->down) {
440 ps2_put_keycode(s, 0xe0);
441 ps2_put_keycode(s, 0x7c);
442 } else {
443 ps2_put_keycode(s, 0xe0);
444 ps2_put_keycode(s, 0xf0);
445 ps2_put_keycode(s, 0x7c);
446 }
8c10e0ba 447 } else {
620775d1
DB
448 if (key->down) {
449 ps2_put_keycode(s, 0xe0);
450 ps2_put_keycode(s, 0x12);
451 ps2_put_keycode(s, 0xe0);
452 ps2_put_keycode(s, 0x7c);
453 } else {
454 ps2_put_keycode(s, 0xe0);
455 ps2_put_keycode(s, 0xf0);
456 ps2_put_keycode(s, 0x7c);
457 ps2_put_keycode(s, 0xe0);
458 ps2_put_keycode(s, 0xf0);
459 ps2_put_keycode(s, 0x12);
460 }
8c10e0ba
HP
461 }
462 } else {
ab8f9d49
DB
463 if (qcode < qemu_input_map_qcode_to_atset2_len)
464 keycode = qemu_input_map_qcode_to_atset2[qcode];
8c10e0ba
HP
465 if (keycode) {
466 if (keycode & 0xff00) {
467 ps2_put_keycode(s, keycode >> 8);
468 }
469 if (!key->down) {
470 ps2_put_keycode(s, 0xf0);
471 }
472 ps2_put_keycode(s, keycode & 0xff);
8c10e0ba 473 } else {
ec044a80
HP
474 qemu_log_mask(LOG_UNIMP,
475 "ps2: ignoring key with qcode %d\n", qcode);
57d5c005
HP
476 }
477 }
8c10e0ba 478 } else if (s->scancode_set == 3) {
ab8f9d49
DB
479 if (qcode < qemu_input_map_qcode_to_atset3_len)
480 keycode = qemu_input_map_qcode_to_atset3[qcode];
8c10e0ba
HP
481 if (keycode) {
482 /* FIXME: break code should be configured on a key by key basis */
483 if (!key->down) {
484 ps2_put_keycode(s, 0xf0);
485 }
486 ps2_put_keycode(s, keycode);
8c10e0ba 487 } else {
ec044a80
HP
488 qemu_log_mask(LOG_UNIMP,
489 "ps2: ignoring key with qcode %d\n", qcode);
8c10e0ba 490 }
66e6536e
GH
491 }
492}
493
8498bb8d 494uint32_t ps2_read_data(PS2State *s)
0e43e99c 495{
0e43e99c
FB
496 PS2Queue *q;
497 int val, index;
3b46e624 498
8498bb8d 499 trace_ps2_read_data(s);
0e43e99c
FB
500 q = &s->queue;
501 if (q->count == 0) {
502 /* NOTE: if no data left, we return the last keyboard one
503 (needed for EMM386) */
504 /* XXX: need a timer to do things correctly */
505 index = q->rptr - 1;
506 if (index < 0)
507 index = PS2_QUEUE_SIZE - 1;
508 val = q->data[index];
509 } else {
510 val = q->data[q->rptr];
511 if (++q->rptr == PS2_QUEUE_SIZE)
512 q->rptr = 0;
513 q->count--;
514 /* reading deasserts IRQ */
515 s->update_irq(s->update_arg, 0);
516 /* reassert IRQs if data left */
517 s->update_irq(s->update_arg, q->count != 0);
518 }
519 return val;
520}
521
7f540ab5
CF
522static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
523{
5edab03d 524 trace_ps2_set_ledstate(s, ledstate);
7f540ab5
CF
525 s->ledstate = ledstate;
526 kbd_put_ledstate(ledstate);
527}
528
0e43e99c
FB
529static void ps2_reset_keyboard(PS2KbdState *s)
530{
5edab03d 531 trace_ps2_reset_keyboard(s);
0e43e99c 532 s->scan_enabled = 1;
e7d93956 533 s->scancode_set = 2;
6e24ee0c 534 ps2_reset_queue(&s->common);
7f540ab5 535 ps2_set_ledstate(s, 0);
0e43e99c
FB
536}
537
538void ps2_write_keyboard(void *opaque, int val)
539{
540 PS2KbdState *s = (PS2KbdState *)opaque;
541
5edab03d 542 trace_ps2_write_keyboard(opaque, val);
0e43e99c
FB
543 switch(s->common.write_cmd) {
544 default:
545 case -1:
546 switch(val) {
547 case 0x00:
548 ps2_queue(&s->common, KBD_REPLY_ACK);
549 break;
550 case 0x05:
551 ps2_queue(&s->common, KBD_REPLY_RESEND);
552 break;
553 case KBD_CMD_GET_ID:
e7d93956 554 /* We emulate a MF2 AT keyboard here */
35c4d671 555 if (s->translate)
7abe7eb2
GM
556 ps2_queue_3(&s->common,
557 KBD_REPLY_ACK,
558 KBD_REPLY_ID,
559 0x41);
35c4d671 560 else
7abe7eb2
GM
561 ps2_queue_3(&s->common,
562 KBD_REPLY_ACK,
563 KBD_REPLY_ID,
564 0x83);
0e43e99c
FB
565 break;
566 case KBD_CMD_ECHO:
567 ps2_queue(&s->common, KBD_CMD_ECHO);
568 break;
569 case KBD_CMD_ENABLE:
570 s->scan_enabled = 1;
571 ps2_queue(&s->common, KBD_REPLY_ACK);
572 break;
e7d93956 573 case KBD_CMD_SCANCODE:
0e43e99c
FB
574 case KBD_CMD_SET_LEDS:
575 case KBD_CMD_SET_RATE:
576 s->common.write_cmd = val;
577 ps2_queue(&s->common, KBD_REPLY_ACK);
578 break;
579 case KBD_CMD_RESET_DISABLE:
580 ps2_reset_keyboard(s);
581 s->scan_enabled = 0;
582 ps2_queue(&s->common, KBD_REPLY_ACK);
583 break;
584 case KBD_CMD_RESET_ENABLE:
585 ps2_reset_keyboard(s);
586 s->scan_enabled = 1;
587 ps2_queue(&s->common, KBD_REPLY_ACK);
588 break;
589 case KBD_CMD_RESET:
590 ps2_reset_keyboard(s);
7abe7eb2
GM
591 ps2_queue_2(&s->common,
592 KBD_REPLY_ACK,
593 KBD_REPLY_POR);
0e43e99c
FB
594 break;
595 default:
06b3611f 596 ps2_queue(&s->common, KBD_REPLY_RESEND);
0e43e99c
FB
597 break;
598 }
599 break;
e7d93956
AJ
600 case KBD_CMD_SCANCODE:
601 if (val == 0) {
7abe7eb2
GM
602 if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) {
603 ps2_queue(&s->common, KBD_REPLY_ACK);
604 ps2_put_keycode(s, s->scancode_set);
605 }
4df23b64
HP
606 } else if (val >= 1 && val <= 3) {
607 s->scancode_set = val;
e7d93956 608 ps2_queue(&s->common, KBD_REPLY_ACK);
4df23b64
HP
609 } else {
610 ps2_queue(&s->common, KBD_REPLY_RESEND);
e7d93956
AJ
611 }
612 s->common.write_cmd = -1;
613 break;
0e43e99c 614 case KBD_CMD_SET_LEDS:
7f540ab5 615 ps2_set_ledstate(s, val);
0e43e99c
FB
616 ps2_queue(&s->common, KBD_REPLY_ACK);
617 s->common.write_cmd = -1;
618 break;
619 case KBD_CMD_SET_RATE:
620 ps2_queue(&s->common, KBD_REPLY_ACK);
621 s->common.write_cmd = -1;
622 break;
623 }
624}
625
f94f5d71
PB
626/* Set the scancode translation mode.
627 0 = raw scancodes.
628 1 = translated scancodes (used by qemu internally). */
629
630void ps2_keyboard_set_translation(void *opaque, int mode)
631{
632 PS2KbdState *s = (PS2KbdState *)opaque;
5edab03d 633 trace_ps2_keyboard_set_translation(opaque, mode);
f94f5d71
PB
634 s->translate = mode;
635}
636
7abe7eb2 637static int ps2_mouse_send_packet(PS2MouseState *s)
0e43e99c 638{
7abe7eb2 639 const int needed = 3 + (s->mouse_type - 2);
0e43e99c
FB
640 unsigned int b;
641 int dx1, dy1, dz1;
642
7abe7eb2
GM
643 if (PS2_QUEUE_SIZE - s->common.queue.count < needed) {
644 return 0;
645 }
646
0e43e99c
FB
647 dx1 = s->mouse_dx;
648 dy1 = s->mouse_dy;
649 dz1 = s->mouse_dz;
650 /* XXX: increase range to 8 bits ? */
651 if (dx1 > 127)
652 dx1 = 127;
653 else if (dx1 < -127)
654 dx1 = -127;
655 if (dy1 > 127)
656 dy1 = 127;
657 else if (dy1 < -127)
658 dy1 = -127;
659 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
7abe7eb2
GM
660 ps2_queue_noirq(&s->common, b);
661 ps2_queue_noirq(&s->common, dx1 & 0xff);
662 ps2_queue_noirq(&s->common, dy1 & 0xff);
0e43e99c
FB
663 /* extra byte for IMPS/2 or IMEX */
664 switch(s->mouse_type) {
665 default:
666 break;
667 case 3:
668 if (dz1 > 127)
669 dz1 = 127;
670 else if (dz1 < -127)
671 dz1 = -127;
7abe7eb2 672 ps2_queue_noirq(&s->common, dz1 & 0xff);
0e43e99c
FB
673 break;
674 case 4:
675 if (dz1 > 7)
676 dz1 = 7;
677 else if (dz1 < -7)
678 dz1 = -7;
679 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
7abe7eb2 680 ps2_queue_noirq(&s->common, b);
0e43e99c
FB
681 break;
682 }
683
7abe7eb2
GM
684 ps2_raise_irq(&s->common);
685
5edab03d 686 trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
0e43e99c
FB
687 /* update deltas */
688 s->mouse_dx -= dx1;
689 s->mouse_dy -= dy1;
690 s->mouse_dz -= dz1;
7abe7eb2
GM
691
692 return 1;
0e43e99c
FB
693}
694
2a766d29
GH
695static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
696 InputEvent *evt)
0e43e99c 697{
7fb1cf16 698 static const int bmap[INPUT_BUTTON__MAX] = {
8b0caab0
FL
699 [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT,
700 [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
701 [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT,
702 [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE,
703 [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA,
2a766d29
GH
704 };
705 PS2MouseState *s = (PS2MouseState *)dev;
b5a1b443
EB
706 InputMoveEvent *move;
707 InputBtnEvent *btn;
0e43e99c
FB
708
709 /* check if deltas are recorded when disabled */
710 if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
711 return;
712
568c73a4 713 switch (evt->type) {
2a766d29 714 case INPUT_EVENT_KIND_REL:
32bafa8f 715 move = evt->u.rel.data;
b5a1b443
EB
716 if (move->axis == INPUT_AXIS_X) {
717 s->mouse_dx += move->value;
718 } else if (move->axis == INPUT_AXIS_Y) {
719 s->mouse_dy -= move->value;
2a766d29
GH
720 }
721 break;
3b46e624 722
2a766d29 723 case INPUT_EVENT_KIND_BTN:
32bafa8f 724 btn = evt->u.btn.data;
b5a1b443
EB
725 if (btn->down) {
726 s->mouse_buttons |= bmap[btn->button];
727 if (btn->button == INPUT_BUTTON_WHEEL_UP) {
2a766d29 728 s->mouse_dz--;
b5a1b443 729 } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
2a766d29
GH
730 s->mouse_dz++;
731 }
732 } else {
b5a1b443 733 s->mouse_buttons &= ~bmap[btn->button];
2a766d29
GH
734 }
735 break;
736
737 default:
738 /* keep gcc happy */
739 break;
fd214d18 740 }
2a766d29 741}
fd214d18 742
2a766d29
GH
743static void ps2_mouse_sync(DeviceState *dev)
744{
745 PS2MouseState *s = (PS2MouseState *)dev;
746
143c04c7
GM
747 /* do not sync while disabled to prevent stream corruption */
748 if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
749 return;
750 }
751
2a766d29 752 if (s->mouse_buttons) {
fb064112 753 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
2a766d29 754 }
2858ab09 755 if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
7abe7eb2
GM
756 /* if not remote, send event. Multiple events are sent if
757 too big deltas */
758 while (ps2_mouse_send_packet(s)) {
0e43e99c
FB
759 if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
760 break;
761 }
762 }
763}
764
548df2ac
TS
765void ps2_mouse_fake_event(void *opaque)
766{
2a766d29 767 PS2MouseState *s = opaque;
5edab03d 768 trace_ps2_mouse_fake_event(opaque);
2a766d29
GH
769 s->mouse_dx++;
770 ps2_mouse_sync(opaque);
548df2ac
TS
771}
772
0e43e99c
FB
773void ps2_write_mouse(void *opaque, int val)
774{
775 PS2MouseState *s = (PS2MouseState *)opaque;
5edab03d
DK
776
777 trace_ps2_write_mouse(opaque, val);
0e43e99c
FB
778#ifdef DEBUG_MOUSE
779 printf("kbd: write mouse 0x%02x\n", val);
780#endif
781 switch(s->common.write_cmd) {
782 default:
783 case -1:
784 /* mouse command */
785 if (s->mouse_wrap) {
786 if (val == AUX_RESET_WRAP) {
787 s->mouse_wrap = 0;
788 ps2_queue(&s->common, AUX_ACK);
789 return;
790 } else if (val != AUX_RESET) {
791 ps2_queue(&s->common, val);
792 return;
793 }
794 }
795 switch(val) {
796 case AUX_SET_SCALE11:
797 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
798 ps2_queue(&s->common, AUX_ACK);
799 break;
800 case AUX_SET_SCALE21:
801 s->mouse_status |= MOUSE_STATUS_SCALE21;
802 ps2_queue(&s->common, AUX_ACK);
803 break;
804 case AUX_SET_STREAM:
805 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
806 ps2_queue(&s->common, AUX_ACK);
807 break;
808 case AUX_SET_WRAP:
809 s->mouse_wrap = 1;
810 ps2_queue(&s->common, AUX_ACK);
811 break;
812 case AUX_SET_REMOTE:
813 s->mouse_status |= MOUSE_STATUS_REMOTE;
814 ps2_queue(&s->common, AUX_ACK);
815 break;
816 case AUX_GET_TYPE:
7abe7eb2
GM
817 ps2_queue_2(&s->common,
818 AUX_ACK,
819 s->mouse_type);
0e43e99c
FB
820 break;
821 case AUX_SET_RES:
822 case AUX_SET_SAMPLE:
823 s->common.write_cmd = val;
824 ps2_queue(&s->common, AUX_ACK);
825 break;
826 case AUX_GET_SCALE:
7abe7eb2
GM
827 ps2_queue_4(&s->common,
828 AUX_ACK,
829 s->mouse_status,
830 s->mouse_resolution,
831 s->mouse_sample_rate);
0e43e99c
FB
832 break;
833 case AUX_POLL:
834 ps2_queue(&s->common, AUX_ACK);
835 ps2_mouse_send_packet(s);
836 break;
837 case AUX_ENABLE_DEV:
838 s->mouse_status |= MOUSE_STATUS_ENABLED;
839 ps2_queue(&s->common, AUX_ACK);
840 break;
841 case AUX_DISABLE_DEV:
842 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
843 ps2_queue(&s->common, AUX_ACK);
844 break;
845 case AUX_SET_DEFAULT:
846 s->mouse_sample_rate = 100;
847 s->mouse_resolution = 2;
848 s->mouse_status = 0;
849 ps2_queue(&s->common, AUX_ACK);
850 break;
851 case AUX_RESET:
852 s->mouse_sample_rate = 100;
853 s->mouse_resolution = 2;
854 s->mouse_status = 0;
855 s->mouse_type = 0;
143c04c7 856 ps2_reset_queue(&s->common);
7abe7eb2
GM
857 ps2_queue_3(&s->common,
858 AUX_ACK,
859 0xaa,
860 s->mouse_type);
0e43e99c
FB
861 break;
862 default:
863 break;
864 }
865 break;
866 case AUX_SET_SAMPLE:
867 s->mouse_sample_rate = val;
868 /* detect IMPS/2 or IMEX */
869 switch(s->mouse_detect_state) {
870 default:
871 case 0:
872 if (val == 200)
873 s->mouse_detect_state = 1;
874 break;
875 case 1:
876 if (val == 100)
877 s->mouse_detect_state = 2;
878 else if (val == 200)
879 s->mouse_detect_state = 3;
880 else
881 s->mouse_detect_state = 0;
882 break;
883 case 2:
5fafdf24 884 if (val == 80)
0e43e99c
FB
885 s->mouse_type = 3; /* IMPS/2 */
886 s->mouse_detect_state = 0;
887 break;
888 case 3:
5fafdf24 889 if (val == 80)
0e43e99c
FB
890 s->mouse_type = 4; /* IMEX */
891 s->mouse_detect_state = 0;
892 break;
893 }
894 ps2_queue(&s->common, AUX_ACK);
895 s->common.write_cmd = -1;
896 break;
897 case AUX_SET_RES:
898 s->mouse_resolution = val;
899 ps2_queue(&s->common, AUX_ACK);
900 s->common.write_cmd = -1;
901 break;
902 }
903}
904
ef74679a 905static void ps2_common_reset(PS2State *s)
0e43e99c 906{
0e43e99c 907 s->write_cmd = -1;
954ee55b 908 ps2_reset_queue(s);
deeccef3 909 s->update_irq(s->update_arg, 0);
0e43e99c
FB
910}
911
2858ab09
GA
912static void ps2_common_post_load(PS2State *s)
913{
914 PS2Queue *q = &s->queue;
802cbcb7
PP
915 uint8_t i, size;
916 uint8_t tmp_data[PS2_QUEUE_SIZE];
2858ab09
GA
917
918 /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
a1f2ed2a
PD
919 size = q->count;
920 if (q->count < 0) {
921 size = 0;
922 } else if (q->count > PS2_QUEUE_SIZE) {
923 size = PS2_QUEUE_SIZE;
924 }
2858ab09
GA
925
926 /* move the queue elements to the start of data array */
802cbcb7
PP
927 for (i = 0; i < size; i++) {
928 if (q->rptr < 0 || q->rptr >= sizeof(q->data)) {
929 q->rptr = 0;
2858ab09 930 }
802cbcb7 931 tmp_data[i] = q->data[q->rptr++];
2858ab09 932 }
802cbcb7
PP
933 memcpy(q->data, tmp_data, size);
934
2858ab09
GA
935 /* reset rptr/wptr/count */
936 q->rptr = 0;
b55a06df 937 q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size;
2858ab09 938 q->count = size;
2858ab09
GA
939}
940
ef74679a
DS
941static void ps2_kbd_reset(void *opaque)
942{
943 PS2KbdState *s = (PS2KbdState *) opaque;
944
5edab03d 945 trace_ps2_kbd_reset(opaque);
ef74679a 946 ps2_common_reset(&s->common);
d2e550a8 947 s->scan_enabled = 1;
ef74679a 948 s->translate = 0;
089adafd 949 s->scancode_set = 2;
620775d1 950 s->modifiers = 0;
ef74679a
DS
951}
952
953static void ps2_mouse_reset(void *opaque)
954{
955 PS2MouseState *s = (PS2MouseState *) opaque;
956
5edab03d 957 trace_ps2_mouse_reset(opaque);
ef74679a
DS
958 ps2_common_reset(&s->common);
959 s->mouse_status = 0;
960 s->mouse_resolution = 0;
961 s->mouse_sample_rate = 0;
962 s->mouse_wrap = 0;
963 s->mouse_type = 0;
964 s->mouse_detect_state = 0;
965 s->mouse_dx = 0;
966 s->mouse_dy = 0;
967 s->mouse_dz = 0;
968 s->mouse_buttons = 0;
969}
970
b31442c3
JQ
971static const VMStateDescription vmstate_ps2_common = {
972 .name = "PS2 Common State",
973 .version_id = 3,
974 .minimum_version_id = 2,
d49805ae 975 .fields = (VMStateField[]) {
b31442c3
JQ
976 VMSTATE_INT32(write_cmd, PS2State),
977 VMSTATE_INT32(queue.rptr, PS2State),
978 VMSTATE_INT32(queue.wptr, PS2State),
979 VMSTATE_INT32(queue.count, PS2State),
980 VMSTATE_BUFFER(queue.data, PS2State),
981 VMSTATE_END_OF_LIST()
982 }
983};
0e43e99c 984
7f540ab5
CF
985static bool ps2_keyboard_ledstate_needed(void *opaque)
986{
987 PS2KbdState *s = opaque;
988
989 return s->ledstate != 0; /* 0 is default state */
990}
991
992static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
993{
994 PS2KbdState *s = opaque;
995
996 kbd_put_ledstate(s->ledstate);
997 return 0;
998}
999
1000static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
1001 .name = "ps2kbd/ledstate",
1002 .version_id = 3,
1003 .minimum_version_id = 2,
7f540ab5 1004 .post_load = ps2_kbd_ledstate_post_load,
5cd8cada 1005 .needed = ps2_keyboard_ledstate_needed,
d49805ae 1006 .fields = (VMStateField[]) {
7f540ab5
CF
1007 VMSTATE_INT32(ledstate, PS2KbdState),
1008 VMSTATE_END_OF_LIST()
1009 }
1010};
1011
57d5c005
HP
1012static bool ps2_keyboard_need_high_bit_needed(void *opaque)
1013{
1014 PS2KbdState *s = opaque;
1015 return s->need_high_bit != 0; /* 0 is the usual state */
1016}
1017
1018static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
1019 .name = "ps2kbd/need_high_bit",
1020 .version_id = 1,
1021 .minimum_version_id = 1,
1022 .needed = ps2_keyboard_need_high_bit_needed,
1023 .fields = (VMStateField[]) {
1024 VMSTATE_BOOL(need_high_bit, PS2KbdState),
1025 VMSTATE_END_OF_LIST()
1026 }
1027};
1028
db596c53 1029static int ps2_kbd_post_load(void* opaque, int version_id)
0e43e99c
FB
1030{
1031 PS2KbdState *s = (PS2KbdState*)opaque;
2858ab09 1032 PS2State *ps2 = &s->common;
7783e9f0 1033
db596c53 1034 if (version_id == 2)
e7d93956 1035 s->scancode_set=2;
2858ab09
GA
1036
1037 ps2_common_post_load(ps2);
1038
0e43e99c
FB
1039 return 0;
1040}
1041
44b1ff31 1042static int ps2_kbd_pre_save(void *opaque)
2858ab09
GA
1043{
1044 PS2KbdState *s = (PS2KbdState *)opaque;
1045 PS2State *ps2 = &s->common;
1046
1047 ps2_common_post_load(ps2);
44b1ff31
DDAG
1048
1049 return 0;
2858ab09
GA
1050}
1051
b31442c3
JQ
1052static const VMStateDescription vmstate_ps2_keyboard = {
1053 .name = "ps2kbd",
1054 .version_id = 3,
db596c53 1055 .minimum_version_id = 2,
db596c53 1056 .post_load = ps2_kbd_post_load,
2858ab09 1057 .pre_save = ps2_kbd_pre_save,
d49805ae 1058 .fields = (VMStateField[]) {
b31442c3
JQ
1059 VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
1060 VMSTATE_INT32(scan_enabled, PS2KbdState),
1061 VMSTATE_INT32(translate, PS2KbdState),
1062 VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
1063 VMSTATE_END_OF_LIST()
7f540ab5 1064 },
5cd8cada
JQ
1065 .subsections = (const VMStateDescription*[]) {
1066 &vmstate_ps2_keyboard_ledstate,
57d5c005 1067 &vmstate_ps2_keyboard_need_high_bit,
5cd8cada 1068 NULL
b31442c3
JQ
1069 }
1070};
7783e9f0 1071
2858ab09
GA
1072static int ps2_mouse_post_load(void *opaque, int version_id)
1073{
1074 PS2MouseState *s = (PS2MouseState *)opaque;
1075 PS2State *ps2 = &s->common;
1076
1077 ps2_common_post_load(ps2);
1078
1079 return 0;
1080}
1081
44b1ff31 1082static int ps2_mouse_pre_save(void *opaque)
2858ab09
GA
1083{
1084 PS2MouseState *s = (PS2MouseState *)opaque;
1085 PS2State *ps2 = &s->common;
1086
1087 ps2_common_post_load(ps2);
44b1ff31
DDAG
1088
1089 return 0;
2858ab09
GA
1090}
1091
b31442c3
JQ
1092static const VMStateDescription vmstate_ps2_mouse = {
1093 .name = "ps2mouse",
1094 .version_id = 2,
1095 .minimum_version_id = 2,
2858ab09
GA
1096 .post_load = ps2_mouse_post_load,
1097 .pre_save = ps2_mouse_pre_save,
d49805ae 1098 .fields = (VMStateField[]) {
b31442c3
JQ
1099 VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
1100 VMSTATE_UINT8(mouse_status, PS2MouseState),
1101 VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1102 VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1103 VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1104 VMSTATE_UINT8(mouse_type, PS2MouseState),
1105 VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1106 VMSTATE_INT32(mouse_dx, PS2MouseState),
1107 VMSTATE_INT32(mouse_dy, PS2MouseState),
1108 VMSTATE_INT32(mouse_dz, PS2MouseState),
1109 VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1110 VMSTATE_END_OF_LIST()
1111 }
1112};
0e43e99c 1113
66e6536e
GH
1114static QemuInputHandler ps2_keyboard_handler = {
1115 .name = "QEMU PS/2 Keyboard",
1116 .mask = INPUT_EVENT_MASK_KEY,
1117 .event = ps2_keyboard_event,
1118};
1119
0e43e99c
FB
1120void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
1121{
7267c094 1122 PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
0e43e99c 1123
5edab03d 1124 trace_ps2_kbd_init(s);
0e43e99c
FB
1125 s->common.update_irq = update_irq;
1126 s->common.update_arg = update_arg;
e7d93956 1127 s->scancode_set = 2;
0be71e32 1128 vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
66e6536e
GH
1129 qemu_input_handler_register((DeviceState *)s,
1130 &ps2_keyboard_handler);
ef74679a 1131 qemu_register_reset(ps2_kbd_reset, s);
0e43e99c
FB
1132 return s;
1133}
1134
2a766d29
GH
1135static QemuInputHandler ps2_mouse_handler = {
1136 .name = "QEMU PS/2 Mouse",
1137 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
1138 .event = ps2_mouse_event,
1139 .sync = ps2_mouse_sync,
1140};
1141
0e43e99c
FB
1142void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
1143{
7267c094 1144 PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
0e43e99c 1145
5edab03d 1146 trace_ps2_mouse_init(s);
0e43e99c
FB
1147 s->common.update_irq = update_irq;
1148 s->common.update_arg = update_arg;
0be71e32 1149 vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
2a766d29
GH
1150 qemu_input_handler_register((DeviceState *)s,
1151 &ps2_mouse_handler);
ef74679a 1152 qemu_register_reset(ps2_mouse_reset, s);
0e43e99c
FB
1153 return s;
1154}