root / hw / ps2.c @ d587e078
History | View | Annotate | Download (18.3 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 | 87ecb68b | pbrook | #include "hw.h" |
25 | 87ecb68b | pbrook | #include "ps2.h" |
26 | 87ecb68b | pbrook | #include "console.h" |
27 | 0e43e99c | bellard | |
28 | 0e43e99c | bellard | /* debug PC keyboard */
|
29 | 0e43e99c | bellard | //#define DEBUG_KBD
|
30 | 0e43e99c | bellard | |
31 | 0e43e99c | bellard | /* debug PC keyboard : only mouse */
|
32 | 0e43e99c | bellard | //#define DEBUG_MOUSE
|
33 | 0e43e99c | bellard | |
34 | 0e43e99c | bellard | /* Keyboard Commands */
|
35 | 0e43e99c | bellard | #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ |
36 | 0e43e99c | bellard | #define KBD_CMD_ECHO 0xEE |
37 | e7d93956 | aurel32 | #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ |
38 | 0e43e99c | bellard | #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ |
39 | 0e43e99c | bellard | #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ |
40 | 0e43e99c | bellard | #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ |
41 | 0e43e99c | bellard | #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ |
42 | 0e43e99c | bellard | #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ |
43 | 0e43e99c | bellard | #define KBD_CMD_RESET 0xFF /* Reset */ |
44 | 0e43e99c | bellard | |
45 | 0e43e99c | bellard | /* Keyboard Replies */
|
46 | 0e43e99c | bellard | #define KBD_REPLY_POR 0xAA /* Power on reset */ |
47 | 35c4d671 | aurel32 | #define KBD_REPLY_ID 0xAB /* Keyboard ID */ |
48 | 0e43e99c | bellard | #define KBD_REPLY_ACK 0xFA /* Command ACK */ |
49 | 0e43e99c | bellard | #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ |
50 | 0e43e99c | bellard | |
51 | 0e43e99c | bellard | /* Mouse Commands */
|
52 | 0e43e99c | bellard | #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ |
53 | 0e43e99c | bellard | #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ |
54 | 0e43e99c | bellard | #define AUX_SET_RES 0xE8 /* Set resolution */ |
55 | 0e43e99c | bellard | #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ |
56 | 0e43e99c | bellard | #define AUX_SET_STREAM 0xEA /* Set stream mode */ |
57 | 0e43e99c | bellard | #define AUX_POLL 0xEB /* Poll */ |
58 | 0e43e99c | bellard | #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ |
59 | 0e43e99c | bellard | #define AUX_SET_WRAP 0xEE /* Set wrap mode */ |
60 | 0e43e99c | bellard | #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ |
61 | 0e43e99c | bellard | #define AUX_GET_TYPE 0xF2 /* Get type */ |
62 | 0e43e99c | bellard | #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ |
63 | 0e43e99c | bellard | #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ |
64 | 0e43e99c | bellard | #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ |
65 | 0e43e99c | bellard | #define AUX_SET_DEFAULT 0xF6 |
66 | 0e43e99c | bellard | #define AUX_RESET 0xFF /* Reset aux device */ |
67 | 0e43e99c | bellard | #define AUX_ACK 0xFA /* Command byte ACK. */ |
68 | 0e43e99c | bellard | |
69 | 0e43e99c | bellard | #define MOUSE_STATUS_REMOTE 0x40 |
70 | 0e43e99c | bellard | #define MOUSE_STATUS_ENABLED 0x20 |
71 | 0e43e99c | bellard | #define MOUSE_STATUS_SCALE21 0x10 |
72 | 0e43e99c | bellard | |
73 | 0e43e99c | bellard | #define PS2_QUEUE_SIZE 256 |
74 | 0e43e99c | bellard | |
75 | 0e43e99c | bellard | typedef struct { |
76 | 0e43e99c | bellard | uint8_t data[PS2_QUEUE_SIZE]; |
77 | 0e43e99c | bellard | int rptr, wptr, count;
|
78 | 0e43e99c | bellard | } PS2Queue; |
79 | 0e43e99c | bellard | |
80 | 0e43e99c | bellard | typedef struct { |
81 | 0e43e99c | bellard | PS2Queue queue; |
82 | 0e43e99c | bellard | int32_t write_cmd; |
83 | 0e43e99c | bellard | void (*update_irq)(void *, int); |
84 | 0e43e99c | bellard | void *update_arg;
|
85 | 0e43e99c | bellard | } PS2State; |
86 | 0e43e99c | bellard | |
87 | 0e43e99c | bellard | typedef struct { |
88 | 0e43e99c | bellard | PS2State common; |
89 | 0e43e99c | bellard | int scan_enabled;
|
90 | f94f5d71 | pbrook | /* Qemu uses translated PC scancodes internally. To avoid multiple
|
91 | f94f5d71 | pbrook | conversions we do the translation (if any) in the PS/2 emulation
|
92 | f94f5d71 | pbrook | not the keyboard controller. */
|
93 | f94f5d71 | pbrook | int translate;
|
94 | e7d93956 | aurel32 | int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ |
95 | 0e43e99c | bellard | } PS2KbdState; |
96 | 0e43e99c | bellard | |
97 | 0e43e99c | bellard | typedef struct { |
98 | 0e43e99c | bellard | PS2State common; |
99 | 0e43e99c | bellard | uint8_t mouse_status; |
100 | 0e43e99c | bellard | uint8_t mouse_resolution; |
101 | 0e43e99c | bellard | uint8_t mouse_sample_rate; |
102 | 0e43e99c | bellard | uint8_t mouse_wrap; |
103 | 0e43e99c | bellard | uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
|
104 | 0e43e99c | bellard | uint8_t mouse_detect_state; |
105 | 0e43e99c | bellard | int mouse_dx; /* current values, needed for 'poll' mode */ |
106 | 0e43e99c | bellard | int mouse_dy;
|
107 | 0e43e99c | bellard | int mouse_dz;
|
108 | 0e43e99c | bellard | uint8_t mouse_buttons; |
109 | 0e43e99c | bellard | } PS2MouseState; |
110 | 0e43e99c | bellard | |
111 | f94f5d71 | pbrook | /* Table to convert from PC scancodes to raw scancodes. */
|
112 | f94f5d71 | pbrook | static const unsigned char ps2_raw_keycode[128] = { |
113 | f94f5d71 | pbrook | 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, |
114 | f94f5d71 | pbrook | 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, |
115 | f94f5d71 | pbrook | 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, |
116 | f94f5d71 | pbrook | 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, |
117 | f94f5d71 | pbrook | 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, |
118 | f94f5d71 | pbrook | 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, |
119 | f94f5d71 | pbrook | 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, |
120 | f94f5d71 | pbrook | 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 |
121 | f94f5d71 | pbrook | }; |
122 | f94f5d71 | pbrook | |
123 | 0e43e99c | bellard | void ps2_queue(void *opaque, int b) |
124 | 0e43e99c | bellard | { |
125 | 0e43e99c | bellard | PS2State *s = (PS2State *)opaque; |
126 | 0e43e99c | bellard | PS2Queue *q = &s->queue; |
127 | 0e43e99c | bellard | |
128 | 0e43e99c | bellard | if (q->count >= PS2_QUEUE_SIZE)
|
129 | 0e43e99c | bellard | return;
|
130 | 0e43e99c | bellard | q->data[q->wptr] = b; |
131 | 0e43e99c | bellard | if (++q->wptr == PS2_QUEUE_SIZE)
|
132 | 0e43e99c | bellard | q->wptr = 0;
|
133 | 0e43e99c | bellard | q->count++; |
134 | 0e43e99c | bellard | s->update_irq(s->update_arg, 1);
|
135 | 0e43e99c | bellard | } |
136 | 0e43e99c | bellard | |
137 | 35c4d671 | aurel32 | /*
|
138 | 35c4d671 | aurel32 | keycode is expressed as follow:
|
139 | 35c4d671 | aurel32 | bit 7 - 0 key pressed, 1 = key released
|
140 | 35c4d671 | aurel32 | bits 6-0 - translated scancode set 2
|
141 | 35c4d671 | aurel32 | */
|
142 | 0e43e99c | bellard | static void ps2_put_keycode(void *opaque, int keycode) |
143 | 0e43e99c | bellard | { |
144 | f94f5d71 | pbrook | PS2KbdState *s = opaque; |
145 | e7d93956 | aurel32 | |
146 | e7d93956 | aurel32 | /* XXX: add support for scancode sets 1 and 3 */
|
147 | e7d93956 | aurel32 | if (!s->translate && keycode < 0xe0 && s->scancode_set == 2) |
148 | f94f5d71 | pbrook | { |
149 | f94f5d71 | pbrook | if (keycode & 0x80) |
150 | f94f5d71 | pbrook | ps2_queue(&s->common, 0xf0);
|
151 | f94f5d71 | pbrook | keycode = ps2_raw_keycode[keycode & 0x7f];
|
152 | f94f5d71 | pbrook | } |
153 | 0e43e99c | bellard | ps2_queue(&s->common, keycode); |
154 | 0e43e99c | bellard | } |
155 | 0e43e99c | bellard | |
156 | 0e43e99c | bellard | uint32_t ps2_read_data(void *opaque)
|
157 | 0e43e99c | bellard | { |
158 | 0e43e99c | bellard | PS2State *s = (PS2State *)opaque; |
159 | 0e43e99c | bellard | PS2Queue *q; |
160 | 0e43e99c | bellard | int val, index;
|
161 | 3b46e624 | ths | |
162 | 0e43e99c | bellard | q = &s->queue; |
163 | 0e43e99c | bellard | if (q->count == 0) { |
164 | 0e43e99c | bellard | /* NOTE: if no data left, we return the last keyboard one
|
165 | 0e43e99c | bellard | (needed for EMM386) */
|
166 | 0e43e99c | bellard | /* XXX: need a timer to do things correctly */
|
167 | 0e43e99c | bellard | index = q->rptr - 1;
|
168 | 0e43e99c | bellard | if (index < 0) |
169 | 0e43e99c | bellard | index = PS2_QUEUE_SIZE - 1;
|
170 | 0e43e99c | bellard | val = q->data[index]; |
171 | 0e43e99c | bellard | } else {
|
172 | 0e43e99c | bellard | val = q->data[q->rptr]; |
173 | 0e43e99c | bellard | if (++q->rptr == PS2_QUEUE_SIZE)
|
174 | 0e43e99c | bellard | q->rptr = 0;
|
175 | 0e43e99c | bellard | q->count--; |
176 | 0e43e99c | bellard | /* reading deasserts IRQ */
|
177 | 0e43e99c | bellard | s->update_irq(s->update_arg, 0);
|
178 | 0e43e99c | bellard | /* reassert IRQs if data left */
|
179 | 0e43e99c | bellard | s->update_irq(s->update_arg, q->count != 0);
|
180 | 0e43e99c | bellard | } |
181 | 0e43e99c | bellard | return val;
|
182 | 0e43e99c | bellard | } |
183 | 0e43e99c | bellard | |
184 | 0e43e99c | bellard | static void ps2_reset_keyboard(PS2KbdState *s) |
185 | 0e43e99c | bellard | { |
186 | 0e43e99c | bellard | s->scan_enabled = 1;
|
187 | e7d93956 | aurel32 | s->scancode_set = 2;
|
188 | 0e43e99c | bellard | } |
189 | 0e43e99c | bellard | |
190 | 0e43e99c | bellard | void ps2_write_keyboard(void *opaque, int val) |
191 | 0e43e99c | bellard | { |
192 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState *)opaque; |
193 | 0e43e99c | bellard | |
194 | 0e43e99c | bellard | switch(s->common.write_cmd) {
|
195 | 0e43e99c | bellard | default:
|
196 | 0e43e99c | bellard | case -1: |
197 | 0e43e99c | bellard | switch(val) {
|
198 | 0e43e99c | bellard | case 0x00: |
199 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
200 | 0e43e99c | bellard | break;
|
201 | 0e43e99c | bellard | case 0x05: |
202 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_RESEND); |
203 | 0e43e99c | bellard | break;
|
204 | 0e43e99c | bellard | case KBD_CMD_GET_ID:
|
205 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
206 | e7d93956 | aurel32 | /* We emulate a MF2 AT keyboard here */
|
207 | 35c4d671 | aurel32 | ps2_queue(&s->common, KBD_REPLY_ID); |
208 | 35c4d671 | aurel32 | if (s->translate)
|
209 | 35c4d671 | aurel32 | ps2_queue(&s->common, 0x41);
|
210 | 35c4d671 | aurel32 | else
|
211 | 35c4d671 | aurel32 | ps2_queue(&s->common, 0x83);
|
212 | 0e43e99c | bellard | break;
|
213 | 0e43e99c | bellard | case KBD_CMD_ECHO:
|
214 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_CMD_ECHO); |
215 | 0e43e99c | bellard | break;
|
216 | 0e43e99c | bellard | case KBD_CMD_ENABLE:
|
217 | 0e43e99c | bellard | s->scan_enabled = 1;
|
218 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
219 | 0e43e99c | bellard | break;
|
220 | e7d93956 | aurel32 | case KBD_CMD_SCANCODE:
|
221 | 0e43e99c | bellard | case KBD_CMD_SET_LEDS:
|
222 | 0e43e99c | bellard | case KBD_CMD_SET_RATE:
|
223 | 0e43e99c | bellard | s->common.write_cmd = val; |
224 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
225 | 0e43e99c | bellard | break;
|
226 | 0e43e99c | bellard | case KBD_CMD_RESET_DISABLE:
|
227 | 0e43e99c | bellard | ps2_reset_keyboard(s); |
228 | 0e43e99c | bellard | s->scan_enabled = 0;
|
229 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
230 | 0e43e99c | bellard | break;
|
231 | 0e43e99c | bellard | case KBD_CMD_RESET_ENABLE:
|
232 | 0e43e99c | bellard | ps2_reset_keyboard(s); |
233 | 0e43e99c | bellard | s->scan_enabled = 1;
|
234 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
235 | 0e43e99c | bellard | break;
|
236 | 0e43e99c | bellard | case KBD_CMD_RESET:
|
237 | 0e43e99c | bellard | ps2_reset_keyboard(s); |
238 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
239 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_POR); |
240 | 0e43e99c | bellard | break;
|
241 | 0e43e99c | bellard | default:
|
242 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
243 | 0e43e99c | bellard | break;
|
244 | 0e43e99c | bellard | } |
245 | 0e43e99c | bellard | break;
|
246 | e7d93956 | aurel32 | case KBD_CMD_SCANCODE:
|
247 | e7d93956 | aurel32 | if (val == 0) { |
248 | e7d93956 | aurel32 | if (s->scancode_set == 1) |
249 | e7d93956 | aurel32 | ps2_put_keycode(s, 0x43);
|
250 | e7d93956 | aurel32 | else if (s->scancode_set == 2) |
251 | e7d93956 | aurel32 | ps2_put_keycode(s, 0x41);
|
252 | e7d93956 | aurel32 | else if (s->scancode_set == 3) |
253 | e7d93956 | aurel32 | ps2_put_keycode(s, 0x3f);
|
254 | e7d93956 | aurel32 | } else {
|
255 | e7d93956 | aurel32 | if (val >= 1 && val <= 3) |
256 | e7d93956 | aurel32 | s->scancode_set = val; |
257 | e7d93956 | aurel32 | ps2_queue(&s->common, KBD_REPLY_ACK); |
258 | e7d93956 | aurel32 | } |
259 | e7d93956 | aurel32 | s->common.write_cmd = -1;
|
260 | e7d93956 | aurel32 | break;
|
261 | 0e43e99c | bellard | case KBD_CMD_SET_LEDS:
|
262 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
263 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
264 | 0e43e99c | bellard | break;
|
265 | 0e43e99c | bellard | case KBD_CMD_SET_RATE:
|
266 | 0e43e99c | bellard | ps2_queue(&s->common, KBD_REPLY_ACK); |
267 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
268 | 0e43e99c | bellard | break;
|
269 | 0e43e99c | bellard | } |
270 | 0e43e99c | bellard | } |
271 | 0e43e99c | bellard | |
272 | f94f5d71 | pbrook | /* Set the scancode translation mode.
|
273 | f94f5d71 | pbrook | 0 = raw scancodes.
|
274 | f94f5d71 | pbrook | 1 = translated scancodes (used by qemu internally). */
|
275 | f94f5d71 | pbrook | |
276 | f94f5d71 | pbrook | void ps2_keyboard_set_translation(void *opaque, int mode) |
277 | f94f5d71 | pbrook | { |
278 | f94f5d71 | pbrook | PS2KbdState *s = (PS2KbdState *)opaque; |
279 | f94f5d71 | pbrook | s->translate = mode; |
280 | f94f5d71 | pbrook | } |
281 | f94f5d71 | pbrook | |
282 | 0e43e99c | bellard | static void ps2_mouse_send_packet(PS2MouseState *s) |
283 | 0e43e99c | bellard | { |
284 | 0e43e99c | bellard | unsigned int b; |
285 | 0e43e99c | bellard | int dx1, dy1, dz1;
|
286 | 0e43e99c | bellard | |
287 | 0e43e99c | bellard | dx1 = s->mouse_dx; |
288 | 0e43e99c | bellard | dy1 = s->mouse_dy; |
289 | 0e43e99c | bellard | dz1 = s->mouse_dz; |
290 | 0e43e99c | bellard | /* XXX: increase range to 8 bits ? */
|
291 | 0e43e99c | bellard | if (dx1 > 127) |
292 | 0e43e99c | bellard | dx1 = 127;
|
293 | 0e43e99c | bellard | else if (dx1 < -127) |
294 | 0e43e99c | bellard | dx1 = -127;
|
295 | 0e43e99c | bellard | if (dy1 > 127) |
296 | 0e43e99c | bellard | dy1 = 127;
|
297 | 0e43e99c | bellard | else if (dy1 < -127) |
298 | 0e43e99c | bellard | dy1 = -127;
|
299 | 0e43e99c | bellard | b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); |
300 | 0e43e99c | bellard | ps2_queue(&s->common, b); |
301 | 0e43e99c | bellard | ps2_queue(&s->common, dx1 & 0xff);
|
302 | 0e43e99c | bellard | ps2_queue(&s->common, dy1 & 0xff);
|
303 | 0e43e99c | bellard | /* extra byte for IMPS/2 or IMEX */
|
304 | 0e43e99c | bellard | switch(s->mouse_type) {
|
305 | 0e43e99c | bellard | default:
|
306 | 0e43e99c | bellard | break;
|
307 | 0e43e99c | bellard | case 3: |
308 | 0e43e99c | bellard | if (dz1 > 127) |
309 | 0e43e99c | bellard | dz1 = 127;
|
310 | 0e43e99c | bellard | else if (dz1 < -127) |
311 | 0e43e99c | bellard | dz1 = -127;
|
312 | 0e43e99c | bellard | ps2_queue(&s->common, dz1 & 0xff);
|
313 | 0e43e99c | bellard | break;
|
314 | 0e43e99c | bellard | case 4: |
315 | 0e43e99c | bellard | if (dz1 > 7) |
316 | 0e43e99c | bellard | dz1 = 7;
|
317 | 0e43e99c | bellard | else if (dz1 < -7) |
318 | 0e43e99c | bellard | dz1 = -7;
|
319 | 0e43e99c | bellard | b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); |
320 | 0e43e99c | bellard | ps2_queue(&s->common, b); |
321 | 0e43e99c | bellard | break;
|
322 | 0e43e99c | bellard | } |
323 | 0e43e99c | bellard | |
324 | 0e43e99c | bellard | /* update deltas */
|
325 | 0e43e99c | bellard | s->mouse_dx -= dx1; |
326 | 0e43e99c | bellard | s->mouse_dy -= dy1; |
327 | 0e43e99c | bellard | s->mouse_dz -= dz1; |
328 | 0e43e99c | bellard | } |
329 | 0e43e99c | bellard | |
330 | 5fafdf24 | ths | static void ps2_mouse_event(void *opaque, |
331 | 0e43e99c | bellard | int dx, int dy, int dz, int buttons_state) |
332 | 0e43e99c | bellard | { |
333 | 0e43e99c | bellard | PS2MouseState *s = opaque; |
334 | 0e43e99c | bellard | |
335 | 0e43e99c | bellard | /* check if deltas are recorded when disabled */
|
336 | 0e43e99c | bellard | if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
|
337 | 0e43e99c | bellard | return;
|
338 | 0e43e99c | bellard | |
339 | 0e43e99c | bellard | s->mouse_dx += dx; |
340 | 0e43e99c | bellard | s->mouse_dy -= dy; |
341 | 0e43e99c | bellard | s->mouse_dz += dz; |
342 | 0e43e99c | bellard | /* XXX: SDL sometimes generates nul events: we delete them */
|
343 | 0e43e99c | bellard | if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && |
344 | 0e43e99c | bellard | s->mouse_buttons == buttons_state) |
345 | 0e43e99c | bellard | return;
|
346 | 0e43e99c | bellard | s->mouse_buttons = buttons_state; |
347 | 3b46e624 | ths | |
348 | 0e43e99c | bellard | if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
|
349 | 0e43e99c | bellard | (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
|
350 | 0e43e99c | bellard | for(;;) {
|
351 | 0e43e99c | bellard | /* if not remote, send event. Multiple events are sent if
|
352 | 0e43e99c | bellard | too big deltas */
|
353 | 0e43e99c | bellard | ps2_mouse_send_packet(s); |
354 | 0e43e99c | bellard | if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) |
355 | 0e43e99c | bellard | break;
|
356 | 0e43e99c | bellard | } |
357 | 0e43e99c | bellard | } |
358 | 0e43e99c | bellard | } |
359 | 0e43e99c | bellard | |
360 | 548df2ac | ths | void ps2_mouse_fake_event(void *opaque) |
361 | 548df2ac | ths | { |
362 | 548df2ac | ths | ps2_mouse_event(opaque, 1, 0, 0, 0); |
363 | 548df2ac | ths | } |
364 | 548df2ac | ths | |
365 | 0e43e99c | bellard | void ps2_write_mouse(void *opaque, int val) |
366 | 0e43e99c | bellard | { |
367 | 0e43e99c | bellard | PS2MouseState *s = (PS2MouseState *)opaque; |
368 | 0e43e99c | bellard | #ifdef DEBUG_MOUSE
|
369 | 0e43e99c | bellard | printf("kbd: write mouse 0x%02x\n", val);
|
370 | 0e43e99c | bellard | #endif
|
371 | 0e43e99c | bellard | switch(s->common.write_cmd) {
|
372 | 0e43e99c | bellard | default:
|
373 | 0e43e99c | bellard | case -1: |
374 | 0e43e99c | bellard | /* mouse command */
|
375 | 0e43e99c | bellard | if (s->mouse_wrap) {
|
376 | 0e43e99c | bellard | if (val == AUX_RESET_WRAP) {
|
377 | 0e43e99c | bellard | s->mouse_wrap = 0;
|
378 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
379 | 0e43e99c | bellard | return;
|
380 | 0e43e99c | bellard | } else if (val != AUX_RESET) { |
381 | 0e43e99c | bellard | ps2_queue(&s->common, val); |
382 | 0e43e99c | bellard | return;
|
383 | 0e43e99c | bellard | } |
384 | 0e43e99c | bellard | } |
385 | 0e43e99c | bellard | switch(val) {
|
386 | 0e43e99c | bellard | case AUX_SET_SCALE11:
|
387 | 0e43e99c | bellard | s->mouse_status &= ~MOUSE_STATUS_SCALE21; |
388 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
389 | 0e43e99c | bellard | break;
|
390 | 0e43e99c | bellard | case AUX_SET_SCALE21:
|
391 | 0e43e99c | bellard | s->mouse_status |= MOUSE_STATUS_SCALE21; |
392 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
393 | 0e43e99c | bellard | break;
|
394 | 0e43e99c | bellard | case AUX_SET_STREAM:
|
395 | 0e43e99c | bellard | s->mouse_status &= ~MOUSE_STATUS_REMOTE; |
396 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
397 | 0e43e99c | bellard | break;
|
398 | 0e43e99c | bellard | case AUX_SET_WRAP:
|
399 | 0e43e99c | bellard | s->mouse_wrap = 1;
|
400 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
401 | 0e43e99c | bellard | break;
|
402 | 0e43e99c | bellard | case AUX_SET_REMOTE:
|
403 | 0e43e99c | bellard | s->mouse_status |= MOUSE_STATUS_REMOTE; |
404 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
405 | 0e43e99c | bellard | break;
|
406 | 0e43e99c | bellard | case AUX_GET_TYPE:
|
407 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
408 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_type); |
409 | 0e43e99c | bellard | break;
|
410 | 0e43e99c | bellard | case AUX_SET_RES:
|
411 | 0e43e99c | bellard | case AUX_SET_SAMPLE:
|
412 | 0e43e99c | bellard | s->common.write_cmd = val; |
413 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
414 | 0e43e99c | bellard | break;
|
415 | 0e43e99c | bellard | case AUX_GET_SCALE:
|
416 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
417 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_status); |
418 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_resolution); |
419 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_sample_rate); |
420 | 0e43e99c | bellard | break;
|
421 | 0e43e99c | bellard | case AUX_POLL:
|
422 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
423 | 0e43e99c | bellard | ps2_mouse_send_packet(s); |
424 | 0e43e99c | bellard | break;
|
425 | 0e43e99c | bellard | case AUX_ENABLE_DEV:
|
426 | 0e43e99c | bellard | s->mouse_status |= MOUSE_STATUS_ENABLED; |
427 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
428 | 0e43e99c | bellard | break;
|
429 | 0e43e99c | bellard | case AUX_DISABLE_DEV:
|
430 | 0e43e99c | bellard | s->mouse_status &= ~MOUSE_STATUS_ENABLED; |
431 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
432 | 0e43e99c | bellard | break;
|
433 | 0e43e99c | bellard | case AUX_SET_DEFAULT:
|
434 | 0e43e99c | bellard | s->mouse_sample_rate = 100;
|
435 | 0e43e99c | bellard | s->mouse_resolution = 2;
|
436 | 0e43e99c | bellard | s->mouse_status = 0;
|
437 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
438 | 0e43e99c | bellard | break;
|
439 | 0e43e99c | bellard | case AUX_RESET:
|
440 | 0e43e99c | bellard | s->mouse_sample_rate = 100;
|
441 | 0e43e99c | bellard | s->mouse_resolution = 2;
|
442 | 0e43e99c | bellard | s->mouse_status = 0;
|
443 | 0e43e99c | bellard | s->mouse_type = 0;
|
444 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
445 | 0e43e99c | bellard | ps2_queue(&s->common, 0xaa);
|
446 | 0e43e99c | bellard | ps2_queue(&s->common, s->mouse_type); |
447 | 0e43e99c | bellard | break;
|
448 | 0e43e99c | bellard | default:
|
449 | 0e43e99c | bellard | break;
|
450 | 0e43e99c | bellard | } |
451 | 0e43e99c | bellard | break;
|
452 | 0e43e99c | bellard | case AUX_SET_SAMPLE:
|
453 | 0e43e99c | bellard | s->mouse_sample_rate = val; |
454 | 0e43e99c | bellard | /* detect IMPS/2 or IMEX */
|
455 | 0e43e99c | bellard | switch(s->mouse_detect_state) {
|
456 | 0e43e99c | bellard | default:
|
457 | 0e43e99c | bellard | case 0: |
458 | 0e43e99c | bellard | if (val == 200) |
459 | 0e43e99c | bellard | s->mouse_detect_state = 1;
|
460 | 0e43e99c | bellard | break;
|
461 | 0e43e99c | bellard | case 1: |
462 | 0e43e99c | bellard | if (val == 100) |
463 | 0e43e99c | bellard | s->mouse_detect_state = 2;
|
464 | 0e43e99c | bellard | else if (val == 200) |
465 | 0e43e99c | bellard | s->mouse_detect_state = 3;
|
466 | 0e43e99c | bellard | else
|
467 | 0e43e99c | bellard | s->mouse_detect_state = 0;
|
468 | 0e43e99c | bellard | break;
|
469 | 0e43e99c | bellard | case 2: |
470 | 5fafdf24 | ths | if (val == 80) |
471 | 0e43e99c | bellard | s->mouse_type = 3; /* IMPS/2 */ |
472 | 0e43e99c | bellard | s->mouse_detect_state = 0;
|
473 | 0e43e99c | bellard | break;
|
474 | 0e43e99c | bellard | case 3: |
475 | 5fafdf24 | ths | if (val == 80) |
476 | 0e43e99c | bellard | s->mouse_type = 4; /* IMEX */ |
477 | 0e43e99c | bellard | s->mouse_detect_state = 0;
|
478 | 0e43e99c | bellard | break;
|
479 | 0e43e99c | bellard | } |
480 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
481 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
482 | 0e43e99c | bellard | break;
|
483 | 0e43e99c | bellard | case AUX_SET_RES:
|
484 | 0e43e99c | bellard | s->mouse_resolution = val; |
485 | 0e43e99c | bellard | ps2_queue(&s->common, AUX_ACK); |
486 | 0e43e99c | bellard | s->common.write_cmd = -1;
|
487 | 0e43e99c | bellard | break;
|
488 | 0e43e99c | bellard | } |
489 | 0e43e99c | bellard | } |
490 | 0e43e99c | bellard | |
491 | ef74679a | Dinesh Subhraveti | static void ps2_common_reset(PS2State *s) |
492 | 0e43e99c | bellard | { |
493 | 0e43e99c | bellard | PS2Queue *q; |
494 | 0e43e99c | bellard | s->write_cmd = -1;
|
495 | 0e43e99c | bellard | q = &s->queue; |
496 | 0e43e99c | bellard | q->rptr = 0;
|
497 | 0e43e99c | bellard | q->wptr = 0;
|
498 | 0e43e99c | bellard | q->count = 0;
|
499 | deeccef3 | aliguori | s->update_irq(s->update_arg, 0);
|
500 | 0e43e99c | bellard | } |
501 | 0e43e99c | bellard | |
502 | ef74679a | Dinesh Subhraveti | static void ps2_kbd_reset(void *opaque) |
503 | ef74679a | Dinesh Subhraveti | { |
504 | ef74679a | Dinesh Subhraveti | PS2KbdState *s = (PS2KbdState *) opaque; |
505 | ef74679a | Dinesh Subhraveti | |
506 | ef74679a | Dinesh Subhraveti | ps2_common_reset(&s->common); |
507 | ef74679a | Dinesh Subhraveti | s->scan_enabled = 0;
|
508 | ef74679a | Dinesh Subhraveti | s->translate = 0;
|
509 | ef74679a | Dinesh Subhraveti | s->scancode_set = 0;
|
510 | ef74679a | Dinesh Subhraveti | } |
511 | ef74679a | Dinesh Subhraveti | |
512 | ef74679a | Dinesh Subhraveti | static void ps2_mouse_reset(void *opaque) |
513 | ef74679a | Dinesh Subhraveti | { |
514 | ef74679a | Dinesh Subhraveti | PS2MouseState *s = (PS2MouseState *) opaque; |
515 | ef74679a | Dinesh Subhraveti | |
516 | ef74679a | Dinesh Subhraveti | ps2_common_reset(&s->common); |
517 | ef74679a | Dinesh Subhraveti | s->mouse_status = 0;
|
518 | ef74679a | Dinesh Subhraveti | s->mouse_resolution = 0;
|
519 | ef74679a | Dinesh Subhraveti | s->mouse_sample_rate = 0;
|
520 | ef74679a | Dinesh Subhraveti | s->mouse_wrap = 0;
|
521 | ef74679a | Dinesh Subhraveti | s->mouse_type = 0;
|
522 | ef74679a | Dinesh Subhraveti | s->mouse_detect_state = 0;
|
523 | ef74679a | Dinesh Subhraveti | s->mouse_dx = 0;
|
524 | ef74679a | Dinesh Subhraveti | s->mouse_dy = 0;
|
525 | ef74679a | Dinesh Subhraveti | s->mouse_dz = 0;
|
526 | ef74679a | Dinesh Subhraveti | s->mouse_buttons = 0;
|
527 | ef74679a | Dinesh Subhraveti | } |
528 | ef74679a | Dinesh Subhraveti | |
529 | b31442c3 | Juan Quintela | static const VMStateDescription vmstate_ps2_common = { |
530 | b31442c3 | Juan Quintela | .name = "PS2 Common State",
|
531 | b31442c3 | Juan Quintela | .version_id = 3,
|
532 | b31442c3 | Juan Quintela | .minimum_version_id = 2,
|
533 | b31442c3 | Juan Quintela | .minimum_version_id_old = 2,
|
534 | b31442c3 | Juan Quintela | .fields = (VMStateField []) { |
535 | b31442c3 | Juan Quintela | VMSTATE_INT32(write_cmd, PS2State), |
536 | b31442c3 | Juan Quintela | VMSTATE_INT32(queue.rptr, PS2State), |
537 | b31442c3 | Juan Quintela | VMSTATE_INT32(queue.wptr, PS2State), |
538 | b31442c3 | Juan Quintela | VMSTATE_INT32(queue.count, PS2State), |
539 | b31442c3 | Juan Quintela | VMSTATE_BUFFER(queue.data, PS2State), |
540 | b31442c3 | Juan Quintela | VMSTATE_END_OF_LIST() |
541 | b31442c3 | Juan Quintela | } |
542 | b31442c3 | Juan Quintela | }; |
543 | 0e43e99c | bellard | |
544 | db596c53 | Juan Quintela | static int ps2_kbd_post_load(void* opaque, int version_id) |
545 | 0e43e99c | bellard | { |
546 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState*)opaque; |
547 | 7783e9f0 | pbrook | |
548 | db596c53 | Juan Quintela | if (version_id == 2) |
549 | e7d93956 | aurel32 | s->scancode_set=2;
|
550 | 0e43e99c | bellard | return 0; |
551 | 0e43e99c | bellard | } |
552 | 0e43e99c | bellard | |
553 | b31442c3 | Juan Quintela | static const VMStateDescription vmstate_ps2_keyboard = { |
554 | b31442c3 | Juan Quintela | .name = "ps2kbd",
|
555 | b31442c3 | Juan Quintela | .version_id = 3,
|
556 | db596c53 | Juan Quintela | .minimum_version_id = 2,
|
557 | b31442c3 | Juan Quintela | .minimum_version_id_old = 2,
|
558 | db596c53 | Juan Quintela | .post_load = ps2_kbd_post_load, |
559 | b31442c3 | Juan Quintela | .fields = (VMStateField []) { |
560 | b31442c3 | Juan Quintela | VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
|
561 | b31442c3 | Juan Quintela | VMSTATE_INT32(scan_enabled, PS2KbdState), |
562 | b31442c3 | Juan Quintela | VMSTATE_INT32(translate, PS2KbdState), |
563 | b31442c3 | Juan Quintela | VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
|
564 | b31442c3 | Juan Quintela | VMSTATE_END_OF_LIST() |
565 | b31442c3 | Juan Quintela | } |
566 | b31442c3 | Juan Quintela | }; |
567 | 7783e9f0 | pbrook | |
568 | b31442c3 | Juan Quintela | static const VMStateDescription vmstate_ps2_mouse = { |
569 | b31442c3 | Juan Quintela | .name = "ps2mouse",
|
570 | b31442c3 | Juan Quintela | .version_id = 2,
|
571 | b31442c3 | Juan Quintela | .minimum_version_id = 2,
|
572 | b31442c3 | Juan Quintela | .minimum_version_id_old = 2,
|
573 | b31442c3 | Juan Quintela | .fields = (VMStateField []) { |
574 | b31442c3 | Juan Quintela | VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
|
575 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_status, PS2MouseState), |
576 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_resolution, PS2MouseState), |
577 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), |
578 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_wrap, PS2MouseState), |
579 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_type, PS2MouseState), |
580 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_detect_state, PS2MouseState), |
581 | b31442c3 | Juan Quintela | VMSTATE_INT32(mouse_dx, PS2MouseState), |
582 | b31442c3 | Juan Quintela | VMSTATE_INT32(mouse_dy, PS2MouseState), |
583 | b31442c3 | Juan Quintela | VMSTATE_INT32(mouse_dz, PS2MouseState), |
584 | b31442c3 | Juan Quintela | VMSTATE_UINT8(mouse_buttons, PS2MouseState), |
585 | b31442c3 | Juan Quintela | VMSTATE_END_OF_LIST() |
586 | b31442c3 | Juan Quintela | } |
587 | b31442c3 | Juan Quintela | }; |
588 | 0e43e99c | bellard | |
589 | 0e43e99c | bellard | void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) |
590 | 0e43e99c | bellard | { |
591 | 0e43e99c | bellard | PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
|
592 | 0e43e99c | bellard | |
593 | 0e43e99c | bellard | s->common.update_irq = update_irq; |
594 | 0e43e99c | bellard | s->common.update_arg = update_arg; |
595 | e7d93956 | aurel32 | s->scancode_set = 2;
|
596 | b31442c3 | Juan Quintela | vmstate_register(0, &vmstate_ps2_keyboard, s);
|
597 | 0e43e99c | bellard | qemu_add_kbd_event_handler(ps2_put_keycode, s); |
598 | ef74679a | Dinesh Subhraveti | qemu_register_reset(ps2_kbd_reset, s); |
599 | 0e43e99c | bellard | return s;
|
600 | 0e43e99c | bellard | } |
601 | 0e43e99c | bellard | |
602 | 0e43e99c | bellard | void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) |
603 | 0e43e99c | bellard | { |
604 | 0e43e99c | bellard | PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
|
605 | 0e43e99c | bellard | |
606 | 0e43e99c | bellard | s->common.update_irq = update_irq; |
607 | 0e43e99c | bellard | s->common.update_arg = update_arg; |
608 | b31442c3 | Juan Quintela | vmstate_register(0, &vmstate_ps2_mouse, s);
|
609 | 455204eb | ths | qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse"); |
610 | ef74679a | Dinesh Subhraveti | qemu_register_reset(ps2_mouse_reset, s); |
611 | 0e43e99c | bellard | return s;
|
612 | 0e43e99c | bellard | } |