xref: /qemu/hw/input/ps2.c (revision 57d5c005d35dc6d6d7e15a6b8c4d9ea16a7c738d)
10e43e99cSbellard /*
20e43e99cSbellard  * QEMU PS/2 keyboard/mouse emulation
30e43e99cSbellard  *
40e43e99cSbellard  * Copyright (c) 2003 Fabrice Bellard
50e43e99cSbellard  *
60e43e99cSbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
70e43e99cSbellard  * of this software and associated documentation files (the "Software"), to deal
80e43e99cSbellard  * in the Software without restriction, including without limitation the rights
90e43e99cSbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100e43e99cSbellard  * copies of the Software, and to permit persons to whom the Software is
110e43e99cSbellard  * furnished to do so, subject to the following conditions:
120e43e99cSbellard  *
130e43e99cSbellard  * The above copyright notice and this permission notice shall be included in
140e43e99cSbellard  * all copies or substantial portions of the Software.
150e43e99cSbellard  *
160e43e99cSbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170e43e99cSbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180e43e99cSbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
190e43e99cSbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200e43e99cSbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210e43e99cSbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
220e43e99cSbellard  * THE SOFTWARE.
230e43e99cSbellard  */
240430891cSPeter Maydell #include "qemu/osdep.h"
2583c9f4caSPaolo Bonzini #include "hw/hw.h"
260d09e41aSPaolo Bonzini #include "hw/input/ps2.h"
2728ecbaeeSPaolo Bonzini #include "ui/console.h"
2866e6536eSGerd Hoffmann #include "ui/input.h"
299c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
300e43e99cSbellard 
315edab03dSDon Koch #include "trace.h"
325edab03dSDon Koch 
330e43e99cSbellard /* debug PC keyboard */
340e43e99cSbellard //#define DEBUG_KBD
350e43e99cSbellard 
360e43e99cSbellard /* debug PC keyboard : only mouse */
370e43e99cSbellard //#define DEBUG_MOUSE
380e43e99cSbellard 
390e43e99cSbellard /* Keyboard Commands */
400e43e99cSbellard #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
410e43e99cSbellard #define KBD_CMD_ECHO     	0xEE
42e7d93956Saurel32 #define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
430e43e99cSbellard #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
440e43e99cSbellard #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
450e43e99cSbellard #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
460e43e99cSbellard #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
470e43e99cSbellard #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
480e43e99cSbellard #define KBD_CMD_RESET		0xFF	/* Reset */
490e43e99cSbellard 
500e43e99cSbellard /* Keyboard Replies */
510e43e99cSbellard #define KBD_REPLY_POR		0xAA	/* Power on reset */
5235c4d671Saurel32 #define KBD_REPLY_ID		0xAB	/* Keyboard ID */
530e43e99cSbellard #define KBD_REPLY_ACK		0xFA	/* Command ACK */
540e43e99cSbellard #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
550e43e99cSbellard 
560e43e99cSbellard /* Mouse Commands */
570e43e99cSbellard #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
580e43e99cSbellard #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
590e43e99cSbellard #define AUX_SET_RES		0xE8	/* Set resolution */
600e43e99cSbellard #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
610e43e99cSbellard #define AUX_SET_STREAM		0xEA	/* Set stream mode */
620e43e99cSbellard #define AUX_POLL		0xEB	/* Poll */
630e43e99cSbellard #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
640e43e99cSbellard #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
650e43e99cSbellard #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
660e43e99cSbellard #define AUX_GET_TYPE		0xF2	/* Get type */
670e43e99cSbellard #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
680e43e99cSbellard #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
690e43e99cSbellard #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
700e43e99cSbellard #define AUX_SET_DEFAULT		0xF6
710e43e99cSbellard #define AUX_RESET		0xFF	/* Reset aux device */
720e43e99cSbellard #define AUX_ACK			0xFA	/* Command byte ACK. */
730e43e99cSbellard 
740e43e99cSbellard #define MOUSE_STATUS_REMOTE     0x40
750e43e99cSbellard #define MOUSE_STATUS_ENABLED    0x20
760e43e99cSbellard #define MOUSE_STATUS_SCALE21    0x10
770e43e99cSbellard 
782858ab09SGonglei #define PS2_QUEUE_SIZE 16  /* Buffer size required by PS/2 protocol */
790e43e99cSbellard 
800e43e99cSbellard typedef struct {
812858ab09SGonglei     /* Keep the data array 256 bytes long, which compatibility
822858ab09SGonglei      with older qemu versions. */
832858ab09SGonglei     uint8_t data[256];
840e43e99cSbellard     int rptr, wptr, count;
850e43e99cSbellard } PS2Queue;
860e43e99cSbellard 
870e43e99cSbellard typedef struct {
880e43e99cSbellard     PS2Queue queue;
890e43e99cSbellard     int32_t write_cmd;
900e43e99cSbellard     void (*update_irq)(void *, int);
910e43e99cSbellard     void *update_arg;
920e43e99cSbellard } PS2State;
930e43e99cSbellard 
940e43e99cSbellard typedef struct {
950e43e99cSbellard     PS2State common;
960e43e99cSbellard     int scan_enabled;
97f94f5d71Spbrook     int translate;
98e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
997f540ab5SChristophe Fergeau     int ledstate;
100*57d5c005SHervé Poussineau     bool need_high_bit;
1010e43e99cSbellard } PS2KbdState;
1020e43e99cSbellard 
1030e43e99cSbellard typedef struct {
1040e43e99cSbellard     PS2State common;
1050e43e99cSbellard     uint8_t mouse_status;
1060e43e99cSbellard     uint8_t mouse_resolution;
1070e43e99cSbellard     uint8_t mouse_sample_rate;
1080e43e99cSbellard     uint8_t mouse_wrap;
1090e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1100e43e99cSbellard     uint8_t mouse_detect_state;
1110e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1120e43e99cSbellard     int mouse_dy;
1130e43e99cSbellard     int mouse_dz;
1140e43e99cSbellard     uint8_t mouse_buttons;
1150e43e99cSbellard } PS2MouseState;
1160e43e99cSbellard 
117f94f5d71Spbrook /* Table to convert from PC scancodes to raw scancodes.  */
118f94f5d71Spbrook static const unsigned char ps2_raw_keycode[128] = {
119f94f5d71Spbrook   0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
120f94f5d71Spbrook  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
121f94f5d71Spbrook  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
122f94f5d71Spbrook  50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
123f94f5d71Spbrook  11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
124f94f5d71Spbrook 114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
125f94f5d71Spbrook  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
126f94f5d71Spbrook  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
127f94f5d71Spbrook };
1287096a96dSRoy Tam static const unsigned char ps2_raw_keycode_set3[128] = {
1297096a96dSRoy Tam   0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
1307096a96dSRoy Tam  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
1317096a96dSRoy Tam  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
1327096a96dSRoy Tam  50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
1337096a96dSRoy Tam  47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
1347096a96dSRoy Tam 114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
1357096a96dSRoy Tam  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
1367096a96dSRoy Tam  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
1377096a96dSRoy Tam };
138f94f5d71Spbrook 
139*57d5c005SHervé Poussineau static uint8_t translate_table[256] = {
140*57d5c005SHervé Poussineau     0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
141*57d5c005SHervé Poussineau     0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
142*57d5c005SHervé Poussineau     0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
143*57d5c005SHervé Poussineau     0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
144*57d5c005SHervé Poussineau     0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
145*57d5c005SHervé Poussineau     0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
146*57d5c005SHervé Poussineau     0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
147*57d5c005SHervé Poussineau     0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
148*57d5c005SHervé Poussineau     0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
149*57d5c005SHervé Poussineau     0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
150*57d5c005SHervé Poussineau     0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
151*57d5c005SHervé Poussineau     0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
152*57d5c005SHervé Poussineau     0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
153*57d5c005SHervé Poussineau     0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
154*57d5c005SHervé Poussineau     0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
155*57d5c005SHervé Poussineau     0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
156*57d5c005SHervé Poussineau     0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
157*57d5c005SHervé Poussineau     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
158*57d5c005SHervé Poussineau     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
159*57d5c005SHervé Poussineau     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
160*57d5c005SHervé Poussineau     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
161*57d5c005SHervé Poussineau     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
162*57d5c005SHervé Poussineau     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
163*57d5c005SHervé Poussineau     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
164*57d5c005SHervé Poussineau     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
165*57d5c005SHervé Poussineau     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
166*57d5c005SHervé Poussineau     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
167*57d5c005SHervé Poussineau     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
168*57d5c005SHervé Poussineau     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
169*57d5c005SHervé Poussineau     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
170*57d5c005SHervé Poussineau     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
171*57d5c005SHervé Poussineau     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
172*57d5c005SHervé Poussineau };
173*57d5c005SHervé Poussineau 
1740e43e99cSbellard void ps2_queue(void *opaque, int b)
1750e43e99cSbellard {
1760e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1770e43e99cSbellard     PS2Queue *q = &s->queue;
1780e43e99cSbellard 
1792858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
1800e43e99cSbellard         return;
1810e43e99cSbellard     q->data[q->wptr] = b;
1820e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
1830e43e99cSbellard         q->wptr = 0;
1840e43e99cSbellard     q->count++;
1850e43e99cSbellard     s->update_irq(s->update_arg, 1);
1860e43e99cSbellard }
1870e43e99cSbellard 
188*57d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */
1890e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
1900e43e99cSbellard {
191f94f5d71Spbrook     PS2KbdState *s = opaque;
192e7d93956Saurel32 
1935edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
194fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
195*57d5c005SHervé Poussineau 
196*57d5c005SHervé Poussineau     if (s->translate) {
197*57d5c005SHervé Poussineau         if (keycode == 0xf0) {
198*57d5c005SHervé Poussineau             s->need_high_bit = true;
199*57d5c005SHervé Poussineau         } else if (s->need_high_bit) {
200*57d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode] | 0x80);
201*57d5c005SHervé Poussineau             s->need_high_bit = false;
202*57d5c005SHervé Poussineau         } else {
203*57d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode]);
2047096a96dSRoy Tam         }
205*57d5c005SHervé Poussineau     } else {
2060e43e99cSbellard         ps2_queue(&s->common, keycode);
2070e43e99cSbellard     }
208*57d5c005SHervé Poussineau }
2090e43e99cSbellard 
21066e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
21166e6536eSGerd Hoffmann                                InputEvent *evt)
21266e6536eSGerd Hoffmann {
21366e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
21466e6536eSGerd Hoffmann     int scancodes[3], i, count;
21532bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
216*57d5c005SHervé Poussineau     int keycode;
21766e6536eSGerd Hoffmann 
21866e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
219b5a1b443SEric Blake     count = qemu_input_key_value_to_scancode(key->key,
220b5a1b443SEric Blake                                              key->down,
22166e6536eSGerd Hoffmann                                              scancodes);
222*57d5c005SHervé Poussineau 
223*57d5c005SHervé Poussineau     /* handle invalid key */
224*57d5c005SHervé Poussineau     if (count == 1 && scancodes[0] == 0x00) {
225*57d5c005SHervé Poussineau         ps2_queue(&s->common, 0x00);
226*57d5c005SHervé Poussineau         return;
227*57d5c005SHervé Poussineau     } else if (count == 1 && scancodes[0] == 0x80) {
228*57d5c005SHervé Poussineau         if (s->translate || s->scancode_set == 1) {
229*57d5c005SHervé Poussineau             ps2_queue(&s->common, 0x80);
230*57d5c005SHervé Poussineau         } else {
231*57d5c005SHervé Poussineau             ps2_queue(&s->common, 0xf0);
232*57d5c005SHervé Poussineau             ps2_queue(&s->common, 0x00);
233*57d5c005SHervé Poussineau         }
234*57d5c005SHervé Poussineau         return;
235*57d5c005SHervé Poussineau     }
236*57d5c005SHervé Poussineau 
23766e6536eSGerd Hoffmann     for (i = 0; i < count; i++) {
238*57d5c005SHervé Poussineau         /* XXX: add support for scancode set 1 */
239*57d5c005SHervé Poussineau         keycode = scancodes[i];
240*57d5c005SHervé Poussineau         if (keycode < 0xe0 && (s->scancode_set > 1 || s->translate)) {
241*57d5c005SHervé Poussineau             if (keycode & 0x80) {
242*57d5c005SHervé Poussineau                 ps2_put_keycode(&s->common, 0xf0);
243*57d5c005SHervé Poussineau             }
244*57d5c005SHervé Poussineau             if (s->scancode_set == 1 || s->scancode_set == 2) {
245*57d5c005SHervé Poussineau                 keycode = ps2_raw_keycode[keycode & 0x7f];
246*57d5c005SHervé Poussineau             } else if (s->scancode_set == 3) {
247*57d5c005SHervé Poussineau                 keycode = ps2_raw_keycode_set3[keycode & 0x7f];
248*57d5c005SHervé Poussineau             }
249*57d5c005SHervé Poussineau         }
250*57d5c005SHervé Poussineau         ps2_put_keycode(s, keycode);
25166e6536eSGerd Hoffmann     }
25266e6536eSGerd Hoffmann }
25366e6536eSGerd Hoffmann 
2540e43e99cSbellard uint32_t ps2_read_data(void *opaque)
2550e43e99cSbellard {
2560e43e99cSbellard     PS2State *s = (PS2State *)opaque;
2570e43e99cSbellard     PS2Queue *q;
2580e43e99cSbellard     int val, index;
2590e43e99cSbellard 
2605edab03dSDon Koch     trace_ps2_read_data(opaque);
2610e43e99cSbellard     q = &s->queue;
2620e43e99cSbellard     if (q->count == 0) {
2630e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
2640e43e99cSbellard            (needed for EMM386) */
2650e43e99cSbellard         /* XXX: need a timer to do things correctly */
2660e43e99cSbellard         index = q->rptr - 1;
2670e43e99cSbellard         if (index < 0)
2680e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
2690e43e99cSbellard         val = q->data[index];
2700e43e99cSbellard     } else {
2710e43e99cSbellard         val = q->data[q->rptr];
2720e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
2730e43e99cSbellard             q->rptr = 0;
2740e43e99cSbellard         q->count--;
2750e43e99cSbellard         /* reading deasserts IRQ */
2760e43e99cSbellard         s->update_irq(s->update_arg, 0);
2770e43e99cSbellard         /* reassert IRQs if data left */
2780e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
2790e43e99cSbellard     }
2800e43e99cSbellard     return val;
2810e43e99cSbellard }
2820e43e99cSbellard 
2837f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
2847f540ab5SChristophe Fergeau {
2855edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
2867f540ab5SChristophe Fergeau     s->ledstate = ledstate;
2877f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
2887f540ab5SChristophe Fergeau }
2897f540ab5SChristophe Fergeau 
2900e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
2910e43e99cSbellard {
2925edab03dSDon Koch     trace_ps2_reset_keyboard(s);
2930e43e99cSbellard     s->scan_enabled = 1;
294e7d93956Saurel32     s->scancode_set = 2;
2957f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
2960e43e99cSbellard }
2970e43e99cSbellard 
2980e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
2990e43e99cSbellard {
3000e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
3010e43e99cSbellard 
3025edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
3030e43e99cSbellard     switch(s->common.write_cmd) {
3040e43e99cSbellard     default:
3050e43e99cSbellard     case -1:
3060e43e99cSbellard         switch(val) {
3070e43e99cSbellard         case 0x00:
3080e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
3090e43e99cSbellard             break;
3100e43e99cSbellard         case 0x05:
3110e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
3120e43e99cSbellard             break;
3130e43e99cSbellard         case KBD_CMD_GET_ID:
3140e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
315e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
31635c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
31735c4d671Saurel32             if (s->translate)
31835c4d671Saurel32                 ps2_queue(&s->common, 0x41);
31935c4d671Saurel32             else
32035c4d671Saurel32                 ps2_queue(&s->common, 0x83);
3210e43e99cSbellard             break;
3220e43e99cSbellard         case KBD_CMD_ECHO:
3230e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
3240e43e99cSbellard             break;
3250e43e99cSbellard         case KBD_CMD_ENABLE:
3260e43e99cSbellard             s->scan_enabled = 1;
3270e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
3280e43e99cSbellard             break;
329e7d93956Saurel32         case KBD_CMD_SCANCODE:
3300e43e99cSbellard         case KBD_CMD_SET_LEDS:
3310e43e99cSbellard         case KBD_CMD_SET_RATE:
3320e43e99cSbellard             s->common.write_cmd = val;
3330e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
3340e43e99cSbellard             break;
3350e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
3360e43e99cSbellard             ps2_reset_keyboard(s);
3370e43e99cSbellard             s->scan_enabled = 0;
3380e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
3390e43e99cSbellard             break;
3400e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
3410e43e99cSbellard             ps2_reset_keyboard(s);
3420e43e99cSbellard             s->scan_enabled = 1;
3430e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
3440e43e99cSbellard             break;
3450e43e99cSbellard         case KBD_CMD_RESET:
3460e43e99cSbellard             ps2_reset_keyboard(s);
3470e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
3480e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
3490e43e99cSbellard             break;
3500e43e99cSbellard         default:
35106b3611fSHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
3520e43e99cSbellard             break;
3530e43e99cSbellard         }
3540e43e99cSbellard         break;
355e7d93956Saurel32     case KBD_CMD_SCANCODE:
356e7d93956Saurel32         if (val == 0) {
3574df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_ACK);
358*57d5c005SHervé Poussineau             ps2_put_keycode(s, s->scancode_set);
3594df23b64SHervé Poussineau         } else if (val >= 1 && val <= 3) {
360e7d93956Saurel32             s->scancode_set = val;
361e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
3624df23b64SHervé Poussineau         } else {
3634df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
364e7d93956Saurel32         }
365e7d93956Saurel32         s->common.write_cmd = -1;
366e7d93956Saurel32         break;
3670e43e99cSbellard     case KBD_CMD_SET_LEDS:
3687f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
3690e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3700e43e99cSbellard         s->common.write_cmd = -1;
3710e43e99cSbellard         break;
3720e43e99cSbellard     case KBD_CMD_SET_RATE:
3730e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3740e43e99cSbellard         s->common.write_cmd = -1;
3750e43e99cSbellard         break;
3760e43e99cSbellard     }
3770e43e99cSbellard }
3780e43e99cSbellard 
379f94f5d71Spbrook /* Set the scancode translation mode.
380f94f5d71Spbrook    0 = raw scancodes.
381f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
382f94f5d71Spbrook 
383f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
384f94f5d71Spbrook {
385f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
3865edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
387f94f5d71Spbrook     s->translate = mode;
388f94f5d71Spbrook }
389f94f5d71Spbrook 
3900e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
3910e43e99cSbellard {
3920e43e99cSbellard     unsigned int b;
3930e43e99cSbellard     int dx1, dy1, dz1;
3940e43e99cSbellard 
3950e43e99cSbellard     dx1 = s->mouse_dx;
3960e43e99cSbellard     dy1 = s->mouse_dy;
3970e43e99cSbellard     dz1 = s->mouse_dz;
3980e43e99cSbellard     /* XXX: increase range to 8 bits ? */
3990e43e99cSbellard     if (dx1 > 127)
4000e43e99cSbellard         dx1 = 127;
4010e43e99cSbellard     else if (dx1 < -127)
4020e43e99cSbellard         dx1 = -127;
4030e43e99cSbellard     if (dy1 > 127)
4040e43e99cSbellard         dy1 = 127;
4050e43e99cSbellard     else if (dy1 < -127)
4060e43e99cSbellard         dy1 = -127;
4070e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
4080e43e99cSbellard     ps2_queue(&s->common, b);
4090e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
4100e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
4110e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
4120e43e99cSbellard     switch(s->mouse_type) {
4130e43e99cSbellard     default:
4140e43e99cSbellard         break;
4150e43e99cSbellard     case 3:
4160e43e99cSbellard         if (dz1 > 127)
4170e43e99cSbellard             dz1 = 127;
4180e43e99cSbellard         else if (dz1 < -127)
4190e43e99cSbellard                 dz1 = -127;
4200e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
4210e43e99cSbellard         break;
4220e43e99cSbellard     case 4:
4230e43e99cSbellard         if (dz1 > 7)
4240e43e99cSbellard             dz1 = 7;
4250e43e99cSbellard         else if (dz1 < -7)
4260e43e99cSbellard             dz1 = -7;
4270e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
4280e43e99cSbellard         ps2_queue(&s->common, b);
4290e43e99cSbellard         break;
4300e43e99cSbellard     }
4310e43e99cSbellard 
4325edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
4330e43e99cSbellard     /* update deltas */
4340e43e99cSbellard     s->mouse_dx -= dx1;
4350e43e99cSbellard     s->mouse_dy -= dy1;
4360e43e99cSbellard     s->mouse_dz -= dz1;
4370e43e99cSbellard }
4380e43e99cSbellard 
4392a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
4402a766d29SGerd Hoffmann                             InputEvent *evt)
4410e43e99cSbellard {
4427fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
4432a766d29SGerd Hoffmann         [INPUT_BUTTON_LEFT]   = MOUSE_EVENT_LBUTTON,
4442a766d29SGerd Hoffmann         [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
4452a766d29SGerd Hoffmann         [INPUT_BUTTON_RIGHT]  = MOUSE_EVENT_RBUTTON,
4462a766d29SGerd Hoffmann     };
4472a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
448b5a1b443SEric Blake     InputMoveEvent *move;
449b5a1b443SEric Blake     InputBtnEvent *btn;
4500e43e99cSbellard 
4510e43e99cSbellard     /* check if deltas are recorded when disabled */
4520e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
4530e43e99cSbellard         return;
4540e43e99cSbellard 
455568c73a4SEric Blake     switch (evt->type) {
4562a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
45732bafa8fSEric Blake         move = evt->u.rel.data;
458b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
459b5a1b443SEric Blake             s->mouse_dx += move->value;
460b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
461b5a1b443SEric Blake             s->mouse_dy -= move->value;
4622a766d29SGerd Hoffmann         }
4632a766d29SGerd Hoffmann         break;
4640e43e99cSbellard 
4652a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
46632bafa8fSEric Blake         btn = evt->u.btn.data;
467b5a1b443SEric Blake         if (btn->down) {
468b5a1b443SEric Blake             s->mouse_buttons |= bmap[btn->button];
469b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
4702a766d29SGerd Hoffmann                 s->mouse_dz--;
471b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
4722a766d29SGerd Hoffmann                 s->mouse_dz++;
4732a766d29SGerd Hoffmann             }
4742a766d29SGerd Hoffmann         } else {
475b5a1b443SEric Blake             s->mouse_buttons &= ~bmap[btn->button];
4762a766d29SGerd Hoffmann         }
4772a766d29SGerd Hoffmann         break;
4782a766d29SGerd Hoffmann 
4792a766d29SGerd Hoffmann     default:
4802a766d29SGerd Hoffmann         /* keep gcc happy */
4812a766d29SGerd Hoffmann         break;
4822a766d29SGerd Hoffmann     }
483fd214d18SGerd Hoffmann }
484fd214d18SGerd Hoffmann 
4852a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
4862a766d29SGerd Hoffmann {
4872a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
4882a766d29SGerd Hoffmann 
4892a766d29SGerd Hoffmann     if (s->mouse_buttons) {
4902a766d29SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
4912a766d29SGerd Hoffmann     }
4922858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
4932858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
4940e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
4950e43e99cSbellard                too big deltas */
4960e43e99cSbellard             ps2_mouse_send_packet(s);
4970e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
4980e43e99cSbellard                 break;
4990e43e99cSbellard         }
5000e43e99cSbellard     }
5010e43e99cSbellard }
5020e43e99cSbellard 
503548df2acSths void ps2_mouse_fake_event(void *opaque)
504548df2acSths {
5052a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
5065edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
5072a766d29SGerd Hoffmann     s->mouse_dx++;
5082a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
509548df2acSths }
510548df2acSths 
5110e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
5120e43e99cSbellard {
5130e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
5145edab03dSDon Koch 
5155edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
5160e43e99cSbellard #ifdef DEBUG_MOUSE
5170e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
5180e43e99cSbellard #endif
5190e43e99cSbellard     switch(s->common.write_cmd) {
5200e43e99cSbellard     default:
5210e43e99cSbellard     case -1:
5220e43e99cSbellard         /* mouse command */
5230e43e99cSbellard         if (s->mouse_wrap) {
5240e43e99cSbellard             if (val == AUX_RESET_WRAP) {
5250e43e99cSbellard                 s->mouse_wrap = 0;
5260e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
5270e43e99cSbellard                 return;
5280e43e99cSbellard             } else if (val != AUX_RESET) {
5290e43e99cSbellard                 ps2_queue(&s->common, val);
5300e43e99cSbellard                 return;
5310e43e99cSbellard             }
5320e43e99cSbellard         }
5330e43e99cSbellard         switch(val) {
5340e43e99cSbellard         case AUX_SET_SCALE11:
5350e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
5360e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5370e43e99cSbellard             break;
5380e43e99cSbellard         case AUX_SET_SCALE21:
5390e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
5400e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5410e43e99cSbellard             break;
5420e43e99cSbellard         case AUX_SET_STREAM:
5430e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
5440e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5450e43e99cSbellard             break;
5460e43e99cSbellard         case AUX_SET_WRAP:
5470e43e99cSbellard             s->mouse_wrap = 1;
5480e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5490e43e99cSbellard             break;
5500e43e99cSbellard         case AUX_SET_REMOTE:
5510e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
5520e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5530e43e99cSbellard             break;
5540e43e99cSbellard         case AUX_GET_TYPE:
5550e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5560e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
5570e43e99cSbellard             break;
5580e43e99cSbellard         case AUX_SET_RES:
5590e43e99cSbellard         case AUX_SET_SAMPLE:
5600e43e99cSbellard             s->common.write_cmd = val;
5610e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5620e43e99cSbellard             break;
5630e43e99cSbellard         case AUX_GET_SCALE:
5640e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5650e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
5660e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
5670e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
5680e43e99cSbellard             break;
5690e43e99cSbellard         case AUX_POLL:
5700e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5710e43e99cSbellard             ps2_mouse_send_packet(s);
5720e43e99cSbellard             break;
5730e43e99cSbellard         case AUX_ENABLE_DEV:
5740e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
5750e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5760e43e99cSbellard             break;
5770e43e99cSbellard         case AUX_DISABLE_DEV:
5780e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
5790e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5800e43e99cSbellard             break;
5810e43e99cSbellard         case AUX_SET_DEFAULT:
5820e43e99cSbellard             s->mouse_sample_rate = 100;
5830e43e99cSbellard             s->mouse_resolution = 2;
5840e43e99cSbellard             s->mouse_status = 0;
5850e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5860e43e99cSbellard             break;
5870e43e99cSbellard         case AUX_RESET:
5880e43e99cSbellard             s->mouse_sample_rate = 100;
5890e43e99cSbellard             s->mouse_resolution = 2;
5900e43e99cSbellard             s->mouse_status = 0;
5910e43e99cSbellard             s->mouse_type = 0;
5920e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5930e43e99cSbellard             ps2_queue(&s->common, 0xaa);
5940e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
5950e43e99cSbellard             break;
5960e43e99cSbellard         default:
5970e43e99cSbellard             break;
5980e43e99cSbellard         }
5990e43e99cSbellard         break;
6000e43e99cSbellard     case AUX_SET_SAMPLE:
6010e43e99cSbellard         s->mouse_sample_rate = val;
6020e43e99cSbellard         /* detect IMPS/2 or IMEX */
6030e43e99cSbellard         switch(s->mouse_detect_state) {
6040e43e99cSbellard         default:
6050e43e99cSbellard         case 0:
6060e43e99cSbellard             if (val == 200)
6070e43e99cSbellard                 s->mouse_detect_state = 1;
6080e43e99cSbellard             break;
6090e43e99cSbellard         case 1:
6100e43e99cSbellard             if (val == 100)
6110e43e99cSbellard                 s->mouse_detect_state = 2;
6120e43e99cSbellard             else if (val == 200)
6130e43e99cSbellard                 s->mouse_detect_state = 3;
6140e43e99cSbellard             else
6150e43e99cSbellard                 s->mouse_detect_state = 0;
6160e43e99cSbellard             break;
6170e43e99cSbellard         case 2:
6180e43e99cSbellard             if (val == 80)
6190e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
6200e43e99cSbellard             s->mouse_detect_state = 0;
6210e43e99cSbellard             break;
6220e43e99cSbellard         case 3:
6230e43e99cSbellard             if (val == 80)
6240e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
6250e43e99cSbellard             s->mouse_detect_state = 0;
6260e43e99cSbellard             break;
6270e43e99cSbellard         }
6280e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
6290e43e99cSbellard         s->common.write_cmd = -1;
6300e43e99cSbellard         break;
6310e43e99cSbellard     case AUX_SET_RES:
6320e43e99cSbellard         s->mouse_resolution = val;
6330e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
6340e43e99cSbellard         s->common.write_cmd = -1;
6350e43e99cSbellard         break;
6360e43e99cSbellard     }
6370e43e99cSbellard }
6380e43e99cSbellard 
639ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
6400e43e99cSbellard {
6410e43e99cSbellard     PS2Queue *q;
6420e43e99cSbellard     s->write_cmd = -1;
6430e43e99cSbellard     q = &s->queue;
6440e43e99cSbellard     q->rptr = 0;
6450e43e99cSbellard     q->wptr = 0;
6460e43e99cSbellard     q->count = 0;
647deeccef3Saliguori     s->update_irq(s->update_arg, 0);
6480e43e99cSbellard }
6490e43e99cSbellard 
6502858ab09SGonglei static void ps2_common_post_load(PS2State *s)
6512858ab09SGonglei {
6522858ab09SGonglei     PS2Queue *q = &s->queue;
6532858ab09SGonglei     int size;
6542858ab09SGonglei     int i;
6552858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
6562858ab09SGonglei 
6572858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
6582858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
6592858ab09SGonglei 
6602858ab09SGonglei     /* move the queue elements to the start of data array */
6612858ab09SGonglei     if (size > 0) {
6622858ab09SGonglei         for (i = 0; i < size; i++) {
6632858ab09SGonglei             /* move the queue elements to the temporary buffer */
6642858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
6652858ab09SGonglei             if (++q->rptr == 256) {
6662858ab09SGonglei                 q->rptr = 0;
6672858ab09SGonglei             }
6682858ab09SGonglei         }
6692858ab09SGonglei         memcpy(q->data, tmp_data, size);
6702858ab09SGonglei     }
6712858ab09SGonglei     /* reset rptr/wptr/count */
6722858ab09SGonglei     q->rptr = 0;
6732858ab09SGonglei     q->wptr = size;
6742858ab09SGonglei     q->count = size;
6752858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
6762858ab09SGonglei }
6772858ab09SGonglei 
678ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
679ef74679aSDinesh Subhraveti {
680ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
681ef74679aSDinesh Subhraveti 
6825edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
683ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
684ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
685ef74679aSDinesh Subhraveti     s->translate = 0;
686089adafdSHervé Poussineau     s->scancode_set = 2;
687ef74679aSDinesh Subhraveti }
688ef74679aSDinesh Subhraveti 
689ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
690ef74679aSDinesh Subhraveti {
691ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
692ef74679aSDinesh Subhraveti 
6935edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
694ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
695ef74679aSDinesh Subhraveti     s->mouse_status = 0;
696ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
697ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
698ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
699ef74679aSDinesh Subhraveti     s->mouse_type = 0;
700ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
701ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
702ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
703ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
704ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
705ef74679aSDinesh Subhraveti }
706ef74679aSDinesh Subhraveti 
707b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
708b31442c3SJuan Quintela     .name = "PS2 Common State",
709b31442c3SJuan Quintela     .version_id = 3,
710b31442c3SJuan Quintela     .minimum_version_id = 2,
711b31442c3SJuan Quintela     .fields = (VMStateField[]) {
712b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
713b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
714b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
715b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
716b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
717b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
7187783e9f0Spbrook     }
719b31442c3SJuan Quintela };
7207783e9f0Spbrook 
7217f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
7227f540ab5SChristophe Fergeau {
7237f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
7247f540ab5SChristophe Fergeau 
7257f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
7267f540ab5SChristophe Fergeau }
7277f540ab5SChristophe Fergeau 
7287f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
7297f540ab5SChristophe Fergeau {
7307f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
7317f540ab5SChristophe Fergeau 
7327f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
7337f540ab5SChristophe Fergeau     return 0;
7347f540ab5SChristophe Fergeau }
7357f540ab5SChristophe Fergeau 
7367f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
7377f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
7387f540ab5SChristophe Fergeau     .version_id = 3,
7397f540ab5SChristophe Fergeau     .minimum_version_id = 2,
7407f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
7415cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
7427f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
7437f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
7447f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
7457f540ab5SChristophe Fergeau     }
7467f540ab5SChristophe Fergeau };
7477f540ab5SChristophe Fergeau 
748*57d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque)
749*57d5c005SHervé Poussineau {
750*57d5c005SHervé Poussineau     PS2KbdState *s = opaque;
751*57d5c005SHervé Poussineau     return s->need_high_bit != 0; /* 0 is the usual state */
752*57d5c005SHervé Poussineau }
753*57d5c005SHervé Poussineau 
754*57d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
755*57d5c005SHervé Poussineau     .name = "ps2kbd/need_high_bit",
756*57d5c005SHervé Poussineau     .version_id = 1,
757*57d5c005SHervé Poussineau     .minimum_version_id = 1,
758*57d5c005SHervé Poussineau     .needed = ps2_keyboard_need_high_bit_needed,
759*57d5c005SHervé Poussineau     .fields = (VMStateField[]) {
760*57d5c005SHervé Poussineau         VMSTATE_BOOL(need_high_bit, PS2KbdState),
761*57d5c005SHervé Poussineau         VMSTATE_END_OF_LIST()
762*57d5c005SHervé Poussineau     }
763*57d5c005SHervé Poussineau };
764*57d5c005SHervé Poussineau 
765db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
7660e43e99cSbellard {
7670e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
7682858ab09SGonglei     PS2State *ps2 = &s->common;
7690e43e99cSbellard 
770db596c53SJuan Quintela     if (version_id == 2)
771e7d93956Saurel32         s->scancode_set=2;
7722858ab09SGonglei 
7732858ab09SGonglei     ps2_common_post_load(ps2);
7742858ab09SGonglei 
7750e43e99cSbellard     return 0;
7760e43e99cSbellard }
7770e43e99cSbellard 
7782858ab09SGonglei static void ps2_kbd_pre_save(void *opaque)
7792858ab09SGonglei {
7802858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
7812858ab09SGonglei     PS2State *ps2 = &s->common;
7822858ab09SGonglei 
7832858ab09SGonglei     ps2_common_post_load(ps2);
7842858ab09SGonglei }
7852858ab09SGonglei 
786b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
787b31442c3SJuan Quintela     .name = "ps2kbd",
788b31442c3SJuan Quintela     .version_id = 3,
789db596c53SJuan Quintela     .minimum_version_id = 2,
790db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
7912858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
792b31442c3SJuan Quintela     .fields = (VMStateField[]) {
793b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
794b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
795b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
796b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
797b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
7987f540ab5SChristophe Fergeau     },
7995cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
8005cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
801*57d5c005SHervé Poussineau         &vmstate_ps2_keyboard_need_high_bit,
8025cd8cadaSJuan Quintela         NULL
8030e43e99cSbellard     }
804b31442c3SJuan Quintela };
805b31442c3SJuan Quintela 
8062858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
8072858ab09SGonglei {
8082858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
8092858ab09SGonglei     PS2State *ps2 = &s->common;
8102858ab09SGonglei 
8112858ab09SGonglei     ps2_common_post_load(ps2);
8122858ab09SGonglei 
8132858ab09SGonglei     return 0;
8142858ab09SGonglei }
8152858ab09SGonglei 
8162858ab09SGonglei static void ps2_mouse_pre_save(void *opaque)
8172858ab09SGonglei {
8182858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
8192858ab09SGonglei     PS2State *ps2 = &s->common;
8202858ab09SGonglei 
8212858ab09SGonglei     ps2_common_post_load(ps2);
8222858ab09SGonglei }
8232858ab09SGonglei 
824b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
825b31442c3SJuan Quintela     .name = "ps2mouse",
826b31442c3SJuan Quintela     .version_id = 2,
827b31442c3SJuan Quintela     .minimum_version_id = 2,
8282858ab09SGonglei     .post_load = ps2_mouse_post_load,
8292858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
830b31442c3SJuan Quintela     .fields = (VMStateField[]) {
831b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
832b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
833b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
834b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
835b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
836b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
837b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
838b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
839b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
840b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
841b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
842b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
843b31442c3SJuan Quintela     }
844b31442c3SJuan Quintela };
8450e43e99cSbellard 
84666e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
84766e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
84866e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
84966e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
85066e6536eSGerd Hoffmann };
85166e6536eSGerd Hoffmann 
8520e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
8530e43e99cSbellard {
8547267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
8550e43e99cSbellard 
8565edab03dSDon Koch     trace_ps2_kbd_init(s);
8570e43e99cSbellard     s->common.update_irq = update_irq;
8580e43e99cSbellard     s->common.update_arg = update_arg;
859e7d93956Saurel32     s->scancode_set = 2;
8600be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
86166e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
86266e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
863ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
8640e43e99cSbellard     return s;
8650e43e99cSbellard }
8660e43e99cSbellard 
8672a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
8682a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
8692a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
8702a766d29SGerd Hoffmann     .event = ps2_mouse_event,
8712a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
8722a766d29SGerd Hoffmann };
8732a766d29SGerd Hoffmann 
8740e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
8750e43e99cSbellard {
8767267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
8770e43e99cSbellard 
8785edab03dSDon Koch     trace_ps2_mouse_init(s);
8790e43e99cSbellard     s->common.update_irq = update_irq;
8800e43e99cSbellard     s->common.update_arg = update_arg;
8810be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
8822a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
8832a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
884ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
8850e43e99cSbellard     return s;
8860e43e99cSbellard }
887