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