xref: /qemu/hw/input/ps2.c (revision 66e6536e0cdc8c1137230b1b935a5af693b5d9ca)
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  */
2483c9f4caSPaolo Bonzini #include "hw/hw.h"
250d09e41aSPaolo Bonzini #include "hw/input/ps2.h"
2628ecbaeeSPaolo Bonzini #include "ui/console.h"
27*66e6536eSGerd Hoffmann #include "ui/input.h"
289c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
290e43e99cSbellard 
300e43e99cSbellard /* debug PC keyboard */
310e43e99cSbellard //#define DEBUG_KBD
320e43e99cSbellard 
330e43e99cSbellard /* debug PC keyboard : only mouse */
340e43e99cSbellard //#define DEBUG_MOUSE
350e43e99cSbellard 
360e43e99cSbellard /* Keyboard Commands */
370e43e99cSbellard #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
380e43e99cSbellard #define KBD_CMD_ECHO     	0xEE
39e7d93956Saurel32 #define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
400e43e99cSbellard #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
410e43e99cSbellard #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
420e43e99cSbellard #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
430e43e99cSbellard #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
440e43e99cSbellard #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
450e43e99cSbellard #define KBD_CMD_RESET		0xFF	/* Reset */
460e43e99cSbellard 
470e43e99cSbellard /* Keyboard Replies */
480e43e99cSbellard #define KBD_REPLY_POR		0xAA	/* Power on reset */
4935c4d671Saurel32 #define KBD_REPLY_ID		0xAB	/* Keyboard ID */
500e43e99cSbellard #define KBD_REPLY_ACK		0xFA	/* Command ACK */
510e43e99cSbellard #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
520e43e99cSbellard 
530e43e99cSbellard /* Mouse Commands */
540e43e99cSbellard #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
550e43e99cSbellard #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
560e43e99cSbellard #define AUX_SET_RES		0xE8	/* Set resolution */
570e43e99cSbellard #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
580e43e99cSbellard #define AUX_SET_STREAM		0xEA	/* Set stream mode */
590e43e99cSbellard #define AUX_POLL		0xEB	/* Poll */
600e43e99cSbellard #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
610e43e99cSbellard #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
620e43e99cSbellard #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
630e43e99cSbellard #define AUX_GET_TYPE		0xF2	/* Get type */
640e43e99cSbellard #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
650e43e99cSbellard #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
660e43e99cSbellard #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
670e43e99cSbellard #define AUX_SET_DEFAULT		0xF6
680e43e99cSbellard #define AUX_RESET		0xFF	/* Reset aux device */
690e43e99cSbellard #define AUX_ACK			0xFA	/* Command byte ACK. */
700e43e99cSbellard 
710e43e99cSbellard #define MOUSE_STATUS_REMOTE     0x40
720e43e99cSbellard #define MOUSE_STATUS_ENABLED    0x20
730e43e99cSbellard #define MOUSE_STATUS_SCALE21    0x10
740e43e99cSbellard 
752858ab09SGonglei #define PS2_QUEUE_SIZE 16  /* Buffer size required by PS/2 protocol */
760e43e99cSbellard 
770e43e99cSbellard typedef struct {
782858ab09SGonglei     /* Keep the data array 256 bytes long, which compatibility
792858ab09SGonglei      with older qemu versions. */
802858ab09SGonglei     uint8_t data[256];
810e43e99cSbellard     int rptr, wptr, count;
820e43e99cSbellard } PS2Queue;
830e43e99cSbellard 
840e43e99cSbellard typedef struct {
850e43e99cSbellard     PS2Queue queue;
860e43e99cSbellard     int32_t write_cmd;
870e43e99cSbellard     void (*update_irq)(void *, int);
880e43e99cSbellard     void *update_arg;
890e43e99cSbellard } PS2State;
900e43e99cSbellard 
910e43e99cSbellard typedef struct {
920e43e99cSbellard     PS2State common;
930e43e99cSbellard     int scan_enabled;
945cbdb3a3SStefan Weil     /* QEMU uses translated PC scancodes internally.  To avoid multiple
95f94f5d71Spbrook        conversions we do the translation (if any) in the PS/2 emulation
96f94f5d71Spbrook        not the keyboard controller.  */
97f94f5d71Spbrook     int translate;
98e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
997f540ab5SChristophe Fergeau     int ledstate;
1000e43e99cSbellard } PS2KbdState;
1010e43e99cSbellard 
1020e43e99cSbellard typedef struct {
1030e43e99cSbellard     PS2State common;
1040e43e99cSbellard     uint8_t mouse_status;
1050e43e99cSbellard     uint8_t mouse_resolution;
1060e43e99cSbellard     uint8_t mouse_sample_rate;
1070e43e99cSbellard     uint8_t mouse_wrap;
1080e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1090e43e99cSbellard     uint8_t mouse_detect_state;
1100e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1110e43e99cSbellard     int mouse_dy;
1120e43e99cSbellard     int mouse_dz;
1130e43e99cSbellard     uint8_t mouse_buttons;
1140e43e99cSbellard } PS2MouseState;
1150e43e99cSbellard 
116f94f5d71Spbrook /* Table to convert from PC scancodes to raw scancodes.  */
117f94f5d71Spbrook static const unsigned char ps2_raw_keycode[128] = {
118f94f5d71Spbrook   0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
119f94f5d71Spbrook  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
120f94f5d71Spbrook  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
121f94f5d71Spbrook  50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
122f94f5d71Spbrook  11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
123f94f5d71Spbrook 114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
124f94f5d71Spbrook  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
125f94f5d71Spbrook  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
126f94f5d71Spbrook };
1277096a96dSRoy Tam static const unsigned char ps2_raw_keycode_set3[128] = {
1287096a96dSRoy Tam   0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
1297096a96dSRoy Tam  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
1307096a96dSRoy Tam  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
1317096a96dSRoy Tam  50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
1327096a96dSRoy Tam  47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
1337096a96dSRoy Tam 114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
1347096a96dSRoy Tam  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
1357096a96dSRoy Tam  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
1367096a96dSRoy Tam };
137f94f5d71Spbrook 
1380e43e99cSbellard void ps2_queue(void *opaque, int b)
1390e43e99cSbellard {
1400e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1410e43e99cSbellard     PS2Queue *q = &s->queue;
1420e43e99cSbellard 
1432858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
1440e43e99cSbellard         return;
1450e43e99cSbellard     q->data[q->wptr] = b;
1460e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
1470e43e99cSbellard         q->wptr = 0;
1480e43e99cSbellard     q->count++;
1490e43e99cSbellard     s->update_irq(s->update_arg, 1);
1500e43e99cSbellard }
1510e43e99cSbellard 
15235c4d671Saurel32 /*
15335c4d671Saurel32    keycode is expressed as follow:
15435c4d671Saurel32    bit 7    - 0 key pressed, 1 = key released
15535c4d671Saurel32    bits 6-0 - translated scancode set 2
15635c4d671Saurel32  */
1570e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
1580e43e99cSbellard {
159f94f5d71Spbrook     PS2KbdState *s = opaque;
160e7d93956Saurel32 
161fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
1627096a96dSRoy Tam     /* XXX: add support for scancode set 1 */
1637096a96dSRoy Tam     if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
1647096a96dSRoy Tam         if (keycode & 0x80) {
165f94f5d71Spbrook             ps2_queue(&s->common, 0xf0);
1667096a96dSRoy Tam         }
1677096a96dSRoy Tam         if (s->scancode_set == 2) {
168f94f5d71Spbrook             keycode = ps2_raw_keycode[keycode & 0x7f];
1697096a96dSRoy Tam         } else if (s->scancode_set == 3) {
1707096a96dSRoy Tam             keycode = ps2_raw_keycode_set3[keycode & 0x7f];
1717096a96dSRoy Tam         }
172f94f5d71Spbrook       }
1730e43e99cSbellard     ps2_queue(&s->common, keycode);
1740e43e99cSbellard }
1750e43e99cSbellard 
176*66e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
177*66e6536eSGerd Hoffmann                                InputEvent *evt)
178*66e6536eSGerd Hoffmann {
179*66e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
180*66e6536eSGerd Hoffmann     int scancodes[3], i, count;
181*66e6536eSGerd Hoffmann 
182*66e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
183*66e6536eSGerd Hoffmann     count = qemu_input_key_value_to_scancode(evt->key->key,
184*66e6536eSGerd Hoffmann                                              evt->key->down,
185*66e6536eSGerd Hoffmann                                              scancodes);
186*66e6536eSGerd Hoffmann     for (i = 0; i < count; i++) {
187*66e6536eSGerd Hoffmann         ps2_put_keycode(s, scancodes[i]);
188*66e6536eSGerd Hoffmann     }
189*66e6536eSGerd Hoffmann }
190*66e6536eSGerd Hoffmann 
1910e43e99cSbellard uint32_t ps2_read_data(void *opaque)
1920e43e99cSbellard {
1930e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1940e43e99cSbellard     PS2Queue *q;
1950e43e99cSbellard     int val, index;
1960e43e99cSbellard 
1970e43e99cSbellard     q = &s->queue;
1980e43e99cSbellard     if (q->count == 0) {
1990e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
2000e43e99cSbellard            (needed for EMM386) */
2010e43e99cSbellard         /* XXX: need a timer to do things correctly */
2020e43e99cSbellard         index = q->rptr - 1;
2030e43e99cSbellard         if (index < 0)
2040e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
2050e43e99cSbellard         val = q->data[index];
2060e43e99cSbellard     } else {
2070e43e99cSbellard         val = q->data[q->rptr];
2080e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
2090e43e99cSbellard             q->rptr = 0;
2100e43e99cSbellard         q->count--;
2110e43e99cSbellard         /* reading deasserts IRQ */
2120e43e99cSbellard         s->update_irq(s->update_arg, 0);
2130e43e99cSbellard         /* reassert IRQs if data left */
2140e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
2150e43e99cSbellard     }
2160e43e99cSbellard     return val;
2170e43e99cSbellard }
2180e43e99cSbellard 
2197f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
2207f540ab5SChristophe Fergeau {
2217f540ab5SChristophe Fergeau     s->ledstate = ledstate;
2227f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
2237f540ab5SChristophe Fergeau }
2247f540ab5SChristophe Fergeau 
2250e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
2260e43e99cSbellard {
2270e43e99cSbellard     s->scan_enabled = 1;
228e7d93956Saurel32     s->scancode_set = 2;
2297f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
2300e43e99cSbellard }
2310e43e99cSbellard 
2320e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
2330e43e99cSbellard {
2340e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
2350e43e99cSbellard 
2360e43e99cSbellard     switch(s->common.write_cmd) {
2370e43e99cSbellard     default:
2380e43e99cSbellard     case -1:
2390e43e99cSbellard         switch(val) {
2400e43e99cSbellard         case 0x00:
2410e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2420e43e99cSbellard             break;
2430e43e99cSbellard         case 0x05:
2440e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
2450e43e99cSbellard             break;
2460e43e99cSbellard         case KBD_CMD_GET_ID:
2470e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
248e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
24935c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
25035c4d671Saurel32             if (s->translate)
25135c4d671Saurel32                 ps2_queue(&s->common, 0x41);
25235c4d671Saurel32             else
25335c4d671Saurel32                 ps2_queue(&s->common, 0x83);
2540e43e99cSbellard             break;
2550e43e99cSbellard         case KBD_CMD_ECHO:
2560e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
2570e43e99cSbellard             break;
2580e43e99cSbellard         case KBD_CMD_ENABLE:
2590e43e99cSbellard             s->scan_enabled = 1;
2600e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2610e43e99cSbellard             break;
262e7d93956Saurel32         case KBD_CMD_SCANCODE:
2630e43e99cSbellard         case KBD_CMD_SET_LEDS:
2640e43e99cSbellard         case KBD_CMD_SET_RATE:
2650e43e99cSbellard             s->common.write_cmd = val;
2660e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2670e43e99cSbellard             break;
2680e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
2690e43e99cSbellard             ps2_reset_keyboard(s);
2700e43e99cSbellard             s->scan_enabled = 0;
2710e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2720e43e99cSbellard             break;
2730e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
2740e43e99cSbellard             ps2_reset_keyboard(s);
2750e43e99cSbellard             s->scan_enabled = 1;
2760e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2770e43e99cSbellard             break;
2780e43e99cSbellard         case KBD_CMD_RESET:
2790e43e99cSbellard             ps2_reset_keyboard(s);
2800e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2810e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
2820e43e99cSbellard             break;
2830e43e99cSbellard         default:
2840e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2850e43e99cSbellard             break;
2860e43e99cSbellard         }
2870e43e99cSbellard         break;
288e7d93956Saurel32     case KBD_CMD_SCANCODE:
289e7d93956Saurel32         if (val == 0) {
290e7d93956Saurel32             if (s->scancode_set == 1)
291e7d93956Saurel32                 ps2_put_keycode(s, 0x43);
292e7d93956Saurel32             else if (s->scancode_set == 2)
293e7d93956Saurel32                 ps2_put_keycode(s, 0x41);
294e7d93956Saurel32             else if (s->scancode_set == 3)
295e7d93956Saurel32                 ps2_put_keycode(s, 0x3f);
296e7d93956Saurel32         } else {
297e7d93956Saurel32             if (val >= 1 && val <= 3)
298e7d93956Saurel32                 s->scancode_set = val;
299e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
300e7d93956Saurel32         }
301e7d93956Saurel32         s->common.write_cmd = -1;
302e7d93956Saurel32         break;
3030e43e99cSbellard     case KBD_CMD_SET_LEDS:
3047f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
3050e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3060e43e99cSbellard         s->common.write_cmd = -1;
3070e43e99cSbellard         break;
3080e43e99cSbellard     case KBD_CMD_SET_RATE:
3090e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3100e43e99cSbellard         s->common.write_cmd = -1;
3110e43e99cSbellard         break;
3120e43e99cSbellard     }
3130e43e99cSbellard }
3140e43e99cSbellard 
315f94f5d71Spbrook /* Set the scancode translation mode.
316f94f5d71Spbrook    0 = raw scancodes.
317f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
318f94f5d71Spbrook 
319f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
320f94f5d71Spbrook {
321f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
322f94f5d71Spbrook     s->translate = mode;
323f94f5d71Spbrook }
324f94f5d71Spbrook 
3250e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
3260e43e99cSbellard {
3270e43e99cSbellard     unsigned int b;
3280e43e99cSbellard     int dx1, dy1, dz1;
3290e43e99cSbellard 
3300e43e99cSbellard     dx1 = s->mouse_dx;
3310e43e99cSbellard     dy1 = s->mouse_dy;
3320e43e99cSbellard     dz1 = s->mouse_dz;
3330e43e99cSbellard     /* XXX: increase range to 8 bits ? */
3340e43e99cSbellard     if (dx1 > 127)
3350e43e99cSbellard         dx1 = 127;
3360e43e99cSbellard     else if (dx1 < -127)
3370e43e99cSbellard         dx1 = -127;
3380e43e99cSbellard     if (dy1 > 127)
3390e43e99cSbellard         dy1 = 127;
3400e43e99cSbellard     else if (dy1 < -127)
3410e43e99cSbellard         dy1 = -127;
3420e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
3430e43e99cSbellard     ps2_queue(&s->common, b);
3440e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
3450e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
3460e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
3470e43e99cSbellard     switch(s->mouse_type) {
3480e43e99cSbellard     default:
3490e43e99cSbellard         break;
3500e43e99cSbellard     case 3:
3510e43e99cSbellard         if (dz1 > 127)
3520e43e99cSbellard             dz1 = 127;
3530e43e99cSbellard         else if (dz1 < -127)
3540e43e99cSbellard                 dz1 = -127;
3550e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
3560e43e99cSbellard         break;
3570e43e99cSbellard     case 4:
3580e43e99cSbellard         if (dz1 > 7)
3590e43e99cSbellard             dz1 = 7;
3600e43e99cSbellard         else if (dz1 < -7)
3610e43e99cSbellard             dz1 = -7;
3620e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
3630e43e99cSbellard         ps2_queue(&s->common, b);
3640e43e99cSbellard         break;
3650e43e99cSbellard     }
3660e43e99cSbellard 
3670e43e99cSbellard     /* update deltas */
3680e43e99cSbellard     s->mouse_dx -= dx1;
3690e43e99cSbellard     s->mouse_dy -= dy1;
3700e43e99cSbellard     s->mouse_dz -= dz1;
3710e43e99cSbellard }
3720e43e99cSbellard 
3730e43e99cSbellard static void ps2_mouse_event(void *opaque,
3740e43e99cSbellard                             int dx, int dy, int dz, int buttons_state)
3750e43e99cSbellard {
3760e43e99cSbellard     PS2MouseState *s = opaque;
3770e43e99cSbellard 
3780e43e99cSbellard     /* check if deltas are recorded when disabled */
3790e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
3800e43e99cSbellard         return;
3810e43e99cSbellard 
3820e43e99cSbellard     s->mouse_dx += dx;
3830e43e99cSbellard     s->mouse_dy -= dy;
3840e43e99cSbellard     s->mouse_dz += dz;
3850e43e99cSbellard     /* XXX: SDL sometimes generates nul events: we delete them */
3860e43e99cSbellard     if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
3870e43e99cSbellard         s->mouse_buttons == buttons_state)
3880e43e99cSbellard 	return;
3890e43e99cSbellard     s->mouse_buttons = buttons_state;
3900e43e99cSbellard 
391fd214d18SGerd Hoffmann     if (buttons_state) {
392fd214d18SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
393fd214d18SGerd Hoffmann     }
394fd214d18SGerd Hoffmann 
3952858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
3962858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
3970e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
3980e43e99cSbellard                too big deltas */
3990e43e99cSbellard             ps2_mouse_send_packet(s);
4000e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
4010e43e99cSbellard                 break;
4020e43e99cSbellard         }
4030e43e99cSbellard     }
4040e43e99cSbellard }
4050e43e99cSbellard 
406548df2acSths void ps2_mouse_fake_event(void *opaque)
407548df2acSths {
408548df2acSths     ps2_mouse_event(opaque, 1, 0, 0, 0);
409548df2acSths }
410548df2acSths 
4110e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
4120e43e99cSbellard {
4130e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
4140e43e99cSbellard #ifdef DEBUG_MOUSE
4150e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
4160e43e99cSbellard #endif
4170e43e99cSbellard     switch(s->common.write_cmd) {
4180e43e99cSbellard     default:
4190e43e99cSbellard     case -1:
4200e43e99cSbellard         /* mouse command */
4210e43e99cSbellard         if (s->mouse_wrap) {
4220e43e99cSbellard             if (val == AUX_RESET_WRAP) {
4230e43e99cSbellard                 s->mouse_wrap = 0;
4240e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
4250e43e99cSbellard                 return;
4260e43e99cSbellard             } else if (val != AUX_RESET) {
4270e43e99cSbellard                 ps2_queue(&s->common, val);
4280e43e99cSbellard                 return;
4290e43e99cSbellard             }
4300e43e99cSbellard         }
4310e43e99cSbellard         switch(val) {
4320e43e99cSbellard         case AUX_SET_SCALE11:
4330e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
4340e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4350e43e99cSbellard             break;
4360e43e99cSbellard         case AUX_SET_SCALE21:
4370e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
4380e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4390e43e99cSbellard             break;
4400e43e99cSbellard         case AUX_SET_STREAM:
4410e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
4420e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4430e43e99cSbellard             break;
4440e43e99cSbellard         case AUX_SET_WRAP:
4450e43e99cSbellard             s->mouse_wrap = 1;
4460e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4470e43e99cSbellard             break;
4480e43e99cSbellard         case AUX_SET_REMOTE:
4490e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
4500e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4510e43e99cSbellard             break;
4520e43e99cSbellard         case AUX_GET_TYPE:
4530e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4540e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
4550e43e99cSbellard             break;
4560e43e99cSbellard         case AUX_SET_RES:
4570e43e99cSbellard         case AUX_SET_SAMPLE:
4580e43e99cSbellard             s->common.write_cmd = val;
4590e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4600e43e99cSbellard             break;
4610e43e99cSbellard         case AUX_GET_SCALE:
4620e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4630e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
4640e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
4650e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
4660e43e99cSbellard             break;
4670e43e99cSbellard         case AUX_POLL:
4680e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4690e43e99cSbellard             ps2_mouse_send_packet(s);
4700e43e99cSbellard             break;
4710e43e99cSbellard         case AUX_ENABLE_DEV:
4720e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
4730e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4740e43e99cSbellard             break;
4750e43e99cSbellard         case AUX_DISABLE_DEV:
4760e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
4770e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4780e43e99cSbellard             break;
4790e43e99cSbellard         case AUX_SET_DEFAULT:
4800e43e99cSbellard             s->mouse_sample_rate = 100;
4810e43e99cSbellard             s->mouse_resolution = 2;
4820e43e99cSbellard             s->mouse_status = 0;
4830e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4840e43e99cSbellard             break;
4850e43e99cSbellard         case AUX_RESET:
4860e43e99cSbellard             s->mouse_sample_rate = 100;
4870e43e99cSbellard             s->mouse_resolution = 2;
4880e43e99cSbellard             s->mouse_status = 0;
4890e43e99cSbellard             s->mouse_type = 0;
4900e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4910e43e99cSbellard             ps2_queue(&s->common, 0xaa);
4920e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
4930e43e99cSbellard             break;
4940e43e99cSbellard         default:
4950e43e99cSbellard             break;
4960e43e99cSbellard         }
4970e43e99cSbellard         break;
4980e43e99cSbellard     case AUX_SET_SAMPLE:
4990e43e99cSbellard         s->mouse_sample_rate = val;
5000e43e99cSbellard         /* detect IMPS/2 or IMEX */
5010e43e99cSbellard         switch(s->mouse_detect_state) {
5020e43e99cSbellard         default:
5030e43e99cSbellard         case 0:
5040e43e99cSbellard             if (val == 200)
5050e43e99cSbellard                 s->mouse_detect_state = 1;
5060e43e99cSbellard             break;
5070e43e99cSbellard         case 1:
5080e43e99cSbellard             if (val == 100)
5090e43e99cSbellard                 s->mouse_detect_state = 2;
5100e43e99cSbellard             else if (val == 200)
5110e43e99cSbellard                 s->mouse_detect_state = 3;
5120e43e99cSbellard             else
5130e43e99cSbellard                 s->mouse_detect_state = 0;
5140e43e99cSbellard             break;
5150e43e99cSbellard         case 2:
5160e43e99cSbellard             if (val == 80)
5170e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
5180e43e99cSbellard             s->mouse_detect_state = 0;
5190e43e99cSbellard             break;
5200e43e99cSbellard         case 3:
5210e43e99cSbellard             if (val == 80)
5220e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
5230e43e99cSbellard             s->mouse_detect_state = 0;
5240e43e99cSbellard             break;
5250e43e99cSbellard         }
5260e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5270e43e99cSbellard         s->common.write_cmd = -1;
5280e43e99cSbellard         break;
5290e43e99cSbellard     case AUX_SET_RES:
5300e43e99cSbellard         s->mouse_resolution = val;
5310e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5320e43e99cSbellard         s->common.write_cmd = -1;
5330e43e99cSbellard         break;
5340e43e99cSbellard     }
5350e43e99cSbellard }
5360e43e99cSbellard 
537ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
5380e43e99cSbellard {
5390e43e99cSbellard     PS2Queue *q;
5400e43e99cSbellard     s->write_cmd = -1;
5410e43e99cSbellard     q = &s->queue;
5420e43e99cSbellard     q->rptr = 0;
5430e43e99cSbellard     q->wptr = 0;
5440e43e99cSbellard     q->count = 0;
545deeccef3Saliguori     s->update_irq(s->update_arg, 0);
5460e43e99cSbellard }
5470e43e99cSbellard 
5482858ab09SGonglei static void ps2_common_post_load(PS2State *s)
5492858ab09SGonglei {
5502858ab09SGonglei     PS2Queue *q = &s->queue;
5512858ab09SGonglei     int size;
5522858ab09SGonglei     int i;
5532858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
5542858ab09SGonglei 
5552858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
5562858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
5572858ab09SGonglei 
5582858ab09SGonglei     /* move the queue elements to the start of data array */
5592858ab09SGonglei     if (size > 0) {
5602858ab09SGonglei         for (i = 0; i < size; i++) {
5612858ab09SGonglei             /* move the queue elements to the temporary buffer */
5622858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
5632858ab09SGonglei             if (++q->rptr == 256) {
5642858ab09SGonglei                 q->rptr = 0;
5652858ab09SGonglei             }
5662858ab09SGonglei         }
5672858ab09SGonglei         memcpy(q->data, tmp_data, size);
5682858ab09SGonglei     }
5692858ab09SGonglei     /* reset rptr/wptr/count */
5702858ab09SGonglei     q->rptr = 0;
5712858ab09SGonglei     q->wptr = size;
5722858ab09SGonglei     q->count = size;
5732858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
5742858ab09SGonglei }
5752858ab09SGonglei 
576ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
577ef74679aSDinesh Subhraveti {
578ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
579ef74679aSDinesh Subhraveti 
580ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
581ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
582ef74679aSDinesh Subhraveti     s->translate = 0;
583ef74679aSDinesh Subhraveti     s->scancode_set = 0;
584ef74679aSDinesh Subhraveti }
585ef74679aSDinesh Subhraveti 
586ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
587ef74679aSDinesh Subhraveti {
588ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
589ef74679aSDinesh Subhraveti 
590ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
591ef74679aSDinesh Subhraveti     s->mouse_status = 0;
592ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
593ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
594ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
595ef74679aSDinesh Subhraveti     s->mouse_type = 0;
596ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
597ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
598ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
599ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
600ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
601ef74679aSDinesh Subhraveti }
602ef74679aSDinesh Subhraveti 
603b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
604b31442c3SJuan Quintela     .name = "PS2 Common State",
605b31442c3SJuan Quintela     .version_id = 3,
606b31442c3SJuan Quintela     .minimum_version_id = 2,
607b31442c3SJuan Quintela     .minimum_version_id_old = 2,
608b31442c3SJuan Quintela     .fields      = (VMStateField []) {
609b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
610b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
611b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
612b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
613b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
614b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
6157783e9f0Spbrook     }
616b31442c3SJuan Quintela };
6177783e9f0Spbrook 
6187f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
6197f540ab5SChristophe Fergeau {
6207f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6217f540ab5SChristophe Fergeau 
6227f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
6237f540ab5SChristophe Fergeau }
6247f540ab5SChristophe Fergeau 
6257f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
6267f540ab5SChristophe Fergeau {
6277f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6287f540ab5SChristophe Fergeau 
6297f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
6307f540ab5SChristophe Fergeau     return 0;
6317f540ab5SChristophe Fergeau }
6327f540ab5SChristophe Fergeau 
6337f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
6347f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
6357f540ab5SChristophe Fergeau     .version_id = 3,
6367f540ab5SChristophe Fergeau     .minimum_version_id = 2,
6377f540ab5SChristophe Fergeau     .minimum_version_id_old = 2,
6387f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
6397f540ab5SChristophe Fergeau     .fields      = (VMStateField []) {
6407f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
6417f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
6427f540ab5SChristophe Fergeau     }
6437f540ab5SChristophe Fergeau };
6447f540ab5SChristophe Fergeau 
645db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
6460e43e99cSbellard {
6470e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
6482858ab09SGonglei     PS2State *ps2 = &s->common;
6490e43e99cSbellard 
650db596c53SJuan Quintela     if (version_id == 2)
651e7d93956Saurel32         s->scancode_set=2;
6522858ab09SGonglei 
6532858ab09SGonglei     ps2_common_post_load(ps2);
6542858ab09SGonglei 
6550e43e99cSbellard     return 0;
6560e43e99cSbellard }
6570e43e99cSbellard 
6582858ab09SGonglei static void ps2_kbd_pre_save(void *opaque)
6592858ab09SGonglei {
6602858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
6612858ab09SGonglei     PS2State *ps2 = &s->common;
6622858ab09SGonglei 
6632858ab09SGonglei     ps2_common_post_load(ps2);
6642858ab09SGonglei }
6652858ab09SGonglei 
666b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
667b31442c3SJuan Quintela     .name = "ps2kbd",
668b31442c3SJuan Quintela     .version_id = 3,
669db596c53SJuan Quintela     .minimum_version_id = 2,
670b31442c3SJuan Quintela     .minimum_version_id_old = 2,
671db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
6722858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
673b31442c3SJuan Quintela     .fields      = (VMStateField []) {
674b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
675b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
676b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
677b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
678b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
6797f540ab5SChristophe Fergeau     },
6807f540ab5SChristophe Fergeau     .subsections = (VMStateSubsection []) {
6817f540ab5SChristophe Fergeau         {
6827f540ab5SChristophe Fergeau             .vmsd = &vmstate_ps2_keyboard_ledstate,
6837f540ab5SChristophe Fergeau             .needed = ps2_keyboard_ledstate_needed,
6847f540ab5SChristophe Fergeau         }, {
6857f540ab5SChristophe Fergeau             /* empty */
6867f540ab5SChristophe Fergeau         }
6870e43e99cSbellard     }
688b31442c3SJuan Quintela };
689b31442c3SJuan Quintela 
6902858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
6912858ab09SGonglei {
6922858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
6932858ab09SGonglei     PS2State *ps2 = &s->common;
6942858ab09SGonglei 
6952858ab09SGonglei     ps2_common_post_load(ps2);
6962858ab09SGonglei 
6972858ab09SGonglei     return 0;
6982858ab09SGonglei }
6992858ab09SGonglei 
7002858ab09SGonglei static void ps2_mouse_pre_save(void *opaque)
7012858ab09SGonglei {
7022858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
7032858ab09SGonglei     PS2State *ps2 = &s->common;
7042858ab09SGonglei 
7052858ab09SGonglei     ps2_common_post_load(ps2);
7062858ab09SGonglei }
7072858ab09SGonglei 
708b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
709b31442c3SJuan Quintela     .name = "ps2mouse",
710b31442c3SJuan Quintela     .version_id = 2,
711b31442c3SJuan Quintela     .minimum_version_id = 2,
712b31442c3SJuan Quintela     .minimum_version_id_old = 2,
7132858ab09SGonglei     .post_load = ps2_mouse_post_load,
7142858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
715b31442c3SJuan Quintela     .fields      = (VMStateField []) {
716b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
717b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
718b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
719b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
720b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
721b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
722b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
723b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
724b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
725b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
726b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
727b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
728b31442c3SJuan Quintela     }
729b31442c3SJuan Quintela };
7300e43e99cSbellard 
731*66e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
732*66e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
733*66e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
734*66e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
735*66e6536eSGerd Hoffmann };
736*66e6536eSGerd Hoffmann 
7370e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
7380e43e99cSbellard {
7397267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
7400e43e99cSbellard 
7410e43e99cSbellard     s->common.update_irq = update_irq;
7420e43e99cSbellard     s->common.update_arg = update_arg;
743e7d93956Saurel32     s->scancode_set = 2;
7440be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
745*66e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
746*66e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
747ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
7480e43e99cSbellard     return s;
7490e43e99cSbellard }
7500e43e99cSbellard 
7510e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
7520e43e99cSbellard {
7537267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
7540e43e99cSbellard 
7550e43e99cSbellard     s->common.update_irq = update_irq;
7560e43e99cSbellard     s->common.update_arg = update_arg;
7570be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
758455204ebSths     qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
759ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
7600e43e99cSbellard     return s;
7610e43e99cSbellard }
762