]>
git.proxmox.com Git - mirror_qemu.git/blob - hw/ps2.c
2 * QEMU PS/2 keyboard/mouse emulation
4 * Copyright (c) 2003 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
26 /* debug PC keyboard */
29 /* debug PC keyboard : only mouse */
32 /* Keyboard Commands */
33 #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
34 #define KBD_CMD_ECHO 0xEE
35 #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
36 #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
37 #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
38 #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
39 #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
40 #define KBD_CMD_RESET 0xFF /* Reset */
42 /* Keyboard Replies */
43 #define KBD_REPLY_POR 0xAA /* Power on reset */
44 #define KBD_REPLY_ACK 0xFA /* Command ACK */
45 #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
48 #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
49 #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
50 #define AUX_SET_RES 0xE8 /* Set resolution */
51 #define AUX_GET_SCALE 0xE9 /* Get scaling factor */
52 #define AUX_SET_STREAM 0xEA /* Set stream mode */
53 #define AUX_POLL 0xEB /* Poll */
54 #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
55 #define AUX_SET_WRAP 0xEE /* Set wrap mode */
56 #define AUX_SET_REMOTE 0xF0 /* Set remote mode */
57 #define AUX_GET_TYPE 0xF2 /* Get type */
58 #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
59 #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
60 #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
61 #define AUX_SET_DEFAULT 0xF6
62 #define AUX_RESET 0xFF /* Reset aux device */
63 #define AUX_ACK 0xFA /* Command byte ACK. */
65 #define MOUSE_STATUS_REMOTE 0x40
66 #define MOUSE_STATUS_ENABLED 0x20
67 #define MOUSE_STATUS_SCALE21 0x10
69 #define PS2_QUEUE_SIZE 256
72 uint8_t data
[PS2_QUEUE_SIZE
];
73 int rptr
, wptr
, count
;
79 void (*update_irq
)(void *, int);
91 uint8_t mouse_resolution
;
92 uint8_t mouse_sample_rate
;
94 uint8_t mouse_type
; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
95 uint8_t mouse_detect_state
;
96 int mouse_dx
; /* current values, needed for 'poll' mode */
99 uint8_t mouse_buttons
;
102 void ps2_queue(void *opaque
, int b
)
104 PS2State
*s
= (PS2State
*)opaque
;
105 PS2Queue
*q
= &s
->queue
;
107 if (q
->count
>= PS2_QUEUE_SIZE
)
109 q
->data
[q
->wptr
] = b
;
110 if (++q
->wptr
== PS2_QUEUE_SIZE
)
113 s
->update_irq(s
->update_arg
, 1);
116 static void ps2_put_keycode(void *opaque
, int keycode
)
118 PS2MouseState
*s
= opaque
;
119 ps2_queue(&s
->common
, keycode
);
122 uint32_t ps2_read_data(void *opaque
)
124 PS2State
*s
= (PS2State
*)opaque
;
130 /* NOTE: if no data left, we return the last keyboard one
131 (needed for EMM386) */
132 /* XXX: need a timer to do things correctly */
135 index
= PS2_QUEUE_SIZE
- 1;
136 val
= q
->data
[index
];
138 val
= q
->data
[q
->rptr
];
139 if (++q
->rptr
== PS2_QUEUE_SIZE
)
142 /* reading deasserts IRQ */
143 s
->update_irq(s
->update_arg
, 0);
144 /* reassert IRQs if data left */
145 s
->update_irq(s
->update_arg
, q
->count
!= 0);
150 static void ps2_reset_keyboard(PS2KbdState
*s
)
155 void ps2_write_keyboard(void *opaque
, int val
)
157 PS2KbdState
*s
= (PS2KbdState
*)opaque
;
159 switch(s
->common
.write_cmd
) {
164 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
167 ps2_queue(&s
->common
, KBD_REPLY_RESEND
);
170 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
171 ps2_queue(&s
->common
, 0xab);
172 ps2_queue(&s
->common
, 0x83);
175 ps2_queue(&s
->common
, KBD_CMD_ECHO
);
179 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
181 case KBD_CMD_SET_LEDS
:
182 case KBD_CMD_SET_RATE
:
183 s
->common
.write_cmd
= val
;
184 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
186 case KBD_CMD_RESET_DISABLE
:
187 ps2_reset_keyboard(s
);
189 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
191 case KBD_CMD_RESET_ENABLE
:
192 ps2_reset_keyboard(s
);
194 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
197 ps2_reset_keyboard(s
);
198 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
199 ps2_queue(&s
->common
, KBD_REPLY_POR
);
202 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
206 case KBD_CMD_SET_LEDS
:
207 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
208 s
->common
.write_cmd
= -1;
210 case KBD_CMD_SET_RATE
:
211 ps2_queue(&s
->common
, KBD_REPLY_ACK
);
212 s
->common
.write_cmd
= -1;
217 static void ps2_mouse_send_packet(PS2MouseState
*s
)
225 /* XXX: increase range to 8 bits ? */
234 b
= 0x08 | ((dx1
< 0) << 4) | ((dy1
< 0) << 5) | (s
->mouse_buttons
& 0x07);
235 ps2_queue(&s
->common
, b
);
236 ps2_queue(&s
->common
, dx1
& 0xff);
237 ps2_queue(&s
->common
, dy1
& 0xff);
238 /* extra byte for IMPS/2 or IMEX */
239 switch(s
->mouse_type
) {
247 ps2_queue(&s
->common
, dz1
& 0xff);
254 b
= (dz1
& 0x0f) | ((s
->mouse_buttons
& 0x18) << 1);
255 ps2_queue(&s
->common
, b
);
265 static void ps2_mouse_event(void *opaque
,
266 int dx
, int dy
, int dz
, int buttons_state
)
268 PS2MouseState
*s
= opaque
;
270 /* check if deltas are recorded when disabled */
271 if (!(s
->mouse_status
& MOUSE_STATUS_ENABLED
))
277 /* XXX: SDL sometimes generates nul events: we delete them */
278 if (s
->mouse_dx
== 0 && s
->mouse_dy
== 0 && s
->mouse_dz
== 0 &&
279 s
->mouse_buttons
== buttons_state
)
281 s
->mouse_buttons
= buttons_state
;
283 if (!(s
->mouse_status
& MOUSE_STATUS_REMOTE
) &&
284 (s
->common
.queue
.count
< (PS2_QUEUE_SIZE
- 16))) {
286 /* if not remote, send event. Multiple events are sent if
288 ps2_mouse_send_packet(s
);
289 if (s
->mouse_dx
== 0 && s
->mouse_dy
== 0 && s
->mouse_dz
== 0)
295 void ps2_write_mouse(void *opaque
, int val
)
297 PS2MouseState
*s
= (PS2MouseState
*)opaque
;
299 printf("kbd: write mouse 0x%02x\n", val
);
301 switch(s
->common
.write_cmd
) {
306 if (val
== AUX_RESET_WRAP
) {
308 ps2_queue(&s
->common
, AUX_ACK
);
310 } else if (val
!= AUX_RESET
) {
311 ps2_queue(&s
->common
, val
);
316 case AUX_SET_SCALE11
:
317 s
->mouse_status
&= ~MOUSE_STATUS_SCALE21
;
318 ps2_queue(&s
->common
, AUX_ACK
);
320 case AUX_SET_SCALE21
:
321 s
->mouse_status
|= MOUSE_STATUS_SCALE21
;
322 ps2_queue(&s
->common
, AUX_ACK
);
325 s
->mouse_status
&= ~MOUSE_STATUS_REMOTE
;
326 ps2_queue(&s
->common
, AUX_ACK
);
330 ps2_queue(&s
->common
, AUX_ACK
);
333 s
->mouse_status
|= MOUSE_STATUS_REMOTE
;
334 ps2_queue(&s
->common
, AUX_ACK
);
337 ps2_queue(&s
->common
, AUX_ACK
);
338 ps2_queue(&s
->common
, s
->mouse_type
);
342 s
->common
.write_cmd
= val
;
343 ps2_queue(&s
->common
, AUX_ACK
);
346 ps2_queue(&s
->common
, AUX_ACK
);
347 ps2_queue(&s
->common
, s
->mouse_status
);
348 ps2_queue(&s
->common
, s
->mouse_resolution
);
349 ps2_queue(&s
->common
, s
->mouse_sample_rate
);
352 ps2_queue(&s
->common
, AUX_ACK
);
353 ps2_mouse_send_packet(s
);
356 s
->mouse_status
|= MOUSE_STATUS_ENABLED
;
357 ps2_queue(&s
->common
, AUX_ACK
);
359 case AUX_DISABLE_DEV
:
360 s
->mouse_status
&= ~MOUSE_STATUS_ENABLED
;
361 ps2_queue(&s
->common
, AUX_ACK
);
363 case AUX_SET_DEFAULT
:
364 s
->mouse_sample_rate
= 100;
365 s
->mouse_resolution
= 2;
367 ps2_queue(&s
->common
, AUX_ACK
);
370 s
->mouse_sample_rate
= 100;
371 s
->mouse_resolution
= 2;
374 ps2_queue(&s
->common
, AUX_ACK
);
375 ps2_queue(&s
->common
, 0xaa);
376 ps2_queue(&s
->common
, s
->mouse_type
);
383 s
->mouse_sample_rate
= val
;
384 /* detect IMPS/2 or IMEX */
385 switch(s
->mouse_detect_state
) {
389 s
->mouse_detect_state
= 1;
393 s
->mouse_detect_state
= 2;
395 s
->mouse_detect_state
= 3;
397 s
->mouse_detect_state
= 0;
401 s
->mouse_type
= 3; /* IMPS/2 */
402 s
->mouse_detect_state
= 0;
406 s
->mouse_type
= 4; /* IMEX */
407 s
->mouse_detect_state
= 0;
410 ps2_queue(&s
->common
, AUX_ACK
);
411 s
->common
.write_cmd
= -1;
414 s
->mouse_resolution
= val
;
415 ps2_queue(&s
->common
, AUX_ACK
);
416 s
->common
.write_cmd
= -1;
421 static void ps2_reset(void *opaque
)
423 PS2State
*s
= (PS2State
*)opaque
;
432 static void ps2_kbd_save(QEMUFile
* f
, void* opaque
)
434 PS2KbdState
*s
= (PS2KbdState
*)opaque
;
436 qemu_put_be32s(f
, &s
->common
.write_cmd
);
437 qemu_put_be32s(f
, &s
->scan_enabled
);
440 static void ps2_mouse_save(QEMUFile
* f
, void* opaque
)
442 PS2MouseState
*s
= (PS2MouseState
*)opaque
;
444 qemu_put_be32s(f
, &s
->common
.write_cmd
);
445 qemu_put_8s(f
, &s
->mouse_status
);
446 qemu_put_8s(f
, &s
->mouse_resolution
);
447 qemu_put_8s(f
, &s
->mouse_sample_rate
);
448 qemu_put_8s(f
, &s
->mouse_wrap
);
449 qemu_put_8s(f
, &s
->mouse_type
);
450 qemu_put_8s(f
, &s
->mouse_detect_state
);
451 qemu_put_be32s(f
, &s
->mouse_dx
);
452 qemu_put_be32s(f
, &s
->mouse_dy
);
453 qemu_put_be32s(f
, &s
->mouse_dz
);
454 qemu_put_8s(f
, &s
->mouse_buttons
);
457 static int ps2_kbd_load(QEMUFile
* f
, void* opaque
, int version_id
)
459 PS2KbdState
*s
= (PS2KbdState
*)opaque
;
463 qemu_get_be32s(f
, &s
->common
.write_cmd
);
464 qemu_get_be32s(f
, &s
->scan_enabled
);
468 static int ps2_mouse_load(QEMUFile
* f
, void* opaque
, int version_id
)
470 PS2MouseState
*s
= (PS2MouseState
*)opaque
;
474 qemu_get_be32s(f
, &s
->common
.write_cmd
);
475 qemu_get_8s(f
, &s
->mouse_status
);
476 qemu_get_8s(f
, &s
->mouse_resolution
);
477 qemu_get_8s(f
, &s
->mouse_sample_rate
);
478 qemu_get_8s(f
, &s
->mouse_wrap
);
479 qemu_get_8s(f
, &s
->mouse_type
);
480 qemu_get_8s(f
, &s
->mouse_detect_state
);
481 qemu_get_be32s(f
, &s
->mouse_dx
);
482 qemu_get_be32s(f
, &s
->mouse_dy
);
483 qemu_get_be32s(f
, &s
->mouse_dz
);
484 qemu_get_8s(f
, &s
->mouse_buttons
);
488 void *ps2_kbd_init(void (*update_irq
)(void *, int), void *update_arg
)
490 PS2KbdState
*s
= (PS2KbdState
*)qemu_mallocz(sizeof(PS2KbdState
));
492 s
->common
.update_irq
= update_irq
;
493 s
->common
.update_arg
= update_arg
;
494 ps2_reset(&s
->common
);
495 register_savevm("ps2kbd", 0, 1, ps2_kbd_save
, ps2_kbd_load
, s
);
496 qemu_add_kbd_event_handler(ps2_put_keycode
, s
);
497 qemu_register_reset(ps2_reset
, &s
->common
);
501 void *ps2_mouse_init(void (*update_irq
)(void *, int), void *update_arg
)
503 PS2MouseState
*s
= (PS2MouseState
*)qemu_mallocz(sizeof(PS2MouseState
));
505 s
->common
.update_irq
= update_irq
;
506 s
->common
.update_arg
= update_arg
;
507 ps2_reset(&s
->common
);
508 register_savevm("ps2mouse", 0, 1, ps2_mouse_save
, ps2_mouse_load
, s
);
509 qemu_add_mouse_event_handler(ps2_mouse_event
, s
);
510 qemu_register_reset(ps2_reset
, &s
->common
);