]> git.proxmox.com Git - mirror_qemu.git/blame - hw/input/ps2.c
Merge tag 'seabios-1.16.2-20230316-pull-request' of https://gitlab.com/kraxel/qemu...
[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"
6beb79e1 27#include "hw/irq.h"
64bbdd13 28#include "hw/sysbus.h"
0d09e41a 29#include "hw/input/ps2.h"
d6454270 30#include "migration/vmstate.h"
28ecbaee 31#include "ui/console.h"
66e6536e 32#include "ui/input.h"
71e8a915 33#include "sysemu/reset.h"
54d31236 34#include "sysemu/runstate.h"
8f84e53c 35#include "qapi/error.h"
0e43e99c 36
5edab03d
DK
37#include "trace.h"
38
0e43e99c 39/* Keyboard Commands */
545e5cf8
MCA
40#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
41#define KBD_CMD_ECHO 0xEE
42#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
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 */
c56b6209
SS
49#define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */
50#define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */
0e43e99c
FB
51
52/* Keyboard Replies */
545e5cf8
MCA
53#define KBD_REPLY_POR 0xAA /* Power on reset */
54#define KBD_REPLY_ID 0xAB /* Keyboard ID */
55#define KBD_REPLY_ACK 0xFA /* Command ACK */
56#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
0e43e99c
FB
57
58/* Mouse Commands */
545e5cf8
MCA
59#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
60#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
61#define AUX_SET_RES 0xE8 /* Set resolution */
62#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
63#define AUX_SET_STREAM 0xEA /* Set stream mode */
64#define AUX_POLL 0xEB /* Poll */
65#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
66#define AUX_SET_WRAP 0xEE /* Set wrap mode */
67#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
68#define AUX_GET_TYPE 0xF2 /* Get type */
69#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
70#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
71#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
72#define AUX_SET_DEFAULT 0xF6
73#define AUX_RESET 0xFF /* Reset aux device */
74#define AUX_ACK 0xFA /* Command byte ACK. */
0e43e99c
FB
75
76#define MOUSE_STATUS_REMOTE 0x40
77#define MOUSE_STATUS_ENABLED 0x20
78#define MOUSE_STATUS_SCALE21 0x10
79
47db2432 80#define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */
4e9bddcb 81#define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */
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
57d5c005
HP
91static uint8_t translate_table[256] = {
92 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
93 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
94 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
95 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
96 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
97 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
98 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
99 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
100 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
101 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
102 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
103 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
104 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
105 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
106 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
107 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
108 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
109 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
110 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
111 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
112 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
113 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
114 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
115 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
116 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
117 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
118 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
119 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
120 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
121 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
122 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
123 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
124};
125
620775d1
DB
126static unsigned int ps2_modifier_bit(QKeyCode key)
127{
128 switch (key) {
129 case Q_KEY_CODE_CTRL:
130 return MOD_CTRL_L;
131 case Q_KEY_CODE_CTRL_R:
132 return MOD_CTRL_R;
133 case Q_KEY_CODE_SHIFT:
134 return MOD_SHIFT_L;
135 case Q_KEY_CODE_SHIFT_R:
136 return MOD_SHIFT_R;
137 case Q_KEY_CODE_ALT:
138 return MOD_ALT_L;
139 case Q_KEY_CODE_ALT_R:
140 return MOD_ALT_R;
141 default:
142 return 0;
143 }
144}
145
954ee55b
GH
146static void ps2_reset_queue(PS2State *s)
147{
148 PS2Queue *q = &s->queue;
149
150 q->rptr = 0;
151 q->wptr = 0;
9e24b2dd 152 q->cwptr = -1;
954ee55b
GH
153 q->count = 0;
154}
155
2a6505b0
SS
156int ps2_queue_empty(PS2State *s)
157{
158 return s->queue.count == 0;
159}
160
7abe7eb2 161void ps2_queue_noirq(PS2State *s, int b)
0e43e99c 162{
0e43e99c
FB
163 PS2Queue *q = &s->queue;
164
9e24b2dd 165 if (q->count >= PS2_QUEUE_SIZE) {
0e43e99c 166 return;
7abe7eb2
GM
167 }
168
0e43e99c 169 q->data[q->wptr] = b;
47db2432 170 if (++q->wptr == PS2_BUFFER_SIZE) {
0e43e99c 171 q->wptr = 0;
47db2432 172 }
0e43e99c 173 q->count++;
7abe7eb2
GM
174}
175
52b28f76 176static void ps2_raise_irq(PS2State *s)
7abe7eb2 177{
7227de94 178 qemu_set_irq(s->irq, 1);
7abe7eb2
GM
179}
180
5cb6e556
MCA
181static void ps2_lower_irq(PS2State *s)
182{
7227de94 183 qemu_set_irq(s->irq, 0);
5cb6e556
MCA
184}
185
7abe7eb2
GM
186void ps2_queue(PS2State *s, int b)
187{
7704bb02
VR
188 if (PS2_QUEUE_SIZE - s->queue.count < 1) {
189 return;
190 }
191
7abe7eb2 192 ps2_queue_noirq(s, b);
96376ab1 193 ps2_raise_irq(s);
7abe7eb2
GM
194}
195
196void ps2_queue_2(PS2State *s, int b1, int b2)
197{
198 if (PS2_QUEUE_SIZE - s->queue.count < 2) {
199 return;
200 }
201
202 ps2_queue_noirq(s, b1);
203 ps2_queue_noirq(s, b2);
96376ab1 204 ps2_raise_irq(s);
7abe7eb2
GM
205}
206
207void ps2_queue_3(PS2State *s, int b1, int b2, int b3)
208{
209 if (PS2_QUEUE_SIZE - s->queue.count < 3) {
210 return;
211 }
212
213 ps2_queue_noirq(s, b1);
214 ps2_queue_noirq(s, b2);
215 ps2_queue_noirq(s, b3);
96376ab1 216 ps2_raise_irq(s);
7abe7eb2
GM
217}
218
219void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4)
220{
221 if (PS2_QUEUE_SIZE - s->queue.count < 4) {
222 return;
223 }
224
225 ps2_queue_noirq(s, b1);
226 ps2_queue_noirq(s, b2);
227 ps2_queue_noirq(s, b3);
228 ps2_queue_noirq(s, b4);
96376ab1 229 ps2_raise_irq(s);
0e43e99c
FB
230}
231
9e24b2dd
VR
232static void ps2_cqueue_data(PS2Queue *q, int b)
233{
234 q->data[q->cwptr] = b;
235 if (++q->cwptr >= PS2_BUFFER_SIZE) {
236 q->cwptr = 0;
237 }
238 q->count++;
239}
240
241static void ps2_cqueue_1(PS2State *s, int b1)
242{
243 PS2Queue *q = &s->queue;
244
245 q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1);
246 q->cwptr = q->rptr;
247 ps2_cqueue_data(q, b1);
248 ps2_raise_irq(s);
249}
250
251static void ps2_cqueue_2(PS2State *s, int b1, int b2)
252{
253 PS2Queue *q = &s->queue;
254
255 q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1);
256 q->cwptr = q->rptr;
257 ps2_cqueue_data(q, b1);
258 ps2_cqueue_data(q, b2);
259 ps2_raise_irq(s);
260}
261
262static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3)
263{
264 PS2Queue *q = &s->queue;
265
266 q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1);
267 q->cwptr = q->rptr;
268 ps2_cqueue_data(q, b1);
269 ps2_cqueue_data(q, b2);
270 ps2_cqueue_data(q, b3);
271 ps2_raise_irq(s);
272}
273
274static void ps2_cqueue_reset(PS2State *s)
275{
276 PS2Queue *q = &s->queue;
277 int ccount;
278
279 if (q->cwptr == -1) {
280 return;
281 }
282
283 ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
284 q->count -= ccount;
285 q->rptr = q->cwptr;
286 q->cwptr = -1;
287}
288
57d5c005 289/* keycode is the untranslated scancode in the current scancode set. */
0e43e99c
FB
290static void ps2_put_keycode(void *opaque, int keycode)
291{
f94f5d71 292 PS2KbdState *s = opaque;
8f84e53c 293 PS2State *ps = PS2_DEVICE(s);
e7d93956 294
5edab03d 295 trace_ps2_put_keycode(opaque, keycode);
fb064112 296 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
57d5c005
HP
297
298 if (s->translate) {
299 if (keycode == 0xf0) {
300 s->need_high_bit = true;
301 } else if (s->need_high_bit) {
8f84e53c 302 ps2_queue(ps, translate_table[keycode] | 0x80);
57d5c005
HP
303 s->need_high_bit = false;
304 } else {
8f84e53c 305 ps2_queue(ps, translate_table[keycode]);
7096a96d 306 }
57d5c005 307 } else {
8f84e53c 308 ps2_queue(ps, keycode);
57d5c005 309 }
0e43e99c
FB
310}
311
66e6536e
GH
312static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
313 InputEvent *evt)
314{
315 PS2KbdState *s = (PS2KbdState *)dev;
32bafa8f 316 InputKeyEvent *key = evt->u.key.data;
8c10e0ba 317 int qcode;
ab8f9d49 318 uint16_t keycode = 0;
620775d1 319 int mod;
66e6536e 320
143c04c7
GM
321 /* do not process events while disabled to prevent stream corruption */
322 if (!s->scan_enabled) {
323 return;
324 }
325
fb064112 326 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
8c10e0ba
HP
327 assert(evt->type == INPUT_EVENT_KIND_KEY);
328 qcode = qemu_input_key_value_to_qcode(key->key);
57d5c005 329
620775d1 330 mod = ps2_modifier_bit(qcode);
644f66bf
DB
331 trace_ps2_keyboard_event(s, qcode, key->down, mod,
332 s->modifiers, s->scancode_set, s->translate);
620775d1
DB
333 if (key->down) {
334 s->modifiers |= mod;
335 } else {
336 s->modifiers &= ~mod;
337 }
338
8c10e0ba
HP
339 if (s->scancode_set == 1) {
340 if (qcode == Q_KEY_CODE_PAUSE) {
29fd23a5
DB
341 if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
342 if (key->down) {
343 ps2_put_keycode(s, 0xe0);
344 ps2_put_keycode(s, 0x46);
345 ps2_put_keycode(s, 0xe0);
346 ps2_put_keycode(s, 0xc6);
347 }
348 } else {
349 if (key->down) {
350 ps2_put_keycode(s, 0xe1);
351 ps2_put_keycode(s, 0x1d);
352 ps2_put_keycode(s, 0x45);
353 ps2_put_keycode(s, 0xe1);
354 ps2_put_keycode(s, 0x9d);
355 ps2_put_keycode(s, 0xc5);
356 }
8c10e0ba
HP
357 }
358 } else if (qcode == Q_KEY_CODE_PRINT) {
620775d1
DB
359 if (s->modifiers & MOD_ALT_L) {
360 if (key->down) {
361 ps2_put_keycode(s, 0xb8);
362 ps2_put_keycode(s, 0x38);
363 ps2_put_keycode(s, 0x54);
364 } else {
365 ps2_put_keycode(s, 0xd4);
366 ps2_put_keycode(s, 0xb8);
367 ps2_put_keycode(s, 0x38);
368 }
369 } else if (s->modifiers & MOD_ALT_R) {
370 if (key->down) {
371 ps2_put_keycode(s, 0xe0);
372 ps2_put_keycode(s, 0xb8);
373 ps2_put_keycode(s, 0xe0);
374 ps2_put_keycode(s, 0x38);
375 ps2_put_keycode(s, 0x54);
376 } else {
377 ps2_put_keycode(s, 0xd4);
378 ps2_put_keycode(s, 0xe0);
379 ps2_put_keycode(s, 0xb8);
380 ps2_put_keycode(s, 0xe0);
381 ps2_put_keycode(s, 0x38);
382 }
8f63458f
DB
383 } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
384 MOD_SHIFT_R | MOD_CTRL_R)) {
385 if (key->down) {
386 ps2_put_keycode(s, 0xe0);
387 ps2_put_keycode(s, 0x37);
388 } else {
389 ps2_put_keycode(s, 0xe0);
390 ps2_put_keycode(s, 0xb7);
391 }
8c10e0ba 392 } else {
620775d1
DB
393 if (key->down) {
394 ps2_put_keycode(s, 0xe0);
395 ps2_put_keycode(s, 0x2a);
396 ps2_put_keycode(s, 0xe0);
397 ps2_put_keycode(s, 0x37);
398 } else {
399 ps2_put_keycode(s, 0xe0);
400 ps2_put_keycode(s, 0xb7);
401 ps2_put_keycode(s, 0xe0);
402 ps2_put_keycode(s, 0xaa);
403 }
8c10e0ba 404 }
92f4a21d
RL
405 } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2)
406 && !key->down) {
407 /* Ignore release for these keys */
57d5c005 408 } else {
545e5cf8 409 if (qcode < qemu_input_map_qcode_to_atset1_len) {
ab8f9d49 410 keycode = qemu_input_map_qcode_to_atset1[qcode];
545e5cf8 411 }
8c10e0ba
HP
412 if (keycode) {
413 if (keycode & 0xff00) {
414 ps2_put_keycode(s, keycode >> 8);
415 }
416 if (!key->down) {
417 keycode |= 0x80;
418 }
419 ps2_put_keycode(s, keycode & 0xff);
420 } else {
ec044a80
HP
421 qemu_log_mask(LOG_UNIMP,
422 "ps2: ignoring key with qcode %d\n", qcode);
8c10e0ba 423 }
57d5c005 424 }
8c10e0ba
HP
425 } else if (s->scancode_set == 2) {
426 if (qcode == Q_KEY_CODE_PAUSE) {
29fd23a5
DB
427 if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
428 if (key->down) {
429 ps2_put_keycode(s, 0xe0);
430 ps2_put_keycode(s, 0x7e);
431 ps2_put_keycode(s, 0xe0);
432 ps2_put_keycode(s, 0xf0);
433 ps2_put_keycode(s, 0x7e);
434 }
435 } else {
436 if (key->down) {
437 ps2_put_keycode(s, 0xe1);
438 ps2_put_keycode(s, 0x14);
439 ps2_put_keycode(s, 0x77);
440 ps2_put_keycode(s, 0xe1);
441 ps2_put_keycode(s, 0xf0);
442 ps2_put_keycode(s, 0x14);
443 ps2_put_keycode(s, 0xf0);
444 ps2_put_keycode(s, 0x77);
445 }
57d5c005 446 }
8c10e0ba 447 } else if (qcode == Q_KEY_CODE_PRINT) {
620775d1
DB
448 if (s->modifiers & MOD_ALT_L) {
449 if (key->down) {
450 ps2_put_keycode(s, 0xf0);
451 ps2_put_keycode(s, 0x11);
452 ps2_put_keycode(s, 0x11);
453 ps2_put_keycode(s, 0x84);
454 } else {
455 ps2_put_keycode(s, 0xf0);
456 ps2_put_keycode(s, 0x84);
457 ps2_put_keycode(s, 0xf0);
458 ps2_put_keycode(s, 0x11);
459 ps2_put_keycode(s, 0x11);
460 }
461 } else if (s->modifiers & MOD_ALT_R) {
462 if (key->down) {
463 ps2_put_keycode(s, 0xe0);
464 ps2_put_keycode(s, 0xf0);
465 ps2_put_keycode(s, 0x11);
466 ps2_put_keycode(s, 0xe0);
467 ps2_put_keycode(s, 0x11);
468 ps2_put_keycode(s, 0x84);
469 } else {
470 ps2_put_keycode(s, 0xf0);
471 ps2_put_keycode(s, 0x84);
472 ps2_put_keycode(s, 0xe0);
473 ps2_put_keycode(s, 0xf0);
474 ps2_put_keycode(s, 0x11);
475 ps2_put_keycode(s, 0xe0);
476 ps2_put_keycode(s, 0x11);
477 }
8f63458f
DB
478 } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
479 MOD_SHIFT_R | MOD_CTRL_R)) {
480 if (key->down) {
481 ps2_put_keycode(s, 0xe0);
482 ps2_put_keycode(s, 0x7c);
483 } else {
484 ps2_put_keycode(s, 0xe0);
485 ps2_put_keycode(s, 0xf0);
486 ps2_put_keycode(s, 0x7c);
487 }
8c10e0ba 488 } else {
620775d1
DB
489 if (key->down) {
490 ps2_put_keycode(s, 0xe0);
491 ps2_put_keycode(s, 0x12);
492 ps2_put_keycode(s, 0xe0);
493 ps2_put_keycode(s, 0x7c);
494 } else {
495 ps2_put_keycode(s, 0xe0);
496 ps2_put_keycode(s, 0xf0);
497 ps2_put_keycode(s, 0x7c);
498 ps2_put_keycode(s, 0xe0);
499 ps2_put_keycode(s, 0xf0);
500 ps2_put_keycode(s, 0x12);
501 }
8c10e0ba 502 }
92f4a21d
RL
503 } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2) &&
504 !key->down) {
505 /* Ignore release for these keys */
8c10e0ba 506 } else {
545e5cf8 507 if (qcode < qemu_input_map_qcode_to_atset2_len) {
ab8f9d49 508 keycode = qemu_input_map_qcode_to_atset2[qcode];
545e5cf8 509 }
8c10e0ba
HP
510 if (keycode) {
511 if (keycode & 0xff00) {
512 ps2_put_keycode(s, keycode >> 8);
513 }
514 if (!key->down) {
515 ps2_put_keycode(s, 0xf0);
516 }
517 ps2_put_keycode(s, keycode & 0xff);
8c10e0ba 518 } else {
ec044a80
HP
519 qemu_log_mask(LOG_UNIMP,
520 "ps2: ignoring key with qcode %d\n", qcode);
57d5c005
HP
521 }
522 }
8c10e0ba 523 } else if (s->scancode_set == 3) {
545e5cf8 524 if (qcode < qemu_input_map_qcode_to_atset3_len) {
ab8f9d49 525 keycode = qemu_input_map_qcode_to_atset3[qcode];
545e5cf8 526 }
8c10e0ba
HP
527 if (keycode) {
528 /* FIXME: break code should be configured on a key by key basis */
529 if (!key->down) {
530 ps2_put_keycode(s, 0xf0);
531 }
532 ps2_put_keycode(s, keycode);
8c10e0ba 533 } else {
ec044a80
HP
534 qemu_log_mask(LOG_UNIMP,
535 "ps2: ignoring key with qcode %d\n", qcode);
8c10e0ba 536 }
66e6536e
GH
537 }
538}
539
8498bb8d 540uint32_t ps2_read_data(PS2State *s)
0e43e99c 541{
0e43e99c
FB
542 PS2Queue *q;
543 int val, index;
3b46e624 544
8498bb8d 545 trace_ps2_read_data(s);
0e43e99c
FB
546 q = &s->queue;
547 if (q->count == 0) {
545e5cf8
MCA
548 /*
549 * NOTE: if no data left, we return the last keyboard one
550 * (needed for EMM386)
551 */
0e43e99c
FB
552 /* XXX: need a timer to do things correctly */
553 index = q->rptr - 1;
47db2432
VR
554 if (index < 0) {
555 index = PS2_BUFFER_SIZE - 1;
556 }
0e43e99c
FB
557 val = q->data[index];
558 } else {
559 val = q->data[q->rptr];
47db2432 560 if (++q->rptr == PS2_BUFFER_SIZE) {
0e43e99c 561 q->rptr = 0;
47db2432 562 }
0e43e99c 563 q->count--;
9e24b2dd
VR
564 if (q->rptr == q->cwptr) {
565 /* command reply queue is empty */
566 q->cwptr = -1;
567 }
0e43e99c 568 /* reading deasserts IRQ */
5cb6e556 569 ps2_lower_irq(s);
0e43e99c 570 /* reassert IRQs if data left */
cec32524 571 if (q->count) {
892e9bbe 572 ps2_raise_irq(s);
cec32524 573 }
0e43e99c
FB
574 }
575 return val;
576}
577
7f540ab5
CF
578static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
579{
5edab03d 580 trace_ps2_set_ledstate(s, ledstate);
7f540ab5
CF
581 s->ledstate = ledstate;
582 kbd_put_ledstate(ledstate);
583}
584
0e43e99c
FB
585static void ps2_reset_keyboard(PS2KbdState *s)
586{
8f84e53c
MCA
587 PS2State *ps2 = PS2_DEVICE(s);
588
5edab03d 589 trace_ps2_reset_keyboard(s);
0e43e99c 590 s->scan_enabled = 1;
e7d93956 591 s->scancode_set = 2;
8f84e53c 592 ps2_reset_queue(ps2);
7f540ab5 593 ps2_set_ledstate(s, 0);
0e43e99c
FB
594}
595
54334e73 596void ps2_write_keyboard(PS2KbdState *s, int val)
0e43e99c 597{
8f84e53c 598 PS2State *ps2 = PS2_DEVICE(s);
0e43e99c 599
54334e73 600 trace_ps2_write_keyboard(s, val);
8f84e53c
MCA
601 ps2_cqueue_reset(ps2);
602 switch (ps2->write_cmd) {
0e43e99c
FB
603 default:
604 case -1:
545e5cf8 605 switch (val) {
0e43e99c 606 case 0x00:
8f84e53c 607 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
0e43e99c
FB
608 break;
609 case 0x05:
8f84e53c 610 ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
0e43e99c
FB
611 break;
612 case KBD_CMD_GET_ID:
e7d93956 613 /* We emulate a MF2 AT keyboard here */
8f84e53c 614 ps2_cqueue_3(ps2, KBD_REPLY_ACK, KBD_REPLY_ID,
545e5cf8 615 s->translate ? 0x41 : 0x83);
0e43e99c
FB
616 break;
617 case KBD_CMD_ECHO:
8f84e53c 618 ps2_cqueue_1(ps2, KBD_CMD_ECHO);
0e43e99c
FB
619 break;
620 case KBD_CMD_ENABLE:
621 s->scan_enabled = 1;
8f84e53c 622 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
0e43e99c 623 break;
e7d93956 624 case KBD_CMD_SCANCODE:
0e43e99c
FB
625 case KBD_CMD_SET_LEDS:
626 case KBD_CMD_SET_RATE:
c56b6209 627 case KBD_CMD_SET_MAKE_BREAK:
8f84e53c
MCA
628 ps2->write_cmd = val;
629 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
0e43e99c
FB
630 break;
631 case KBD_CMD_RESET_DISABLE:
632 ps2_reset_keyboard(s);
633 s->scan_enabled = 0;
8f84e53c 634 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
0e43e99c
FB
635 break;
636 case KBD_CMD_RESET_ENABLE:
637 ps2_reset_keyboard(s);
638 s->scan_enabled = 1;
8f84e53c 639 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
0e43e99c
FB
640 break;
641 case KBD_CMD_RESET:
642 ps2_reset_keyboard(s);
8f84e53c 643 ps2_cqueue_2(ps2,
545e5cf8
MCA
644 KBD_REPLY_ACK,
645 KBD_REPLY_POR);
0e43e99c 646 break;
c56b6209 647 case KBD_CMD_SET_TYPEMATIC:
8f84e53c 648 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
c56b6209 649 break;
0e43e99c 650 default:
8f84e53c 651 ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
0e43e99c
FB
652 break;
653 }
654 break;
c56b6209 655 case KBD_CMD_SET_MAKE_BREAK:
8f84e53c
MCA
656 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
657 ps2->write_cmd = -1;
c56b6209 658 break;
e7d93956
AJ
659 case KBD_CMD_SCANCODE:
660 if (val == 0) {
8f84e53c 661 ps2_cqueue_2(ps2, KBD_REPLY_ACK, s->translate ?
9e24b2dd 662 translate_table[s->scancode_set] : s->scancode_set);
4df23b64
HP
663 } else if (val >= 1 && val <= 3) {
664 s->scancode_set = val;
8f84e53c 665 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
4df23b64 666 } else {
8f84e53c 667 ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
e7d93956 668 }
8f84e53c 669 ps2->write_cmd = -1;
e7d93956 670 break;
0e43e99c 671 case KBD_CMD_SET_LEDS:
7f540ab5 672 ps2_set_ledstate(s, val);
8f84e53c
MCA
673 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
674 ps2->write_cmd = -1;
0e43e99c
FB
675 break;
676 case KBD_CMD_SET_RATE:
8f84e53c
MCA
677 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
678 ps2->write_cmd = -1;
0e43e99c
FB
679 break;
680 }
681}
682
545e5cf8
MCA
683/*
684 * Set the scancode translation mode.
685 * 0 = raw scancodes.
686 * 1 = translated scancodes (used by qemu internally).
687 */
f94f5d71 688
54334e73 689void ps2_keyboard_set_translation(PS2KbdState *s, int mode)
f94f5d71 690{
54334e73 691 trace_ps2_keyboard_set_translation(s, mode);
f94f5d71
PB
692 s->translate = mode;
693}
694
7abe7eb2 695static int ps2_mouse_send_packet(PS2MouseState *s)
0e43e99c 696{
2d135409 697 PS2State *ps2 = PS2_DEVICE(s);
76968101
VR
698 /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */
699 const int needed = s->mouse_type ? 4 : 3;
0e43e99c 700 unsigned int b;
64ebbb7d 701 int dx1, dy1, dz1, dw1;
0e43e99c 702
2d135409 703 if (PS2_QUEUE_SIZE - ps2->queue.count < needed) {
7abe7eb2
GM
704 return 0;
705 }
706
0e43e99c
FB
707 dx1 = s->mouse_dx;
708 dy1 = s->mouse_dy;
709 dz1 = s->mouse_dz;
64ebbb7d 710 dw1 = s->mouse_dw;
0e43e99c 711 /* XXX: increase range to 8 bits ? */
545e5cf8 712 if (dx1 > 127) {
0e43e99c 713 dx1 = 127;
545e5cf8 714 } else if (dx1 < -127) {
0e43e99c 715 dx1 = -127;
545e5cf8
MCA
716 }
717 if (dy1 > 127) {
0e43e99c 718 dy1 = 127;
545e5cf8 719 } else if (dy1 < -127) {
0e43e99c 720 dy1 = -127;
545e5cf8 721 }
0e43e99c 722 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
2d135409
MCA
723 ps2_queue_noirq(ps2, b);
724 ps2_queue_noirq(ps2, dx1 & 0xff);
725 ps2_queue_noirq(ps2, dy1 & 0xff);
0e43e99c 726 /* extra byte for IMPS/2 or IMEX */
545e5cf8 727 switch (s->mouse_type) {
0e43e99c 728 default:
64ebbb7d
DP
729 /* Just ignore the wheels if not supported */
730 s->mouse_dz = 0;
731 s->mouse_dw = 0;
0e43e99c
FB
732 break;
733 case 3:
545e5cf8 734 if (dz1 > 127) {
0e43e99c 735 dz1 = 127;
545e5cf8
MCA
736 } else if (dz1 < -127) {
737 dz1 = -127;
738 }
2d135409 739 ps2_queue_noirq(ps2, dz1 & 0xff);
64ebbb7d
DP
740 s->mouse_dz -= dz1;
741 s->mouse_dw = 0;
0e43e99c
FB
742 break;
743 case 4:
64ebbb7d
DP
744 /*
745 * This matches what the Linux kernel expects for exps/2 in
746 * drivers/input/mouse/psmouse-base.c. Note, if you happen to
747 * press/release the 4th or 5th buttons at the same moment as a
748 * horizontal wheel scroll, those button presses will get lost. I'm not
749 * sure what to do about that, since by this point we don't know
750 * whether those buttons actually changed state.
751 */
752 if (dw1 != 0) {
753 if (dw1 > 31) {
754 dw1 = 31;
755 } else if (dw1 < -31) {
756 dw1 = -31;
757 }
758
759 /*
760 * linux kernel expects first 6 bits to represent the value
761 * for horizontal scroll
762 */
763 b = (dw1 & 0x3f) | 0x40;
764 s->mouse_dw -= dw1;
765 } else {
766 if (dz1 > 7) {
767 dz1 = 7;
768 } else if (dz1 < -7) {
769 dz1 = -7;
770 }
771
772 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
773 s->mouse_dz -= dz1;
774 }
2d135409 775 ps2_queue_noirq(ps2, b);
0e43e99c
FB
776 break;
777 }
778
2d135409 779 ps2_raise_irq(ps2);
7abe7eb2 780
5edab03d 781 trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
0e43e99c
FB
782 /* update deltas */
783 s->mouse_dx -= dx1;
784 s->mouse_dy -= dy1;
7abe7eb2
GM
785
786 return 1;
0e43e99c
FB
787}
788
2a766d29
GH
789static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
790 InputEvent *evt)
0e43e99c 791{
7fb1cf16 792 static const int bmap[INPUT_BUTTON__MAX] = {
8b0caab0
FL
793 [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT,
794 [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
795 [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT,
796 [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE,
797 [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA,
2a766d29
GH
798 };
799 PS2MouseState *s = (PS2MouseState *)dev;
b5a1b443
EB
800 InputMoveEvent *move;
801 InputBtnEvent *btn;
0e43e99c
FB
802
803 /* check if deltas are recorded when disabled */
545e5cf8 804 if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
0e43e99c 805 return;
545e5cf8 806 }
0e43e99c 807
568c73a4 808 switch (evt->type) {
2a766d29 809 case INPUT_EVENT_KIND_REL:
32bafa8f 810 move = evt->u.rel.data;
b5a1b443
EB
811 if (move->axis == INPUT_AXIS_X) {
812 s->mouse_dx += move->value;
813 } else if (move->axis == INPUT_AXIS_Y) {
814 s->mouse_dy -= move->value;
2a766d29
GH
815 }
816 break;
3b46e624 817
2a766d29 818 case INPUT_EVENT_KIND_BTN:
32bafa8f 819 btn = evt->u.btn.data;
b5a1b443
EB
820 if (btn->down) {
821 s->mouse_buttons |= bmap[btn->button];
822 if (btn->button == INPUT_BUTTON_WHEEL_UP) {
2a766d29 823 s->mouse_dz--;
b5a1b443 824 } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
2a766d29
GH
825 s->mouse_dz++;
826 }
64ebbb7d
DP
827
828 if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) {
829 s->mouse_dw--;
830 } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) {
831 s->mouse_dw++;
832 }
2a766d29 833 } else {
b5a1b443 834 s->mouse_buttons &= ~bmap[btn->button];
2a766d29
GH
835 }
836 break;
837
838 default:
839 /* keep gcc happy */
840 break;
fd214d18 841 }
2a766d29 842}
fd214d18 843
2a766d29
GH
844static void ps2_mouse_sync(DeviceState *dev)
845{
846 PS2MouseState *s = (PS2MouseState *)dev;
847
143c04c7
GM
848 /* do not sync while disabled to prevent stream corruption */
849 if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
850 return;
851 }
852
2a766d29 853 if (s->mouse_buttons) {
fb064112 854 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
2a766d29 855 }
2858ab09 856 if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
545e5cf8
MCA
857 /*
858 * if not remote, send event. Multiple events are sent if
859 * too big deltas
860 */
7abe7eb2 861 while (ps2_mouse_send_packet(s)) {
64ebbb7d
DP
862 if (s->mouse_dx == 0 && s->mouse_dy == 0
863 && s->mouse_dz == 0 && s->mouse_dw == 0) {
0e43e99c 864 break;
64ebbb7d 865 }
0e43e99c
FB
866 }
867 }
868}
869
54334e73 870void ps2_mouse_fake_event(PS2MouseState *s)
548df2ac 871{
54334e73 872 trace_ps2_mouse_fake_event(s);
2a766d29 873 s->mouse_dx++;
54334e73 874 ps2_mouse_sync(DEVICE(s));
548df2ac
TS
875}
876
54334e73 877void ps2_write_mouse(PS2MouseState *s, int val)
0e43e99c 878{
2d135409 879 PS2State *ps2 = PS2_DEVICE(s);
5edab03d 880
54334e73 881 trace_ps2_write_mouse(s, val);
2d135409 882 switch (ps2->write_cmd) {
0e43e99c
FB
883 default:
884 case -1:
885 /* mouse command */
886 if (s->mouse_wrap) {
887 if (val == AUX_RESET_WRAP) {
888 s->mouse_wrap = 0;
2d135409 889 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
890 return;
891 } else if (val != AUX_RESET) {
2d135409 892 ps2_queue(ps2, val);
0e43e99c
FB
893 return;
894 }
895 }
545e5cf8 896 switch (val) {
0e43e99c
FB
897 case AUX_SET_SCALE11:
898 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
2d135409 899 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
900 break;
901 case AUX_SET_SCALE21:
902 s->mouse_status |= MOUSE_STATUS_SCALE21;
2d135409 903 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
904 break;
905 case AUX_SET_STREAM:
906 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
2d135409 907 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
908 break;
909 case AUX_SET_WRAP:
910 s->mouse_wrap = 1;
2d135409 911 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
912 break;
913 case AUX_SET_REMOTE:
914 s->mouse_status |= MOUSE_STATUS_REMOTE;
2d135409 915 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
916 break;
917 case AUX_GET_TYPE:
2d135409 918 ps2_queue_2(ps2,
7abe7eb2
GM
919 AUX_ACK,
920 s->mouse_type);
0e43e99c
FB
921 break;
922 case AUX_SET_RES:
923 case AUX_SET_SAMPLE:
2d135409
MCA
924 ps2->write_cmd = val;
925 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
926 break;
927 case AUX_GET_SCALE:
2d135409 928 ps2_queue_4(ps2,
7abe7eb2
GM
929 AUX_ACK,
930 s->mouse_status,
931 s->mouse_resolution,
932 s->mouse_sample_rate);
0e43e99c
FB
933 break;
934 case AUX_POLL:
2d135409 935 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
936 ps2_mouse_send_packet(s);
937 break;
938 case AUX_ENABLE_DEV:
939 s->mouse_status |= MOUSE_STATUS_ENABLED;
2d135409 940 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
941 break;
942 case AUX_DISABLE_DEV:
943 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
2d135409 944 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
945 break;
946 case AUX_SET_DEFAULT:
947 s->mouse_sample_rate = 100;
948 s->mouse_resolution = 2;
949 s->mouse_status = 0;
2d135409 950 ps2_queue(ps2, AUX_ACK);
0e43e99c
FB
951 break;
952 case AUX_RESET:
953 s->mouse_sample_rate = 100;
954 s->mouse_resolution = 2;
955 s->mouse_status = 0;
956 s->mouse_type = 0;
2d135409
MCA
957 ps2_reset_queue(ps2);
958 ps2_queue_3(ps2,
7abe7eb2
GM
959 AUX_ACK,
960 0xaa,
961 s->mouse_type);
0e43e99c
FB
962 break;
963 default:
964 break;
965 }
966 break;
967 case AUX_SET_SAMPLE:
968 s->mouse_sample_rate = val;
969 /* detect IMPS/2 or IMEX */
545e5cf8 970 switch (s->mouse_detect_state) {
0e43e99c
FB
971 default:
972 case 0:
545e5cf8 973 if (val == 200) {
0e43e99c 974 s->mouse_detect_state = 1;
545e5cf8 975 }
0e43e99c
FB
976 break;
977 case 1:
545e5cf8 978 if (val == 100) {
0e43e99c 979 s->mouse_detect_state = 2;
545e5cf8 980 } else if (val == 200) {
0e43e99c 981 s->mouse_detect_state = 3;
545e5cf8 982 } else {
0e43e99c 983 s->mouse_detect_state = 0;
545e5cf8 984 }
0e43e99c
FB
985 break;
986 case 2:
545e5cf8 987 if (val == 80) {
0e43e99c 988 s->mouse_type = 3; /* IMPS/2 */
545e5cf8 989 }
0e43e99c
FB
990 s->mouse_detect_state = 0;
991 break;
992 case 3:
545e5cf8 993 if (val == 80) {
0e43e99c 994 s->mouse_type = 4; /* IMEX */
545e5cf8 995 }
0e43e99c
FB
996 s->mouse_detect_state = 0;
997 break;
998 }
2d135409
MCA
999 ps2_queue(ps2, AUX_ACK);
1000 ps2->write_cmd = -1;
0e43e99c
FB
1001 break;
1002 case AUX_SET_RES:
1003 s->mouse_resolution = val;
2d135409
MCA
1004 ps2_queue(ps2, AUX_ACK);
1005 ps2->write_cmd = -1;
0e43e99c
FB
1006 break;
1007 }
1008}
1009
2bb3f930 1010static void ps2_reset_hold(Object *obj)
0e43e99c 1011{
2bb3f930 1012 PS2State *s = PS2_DEVICE(obj);
108cb22e 1013
0e43e99c 1014 s->write_cmd = -1;
954ee55b 1015 ps2_reset_queue(s);
2bb3f930
PM
1016}
1017
1018static void ps2_reset_exit(Object *obj)
1019{
1020 PS2State *s = PS2_DEVICE(obj);
1021
5cb6e556 1022 ps2_lower_irq(s);
0e43e99c
FB
1023}
1024
2858ab09
GA
1025static void ps2_common_post_load(PS2State *s)
1026{
1027 PS2Queue *q = &s->queue;
4e9bddcb 1028 int ccount = 0;
2858ab09 1029
4e9bddcb
VR
1030 /* limit the number of queued command replies to PS2_QUEUE_HEADROOM */
1031 if (q->cwptr != -1) {
1032 ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
1033 if (ccount > PS2_QUEUE_HEADROOM) {
1034 ccount = PS2_QUEUE_HEADROOM;
1035 }
1036 }
1037
1038 /* limit the scancode queue size to PS2_QUEUE_SIZE */
1039 if (q->count < ccount) {
1040 q->count = ccount;
1041 } else if (q->count > ccount + PS2_QUEUE_SIZE) {
1042 q->count = ccount + PS2_QUEUE_SIZE;
2858ab09 1043 }
802cbcb7 1044
4e9bddcb 1045 /* sanitize rptr and recalculate wptr and cwptr */
47db2432
VR
1046 q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1);
1047 q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1);
4e9bddcb 1048 q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1;
2858ab09
GA
1049}
1050
fc2fc3c1 1051static void ps2_kbd_reset_hold(Object *obj)
ef74679a 1052{
fc2fc3c1
PM
1053 PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
1054 PS2KbdState *s = PS2_KBD_DEVICE(obj);
108cb22e
MCA
1055
1056 trace_ps2_kbd_reset(s);
fc2fc3c1
PM
1057
1058 if (ps2dc->parent_phases.hold) {
1059 ps2dc->parent_phases.hold(obj);
1060 }
ef74679a 1061
d2e550a8 1062 s->scan_enabled = 1;
ef74679a 1063 s->translate = 0;
089adafd 1064 s->scancode_set = 2;
620775d1 1065 s->modifiers = 0;
ef74679a
DS
1066}
1067
fc2fc3c1 1068static void ps2_mouse_reset_hold(Object *obj)
ef74679a 1069{
fc2fc3c1
PM
1070 PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
1071 PS2MouseState *s = PS2_MOUSE_DEVICE(obj);
108cb22e
MCA
1072
1073 trace_ps2_mouse_reset(s);
fc2fc3c1
PM
1074
1075 if (ps2dc->parent_phases.hold) {
1076 ps2dc->parent_phases.hold(obj);
1077 }
ef74679a 1078
ef74679a
DS
1079 s->mouse_status = 0;
1080 s->mouse_resolution = 0;
1081 s->mouse_sample_rate = 0;
1082 s->mouse_wrap = 0;
1083 s->mouse_type = 0;
1084 s->mouse_detect_state = 0;
1085 s->mouse_dx = 0;
1086 s->mouse_dy = 0;
1087 s->mouse_dz = 0;
64ebbb7d 1088 s->mouse_dw = 0;
ef74679a
DS
1089 s->mouse_buttons = 0;
1090}
1091
b31442c3
JQ
1092static const VMStateDescription vmstate_ps2_common = {
1093 .name = "PS2 Common State",
1094 .version_id = 3,
1095 .minimum_version_id = 2,
d49805ae 1096 .fields = (VMStateField[]) {
b31442c3
JQ
1097 VMSTATE_INT32(write_cmd, PS2State),
1098 VMSTATE_INT32(queue.rptr, PS2State),
1099 VMSTATE_INT32(queue.wptr, PS2State),
1100 VMSTATE_INT32(queue.count, PS2State),
1101 VMSTATE_BUFFER(queue.data, PS2State),
1102 VMSTATE_END_OF_LIST()
1103 }
1104};
0e43e99c 1105
7f540ab5
CF
1106static bool ps2_keyboard_ledstate_needed(void *opaque)
1107{
1108 PS2KbdState *s = opaque;
1109
1110 return s->ledstate != 0; /* 0 is default state */
1111}
1112
1113static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
1114{
1115 PS2KbdState *s = opaque;
1116
1117 kbd_put_ledstate(s->ledstate);
1118 return 0;
1119}
1120
1121static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
1122 .name = "ps2kbd/ledstate",
1123 .version_id = 3,
1124 .minimum_version_id = 2,
7f540ab5 1125 .post_load = ps2_kbd_ledstate_post_load,
5cd8cada 1126 .needed = ps2_keyboard_ledstate_needed,
d49805ae 1127 .fields = (VMStateField[]) {
7f540ab5
CF
1128 VMSTATE_INT32(ledstate, PS2KbdState),
1129 VMSTATE_END_OF_LIST()
1130 }
1131};
1132
57d5c005
HP
1133static bool ps2_keyboard_need_high_bit_needed(void *opaque)
1134{
1135 PS2KbdState *s = opaque;
1136 return s->need_high_bit != 0; /* 0 is the usual state */
1137}
1138
1139static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
1140 .name = "ps2kbd/need_high_bit",
1141 .version_id = 1,
1142 .minimum_version_id = 1,
1143 .needed = ps2_keyboard_need_high_bit_needed,
1144 .fields = (VMStateField[]) {
1145 VMSTATE_BOOL(need_high_bit, PS2KbdState),
1146 VMSTATE_END_OF_LIST()
1147 }
1148};
1149
4e9bddcb
VR
1150static bool ps2_keyboard_cqueue_needed(void *opaque)
1151{
1152 PS2KbdState *s = opaque;
8f84e53c 1153 PS2State *ps2 = PS2_DEVICE(s);
4e9bddcb 1154
8f84e53c 1155 return ps2->queue.cwptr != -1; /* the queue is mostly empty */
4e9bddcb
VR
1156}
1157
1158static const VMStateDescription vmstate_ps2_keyboard_cqueue = {
1159 .name = "ps2kbd/command_reply_queue",
1160 .needed = ps2_keyboard_cqueue_needed,
1161 .fields = (VMStateField[]) {
8f84e53c 1162 VMSTATE_INT32(parent_obj.queue.cwptr, PS2KbdState),
4e9bddcb
VR
1163 VMSTATE_END_OF_LIST()
1164 }
1165};
1166
545e5cf8 1167static int ps2_kbd_post_load(void *opaque, int version_id)
0e43e99c 1168{
545e5cf8 1169 PS2KbdState *s = (PS2KbdState *)opaque;
8f84e53c 1170 PS2State *ps2 = PS2_DEVICE(s);
7783e9f0 1171
545e5cf8
MCA
1172 if (version_id == 2) {
1173 s->scancode_set = 2;
1174 }
2858ab09
GA
1175
1176 ps2_common_post_load(ps2);
1177
0e43e99c
FB
1178 return 0;
1179}
1180
b31442c3
JQ
1181static const VMStateDescription vmstate_ps2_keyboard = {
1182 .name = "ps2kbd",
1183 .version_id = 3,
db596c53 1184 .minimum_version_id = 2,
db596c53 1185 .post_load = ps2_kbd_post_load,
d49805ae 1186 .fields = (VMStateField[]) {
8f84e53c
MCA
1187 VMSTATE_STRUCT(parent_obj, PS2KbdState, 0, vmstate_ps2_common,
1188 PS2State),
b31442c3
JQ
1189 VMSTATE_INT32(scan_enabled, PS2KbdState),
1190 VMSTATE_INT32(translate, PS2KbdState),
545e5cf8 1191 VMSTATE_INT32_V(scancode_set, PS2KbdState, 3),
b31442c3 1192 VMSTATE_END_OF_LIST()
7f540ab5 1193 },
545e5cf8 1194 .subsections = (const VMStateDescription * []) {
5cd8cada 1195 &vmstate_ps2_keyboard_ledstate,
57d5c005 1196 &vmstate_ps2_keyboard_need_high_bit,
4e9bddcb 1197 &vmstate_ps2_keyboard_cqueue,
5cd8cada 1198 NULL
b31442c3
JQ
1199 }
1200};
7783e9f0 1201
2858ab09
GA
1202static int ps2_mouse_post_load(void *opaque, int version_id)
1203{
1204 PS2MouseState *s = (PS2MouseState *)opaque;
2d135409 1205 PS2State *ps2 = PS2_DEVICE(s);
2858ab09
GA
1206
1207 ps2_common_post_load(ps2);
1208
1209 return 0;
1210}
1211
b31442c3
JQ
1212static const VMStateDescription vmstate_ps2_mouse = {
1213 .name = "ps2mouse",
1214 .version_id = 2,
1215 .minimum_version_id = 2,
2858ab09 1216 .post_load = ps2_mouse_post_load,
d49805ae 1217 .fields = (VMStateField[]) {
2d135409
MCA
1218 VMSTATE_STRUCT(parent_obj, PS2MouseState, 0, vmstate_ps2_common,
1219 PS2State),
b31442c3
JQ
1220 VMSTATE_UINT8(mouse_status, PS2MouseState),
1221 VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1222 VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1223 VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1224 VMSTATE_UINT8(mouse_type, PS2MouseState),
1225 VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1226 VMSTATE_INT32(mouse_dx, PS2MouseState),
1227 VMSTATE_INT32(mouse_dy, PS2MouseState),
1228 VMSTATE_INT32(mouse_dz, PS2MouseState),
1229 VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1230 VMSTATE_END_OF_LIST()
1231 }
1232};
0e43e99c 1233
66e6536e
GH
1234static QemuInputHandler ps2_keyboard_handler = {
1235 .name = "QEMU PS/2 Keyboard",
1236 .mask = INPUT_EVENT_MASK_KEY,
1237 .event = ps2_keyboard_event,
1238};
1239
ea247a0f
MCA
1240static void ps2_kbd_realize(DeviceState *dev, Error **errp)
1241{
1242 qemu_input_handler_register(dev, &ps2_keyboard_handler);
1243}
1244
2a766d29
GH
1245static QemuInputHandler ps2_mouse_handler = {
1246 .name = "QEMU PS/2 Mouse",
1247 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
1248 .event = ps2_mouse_event,
1249 .sync = ps2_mouse_sync,
1250};
1251
4a68b482
MCA
1252static void ps2_mouse_realize(DeviceState *dev, Error **errp)
1253{
1254 qemu_input_handler_register(dev, &ps2_mouse_handler);
1255}
1256
108cb22e
MCA
1257static void ps2_kbd_class_init(ObjectClass *klass, void *data)
1258{
1259 DeviceClass *dc = DEVICE_CLASS(klass);
fc2fc3c1 1260 ResettableClass *rc = RESETTABLE_CLASS(klass);
108cb22e
MCA
1261 PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass);
1262
ea247a0f 1263 dc->realize = ps2_kbd_realize;
fc2fc3c1
PM
1264 resettable_class_set_parent_phases(rc, NULL, ps2_kbd_reset_hold, NULL,
1265 &ps2dc->parent_phases);
f055f507 1266 dc->vmsd = &vmstate_ps2_keyboard;
108cb22e
MCA
1267}
1268
8f84e53c
MCA
1269static const TypeInfo ps2_kbd_info = {
1270 .name = TYPE_PS2_KBD_DEVICE,
1271 .parent = TYPE_PS2_DEVICE,
1272 .instance_size = sizeof(PS2KbdState),
108cb22e 1273 .class_init = ps2_kbd_class_init
8f84e53c
MCA
1274};
1275
108cb22e
MCA
1276static void ps2_mouse_class_init(ObjectClass *klass, void *data)
1277{
1278 DeviceClass *dc = DEVICE_CLASS(klass);
fc2fc3c1 1279 ResettableClass *rc = RESETTABLE_CLASS(klass);
108cb22e
MCA
1280 PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass);
1281
4a68b482 1282 dc->realize = ps2_mouse_realize;
fc2fc3c1
PM
1283 resettable_class_set_parent_phases(rc, NULL, ps2_mouse_reset_hold, NULL,
1284 &ps2dc->parent_phases);
97259e70 1285 dc->vmsd = &vmstate_ps2_mouse;
108cb22e
MCA
1286}
1287
2d135409
MCA
1288static const TypeInfo ps2_mouse_info = {
1289 .name = TYPE_PS2_MOUSE_DEVICE,
1290 .parent = TYPE_PS2_DEVICE,
1291 .instance_size = sizeof(PS2MouseState),
108cb22e 1292 .class_init = ps2_mouse_class_init
2d135409
MCA
1293};
1294
6beb79e1
MCA
1295static void ps2_init(Object *obj)
1296{
1297 PS2State *s = PS2_DEVICE(obj);
1298
1299 qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
1300}
1301
64bbdd13
MCA
1302static void ps2_class_init(ObjectClass *klass, void *data)
1303{
1304 DeviceClass *dc = DEVICE_CLASS(klass);
2bb3f930 1305 ResettableClass *rc = RESETTABLE_CLASS(klass);
64bbdd13 1306
2bb3f930
PM
1307 rc->phases.hold = ps2_reset_hold;
1308 rc->phases.exit = ps2_reset_exit;
64bbdd13
MCA
1309 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1310}
1311
1312static const TypeInfo ps2_info = {
1313 .name = TYPE_PS2_DEVICE,
1314 .parent = TYPE_SYS_BUS_DEVICE,
6beb79e1 1315 .instance_init = ps2_init,
64bbdd13
MCA
1316 .instance_size = sizeof(PS2State),
1317 .class_init = ps2_class_init,
494145b2 1318 .class_size = sizeof(PS2DeviceClass),
64bbdd13
MCA
1319 .abstract = true
1320};
1321
1322static void ps2_register_types(void)
1323{
1324 type_register_static(&ps2_info);
8f84e53c 1325 type_register_static(&ps2_kbd_info);
2d135409 1326 type_register_static(&ps2_mouse_info);
64bbdd13
MCA
1327}
1328
1329type_init(ps2_register_types)