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