xref: /qemu/hw/input/ps2.c (revision 7fb1cf1606c78c9d5b538f29176fd5a101726a9d)
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"
2766e6536eSGerd Hoffmann #include "ui/input.h"
289c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
290e43e99cSbellard 
305edab03dSDon Koch #include "trace.h"
315edab03dSDon Koch 
320e43e99cSbellard /* debug PC keyboard */
330e43e99cSbellard //#define DEBUG_KBD
340e43e99cSbellard 
350e43e99cSbellard /* debug PC keyboard : only mouse */
360e43e99cSbellard //#define DEBUG_MOUSE
370e43e99cSbellard 
380e43e99cSbellard /* Keyboard Commands */
390e43e99cSbellard #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
400e43e99cSbellard #define KBD_CMD_ECHO     	0xEE
41e7d93956Saurel32 #define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
420e43e99cSbellard #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
430e43e99cSbellard #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
440e43e99cSbellard #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
450e43e99cSbellard #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
460e43e99cSbellard #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
470e43e99cSbellard #define KBD_CMD_RESET		0xFF	/* Reset */
480e43e99cSbellard 
490e43e99cSbellard /* Keyboard Replies */
500e43e99cSbellard #define KBD_REPLY_POR		0xAA	/* Power on reset */
5135c4d671Saurel32 #define KBD_REPLY_ID		0xAB	/* Keyboard ID */
520e43e99cSbellard #define KBD_REPLY_ACK		0xFA	/* Command ACK */
530e43e99cSbellard #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
540e43e99cSbellard 
550e43e99cSbellard /* Mouse Commands */
560e43e99cSbellard #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
570e43e99cSbellard #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
580e43e99cSbellard #define AUX_SET_RES		0xE8	/* Set resolution */
590e43e99cSbellard #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
600e43e99cSbellard #define AUX_SET_STREAM		0xEA	/* Set stream mode */
610e43e99cSbellard #define AUX_POLL		0xEB	/* Poll */
620e43e99cSbellard #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
630e43e99cSbellard #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
640e43e99cSbellard #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
650e43e99cSbellard #define AUX_GET_TYPE		0xF2	/* Get type */
660e43e99cSbellard #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
670e43e99cSbellard #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
680e43e99cSbellard #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
690e43e99cSbellard #define AUX_SET_DEFAULT		0xF6
700e43e99cSbellard #define AUX_RESET		0xFF	/* Reset aux device */
710e43e99cSbellard #define AUX_ACK			0xFA	/* Command byte ACK. */
720e43e99cSbellard 
730e43e99cSbellard #define MOUSE_STATUS_REMOTE     0x40
740e43e99cSbellard #define MOUSE_STATUS_ENABLED    0x20
750e43e99cSbellard #define MOUSE_STATUS_SCALE21    0x10
760e43e99cSbellard 
772858ab09SGonglei #define PS2_QUEUE_SIZE 16  /* Buffer size required by PS/2 protocol */
780e43e99cSbellard 
790e43e99cSbellard typedef struct {
802858ab09SGonglei     /* Keep the data array 256 bytes long, which compatibility
812858ab09SGonglei      with older qemu versions. */
822858ab09SGonglei     uint8_t data[256];
830e43e99cSbellard     int rptr, wptr, count;
840e43e99cSbellard } PS2Queue;
850e43e99cSbellard 
860e43e99cSbellard typedef struct {
870e43e99cSbellard     PS2Queue queue;
880e43e99cSbellard     int32_t write_cmd;
890e43e99cSbellard     void (*update_irq)(void *, int);
900e43e99cSbellard     void *update_arg;
910e43e99cSbellard } PS2State;
920e43e99cSbellard 
930e43e99cSbellard typedef struct {
940e43e99cSbellard     PS2State common;
950e43e99cSbellard     int scan_enabled;
965cbdb3a3SStefan Weil     /* QEMU uses translated PC scancodes internally.  To avoid multiple
97f94f5d71Spbrook        conversions we do the translation (if any) in the PS/2 emulation
98f94f5d71Spbrook        not the keyboard controller.  */
99f94f5d71Spbrook     int translate;
100e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
1017f540ab5SChristophe Fergeau     int ledstate;
1020e43e99cSbellard } PS2KbdState;
1030e43e99cSbellard 
1040e43e99cSbellard typedef struct {
1050e43e99cSbellard     PS2State common;
1060e43e99cSbellard     uint8_t mouse_status;
1070e43e99cSbellard     uint8_t mouse_resolution;
1080e43e99cSbellard     uint8_t mouse_sample_rate;
1090e43e99cSbellard     uint8_t mouse_wrap;
1100e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1110e43e99cSbellard     uint8_t mouse_detect_state;
1120e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1130e43e99cSbellard     int mouse_dy;
1140e43e99cSbellard     int mouse_dz;
1150e43e99cSbellard     uint8_t mouse_buttons;
1160e43e99cSbellard } PS2MouseState;
1170e43e99cSbellard 
118f94f5d71Spbrook /* Table to convert from PC scancodes to raw scancodes.  */
119f94f5d71Spbrook static const unsigned char ps2_raw_keycode[128] = {
120f94f5d71Spbrook   0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
121f94f5d71Spbrook  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
122f94f5d71Spbrook  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
123f94f5d71Spbrook  50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
124f94f5d71Spbrook  11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
125f94f5d71Spbrook 114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
126f94f5d71Spbrook  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
127f94f5d71Spbrook  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
128f94f5d71Spbrook };
1297096a96dSRoy Tam static const unsigned char ps2_raw_keycode_set3[128] = {
1307096a96dSRoy Tam   0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
1317096a96dSRoy Tam  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
1327096a96dSRoy Tam  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
1337096a96dSRoy Tam  50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
1347096a96dSRoy Tam  47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
1357096a96dSRoy Tam 114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
1367096a96dSRoy Tam  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
1377096a96dSRoy Tam  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
1387096a96dSRoy Tam };
139f94f5d71Spbrook 
1400e43e99cSbellard void ps2_queue(void *opaque, int b)
1410e43e99cSbellard {
1420e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1430e43e99cSbellard     PS2Queue *q = &s->queue;
1440e43e99cSbellard 
1452858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
1460e43e99cSbellard         return;
1470e43e99cSbellard     q->data[q->wptr] = b;
1480e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
1490e43e99cSbellard         q->wptr = 0;
1500e43e99cSbellard     q->count++;
1510e43e99cSbellard     s->update_irq(s->update_arg, 1);
1520e43e99cSbellard }
1530e43e99cSbellard 
15435c4d671Saurel32 /*
15535c4d671Saurel32    keycode is expressed as follow:
15635c4d671Saurel32    bit 7    - 0 key pressed, 1 = key released
15735c4d671Saurel32    bits 6-0 - translated scancode set 2
15835c4d671Saurel32  */
1590e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
1600e43e99cSbellard {
161f94f5d71Spbrook     PS2KbdState *s = opaque;
162e7d93956Saurel32 
1635edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
164fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
1657096a96dSRoy Tam     /* XXX: add support for scancode set 1 */
1667096a96dSRoy Tam     if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
1677096a96dSRoy Tam         if (keycode & 0x80) {
168f94f5d71Spbrook             ps2_queue(&s->common, 0xf0);
1697096a96dSRoy Tam         }
1707096a96dSRoy Tam         if (s->scancode_set == 2) {
171f94f5d71Spbrook             keycode = ps2_raw_keycode[keycode & 0x7f];
1727096a96dSRoy Tam         } else if (s->scancode_set == 3) {
1737096a96dSRoy Tam             keycode = ps2_raw_keycode_set3[keycode & 0x7f];
1747096a96dSRoy Tam         }
175f94f5d71Spbrook       }
1760e43e99cSbellard     ps2_queue(&s->common, keycode);
1770e43e99cSbellard }
1780e43e99cSbellard 
17966e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
18066e6536eSGerd Hoffmann                                InputEvent *evt)
18166e6536eSGerd Hoffmann {
18266e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
18366e6536eSGerd Hoffmann     int scancodes[3], i, count;
18466e6536eSGerd Hoffmann 
18566e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
186568c73a4SEric Blake     count = qemu_input_key_value_to_scancode(evt->u.key->key,
187568c73a4SEric Blake                                              evt->u.key->down,
18866e6536eSGerd Hoffmann                                              scancodes);
18966e6536eSGerd Hoffmann     for (i = 0; i < count; i++) {
19066e6536eSGerd Hoffmann         ps2_put_keycode(s, scancodes[i]);
19166e6536eSGerd Hoffmann     }
19266e6536eSGerd Hoffmann }
19366e6536eSGerd Hoffmann 
1940e43e99cSbellard uint32_t ps2_read_data(void *opaque)
1950e43e99cSbellard {
1960e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1970e43e99cSbellard     PS2Queue *q;
1980e43e99cSbellard     int val, index;
1990e43e99cSbellard 
2005edab03dSDon Koch     trace_ps2_read_data(opaque);
2010e43e99cSbellard     q = &s->queue;
2020e43e99cSbellard     if (q->count == 0) {
2030e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
2040e43e99cSbellard            (needed for EMM386) */
2050e43e99cSbellard         /* XXX: need a timer to do things correctly */
2060e43e99cSbellard         index = q->rptr - 1;
2070e43e99cSbellard         if (index < 0)
2080e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
2090e43e99cSbellard         val = q->data[index];
2100e43e99cSbellard     } else {
2110e43e99cSbellard         val = q->data[q->rptr];
2120e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
2130e43e99cSbellard             q->rptr = 0;
2140e43e99cSbellard         q->count--;
2150e43e99cSbellard         /* reading deasserts IRQ */
2160e43e99cSbellard         s->update_irq(s->update_arg, 0);
2170e43e99cSbellard         /* reassert IRQs if data left */
2180e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
2190e43e99cSbellard     }
2200e43e99cSbellard     return val;
2210e43e99cSbellard }
2220e43e99cSbellard 
2237f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
2247f540ab5SChristophe Fergeau {
2255edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
2267f540ab5SChristophe Fergeau     s->ledstate = ledstate;
2277f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
2287f540ab5SChristophe Fergeau }
2297f540ab5SChristophe Fergeau 
2300e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
2310e43e99cSbellard {
2325edab03dSDon Koch     trace_ps2_reset_keyboard(s);
2330e43e99cSbellard     s->scan_enabled = 1;
234e7d93956Saurel32     s->scancode_set = 2;
2357f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
2360e43e99cSbellard }
2370e43e99cSbellard 
2380e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
2390e43e99cSbellard {
2400e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
2410e43e99cSbellard 
2425edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
2430e43e99cSbellard     switch(s->common.write_cmd) {
2440e43e99cSbellard     default:
2450e43e99cSbellard     case -1:
2460e43e99cSbellard         switch(val) {
2470e43e99cSbellard         case 0x00:
2480e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2490e43e99cSbellard             break;
2500e43e99cSbellard         case 0x05:
2510e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
2520e43e99cSbellard             break;
2530e43e99cSbellard         case KBD_CMD_GET_ID:
2540e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
255e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
25635c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
25735c4d671Saurel32             if (s->translate)
25835c4d671Saurel32                 ps2_queue(&s->common, 0x41);
25935c4d671Saurel32             else
26035c4d671Saurel32                 ps2_queue(&s->common, 0x83);
2610e43e99cSbellard             break;
2620e43e99cSbellard         case KBD_CMD_ECHO:
2630e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
2640e43e99cSbellard             break;
2650e43e99cSbellard         case KBD_CMD_ENABLE:
2660e43e99cSbellard             s->scan_enabled = 1;
2670e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2680e43e99cSbellard             break;
269e7d93956Saurel32         case KBD_CMD_SCANCODE:
2700e43e99cSbellard         case KBD_CMD_SET_LEDS:
2710e43e99cSbellard         case KBD_CMD_SET_RATE:
2720e43e99cSbellard             s->common.write_cmd = val;
2730e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2740e43e99cSbellard             break;
2750e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
2760e43e99cSbellard             ps2_reset_keyboard(s);
2770e43e99cSbellard             s->scan_enabled = 0;
2780e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2790e43e99cSbellard             break;
2800e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
2810e43e99cSbellard             ps2_reset_keyboard(s);
2820e43e99cSbellard             s->scan_enabled = 1;
2830e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2840e43e99cSbellard             break;
2850e43e99cSbellard         case KBD_CMD_RESET:
2860e43e99cSbellard             ps2_reset_keyboard(s);
2870e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2880e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
2890e43e99cSbellard             break;
2900e43e99cSbellard         default:
2910e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2920e43e99cSbellard             break;
2930e43e99cSbellard         }
2940e43e99cSbellard         break;
295e7d93956Saurel32     case KBD_CMD_SCANCODE:
296e7d93956Saurel32         if (val == 0) {
297e7d93956Saurel32             if (s->scancode_set == 1)
298e7d93956Saurel32                 ps2_put_keycode(s, 0x43);
299e7d93956Saurel32             else if (s->scancode_set == 2)
300e7d93956Saurel32                 ps2_put_keycode(s, 0x41);
301e7d93956Saurel32             else if (s->scancode_set == 3)
302e7d93956Saurel32                 ps2_put_keycode(s, 0x3f);
303e7d93956Saurel32         } else {
304e7d93956Saurel32             if (val >= 1 && val <= 3)
305e7d93956Saurel32                 s->scancode_set = val;
306e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
307e7d93956Saurel32         }
308e7d93956Saurel32         s->common.write_cmd = -1;
309e7d93956Saurel32         break;
3100e43e99cSbellard     case KBD_CMD_SET_LEDS:
3117f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
3120e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3130e43e99cSbellard         s->common.write_cmd = -1;
3140e43e99cSbellard         break;
3150e43e99cSbellard     case KBD_CMD_SET_RATE:
3160e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
3170e43e99cSbellard         s->common.write_cmd = -1;
3180e43e99cSbellard         break;
3190e43e99cSbellard     }
3200e43e99cSbellard }
3210e43e99cSbellard 
322f94f5d71Spbrook /* Set the scancode translation mode.
323f94f5d71Spbrook    0 = raw scancodes.
324f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
325f94f5d71Spbrook 
326f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
327f94f5d71Spbrook {
328f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
3295edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
330f94f5d71Spbrook     s->translate = mode;
331f94f5d71Spbrook }
332f94f5d71Spbrook 
3330e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
3340e43e99cSbellard {
3350e43e99cSbellard     unsigned int b;
3360e43e99cSbellard     int dx1, dy1, dz1;
3370e43e99cSbellard 
3380e43e99cSbellard     dx1 = s->mouse_dx;
3390e43e99cSbellard     dy1 = s->mouse_dy;
3400e43e99cSbellard     dz1 = s->mouse_dz;
3410e43e99cSbellard     /* XXX: increase range to 8 bits ? */
3420e43e99cSbellard     if (dx1 > 127)
3430e43e99cSbellard         dx1 = 127;
3440e43e99cSbellard     else if (dx1 < -127)
3450e43e99cSbellard         dx1 = -127;
3460e43e99cSbellard     if (dy1 > 127)
3470e43e99cSbellard         dy1 = 127;
3480e43e99cSbellard     else if (dy1 < -127)
3490e43e99cSbellard         dy1 = -127;
3500e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
3510e43e99cSbellard     ps2_queue(&s->common, b);
3520e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
3530e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
3540e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
3550e43e99cSbellard     switch(s->mouse_type) {
3560e43e99cSbellard     default:
3570e43e99cSbellard         break;
3580e43e99cSbellard     case 3:
3590e43e99cSbellard         if (dz1 > 127)
3600e43e99cSbellard             dz1 = 127;
3610e43e99cSbellard         else if (dz1 < -127)
3620e43e99cSbellard                 dz1 = -127;
3630e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
3640e43e99cSbellard         break;
3650e43e99cSbellard     case 4:
3660e43e99cSbellard         if (dz1 > 7)
3670e43e99cSbellard             dz1 = 7;
3680e43e99cSbellard         else if (dz1 < -7)
3690e43e99cSbellard             dz1 = -7;
3700e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
3710e43e99cSbellard         ps2_queue(&s->common, b);
3720e43e99cSbellard         break;
3730e43e99cSbellard     }
3740e43e99cSbellard 
3755edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
3760e43e99cSbellard     /* update deltas */
3770e43e99cSbellard     s->mouse_dx -= dx1;
3780e43e99cSbellard     s->mouse_dy -= dy1;
3790e43e99cSbellard     s->mouse_dz -= dz1;
3800e43e99cSbellard }
3810e43e99cSbellard 
3822a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
3832a766d29SGerd Hoffmann                             InputEvent *evt)
3840e43e99cSbellard {
385*7fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
3862a766d29SGerd Hoffmann         [INPUT_BUTTON_LEFT]   = MOUSE_EVENT_LBUTTON,
3872a766d29SGerd Hoffmann         [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
3882a766d29SGerd Hoffmann         [INPUT_BUTTON_RIGHT]  = MOUSE_EVENT_RBUTTON,
3892a766d29SGerd Hoffmann     };
3902a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
3910e43e99cSbellard 
3920e43e99cSbellard     /* check if deltas are recorded when disabled */
3930e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
3940e43e99cSbellard         return;
3950e43e99cSbellard 
396568c73a4SEric Blake     switch (evt->type) {
3972a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
398568c73a4SEric Blake         if (evt->u.rel->axis == INPUT_AXIS_X) {
399568c73a4SEric Blake             s->mouse_dx += evt->u.rel->value;
400568c73a4SEric Blake         } else if (evt->u.rel->axis == INPUT_AXIS_Y) {
401568c73a4SEric Blake             s->mouse_dy -= evt->u.rel->value;
4022a766d29SGerd Hoffmann         }
4032a766d29SGerd Hoffmann         break;
4040e43e99cSbellard 
4052a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
406568c73a4SEric Blake         if (evt->u.btn->down) {
407568c73a4SEric Blake             s->mouse_buttons |= bmap[evt->u.btn->button];
408568c73a4SEric Blake             if (evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
4092a766d29SGerd Hoffmann                 s->mouse_dz--;
410568c73a4SEric Blake             } else if (evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
4112a766d29SGerd Hoffmann                 s->mouse_dz++;
4122a766d29SGerd Hoffmann             }
4132a766d29SGerd Hoffmann         } else {
414568c73a4SEric Blake             s->mouse_buttons &= ~bmap[evt->u.btn->button];
4152a766d29SGerd Hoffmann         }
4162a766d29SGerd Hoffmann         break;
4172a766d29SGerd Hoffmann 
4182a766d29SGerd Hoffmann     default:
4192a766d29SGerd Hoffmann         /* keep gcc happy */
4202a766d29SGerd Hoffmann         break;
4212a766d29SGerd Hoffmann     }
422fd214d18SGerd Hoffmann }
423fd214d18SGerd Hoffmann 
4242a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
4252a766d29SGerd Hoffmann {
4262a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
4272a766d29SGerd Hoffmann 
4282a766d29SGerd Hoffmann     if (s->mouse_buttons) {
4292a766d29SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
4302a766d29SGerd Hoffmann     }
4312858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
4322858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
4330e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
4340e43e99cSbellard                too big deltas */
4350e43e99cSbellard             ps2_mouse_send_packet(s);
4360e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
4370e43e99cSbellard                 break;
4380e43e99cSbellard         }
4390e43e99cSbellard     }
4400e43e99cSbellard }
4410e43e99cSbellard 
442548df2acSths void ps2_mouse_fake_event(void *opaque)
443548df2acSths {
4442a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
4455edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
4462a766d29SGerd Hoffmann     s->mouse_dx++;
4472a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
448548df2acSths }
449548df2acSths 
4500e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
4510e43e99cSbellard {
4520e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
4535edab03dSDon Koch 
4545edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
4550e43e99cSbellard #ifdef DEBUG_MOUSE
4560e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
4570e43e99cSbellard #endif
4580e43e99cSbellard     switch(s->common.write_cmd) {
4590e43e99cSbellard     default:
4600e43e99cSbellard     case -1:
4610e43e99cSbellard         /* mouse command */
4620e43e99cSbellard         if (s->mouse_wrap) {
4630e43e99cSbellard             if (val == AUX_RESET_WRAP) {
4640e43e99cSbellard                 s->mouse_wrap = 0;
4650e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
4660e43e99cSbellard                 return;
4670e43e99cSbellard             } else if (val != AUX_RESET) {
4680e43e99cSbellard                 ps2_queue(&s->common, val);
4690e43e99cSbellard                 return;
4700e43e99cSbellard             }
4710e43e99cSbellard         }
4720e43e99cSbellard         switch(val) {
4730e43e99cSbellard         case AUX_SET_SCALE11:
4740e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
4750e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4760e43e99cSbellard             break;
4770e43e99cSbellard         case AUX_SET_SCALE21:
4780e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
4790e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4800e43e99cSbellard             break;
4810e43e99cSbellard         case AUX_SET_STREAM:
4820e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
4830e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4840e43e99cSbellard             break;
4850e43e99cSbellard         case AUX_SET_WRAP:
4860e43e99cSbellard             s->mouse_wrap = 1;
4870e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4880e43e99cSbellard             break;
4890e43e99cSbellard         case AUX_SET_REMOTE:
4900e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
4910e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4920e43e99cSbellard             break;
4930e43e99cSbellard         case AUX_GET_TYPE:
4940e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4950e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
4960e43e99cSbellard             break;
4970e43e99cSbellard         case AUX_SET_RES:
4980e43e99cSbellard         case AUX_SET_SAMPLE:
4990e43e99cSbellard             s->common.write_cmd = val;
5000e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5010e43e99cSbellard             break;
5020e43e99cSbellard         case AUX_GET_SCALE:
5030e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5040e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
5050e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
5060e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
5070e43e99cSbellard             break;
5080e43e99cSbellard         case AUX_POLL:
5090e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5100e43e99cSbellard             ps2_mouse_send_packet(s);
5110e43e99cSbellard             break;
5120e43e99cSbellard         case AUX_ENABLE_DEV:
5130e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
5140e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5150e43e99cSbellard             break;
5160e43e99cSbellard         case AUX_DISABLE_DEV:
5170e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
5180e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5190e43e99cSbellard             break;
5200e43e99cSbellard         case AUX_SET_DEFAULT:
5210e43e99cSbellard             s->mouse_sample_rate = 100;
5220e43e99cSbellard             s->mouse_resolution = 2;
5230e43e99cSbellard             s->mouse_status = 0;
5240e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5250e43e99cSbellard             break;
5260e43e99cSbellard         case AUX_RESET:
5270e43e99cSbellard             s->mouse_sample_rate = 100;
5280e43e99cSbellard             s->mouse_resolution = 2;
5290e43e99cSbellard             s->mouse_status = 0;
5300e43e99cSbellard             s->mouse_type = 0;
5310e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
5320e43e99cSbellard             ps2_queue(&s->common, 0xaa);
5330e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
5340e43e99cSbellard             break;
5350e43e99cSbellard         default:
5360e43e99cSbellard             break;
5370e43e99cSbellard         }
5380e43e99cSbellard         break;
5390e43e99cSbellard     case AUX_SET_SAMPLE:
5400e43e99cSbellard         s->mouse_sample_rate = val;
5410e43e99cSbellard         /* detect IMPS/2 or IMEX */
5420e43e99cSbellard         switch(s->mouse_detect_state) {
5430e43e99cSbellard         default:
5440e43e99cSbellard         case 0:
5450e43e99cSbellard             if (val == 200)
5460e43e99cSbellard                 s->mouse_detect_state = 1;
5470e43e99cSbellard             break;
5480e43e99cSbellard         case 1:
5490e43e99cSbellard             if (val == 100)
5500e43e99cSbellard                 s->mouse_detect_state = 2;
5510e43e99cSbellard             else if (val == 200)
5520e43e99cSbellard                 s->mouse_detect_state = 3;
5530e43e99cSbellard             else
5540e43e99cSbellard                 s->mouse_detect_state = 0;
5550e43e99cSbellard             break;
5560e43e99cSbellard         case 2:
5570e43e99cSbellard             if (val == 80)
5580e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
5590e43e99cSbellard             s->mouse_detect_state = 0;
5600e43e99cSbellard             break;
5610e43e99cSbellard         case 3:
5620e43e99cSbellard             if (val == 80)
5630e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
5640e43e99cSbellard             s->mouse_detect_state = 0;
5650e43e99cSbellard             break;
5660e43e99cSbellard         }
5670e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5680e43e99cSbellard         s->common.write_cmd = -1;
5690e43e99cSbellard         break;
5700e43e99cSbellard     case AUX_SET_RES:
5710e43e99cSbellard         s->mouse_resolution = val;
5720e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5730e43e99cSbellard         s->common.write_cmd = -1;
5740e43e99cSbellard         break;
5750e43e99cSbellard     }
5760e43e99cSbellard }
5770e43e99cSbellard 
578ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
5790e43e99cSbellard {
5800e43e99cSbellard     PS2Queue *q;
5810e43e99cSbellard     s->write_cmd = -1;
5820e43e99cSbellard     q = &s->queue;
5830e43e99cSbellard     q->rptr = 0;
5840e43e99cSbellard     q->wptr = 0;
5850e43e99cSbellard     q->count = 0;
586deeccef3Saliguori     s->update_irq(s->update_arg, 0);
5870e43e99cSbellard }
5880e43e99cSbellard 
5892858ab09SGonglei static void ps2_common_post_load(PS2State *s)
5902858ab09SGonglei {
5912858ab09SGonglei     PS2Queue *q = &s->queue;
5922858ab09SGonglei     int size;
5932858ab09SGonglei     int i;
5942858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
5952858ab09SGonglei 
5962858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
5972858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
5982858ab09SGonglei 
5992858ab09SGonglei     /* move the queue elements to the start of data array */
6002858ab09SGonglei     if (size > 0) {
6012858ab09SGonglei         for (i = 0; i < size; i++) {
6022858ab09SGonglei             /* move the queue elements to the temporary buffer */
6032858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
6042858ab09SGonglei             if (++q->rptr == 256) {
6052858ab09SGonglei                 q->rptr = 0;
6062858ab09SGonglei             }
6072858ab09SGonglei         }
6082858ab09SGonglei         memcpy(q->data, tmp_data, size);
6092858ab09SGonglei     }
6102858ab09SGonglei     /* reset rptr/wptr/count */
6112858ab09SGonglei     q->rptr = 0;
6122858ab09SGonglei     q->wptr = size;
6132858ab09SGonglei     q->count = size;
6142858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
6152858ab09SGonglei }
6162858ab09SGonglei 
617ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
618ef74679aSDinesh Subhraveti {
619ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
620ef74679aSDinesh Subhraveti 
6215edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
622ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
623ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
624ef74679aSDinesh Subhraveti     s->translate = 0;
625ef74679aSDinesh Subhraveti     s->scancode_set = 0;
626ef74679aSDinesh Subhraveti }
627ef74679aSDinesh Subhraveti 
628ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
629ef74679aSDinesh Subhraveti {
630ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
631ef74679aSDinesh Subhraveti 
6325edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
633ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
634ef74679aSDinesh Subhraveti     s->mouse_status = 0;
635ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
636ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
637ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
638ef74679aSDinesh Subhraveti     s->mouse_type = 0;
639ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
640ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
641ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
642ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
643ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
644ef74679aSDinesh Subhraveti }
645ef74679aSDinesh Subhraveti 
646b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
647b31442c3SJuan Quintela     .name = "PS2 Common State",
648b31442c3SJuan Quintela     .version_id = 3,
649b31442c3SJuan Quintela     .minimum_version_id = 2,
650b31442c3SJuan Quintela     .fields = (VMStateField[]) {
651b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
652b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
653b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
654b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
655b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
656b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
6577783e9f0Spbrook     }
658b31442c3SJuan Quintela };
6597783e9f0Spbrook 
6607f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
6617f540ab5SChristophe Fergeau {
6627f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6637f540ab5SChristophe Fergeau 
6647f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
6657f540ab5SChristophe Fergeau }
6667f540ab5SChristophe Fergeau 
6677f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
6687f540ab5SChristophe Fergeau {
6697f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6707f540ab5SChristophe Fergeau 
6717f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
6727f540ab5SChristophe Fergeau     return 0;
6737f540ab5SChristophe Fergeau }
6747f540ab5SChristophe Fergeau 
6757f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
6767f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
6777f540ab5SChristophe Fergeau     .version_id = 3,
6787f540ab5SChristophe Fergeau     .minimum_version_id = 2,
6797f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
6805cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
6817f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
6827f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
6837f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
6847f540ab5SChristophe Fergeau     }
6857f540ab5SChristophe Fergeau };
6867f540ab5SChristophe Fergeau 
687db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
6880e43e99cSbellard {
6890e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
6902858ab09SGonglei     PS2State *ps2 = &s->common;
6910e43e99cSbellard 
692db596c53SJuan Quintela     if (version_id == 2)
693e7d93956Saurel32         s->scancode_set=2;
6942858ab09SGonglei 
6952858ab09SGonglei     ps2_common_post_load(ps2);
6962858ab09SGonglei 
6970e43e99cSbellard     return 0;
6980e43e99cSbellard }
6990e43e99cSbellard 
7002858ab09SGonglei static void ps2_kbd_pre_save(void *opaque)
7012858ab09SGonglei {
7022858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
7032858ab09SGonglei     PS2State *ps2 = &s->common;
7042858ab09SGonglei 
7052858ab09SGonglei     ps2_common_post_load(ps2);
7062858ab09SGonglei }
7072858ab09SGonglei 
708b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
709b31442c3SJuan Quintela     .name = "ps2kbd",
710b31442c3SJuan Quintela     .version_id = 3,
711db596c53SJuan Quintela     .minimum_version_id = 2,
712db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
7132858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
714b31442c3SJuan Quintela     .fields = (VMStateField[]) {
715b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
716b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
717b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
718b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
719b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
7207f540ab5SChristophe Fergeau     },
7215cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
7225cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
7235cd8cadaSJuan Quintela         NULL
7240e43e99cSbellard     }
725b31442c3SJuan Quintela };
726b31442c3SJuan Quintela 
7272858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
7282858ab09SGonglei {
7292858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
7302858ab09SGonglei     PS2State *ps2 = &s->common;
7312858ab09SGonglei 
7322858ab09SGonglei     ps2_common_post_load(ps2);
7332858ab09SGonglei 
7342858ab09SGonglei     return 0;
7352858ab09SGonglei }
7362858ab09SGonglei 
7372858ab09SGonglei static void ps2_mouse_pre_save(void *opaque)
7382858ab09SGonglei {
7392858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
7402858ab09SGonglei     PS2State *ps2 = &s->common;
7412858ab09SGonglei 
7422858ab09SGonglei     ps2_common_post_load(ps2);
7432858ab09SGonglei }
7442858ab09SGonglei 
745b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
746b31442c3SJuan Quintela     .name = "ps2mouse",
747b31442c3SJuan Quintela     .version_id = 2,
748b31442c3SJuan Quintela     .minimum_version_id = 2,
7492858ab09SGonglei     .post_load = ps2_mouse_post_load,
7502858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
751b31442c3SJuan Quintela     .fields = (VMStateField[]) {
752b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
753b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
754b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
755b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
756b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
757b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
758b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
759b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
760b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
761b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
762b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
763b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
764b31442c3SJuan Quintela     }
765b31442c3SJuan Quintela };
7660e43e99cSbellard 
76766e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
76866e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
76966e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
77066e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
77166e6536eSGerd Hoffmann };
77266e6536eSGerd Hoffmann 
7730e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
7740e43e99cSbellard {
7757267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
7760e43e99cSbellard 
7775edab03dSDon Koch     trace_ps2_kbd_init(s);
7780e43e99cSbellard     s->common.update_irq = update_irq;
7790e43e99cSbellard     s->common.update_arg = update_arg;
780e7d93956Saurel32     s->scancode_set = 2;
7810be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
78266e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
78366e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
784ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
7850e43e99cSbellard     return s;
7860e43e99cSbellard }
7870e43e99cSbellard 
7882a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
7892a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
7902a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
7912a766d29SGerd Hoffmann     .event = ps2_mouse_event,
7922a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
7932a766d29SGerd Hoffmann };
7942a766d29SGerd Hoffmann 
7950e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
7960e43e99cSbellard {
7977267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
7980e43e99cSbellard 
7995edab03dSDon Koch     trace_ps2_mouse_init(s);
8000e43e99cSbellard     s->common.update_irq = update_irq;
8010e43e99cSbellard     s->common.update_arg = update_arg;
8020be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
8032a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
8042a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
805ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
8060e43e99cSbellard     return s;
8070e43e99cSbellard }
808