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