root / hw / ps2.c @ 83fa1010
History | View | Annotate | Download (16.9 kB)
1 | 0e43e99c | bellard | /*
|
---|---|---|---|
2 | 0e43e99c | bellard | * QEMU PS/2 keyboard/mouse emulation
|
3 | 5fafdf24 | ths | *
|
4 | 0e43e99c | bellard | * Copyright (c) 2003 Fabrice Bellard
|
5 | 5fafdf24 | ths | *
|
6 | 0e43e99c | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 0e43e99c | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | 0e43e99c | bellard | * in the Software without restriction, including without limitation the rights
|
9 | 0e43e99c | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 0e43e99c | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | 0e43e99c | bellard | * furnished to do so, subject to the following conditions:
|
12 | 0e43e99c | bellard | *
|
13 | 0e43e99c | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | 0e43e99c | bellard | * all copies or substantial portions of the Software.
|
15 | 0e43e99c | bellard | *
|
16 | 0e43e99c | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 0e43e99c | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 0e43e99c | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 0e43e99c | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 0e43e99c | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 0e43e99c | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 0e43e99c | bellard | * THE SOFTWARE.
|
23 | 0e43e99c | bellard | */
|
24 | 0e43e99c | bellard | #include "vl.h" |
25 | 0e43e99c | bellard | |
26 | 0e43e99c | bellard | /* debug PC keyboard */
|
27 | 0e43e99c | bellard | //#define DEBUG_KBD
|
28 | 0e43e99c | bellard | |
29 | 0e43e99c | bellard | /* debug PC keyboard : only mouse */
|
30 | 0e43e99c | bellard | //#define DEBUG_MOUSE
|
31 | 0e43e99c | bellard | |
32 | 0e43e99c | bellard | /* Keyboard Commands */
|
33 | 0e43e99c | bellard | #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ |
34 | 0e43e99c | bellard | #define KBD_CMD_ECHO 0xEE |
35 | 0e43e99c | bellard | #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ |
36 | 0e43e99c | bellard | #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ |
37 | 0e43e99c | bellard | #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ |
38 | 0e43e99c | bellard | #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ |
39 | 0e43e99c | bellard | #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ |
40 | 0e43e99c | bellard | #define KBD_CMD_RESET 0xFF /* Reset */ |
41 | 0e43e99c | bellard | |
42 | 0e43e99c | bellard | /* Keyboard Replies */
|
43 | 0e43e99c | bellard | #define KBD_REPLY_POR 0xAA /* Power on reset */ |
44 | 0e43e99c | bellard | #define KBD_REPLY_ACK 0xFA /* Command ACK */ |
45 | 0e43e99c | bellard | #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ |
46 | 0e43e99c | bellard | |
47 | 0e43e99c | bellard | /* Mouse Commands */
|
48 | 0e43e99c | bellard | #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ |
49 | 0e43e99c | bellard | #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ |
50 | 0e43e99c | bellard | #define AUX_SET_RES 0xE8 /* Set resolution */ |
51 | 0e43e99c | bellard | #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ |
52 | 0e43e99c | bellard | #define AUX_SET_STREAM 0xEA /* Set stream mode */ |
53 | 0e43e99c | bellard | #define AUX_POLL 0xEB /* Poll */ |
54 | 0e43e99c | bellard | #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ |
55 | 0e43e99c | bellard | #define AUX_SET_WRAP 0xEE /* Set wrap mode */ |
56 | 0e43e99c | bellard | #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ |
57 | 0e43e99c | bellard | #define AUX_GET_TYPE 0xF2 /* Get type */ |
58 | 0e43e99c | bellard | #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ |
59 | 0e43e99c | bellard | #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ |
60 | 0e43e99c | bellard | #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ |
61 | 0e43e99c | bellard | #define AUX_SET_DEFAULT 0xF6 |
62 | 0e43e99c | bellard | #define AUX_RESET 0xFF /* Reset aux device */ |
63 | 0e43e99c | bellard | #define AUX_ACK 0xFA /* Command byte ACK. */ |
64 | 0e43e99c | bellard | |
65 | 0e43e99c | bellard | #define MOUSE_STATUS_REMOTE 0x40 |
66 | 0e43e99c | bellard | #define MOUSE_STATUS_ENABLED 0x20 |
67 | 0e43e99c | bellard | #define MOUSE_STATUS_SCALE21 0x10 |
68 | 0e43e99c | bellard | |
69 | 0e43e99c | bellard | #define PS2_QUEUE_SIZE 256 |
70 | 0e43e99c | bellard | |
71 | 0e43e99c | bellard | typedef struct { |
72 | 0e43e99c | bellard | uint8_t data[PS2_QUEUE_SIZE]; |
73 | 0e43e99c | bellard | int rptr, wptr, count;
|
74 | 0e43e99c | bellard | } PS2Queue; |
75 | 0e43e99c | bellard | |
76 | 0e43e99c | bellard | typedef struct { |
77 | 0e43e99c | bellard | PS2Queue queue; |
78 | 0e43e99c | bellard | int32_t write_cmd; |
79 | 0e43e99c | bellard | void (*update_irq)(void *, int); |
80 | 0e43e99c | bellard | void *update_arg;
|
81 | 0e43e99c | bellard | } PS2State; |
82 | 0e43e99c | bellard | |
83 | 0e43e99c | bellard | typedef struct { |
84 | 0e43e99c | bellard | PS2State common; |
85 | 0e43e99c | bellard | int scan_enabled;
|
86 | f94f5d71 | pbrook | /* Qemu uses translated PC scancodes internally. To avoid multiple
|
87 | f94f5d71 | pbrook | conversions we do the translation (if any) in the PS/2 emulation
|
88 | f94f5d71 | pbrook | not the keyboard controller. */
|
89 | f94f5d71 | pbrook | int translate;
|
90 | 0e43e99c | bellard | } PS2KbdState; |
91 | 0e43e99c | bellard | |
92 | 0e43e99c | bellard | typedef struct { |
93 | 0e43e99c | bellard | PS2State common; |
94 | 0e43e99c | bellard | uint8_t mouse_status; |
95 | 0e43e99c | bellard | uint8_t mouse_resolution; |
96 | 0e43e99c | bellard | uint8_t mouse_sample_rate; |
97 | 0e43e99c | bellard | uint8_t mouse_wrap; |
98 | 0e43e99c | bellard | uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
|
99 | 0e43e99c | bellard | uint8_t mouse_detect_state; |
100 | 0e43e99c | bellard | int mouse_dx; /* current values, needed for 'poll' mode */ |
101 | 0e43e99c | bellard | int mouse_dy;
|
102 | 0e43e99c | bellard | int mouse_dz;
|
103 | 0e43e99c | bellard | uint8_t mouse_buttons; |
104 | 0e43e99c | bellard | } PS2MouseState; |
105 | 0e43e99c | bellard | |
106 | f94f5d71 | pbrook | /* Table to convert from PC scancodes to raw scancodes. */
|
107 | f94f5d71 | pbrook | static const unsigned char ps2_raw_keycode[128] = { |
108 | f94f5d71 | pbrook | 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, |
109 | f94f5d71 | pbrook | 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, |
110 | f94f5d71 | pbrook | 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, |
111 | f94f5d71 | pbrook | 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, |
112 | f94f5d71 | pbrook | 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, |
113 | f94f5d71 | pbrook | 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, |
114 | f94f5d71 | pbrook | 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, |
115 | f94f5d71 | pbrook | 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 |
116 | f94f5d71 | pbrook | }; |
117 | f94f5d71 | pbrook | |
118 | 0e43e99c | bellard | void ps2_queue(void *opaque, int b) |
119 | 0e43e99c | bellard | { |
120 | 0e43e99c | bellard | PS2State *s = (PS2State *)opaque; |
121 | 0e43e99c | bellard | PS2Queue *q = &s->queue; |
122 | 0e43e99c | bellard | |
123 | 0e43e99c | bellard | if (q->count >= PS2_QUEUE_SIZE)
|
124 | 0e43e99c | bellard | return;
|
125 | 0e43e99c | bellard | q->data[q->wptr] = b; |
126 | 0e43e99c | bellard | if (++q->wptr == PS2_QUEUE_SIZE)
|
127 | 0e43e99c | bellard | q->wptr = 0;
|
128 | 0e43e99c | bellard | q->count++; |
129 | 0e43e99c | bellard | s->update_irq(s->update_arg, 1);
|
130 | 0e43e99c | bellard | } |
131 | 0e43e99c | bellard | |
132 | 0e43e99c | bellard | static void ps2_put_keycode(void *opaque, int keycode) |
133 | 0e43e99c | bellard | { |
134 | f94f5d71 | pbrook | PS2KbdState *s = opaque; |
135 | f94f5d71 | pbrook | if (!s->translate && keycode < 0xe0) |
136 | f94f5d71 | pbrook | { |
137 | f94f5d71 | pbrook | if (keycode & 0x80) |
138 | f94f5d71 | pbrook | ps2_queue(&s->common, 0xf0);
|
139 | f94f5d71 | pbrook | keycode = ps2_raw_keycode[keycode & 0x7f];
|
140 | f94f5d71 | pbrook | } |
141 | 0e43e99c | bellard | ps2_queue(&s->common, keycode); |
142 | 0e43e99c | bellard | } |
143 | 0e43e99c | bellard | |
144 | 0e43e99c | bellard | uint32_t ps2_read_data(void *opaque)
|
145 | 0e43e99c | bellard | { |
146 | 0e43e99c | bellard | PS2State *s = (PS2State *)opaque; |
147 | 0e43e99c | bellard | PS2Queue *q; |
148 | 0e43e99c | bellard | int val, index;
|
149 | 3b46e624 | ths | |
150 | 0e43e99c | bellard | q = &s->queue; |
151 | 0e43e99c | bellard | if (q->count == 0) { |
152 | 0e43e99c | bellard | /* NOTE: if no data left, we return the last keyboard one
|
153 | 0e43e99c | bellard | (needed for EMM386) */
|
154 | 0e43e99c | bellard | /* XXX: need a timer to do things correctly */
|
155 | 0e43e99c | bellard | index = q->rptr - 1;
|
156 | 0e43e99c | bellard | if (index < 0) |
157 | 0e43e99c | bellard | index = PS2_QUEUE_SIZE - 1;
|
158 | 0e43e99c | bellard | val = q->data[index]; |
159 | 0e43e99c | bellard | } else {
|
160 | 0e43e99c | bellard | val = q->data[q->rptr]; |
161 | 0e43e99c | bellard | if (++q->rptr == PS2_QUEUE_SIZE)
|
162 | 0e43e99c | bellard | q->rptr = 0;
|
163 | 0e43e99c | bellard | q->count--; |
164 | 0e43e99c | bellard | /* reading deasserts IRQ */
|
165 | 0e43e99c | bellard | s->update_irq(s->update_arg, 0);
|
166 | 0e43e99c | bellard | /* reassert IRQs if data left */
|
167 | 0e43e99c | bellard | s->update_irq(s->update_arg, q->count != 0);
|
168 | 0e43e99c | bellard | } |
169 | 0e43e99c | bellard | return val;
|
170 | 0e43e99c | bellard | } |
171 | 0e43e99c | bellard | |
172 | 0e43e99c | bellard | static void ps2_reset_keyboard(PS2KbdState *s) |
173 | 0e43e99c | bellard | { |
174 | 0e43e99c | bellard | s->scan_enabled = 1;
|
175 | 0e43e99c | bellard | } |
176 | 0e43e99c | bellard | |
177 | 0e43e99c | bellard | void ps2_write_keyboard(void *opaque, int val) |
178 | 0e43e99c | bellard | { |
179 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState *)opaque; |
180 | 0e43e99c | bellard | |
181 | 0e43e99c | bellard | switch(s->common.write_cmd) {
|
182 | 0e43e99c | bellard | default:
|
183 | 0e43e99c | bellard | case -1: |
184 | 0e43e99c | bellard | switch(val) {
|
185 | 0e43e99c | bellard | case 0x00: |
186 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
187 | 0e43e99c | bellard | break;
|
188 | 0e43e99c | bellard | case 0x05: |
189 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_RESEND); |
190 | 0e43e99c | bellard | break;
|
191 | 0e43e99c | bellard | case KBD_CMD_GET_ID:
|
192 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
193 | 0e43e99c | bellard | ps2_queue(&s->common, 0xab);
|
194 | 0e43e99c | bellard | ps2_queue(&s->common, 0x83);
|
195 | 0e43e99c | bellard | break;
|
196 | 0e43e99c | bellard | case KBD_CMD_ECHO:
|
197 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_CMD_ECHO); |
198 | 0e43e99c | bellard | break;
|
199 | 0e43e99c | bellard | case KBD_CMD_ENABLE:
|
200 | 0e43e99c | bellard | s->scan_enabled = 1;
|
201 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
202 | 0e43e99c | bellard | break;
|
203 | 0e43e99c | bellard | case KBD_CMD_SET_LEDS:
|
204 | 0e43e99c | bellard | case KBD_CMD_SET_RATE:
|
205 | 0e43e99c | bellard | s->common.write_cmd = val; |
206 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
207 | 0e43e99c | bellard | break;
|
208 | 0e43e99c | bellard | case KBD_CMD_RESET_DISABLE:
|
209 | 0e43e99c | bellard | ps2_reset_keyboard(s); |
210 | 0e43e99c | bellard | s->scan_enabled = 0;
|
211 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
212 | 0e43e99c | bellard | break;
|
213 | 0e43e99c | bellard | case KBD_CMD_RESET_ENABLE:
|
214 | 0e43e99c | bellard | ps2_reset_keyboard(s); |
215 | 0e43e99c | bellard | s->scan_enabled = 1;
|
216 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
217 | 0e43e99c | bellard | break;
|
218 | 0e43e99c | bellard | case KBD_CMD_RESET:
|
219 | 0e43e99c | bellard | ps2_reset_keyboard(s); |
220 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
221 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_POR); |
222 | 0e43e99c | bellard | break;
|
223 | 0e43e99c | bellard | default:
|
224 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
225 | 0e43e99c | bellard | break;
|
226 | 0e43e99c | bellard | } |
227 | 0e43e99c | bellard | break;
|
228 | 0e43e99c | bellard | case KBD_CMD_SET_LEDS:
|
229 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
230 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
231 | 0e43e99c | bellard | break;
|
232 | 0e43e99c | bellard | case KBD_CMD_SET_RATE:
|
233 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
234 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
235 | 0e43e99c | bellard | break;
|
236 | 0e43e99c | bellard | } |
237 | 0e43e99c | bellard | } |
238 | 0e43e99c | bellard | |
239 | f94f5d71 | pbrook | /* Set the scancode translation mode.
|
240 | f94f5d71 | pbrook | 0 = raw scancodes.
|
241 | f94f5d71 | pbrook | 1 = translated scancodes (used by qemu internally). */
|
242 | f94f5d71 | pbrook | |
243 | f94f5d71 | pbrook | void ps2_keyboard_set_translation(void *opaque, int mode) |
244 | f94f5d71 | pbrook | { |
245 | f94f5d71 | pbrook | PS2KbdState *s = (PS2KbdState *)opaque; |
246 | f94f5d71 | pbrook | s->translate = mode; |
247 | f94f5d71 | pbrook | } |
248 | f94f5d71 | pbrook | |
249 | 0e43e99c | bellard | static void ps2_mouse_send_packet(PS2MouseState *s) |
250 | 0e43e99c | bellard | { |
251 | 0e43e99c | bellard | unsigned int b; |
252 | 0e43e99c | bellard | int dx1, dy1, dz1;
|
253 | 0e43e99c | bellard | |
254 | 0e43e99c | bellard | dx1 = s->mouse_dx; |
255 | 0e43e99c | bellard | dy1 = s->mouse_dy; |
256 | 0e43e99c | bellard | dz1 = s->mouse_dz; |
257 | 0e43e99c | bellard | /* XXX: increase range to 8 bits ? */
|
258 | 0e43e99c | bellard | if (dx1 > 127) |
259 | 0e43e99c | bellard | dx1 = 127;
|
260 | 0e43e99c | bellard | else if (dx1 < -127) |
261 | 0e43e99c | bellard | dx1 = -127;
|
262 | 0e43e99c | bellard | if (dy1 > 127) |
263 | 0e43e99c | bellard | dy1 = 127;
|
264 | 0e43e99c | bellard | else if (dy1 < -127) |
265 | 0e43e99c | bellard | dy1 = -127;
|
266 | 0e43e99c | bellard | b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); |
267 | 0e43e99c | bellard | ps2_queue(&s->common, b); |
268 | 0e43e99c | bellard | ps2_queue(&s->common, dx1 & 0xff);
|
269 | 0e43e99c | bellard | ps2_queue(&s->common, dy1 & 0xff);
|
270 | 0e43e99c | bellard | /* extra byte for IMPS/2 or IMEX */
|
271 | 0e43e99c | bellard | switch(s->mouse_type) {
|
272 | 0e43e99c | bellard | default:
|
273 | 0e43e99c | bellard | break;
|
274 | 0e43e99c | bellard | case 3: |
275 | 0e43e99c | bellard | if (dz1 > 127) |
276 | 0e43e99c | bellard | dz1 = 127;
|
277 | 0e43e99c | bellard | else if (dz1 < -127) |
278 | 0e43e99c | bellard | dz1 = -127;
|
279 | 0e43e99c | bellard | ps2_queue(&s->common, dz1 & 0xff);
|
280 | 0e43e99c | bellard | break;
|
281 | 0e43e99c | bellard | case 4: |
282 | 0e43e99c | bellard | if (dz1 > 7) |
283 | 0e43e99c | bellard | dz1 = 7;
|
284 | 0e43e99c | bellard | else if (dz1 < -7) |
285 | 0e43e99c | bellard | dz1 = -7;
|
286 | 0e43e99c | bellard | b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); |
287 | 0e43e99c | bellard | ps2_queue(&s->common, b); |
288 | 0e43e99c | bellard | break;
|
289 | 0e43e99c | bellard | } |
290 | 0e43e99c | bellard | |
291 | 0e43e99c | bellard | /* update deltas */
|
292 | 0e43e99c | bellard | s->mouse_dx -= dx1; |
293 | 0e43e99c | bellard | s->mouse_dy -= dy1; |
294 | 0e43e99c | bellard | s->mouse_dz -= dz1; |
295 | 0e43e99c | bellard | } |
296 | 0e43e99c | bellard | |
297 | 5fafdf24 | ths | static void ps2_mouse_event(void *opaque, |
298 | 0e43e99c | bellard | int dx, int dy, int dz, int buttons_state) |
299 | 0e43e99c | bellard | { |
300 | 0e43e99c | bellard | PS2MouseState *s = opaque; |
301 | 0e43e99c | bellard | |
302 | 0e43e99c | bellard | /* check if deltas are recorded when disabled */
|
303 | 0e43e99c | bellard | if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
|
304 | 0e43e99c | bellard | return;
|
305 | 0e43e99c | bellard | |
306 | 0e43e99c | bellard | s->mouse_dx += dx; |
307 | 0e43e99c | bellard | s->mouse_dy -= dy; |
308 | 0e43e99c | bellard | s->mouse_dz += dz; |
309 | 0e43e99c | bellard | /* XXX: SDL sometimes generates nul events: we delete them */
|
310 | 0e43e99c | bellard | if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && |
311 | 0e43e99c | bellard | s->mouse_buttons == buttons_state) |
312 | 0e43e99c | bellard | return;
|
313 | 0e43e99c | bellard | s->mouse_buttons = buttons_state; |
314 | 3b46e624 | ths | |
315 | 0e43e99c | bellard | if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
|
316 | 0e43e99c | bellard | (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
|
317 | 0e43e99c | bellard | for(;;) {
|
318 | 0e43e99c | bellard | /* if not remote, send event. Multiple events are sent if
|
319 | 0e43e99c | bellard | too big deltas */
|
320 | 0e43e99c | bellard | ps2_mouse_send_packet(s); |
321 | 0e43e99c | bellard | if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) |
322 | 0e43e99c | bellard | break;
|
323 | 0e43e99c | bellard | } |
324 | 0e43e99c | bellard | } |
325 | 0e43e99c | bellard | } |
326 | 0e43e99c | bellard | |
327 | 548df2ac | ths | void ps2_mouse_fake_event(void *opaque) |
328 | 548df2ac | ths | { |
329 | 548df2ac | ths | ps2_mouse_event(opaque, 1, 0, 0, 0); |
330 | 548df2ac | ths | } |
331 | 548df2ac | ths | |
332 | 0e43e99c | bellard | void ps2_write_mouse(void *opaque, int val) |
333 | 0e43e99c | bellard | { |
334 | 0e43e99c | bellard | PS2MouseState *s = (PS2MouseState *)opaque; |
335 | 0e43e99c | bellard | #ifdef DEBUG_MOUSE
|
336 | 0e43e99c | bellard | printf("kbd: write mouse 0x%02x\n", val);
|
337 | 0e43e99c | bellard | #endif
|
338 | 0e43e99c | bellard | switch(s->common.write_cmd) {
|
339 | 0e43e99c | bellard | default:
|
340 | 0e43e99c | bellard | case -1: |
341 | 0e43e99c | bellard | /* mouse command */
|
342 | 0e43e99c | bellard | if (s->mouse_wrap) {
|
343 | 0e43e99c | bellard | if (val == AUX_RESET_WRAP) {
|
344 | 0e43e99c | bellard | s->mouse_wrap = 0;
|
345 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
346 | 0e43e99c | bellard | return;
|
347 | 0e43e99c | bellard | } else if (val != AUX_RESET) { |
348 | 0e43e99c | bellard | ps2_queue(&s->common, val); |
349 | 0e43e99c | bellard | return;
|
350 | 0e43e99c | bellard | } |
351 | 0e43e99c | bellard | } |
352 | 0e43e99c | bellard | switch(val) {
|
353 | 0e43e99c | bellard | case AUX_SET_SCALE11:
|
354 | 0e43e99c | bellard | s->mouse_status &= ~MOUSE_STATUS_SCALE21; |
355 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
356 | 0e43e99c | bellard | break;
|
357 | 0e43e99c | bellard | case AUX_SET_SCALE21:
|
358 | 0e43e99c | bellard | s->mouse_status |= MOUSE_STATUS_SCALE21; |
359 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
360 | 0e43e99c | bellard | break;
|
361 | 0e43e99c | bellard | case AUX_SET_STREAM:
|
362 | 0e43e99c | bellard | s->mouse_status &= ~MOUSE_STATUS_REMOTE; |
363 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
364 | 0e43e99c | bellard | break;
|
365 | 0e43e99c | bellard | case AUX_SET_WRAP:
|
366 | 0e43e99c | bellard | s->mouse_wrap = 1;
|
367 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
368 | 0e43e99c | bellard | break;
|
369 | 0e43e99c | bellard | case AUX_SET_REMOTE:
|
370 | 0e43e99c | bellard | s->mouse_status |= MOUSE_STATUS_REMOTE; |
371 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
372 | 0e43e99c | bellard | break;
|
373 | 0e43e99c | bellard | case AUX_GET_TYPE:
|
374 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
375 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_type); |
376 | 0e43e99c | bellard | break;
|
377 | 0e43e99c | bellard | case AUX_SET_RES:
|
378 | 0e43e99c | bellard | case AUX_SET_SAMPLE:
|
379 | 0e43e99c | bellard | s->common.write_cmd = val; |
380 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
381 | 0e43e99c | bellard | break;
|
382 | 0e43e99c | bellard | case AUX_GET_SCALE:
|
383 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
384 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_status); |
385 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_resolution); |
386 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_sample_rate); |
387 | 0e43e99c | bellard | break;
|
388 | 0e43e99c | bellard | case AUX_POLL:
|
389 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
390 | 0e43e99c | bellard | ps2_mouse_send_packet(s); |
391 | 0e43e99c | bellard | break;
|
392 | 0e43e99c | bellard | case AUX_ENABLE_DEV:
|
393 | 0e43e99c | bellard | s->mouse_status |= MOUSE_STATUS_ENABLED; |
394 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
395 | 0e43e99c | bellard | break;
|
396 | 0e43e99c | bellard | case AUX_DISABLE_DEV:
|
397 | 0e43e99c | bellard | s->mouse_status &= ~MOUSE_STATUS_ENABLED; |
398 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
399 | 0e43e99c | bellard | break;
|
400 | 0e43e99c | bellard | case AUX_SET_DEFAULT:
|
401 | 0e43e99c | bellard | s->mouse_sample_rate = 100;
|
402 | 0e43e99c | bellard | s->mouse_resolution = 2;
|
403 | 0e43e99c | bellard | s->mouse_status = 0;
|
404 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
405 | 0e43e99c | bellard | break;
|
406 | 0e43e99c | bellard | case AUX_RESET:
|
407 | 0e43e99c | bellard | s->mouse_sample_rate = 100;
|
408 | 0e43e99c | bellard | s->mouse_resolution = 2;
|
409 | 0e43e99c | bellard | s->mouse_status = 0;
|
410 | 0e43e99c | bellard | s->mouse_type = 0;
|
411 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
412 | 0e43e99c | bellard | ps2_queue(&s->common, 0xaa);
|
413 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_type); |
414 | 0e43e99c | bellard | break;
|
415 | 0e43e99c | bellard | default:
|
416 | 0e43e99c | bellard | break;
|
417 | 0e43e99c | bellard | } |
418 | 0e43e99c | bellard | break;
|
419 | 0e43e99c | bellard | case AUX_SET_SAMPLE:
|
420 | 0e43e99c | bellard | s->mouse_sample_rate = val; |
421 | 0e43e99c | bellard | /* detect IMPS/2 or IMEX */
|
422 | 0e43e99c | bellard | switch(s->mouse_detect_state) {
|
423 | 0e43e99c | bellard | default:
|
424 | 0e43e99c | bellard | case 0: |
425 | 0e43e99c | bellard | if (val == 200) |
426 | 0e43e99c | bellard | s->mouse_detect_state = 1;
|
427 | 0e43e99c | bellard | break;
|
428 | 0e43e99c | bellard | case 1: |
429 | 0e43e99c | bellard | if (val == 100) |
430 | 0e43e99c | bellard | s->mouse_detect_state = 2;
|
431 | 0e43e99c | bellard | else if (val == 200) |
432 | 0e43e99c | bellard | s->mouse_detect_state = 3;
|
433 | 0e43e99c | bellard | else
|
434 | 0e43e99c | bellard | s->mouse_detect_state = 0;
|
435 | 0e43e99c | bellard | break;
|
436 | 0e43e99c | bellard | case 2: |
437 | 5fafdf24 | ths | if (val == 80) |
438 | 0e43e99c | bellard | s->mouse_type = 3; /* IMPS/2 */ |
439 | 0e43e99c | bellard | s->mouse_detect_state = 0;
|
440 | 0e43e99c | bellard | break;
|
441 | 0e43e99c | bellard | case 3: |
442 | 5fafdf24 | ths | if (val == 80) |
443 | 0e43e99c | bellard | s->mouse_type = 4; /* IMEX */ |
444 | 0e43e99c | bellard | s->mouse_detect_state = 0;
|
445 | 0e43e99c | bellard | break;
|
446 | 0e43e99c | bellard | } |
447 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
448 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
449 | 0e43e99c | bellard | break;
|
450 | 0e43e99c | bellard | case AUX_SET_RES:
|
451 | 0e43e99c | bellard | s->mouse_resolution = val; |
452 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
453 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
454 | 0e43e99c | bellard | break;
|
455 | 0e43e99c | bellard | } |
456 | 0e43e99c | bellard | } |
457 | 0e43e99c | bellard | |
458 | 0e43e99c | bellard | static void ps2_reset(void *opaque) |
459 | 0e43e99c | bellard | { |
460 | 0e43e99c | bellard | PS2State *s = (PS2State *)opaque; |
461 | 0e43e99c | bellard | PS2Queue *q; |
462 | 0e43e99c | bellard | s->write_cmd = -1;
|
463 | 0e43e99c | bellard | q = &s->queue; |
464 | 0e43e99c | bellard | q->rptr = 0;
|
465 | 0e43e99c | bellard | q->wptr = 0;
|
466 | 0e43e99c | bellard | q->count = 0;
|
467 | 0e43e99c | bellard | } |
468 | 0e43e99c | bellard | |
469 | 7783e9f0 | pbrook | static void ps2_common_save (QEMUFile *f, PS2State *s) |
470 | 7783e9f0 | pbrook | { |
471 | 7783e9f0 | pbrook | qemu_put_be32s (f, &s->write_cmd); |
472 | 7783e9f0 | pbrook | qemu_put_be32s (f, &s->queue.rptr); |
473 | 7783e9f0 | pbrook | qemu_put_be32s (f, &s->queue.wptr); |
474 | 7783e9f0 | pbrook | qemu_put_be32s (f, &s->queue.count); |
475 | 7783e9f0 | pbrook | qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data));
|
476 | 7783e9f0 | pbrook | } |
477 | 7783e9f0 | pbrook | |
478 | 7783e9f0 | pbrook | static void ps2_common_load (QEMUFile *f, PS2State *s) |
479 | 7783e9f0 | pbrook | { |
480 | 7783e9f0 | pbrook | qemu_get_be32s (f, &s->write_cmd); |
481 | 7783e9f0 | pbrook | qemu_get_be32s (f, &s->queue.rptr); |
482 | 7783e9f0 | pbrook | qemu_get_be32s (f, &s->queue.wptr); |
483 | 7783e9f0 | pbrook | qemu_get_be32s (f, &s->queue.count); |
484 | 7783e9f0 | pbrook | qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data));
|
485 | 7783e9f0 | pbrook | } |
486 | 7783e9f0 | pbrook | |
487 | 0e43e99c | bellard | static void ps2_kbd_save(QEMUFile* f, void* opaque) |
488 | 0e43e99c | bellard | { |
489 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState*)opaque; |
490 | 7783e9f0 | pbrook | |
491 | 7783e9f0 | pbrook | ps2_common_save (f, &s->common); |
492 | 0e43e99c | bellard | qemu_put_be32s(f, &s->scan_enabled); |
493 | 7783e9f0 | pbrook | qemu_put_be32s(f, &s->translate); |
494 | 0e43e99c | bellard | } |
495 | 0e43e99c | bellard | |
496 | 0e43e99c | bellard | static void ps2_mouse_save(QEMUFile* f, void* opaque) |
497 | 0e43e99c | bellard | { |
498 | 0e43e99c | bellard | PS2MouseState *s = (PS2MouseState*)opaque; |
499 | 7783e9f0 | pbrook | |
500 | 7783e9f0 | pbrook | ps2_common_save (f, &s->common); |
501 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_status); |
502 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_resolution); |
503 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_sample_rate); |
504 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_wrap); |
505 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_type); |
506 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_detect_state); |
507 | 0e43e99c | bellard | qemu_put_be32s(f, &s->mouse_dx); |
508 | 0e43e99c | bellard | qemu_put_be32s(f, &s->mouse_dy); |
509 | 0e43e99c | bellard | qemu_put_be32s(f, &s->mouse_dz); |
510 | 0e43e99c | bellard | qemu_put_8s(f, &s->mouse_buttons); |
511 | 0e43e99c | bellard | } |
512 | 0e43e99c | bellard | |
513 | 0e43e99c | bellard | static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) |
514 | 0e43e99c | bellard | { |
515 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState*)opaque; |
516 | 7783e9f0 | pbrook | |
517 | 7783e9f0 | pbrook | if (version_id != 2) |
518 | 0e43e99c | bellard | return -EINVAL;
|
519 | 7783e9f0 | pbrook | |
520 | 7783e9f0 | pbrook | ps2_common_load (f, &s->common); |
521 | 0e43e99c | bellard | qemu_get_be32s(f, &s->scan_enabled); |
522 | 7783e9f0 | pbrook | qemu_get_be32s(f, &s->translate); |
523 | 0e43e99c | bellard | return 0; |
524 | 0e43e99c | bellard | } |
525 | 0e43e99c | bellard | |
526 | 0e43e99c | bellard | static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) |
527 | 0e43e99c | bellard | { |
528 | 0e43e99c | bellard | PS2MouseState *s = (PS2MouseState*)opaque; |
529 | 7783e9f0 | pbrook | |
530 | 7783e9f0 | pbrook | if (version_id != 2) |
531 | 0e43e99c | bellard | return -EINVAL;
|
532 | 7783e9f0 | pbrook | |
533 | 7783e9f0 | pbrook | ps2_common_load (f, &s->common); |
534 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_status); |
535 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_resolution); |
536 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_sample_rate); |
537 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_wrap); |
538 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_type); |
539 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_detect_state); |
540 | 0e43e99c | bellard | qemu_get_be32s(f, &s->mouse_dx); |
541 | 0e43e99c | bellard | qemu_get_be32s(f, &s->mouse_dy); |
542 | 0e43e99c | bellard | qemu_get_be32s(f, &s->mouse_dz); |
543 | 0e43e99c | bellard | qemu_get_8s(f, &s->mouse_buttons); |
544 | 0e43e99c | bellard | return 0; |
545 | 0e43e99c | bellard | } |
546 | 0e43e99c | bellard | |
547 | 0e43e99c | bellard | void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) |
548 | 0e43e99c | bellard | { |
549 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
|
550 | 0e43e99c | bellard | |
551 | 0e43e99c | bellard | s->common.update_irq = update_irq; |
552 | 0e43e99c | bellard | s->common.update_arg = update_arg; |
553 | 0e43e99c | bellard | ps2_reset(&s->common); |
554 | 7783e9f0 | pbrook | register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s); |
555 | 0e43e99c | bellard | qemu_add_kbd_event_handler(ps2_put_keycode, s); |
556 | 0e43e99c | bellard | qemu_register_reset(ps2_reset, &s->common); |
557 | 0e43e99c | bellard | return s;
|
558 | 0e43e99c | bellard | } |
559 | 0e43e99c | bellard | |
560 | 0e43e99c | bellard | void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) |
561 | 0e43e99c | bellard | { |
562 | 0e43e99c | bellard | PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
|
563 | 0e43e99c | bellard | |
564 | 0e43e99c | bellard | s->common.update_irq = update_irq; |
565 | 0e43e99c | bellard | s->common.update_arg = update_arg; |
566 | 0e43e99c | bellard | ps2_reset(&s->common); |
567 | 7783e9f0 | pbrook | register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); |
568 | 455204eb | ths | qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse"); |
569 | 0e43e99c | bellard | qemu_register_reset(ps2_reset, &s->common); |
570 | 0e43e99c | bellard | return s;
|
571 | 0e43e99c | bellard | } |