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