xref: /qemu/hw/input/ps2.c (revision 4df23b64c51cc830d19eb29801070d31aa1e81cd)
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;
975cbdb3a3SStefan Weil     /* QEMU uses translated PC scancodes internally.  To avoid multiple
98f94f5d71Spbrook        conversions we do the translation (if any) in the PS/2 emulation
99f94f5d71Spbrook        not the keyboard controller.  */
100f94f5d71Spbrook     int translate;
101e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
1027f540ab5SChristophe Fergeau     int ledstate;
1030e43e99cSbellard } PS2KbdState;
1040e43e99cSbellard 
1050e43e99cSbellard typedef struct {
1060e43e99cSbellard     PS2State common;
1070e43e99cSbellard     uint8_t mouse_status;
1080e43e99cSbellard     uint8_t mouse_resolution;
1090e43e99cSbellard     uint8_t mouse_sample_rate;
1100e43e99cSbellard     uint8_t mouse_wrap;
1110e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1120e43e99cSbellard     uint8_t mouse_detect_state;
1130e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1140e43e99cSbellard     int mouse_dy;
1150e43e99cSbellard     int mouse_dz;
1160e43e99cSbellard     uint8_t mouse_buttons;
1170e43e99cSbellard } PS2MouseState;
1180e43e99cSbellard 
119f94f5d71Spbrook /* Table to convert from PC scancodes to raw scancodes.  */
120f94f5d71Spbrook static const unsigned char ps2_raw_keycode[128] = {
121f94f5d71Spbrook   0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
122f94f5d71Spbrook  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
123f94f5d71Spbrook  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
124f94f5d71Spbrook  50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
125f94f5d71Spbrook  11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
126f94f5d71Spbrook 114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
127f94f5d71Spbrook  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
128f94f5d71Spbrook  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
129f94f5d71Spbrook };
1307096a96dSRoy Tam static const unsigned char ps2_raw_keycode_set3[128] = {
1317096a96dSRoy Tam   0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
1327096a96dSRoy Tam  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
1337096a96dSRoy Tam  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
1347096a96dSRoy Tam  50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
1357096a96dSRoy Tam  47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
1367096a96dSRoy Tam 114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
1377096a96dSRoy Tam  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
1387096a96dSRoy Tam  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
1397096a96dSRoy Tam };
140f94f5d71Spbrook 
1410e43e99cSbellard void ps2_queue(void *opaque, int b)
1420e43e99cSbellard {
1430e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1440e43e99cSbellard     PS2Queue *q = &s->queue;
1450e43e99cSbellard 
1462858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
1470e43e99cSbellard         return;
1480e43e99cSbellard     q->data[q->wptr] = b;
1490e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
1500e43e99cSbellard         q->wptr = 0;
1510e43e99cSbellard     q->count++;
1520e43e99cSbellard     s->update_irq(s->update_arg, 1);
1530e43e99cSbellard }
1540e43e99cSbellard 
15535c4d671Saurel32 /*
15635c4d671Saurel32    keycode is expressed as follow:
15735c4d671Saurel32    bit 7    - 0 key pressed, 1 = key released
15835c4d671Saurel32    bits 6-0 - translated scancode set 2
15935c4d671Saurel32  */
1600e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
1610e43e99cSbellard {
162f94f5d71Spbrook     PS2KbdState *s = opaque;
163e7d93956Saurel32 
1645edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
165fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
1667096a96dSRoy Tam     /* XXX: add support for scancode set 1 */
1677096a96dSRoy Tam     if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
1687096a96dSRoy Tam         if (keycode & 0x80) {
169f94f5d71Spbrook             ps2_queue(&s->common, 0xf0);
1707096a96dSRoy Tam         }
1717096a96dSRoy Tam         if (s->scancode_set == 2) {
172f94f5d71Spbrook             keycode = ps2_raw_keycode[keycode & 0x7f];
1737096a96dSRoy Tam         } else if (s->scancode_set == 3) {
1747096a96dSRoy Tam             keycode = ps2_raw_keycode_set3[keycode & 0x7f];
1757096a96dSRoy Tam         }
176f94f5d71Spbrook       }
1770e43e99cSbellard     ps2_queue(&s->common, keycode);
1780e43e99cSbellard }
1790e43e99cSbellard 
18066e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
18166e6536eSGerd Hoffmann                                InputEvent *evt)
18266e6536eSGerd Hoffmann {
18366e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
18466e6536eSGerd Hoffmann     int scancodes[3], i, count;
18532bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
18666e6536eSGerd Hoffmann 
18766e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
188b5a1b443SEric Blake     count = qemu_input_key_value_to_scancode(key->key,
189b5a1b443SEric Blake                                              key->down,
19066e6536eSGerd Hoffmann                                              scancodes);
19166e6536eSGerd Hoffmann     for (i = 0; i < count; i++) {
19266e6536eSGerd Hoffmann         ps2_put_keycode(s, scancodes[i]);
19366e6536eSGerd Hoffmann     }
19466e6536eSGerd Hoffmann }
19566e6536eSGerd Hoffmann 
1960e43e99cSbellard uint32_t ps2_read_data(void *opaque)
1970e43e99cSbellard {
1980e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1990e43e99cSbellard     PS2Queue *q;
2000e43e99cSbellard     int val, index;
2010e43e99cSbellard 
2025edab03dSDon Koch     trace_ps2_read_data(opaque);
2030e43e99cSbellard     q = &s->queue;
2040e43e99cSbellard     if (q->count == 0) {
2050e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
2060e43e99cSbellard            (needed for EMM386) */
2070e43e99cSbellard         /* XXX: need a timer to do things correctly */
2080e43e99cSbellard         index = q->rptr - 1;
2090e43e99cSbellard         if (index < 0)
2100e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
2110e43e99cSbellard         val = q->data[index];
2120e43e99cSbellard     } else {
2130e43e99cSbellard         val = q->data[q->rptr];
2140e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
2150e43e99cSbellard             q->rptr = 0;
2160e43e99cSbellard         q->count--;
2170e43e99cSbellard         /* reading deasserts IRQ */
2180e43e99cSbellard         s->update_irq(s->update_arg, 0);
2190e43e99cSbellard         /* reassert IRQs if data left */
2200e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
2210e43e99cSbellard     }
2220e43e99cSbellard     return val;
2230e43e99cSbellard }
2240e43e99cSbellard 
2257f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
2267f540ab5SChristophe Fergeau {
2275edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
2287f540ab5SChristophe Fergeau     s->ledstate = ledstate;
2297f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
2307f540ab5SChristophe Fergeau }
2317f540ab5SChristophe Fergeau 
2320e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
2330e43e99cSbellard {
2345edab03dSDon Koch     trace_ps2_reset_keyboard(s);
2350e43e99cSbellard     s->scan_enabled = 1;
236e7d93956Saurel32     s->scancode_set = 2;
2377f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
2380e43e99cSbellard }
2390e43e99cSbellard 
2400e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
2410e43e99cSbellard {
2420e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
2430e43e99cSbellard 
2445edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
2450e43e99cSbellard     switch(s->common.write_cmd) {
2460e43e99cSbellard     default:
2470e43e99cSbellard     case -1:
2480e43e99cSbellard         switch(val) {
2490e43e99cSbellard         case 0x00:
2500e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2510e43e99cSbellard             break;
2520e43e99cSbellard         case 0x05:
2530e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
2540e43e99cSbellard             break;
2550e43e99cSbellard         case KBD_CMD_GET_ID:
2560e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
257e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
25835c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
25935c4d671Saurel32             if (s->translate)
26035c4d671Saurel32                 ps2_queue(&s->common, 0x41);
26135c4d671Saurel32             else
26235c4d671Saurel32                 ps2_queue(&s->common, 0x83);
2630e43e99cSbellard             break;
2640e43e99cSbellard         case KBD_CMD_ECHO:
2650e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
2660e43e99cSbellard             break;
2670e43e99cSbellard         case KBD_CMD_ENABLE:
2680e43e99cSbellard             s->scan_enabled = 1;
2690e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2700e43e99cSbellard             break;
271e7d93956Saurel32         case KBD_CMD_SCANCODE:
2720e43e99cSbellard         case KBD_CMD_SET_LEDS:
2730e43e99cSbellard         case KBD_CMD_SET_RATE:
2740e43e99cSbellard             s->common.write_cmd = val;
2750e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2760e43e99cSbellard             break;
2770e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
2780e43e99cSbellard             ps2_reset_keyboard(s);
2790e43e99cSbellard             s->scan_enabled = 0;
2800e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2810e43e99cSbellard             break;
2820e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
2830e43e99cSbellard             ps2_reset_keyboard(s);
2840e43e99cSbellard             s->scan_enabled = 1;
2850e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2860e43e99cSbellard             break;
2870e43e99cSbellard         case KBD_CMD_RESET:
2880e43e99cSbellard             ps2_reset_keyboard(s);
2890e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2900e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
2910e43e99cSbellard             break;
2920e43e99cSbellard         default:
29306b3611fSHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
2940e43e99cSbellard             break;
2950e43e99cSbellard         }
2960e43e99cSbellard         break;
297e7d93956Saurel32     case KBD_CMD_SCANCODE:
298e7d93956Saurel32         if (val == 0) {
299*4df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_ACK);
300e7d93956Saurel32             if (s->scancode_set == 1)
301e7d93956Saurel32                 ps2_put_keycode(s, 0x43);
302e7d93956Saurel32             else if (s->scancode_set == 2)
303e7d93956Saurel32                 ps2_put_keycode(s, 0x41);
304e7d93956Saurel32             else if (s->scancode_set == 3)
305e7d93956Saurel32                 ps2_put_keycode(s, 0x3f);
306*4df23b64SHervé Poussineau         } else if (val >= 1 && val <= 3) {
307e7d93956Saurel32             s->scancode_set = val;
308e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
309*4df23b64SHervé Poussineau         } else {
310*4df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
311e7d93956Saurel32         }
312e7d93956Saurel32         s->common.write_cmd = -1;
313e7d93956Saurel32         break;
3140e43e99cSbellard     case KBD_CMD_SET_LEDS:
3157f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
3160e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3170e43e99cSbellard         s->common.write_cmd = -1;
3180e43e99cSbellard         break;
3190e43e99cSbellard     case KBD_CMD_SET_RATE:
3200e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3210e43e99cSbellard         s->common.write_cmd = -1;
3220e43e99cSbellard         break;
3230e43e99cSbellard     }
3240e43e99cSbellard }
3250e43e99cSbellard 
326f94f5d71Spbrook /* Set the scancode translation mode.
327f94f5d71Spbrook    0 = raw scancodes.
328f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
329f94f5d71Spbrook 
330f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
331f94f5d71Spbrook {
332f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
3335edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
334f94f5d71Spbrook     s->translate = mode;
335f94f5d71Spbrook }
336f94f5d71Spbrook 
3370e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
3380e43e99cSbellard {
3390e43e99cSbellard     unsigned int b;
3400e43e99cSbellard     int dx1, dy1, dz1;
3410e43e99cSbellard 
3420e43e99cSbellard     dx1 = s->mouse_dx;
3430e43e99cSbellard     dy1 = s->mouse_dy;
3440e43e99cSbellard     dz1 = s->mouse_dz;
3450e43e99cSbellard     /* XXX: increase range to 8 bits ? */
3460e43e99cSbellard     if (dx1 > 127)
3470e43e99cSbellard         dx1 = 127;
3480e43e99cSbellard     else if (dx1 < -127)
3490e43e99cSbellard         dx1 = -127;
3500e43e99cSbellard     if (dy1 > 127)
3510e43e99cSbellard         dy1 = 127;
3520e43e99cSbellard     else if (dy1 < -127)
3530e43e99cSbellard         dy1 = -127;
3540e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
3550e43e99cSbellard     ps2_queue(&s->common, b);
3560e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
3570e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
3580e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
3590e43e99cSbellard     switch(s->mouse_type) {
3600e43e99cSbellard     default:
3610e43e99cSbellard         break;
3620e43e99cSbellard     case 3:
3630e43e99cSbellard         if (dz1 > 127)
3640e43e99cSbellard             dz1 = 127;
3650e43e99cSbellard         else if (dz1 < -127)
3660e43e99cSbellard                 dz1 = -127;
3670e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
3680e43e99cSbellard         break;
3690e43e99cSbellard     case 4:
3700e43e99cSbellard         if (dz1 > 7)
3710e43e99cSbellard             dz1 = 7;
3720e43e99cSbellard         else if (dz1 < -7)
3730e43e99cSbellard             dz1 = -7;
3740e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
3750e43e99cSbellard         ps2_queue(&s->common, b);
3760e43e99cSbellard         break;
3770e43e99cSbellard     }
3780e43e99cSbellard 
3795edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
3800e43e99cSbellard     /* update deltas */
3810e43e99cSbellard     s->mouse_dx -= dx1;
3820e43e99cSbellard     s->mouse_dy -= dy1;
3830e43e99cSbellard     s->mouse_dz -= dz1;
3840e43e99cSbellard }
3850e43e99cSbellard 
3862a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
3872a766d29SGerd Hoffmann                             InputEvent *evt)
3880e43e99cSbellard {
3897fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
3902a766d29SGerd Hoffmann         [INPUT_BUTTON_LEFT]   = MOUSE_EVENT_LBUTTON,
3912a766d29SGerd Hoffmann         [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
3922a766d29SGerd Hoffmann         [INPUT_BUTTON_RIGHT]  = MOUSE_EVENT_RBUTTON,
3932a766d29SGerd Hoffmann     };
3942a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
395b5a1b443SEric Blake     InputMoveEvent *move;
396b5a1b443SEric Blake     InputBtnEvent *btn;
3970e43e99cSbellard 
3980e43e99cSbellard     /* check if deltas are recorded when disabled */
3990e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
4000e43e99cSbellard         return;
4010e43e99cSbellard 
402568c73a4SEric Blake     switch (evt->type) {
4032a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
40432bafa8fSEric Blake         move = evt->u.rel.data;
405b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
406b5a1b443SEric Blake             s->mouse_dx += move->value;
407b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
408b5a1b443SEric Blake             s->mouse_dy -= move->value;
4092a766d29SGerd Hoffmann         }
4102a766d29SGerd Hoffmann         break;
4110e43e99cSbellard 
4122a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
41332bafa8fSEric Blake         btn = evt->u.btn.data;
414b5a1b443SEric Blake         if (btn->down) {
415b5a1b443SEric Blake             s->mouse_buttons |= bmap[btn->button];
416b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
4172a766d29SGerd Hoffmann                 s->mouse_dz--;
418b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
4192a766d29SGerd Hoffmann                 s->mouse_dz++;
4202a766d29SGerd Hoffmann             }
4212a766d29SGerd Hoffmann         } else {
422b5a1b443SEric Blake             s->mouse_buttons &= ~bmap[btn->button];
4232a766d29SGerd Hoffmann         }
4242a766d29SGerd Hoffmann         break;
4252a766d29SGerd Hoffmann 
4262a766d29SGerd Hoffmann     default:
4272a766d29SGerd Hoffmann         /* keep gcc happy */
4282a766d29SGerd Hoffmann         break;
4292a766d29SGerd Hoffmann     }
430fd214d18SGerd Hoffmann }
431fd214d18SGerd Hoffmann 
4322a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
4332a766d29SGerd Hoffmann {
4342a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
4352a766d29SGerd Hoffmann 
4362a766d29SGerd Hoffmann     if (s->mouse_buttons) {
4372a766d29SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
4382a766d29SGerd Hoffmann     }
4392858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
4402858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
4410e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
4420e43e99cSbellard                too big deltas */
4430e43e99cSbellard             ps2_mouse_send_packet(s);
4440e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
4450e43e99cSbellard                 break;
4460e43e99cSbellard         }
4470e43e99cSbellard     }
4480e43e99cSbellard }
4490e43e99cSbellard 
450548df2acSths void ps2_mouse_fake_event(void *opaque)
451548df2acSths {
4522a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
4535edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
4542a766d29SGerd Hoffmann     s->mouse_dx++;
4552a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
456548df2acSths }
457548df2acSths 
4580e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
4590e43e99cSbellard {
4600e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
4615edab03dSDon Koch 
4625edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
4630e43e99cSbellard #ifdef DEBUG_MOUSE
4640e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
4650e43e99cSbellard #endif
4660e43e99cSbellard     switch(s->common.write_cmd) {
4670e43e99cSbellard     default:
4680e43e99cSbellard     case -1:
4690e43e99cSbellard         /* mouse command */
4700e43e99cSbellard         if (s->mouse_wrap) {
4710e43e99cSbellard             if (val == AUX_RESET_WRAP) {
4720e43e99cSbellard                 s->mouse_wrap = 0;
4730e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
4740e43e99cSbellard                 return;
4750e43e99cSbellard             } else if (val != AUX_RESET) {
4760e43e99cSbellard                 ps2_queue(&s->common, val);
4770e43e99cSbellard                 return;
4780e43e99cSbellard             }
4790e43e99cSbellard         }
4800e43e99cSbellard         switch(val) {
4810e43e99cSbellard         case AUX_SET_SCALE11:
4820e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
4830e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4840e43e99cSbellard             break;
4850e43e99cSbellard         case AUX_SET_SCALE21:
4860e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
4870e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4880e43e99cSbellard             break;
4890e43e99cSbellard         case AUX_SET_STREAM:
4900e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
4910e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4920e43e99cSbellard             break;
4930e43e99cSbellard         case AUX_SET_WRAP:
4940e43e99cSbellard             s->mouse_wrap = 1;
4950e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4960e43e99cSbellard             break;
4970e43e99cSbellard         case AUX_SET_REMOTE:
4980e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
4990e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5000e43e99cSbellard             break;
5010e43e99cSbellard         case AUX_GET_TYPE:
5020e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5030e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
5040e43e99cSbellard             break;
5050e43e99cSbellard         case AUX_SET_RES:
5060e43e99cSbellard         case AUX_SET_SAMPLE:
5070e43e99cSbellard             s->common.write_cmd = val;
5080e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5090e43e99cSbellard             break;
5100e43e99cSbellard         case AUX_GET_SCALE:
5110e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5120e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
5130e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
5140e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
5150e43e99cSbellard             break;
5160e43e99cSbellard         case AUX_POLL:
5170e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5180e43e99cSbellard             ps2_mouse_send_packet(s);
5190e43e99cSbellard             break;
5200e43e99cSbellard         case AUX_ENABLE_DEV:
5210e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
5220e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5230e43e99cSbellard             break;
5240e43e99cSbellard         case AUX_DISABLE_DEV:
5250e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
5260e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5270e43e99cSbellard             break;
5280e43e99cSbellard         case AUX_SET_DEFAULT:
5290e43e99cSbellard             s->mouse_sample_rate = 100;
5300e43e99cSbellard             s->mouse_resolution = 2;
5310e43e99cSbellard             s->mouse_status = 0;
5320e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5330e43e99cSbellard             break;
5340e43e99cSbellard         case AUX_RESET:
5350e43e99cSbellard             s->mouse_sample_rate = 100;
5360e43e99cSbellard             s->mouse_resolution = 2;
5370e43e99cSbellard             s->mouse_status = 0;
5380e43e99cSbellard             s->mouse_type = 0;
5390e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5400e43e99cSbellard             ps2_queue(&s->common, 0xaa);
5410e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
5420e43e99cSbellard             break;
5430e43e99cSbellard         default:
5440e43e99cSbellard             break;
5450e43e99cSbellard         }
5460e43e99cSbellard         break;
5470e43e99cSbellard     case AUX_SET_SAMPLE:
5480e43e99cSbellard         s->mouse_sample_rate = val;
5490e43e99cSbellard         /* detect IMPS/2 or IMEX */
5500e43e99cSbellard         switch(s->mouse_detect_state) {
5510e43e99cSbellard         default:
5520e43e99cSbellard         case 0:
5530e43e99cSbellard             if (val == 200)
5540e43e99cSbellard                 s->mouse_detect_state = 1;
5550e43e99cSbellard             break;
5560e43e99cSbellard         case 1:
5570e43e99cSbellard             if (val == 100)
5580e43e99cSbellard                 s->mouse_detect_state = 2;
5590e43e99cSbellard             else if (val == 200)
5600e43e99cSbellard                 s->mouse_detect_state = 3;
5610e43e99cSbellard             else
5620e43e99cSbellard                 s->mouse_detect_state = 0;
5630e43e99cSbellard             break;
5640e43e99cSbellard         case 2:
5650e43e99cSbellard             if (val == 80)
5660e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
5670e43e99cSbellard             s->mouse_detect_state = 0;
5680e43e99cSbellard             break;
5690e43e99cSbellard         case 3:
5700e43e99cSbellard             if (val == 80)
5710e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
5720e43e99cSbellard             s->mouse_detect_state = 0;
5730e43e99cSbellard             break;
5740e43e99cSbellard         }
5750e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5760e43e99cSbellard         s->common.write_cmd = -1;
5770e43e99cSbellard         break;
5780e43e99cSbellard     case AUX_SET_RES:
5790e43e99cSbellard         s->mouse_resolution = val;
5800e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5810e43e99cSbellard         s->common.write_cmd = -1;
5820e43e99cSbellard         break;
5830e43e99cSbellard     }
5840e43e99cSbellard }
5850e43e99cSbellard 
586ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
5870e43e99cSbellard {
5880e43e99cSbellard     PS2Queue *q;
5890e43e99cSbellard     s->write_cmd = -1;
5900e43e99cSbellard     q = &s->queue;
5910e43e99cSbellard     q->rptr = 0;
5920e43e99cSbellard     q->wptr = 0;
5930e43e99cSbellard     q->count = 0;
594deeccef3Saliguori     s->update_irq(s->update_arg, 0);
5950e43e99cSbellard }
5960e43e99cSbellard 
5972858ab09SGonglei static void ps2_common_post_load(PS2State *s)
5982858ab09SGonglei {
5992858ab09SGonglei     PS2Queue *q = &s->queue;
6002858ab09SGonglei     int size;
6012858ab09SGonglei     int i;
6022858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
6032858ab09SGonglei 
6042858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
6052858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
6062858ab09SGonglei 
6072858ab09SGonglei     /* move the queue elements to the start of data array */
6082858ab09SGonglei     if (size > 0) {
6092858ab09SGonglei         for (i = 0; i < size; i++) {
6102858ab09SGonglei             /* move the queue elements to the temporary buffer */
6112858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
6122858ab09SGonglei             if (++q->rptr == 256) {
6132858ab09SGonglei                 q->rptr = 0;
6142858ab09SGonglei             }
6152858ab09SGonglei         }
6162858ab09SGonglei         memcpy(q->data, tmp_data, size);
6172858ab09SGonglei     }
6182858ab09SGonglei     /* reset rptr/wptr/count */
6192858ab09SGonglei     q->rptr = 0;
6202858ab09SGonglei     q->wptr = size;
6212858ab09SGonglei     q->count = size;
6222858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
6232858ab09SGonglei }
6242858ab09SGonglei 
625ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
626ef74679aSDinesh Subhraveti {
627ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
628ef74679aSDinesh Subhraveti 
6295edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
630ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
631ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
632ef74679aSDinesh Subhraveti     s->translate = 0;
633089adafdSHervé Poussineau     s->scancode_set = 2;
634ef74679aSDinesh Subhraveti }
635ef74679aSDinesh Subhraveti 
636ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
637ef74679aSDinesh Subhraveti {
638ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
639ef74679aSDinesh Subhraveti 
6405edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
641ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
642ef74679aSDinesh Subhraveti     s->mouse_status = 0;
643ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
644ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
645ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
646ef74679aSDinesh Subhraveti     s->mouse_type = 0;
647ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
648ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
649ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
650ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
651ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
652ef74679aSDinesh Subhraveti }
653ef74679aSDinesh Subhraveti 
654b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
655b31442c3SJuan Quintela     .name = "PS2 Common State",
656b31442c3SJuan Quintela     .version_id = 3,
657b31442c3SJuan Quintela     .minimum_version_id = 2,
658b31442c3SJuan Quintela     .fields = (VMStateField[]) {
659b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
660b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
661b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
662b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
663b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
664b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
6657783e9f0Spbrook     }
666b31442c3SJuan Quintela };
6677783e9f0Spbrook 
6687f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
6697f540ab5SChristophe Fergeau {
6707f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6717f540ab5SChristophe Fergeau 
6727f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
6737f540ab5SChristophe Fergeau }
6747f540ab5SChristophe Fergeau 
6757f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
6767f540ab5SChristophe Fergeau {
6777f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6787f540ab5SChristophe Fergeau 
6797f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
6807f540ab5SChristophe Fergeau     return 0;
6817f540ab5SChristophe Fergeau }
6827f540ab5SChristophe Fergeau 
6837f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
6847f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
6857f540ab5SChristophe Fergeau     .version_id = 3,
6867f540ab5SChristophe Fergeau     .minimum_version_id = 2,
6877f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
6885cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
6897f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
6907f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
6917f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
6927f540ab5SChristophe Fergeau     }
6937f540ab5SChristophe Fergeau };
6947f540ab5SChristophe Fergeau 
695db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
6960e43e99cSbellard {
6970e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
6982858ab09SGonglei     PS2State *ps2 = &s->common;
6990e43e99cSbellard 
700db596c53SJuan Quintela     if (version_id == 2)
701e7d93956Saurel32         s->scancode_set=2;
7022858ab09SGonglei 
7032858ab09SGonglei     ps2_common_post_load(ps2);
7042858ab09SGonglei 
7050e43e99cSbellard     return 0;
7060e43e99cSbellard }
7070e43e99cSbellard 
7082858ab09SGonglei static void ps2_kbd_pre_save(void *opaque)
7092858ab09SGonglei {
7102858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
7112858ab09SGonglei     PS2State *ps2 = &s->common;
7122858ab09SGonglei 
7132858ab09SGonglei     ps2_common_post_load(ps2);
7142858ab09SGonglei }
7152858ab09SGonglei 
716b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
717b31442c3SJuan Quintela     .name = "ps2kbd",
718b31442c3SJuan Quintela     .version_id = 3,
719db596c53SJuan Quintela     .minimum_version_id = 2,
720db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
7212858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
722b31442c3SJuan Quintela     .fields = (VMStateField[]) {
723b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
724b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
725b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
726b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
727b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
7287f540ab5SChristophe Fergeau     },
7295cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
7305cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
7315cd8cadaSJuan Quintela         NULL
7320e43e99cSbellard     }
733b31442c3SJuan Quintela };
734b31442c3SJuan Quintela 
7352858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
7362858ab09SGonglei {
7372858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
7382858ab09SGonglei     PS2State *ps2 = &s->common;
7392858ab09SGonglei 
7402858ab09SGonglei     ps2_common_post_load(ps2);
7412858ab09SGonglei 
7422858ab09SGonglei     return 0;
7432858ab09SGonglei }
7442858ab09SGonglei 
7452858ab09SGonglei static void ps2_mouse_pre_save(void *opaque)
7462858ab09SGonglei {
7472858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
7482858ab09SGonglei     PS2State *ps2 = &s->common;
7492858ab09SGonglei 
7502858ab09SGonglei     ps2_common_post_load(ps2);
7512858ab09SGonglei }
7522858ab09SGonglei 
753b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
754b31442c3SJuan Quintela     .name = "ps2mouse",
755b31442c3SJuan Quintela     .version_id = 2,
756b31442c3SJuan Quintela     .minimum_version_id = 2,
7572858ab09SGonglei     .post_load = ps2_mouse_post_load,
7582858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
759b31442c3SJuan Quintela     .fields = (VMStateField[]) {
760b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
761b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
762b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
763b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
764b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
765b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
766b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
767b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
768b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
769b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
770b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
771b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
772b31442c3SJuan Quintela     }
773b31442c3SJuan Quintela };
7740e43e99cSbellard 
77566e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
77666e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
77766e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
77866e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
77966e6536eSGerd Hoffmann };
78066e6536eSGerd Hoffmann 
7810e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
7820e43e99cSbellard {
7837267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
7840e43e99cSbellard 
7855edab03dSDon Koch     trace_ps2_kbd_init(s);
7860e43e99cSbellard     s->common.update_irq = update_irq;
7870e43e99cSbellard     s->common.update_arg = update_arg;
788e7d93956Saurel32     s->scancode_set = 2;
7890be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
79066e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
79166e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
792ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
7930e43e99cSbellard     return s;
7940e43e99cSbellard }
7950e43e99cSbellard 
7962a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
7972a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
7982a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
7992a766d29SGerd Hoffmann     .event = ps2_mouse_event,
8002a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
8012a766d29SGerd Hoffmann };
8022a766d29SGerd Hoffmann 
8030e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
8040e43e99cSbellard {
8057267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
8060e43e99cSbellard 
8075edab03dSDon Koch     trace_ps2_mouse_init(s);
8080e43e99cSbellard     s->common.update_irq = update_irq;
8090e43e99cSbellard     s->common.update_arg = update_arg;
8100be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
8112a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
8122a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
813ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
8140e43e99cSbellard     return s;
8150e43e99cSbellard }
816