xref: /qemu/hw/input/ps2.c (revision 2858ab09e6f708e381fc1a1cc87e747a690c4884)
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"
279c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
280e43e99cSbellard 
290e43e99cSbellard /* debug PC keyboard */
300e43e99cSbellard //#define DEBUG_KBD
310e43e99cSbellard 
320e43e99cSbellard /* debug PC keyboard : only mouse */
330e43e99cSbellard //#define DEBUG_MOUSE
340e43e99cSbellard 
350e43e99cSbellard /* Keyboard Commands */
360e43e99cSbellard #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
370e43e99cSbellard #define KBD_CMD_ECHO     	0xEE
38e7d93956Saurel32 #define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
390e43e99cSbellard #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
400e43e99cSbellard #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
410e43e99cSbellard #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
420e43e99cSbellard #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
430e43e99cSbellard #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
440e43e99cSbellard #define KBD_CMD_RESET		0xFF	/* Reset */
450e43e99cSbellard 
460e43e99cSbellard /* Keyboard Replies */
470e43e99cSbellard #define KBD_REPLY_POR		0xAA	/* Power on reset */
4835c4d671Saurel32 #define KBD_REPLY_ID		0xAB	/* Keyboard ID */
490e43e99cSbellard #define KBD_REPLY_ACK		0xFA	/* Command ACK */
500e43e99cSbellard #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
510e43e99cSbellard 
520e43e99cSbellard /* Mouse Commands */
530e43e99cSbellard #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
540e43e99cSbellard #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
550e43e99cSbellard #define AUX_SET_RES		0xE8	/* Set resolution */
560e43e99cSbellard #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
570e43e99cSbellard #define AUX_SET_STREAM		0xEA	/* Set stream mode */
580e43e99cSbellard #define AUX_POLL		0xEB	/* Poll */
590e43e99cSbellard #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
600e43e99cSbellard #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
610e43e99cSbellard #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
620e43e99cSbellard #define AUX_GET_TYPE		0xF2	/* Get type */
630e43e99cSbellard #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
640e43e99cSbellard #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
650e43e99cSbellard #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
660e43e99cSbellard #define AUX_SET_DEFAULT		0xF6
670e43e99cSbellard #define AUX_RESET		0xFF	/* Reset aux device */
680e43e99cSbellard #define AUX_ACK			0xFA	/* Command byte ACK. */
690e43e99cSbellard 
700e43e99cSbellard #define MOUSE_STATUS_REMOTE     0x40
710e43e99cSbellard #define MOUSE_STATUS_ENABLED    0x20
720e43e99cSbellard #define MOUSE_STATUS_SCALE21    0x10
730e43e99cSbellard 
74*2858ab09SGonglei #define PS2_QUEUE_SIZE 16  /* Buffer size required by PS/2 protocol */
750e43e99cSbellard 
760e43e99cSbellard typedef struct {
77*2858ab09SGonglei     /* Keep the data array 256 bytes long, which compatibility
78*2858ab09SGonglei      with older qemu versions. */
79*2858ab09SGonglei     uint8_t data[256];
800e43e99cSbellard     int rptr, wptr, count;
810e43e99cSbellard } PS2Queue;
820e43e99cSbellard 
830e43e99cSbellard typedef struct {
840e43e99cSbellard     PS2Queue queue;
850e43e99cSbellard     int32_t write_cmd;
860e43e99cSbellard     void (*update_irq)(void *, int);
870e43e99cSbellard     void *update_arg;
880e43e99cSbellard } PS2State;
890e43e99cSbellard 
900e43e99cSbellard typedef struct {
910e43e99cSbellard     PS2State common;
920e43e99cSbellard     int scan_enabled;
935cbdb3a3SStefan Weil     /* QEMU uses translated PC scancodes internally.  To avoid multiple
94f94f5d71Spbrook        conversions we do the translation (if any) in the PS/2 emulation
95f94f5d71Spbrook        not the keyboard controller.  */
96f94f5d71Spbrook     int translate;
97e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
987f540ab5SChristophe Fergeau     int ledstate;
990e43e99cSbellard } PS2KbdState;
1000e43e99cSbellard 
1010e43e99cSbellard typedef struct {
1020e43e99cSbellard     PS2State common;
1030e43e99cSbellard     uint8_t mouse_status;
1040e43e99cSbellard     uint8_t mouse_resolution;
1050e43e99cSbellard     uint8_t mouse_sample_rate;
1060e43e99cSbellard     uint8_t mouse_wrap;
1070e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1080e43e99cSbellard     uint8_t mouse_detect_state;
1090e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1100e43e99cSbellard     int mouse_dy;
1110e43e99cSbellard     int mouse_dz;
1120e43e99cSbellard     uint8_t mouse_buttons;
1130e43e99cSbellard } PS2MouseState;
1140e43e99cSbellard 
115f94f5d71Spbrook /* Table to convert from PC scancodes to raw scancodes.  */
116f94f5d71Spbrook static const unsigned char ps2_raw_keycode[128] = {
117f94f5d71Spbrook   0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
118f94f5d71Spbrook  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
119f94f5d71Spbrook  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
120f94f5d71Spbrook  50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
121f94f5d71Spbrook  11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
122f94f5d71Spbrook 114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
123f94f5d71Spbrook  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
124f94f5d71Spbrook  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
125f94f5d71Spbrook };
1267096a96dSRoy Tam static const unsigned char ps2_raw_keycode_set3[128] = {
1277096a96dSRoy Tam   0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
1287096a96dSRoy Tam  21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
1297096a96dSRoy Tam  35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
1307096a96dSRoy Tam  50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
1317096a96dSRoy Tam  47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
1327096a96dSRoy Tam 114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
1337096a96dSRoy Tam  71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
1347096a96dSRoy Tam  19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
1357096a96dSRoy Tam };
136f94f5d71Spbrook 
1370e43e99cSbellard void ps2_queue(void *opaque, int b)
1380e43e99cSbellard {
1390e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1400e43e99cSbellard     PS2Queue *q = &s->queue;
1410e43e99cSbellard 
142*2858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
1430e43e99cSbellard         return;
1440e43e99cSbellard     q->data[q->wptr] = b;
1450e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
1460e43e99cSbellard         q->wptr = 0;
1470e43e99cSbellard     q->count++;
1480e43e99cSbellard     s->update_irq(s->update_arg, 1);
1490e43e99cSbellard }
1500e43e99cSbellard 
15135c4d671Saurel32 /*
15235c4d671Saurel32    keycode is expressed as follow:
15335c4d671Saurel32    bit 7    - 0 key pressed, 1 = key released
15435c4d671Saurel32    bits 6-0 - translated scancode set 2
15535c4d671Saurel32  */
1560e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
1570e43e99cSbellard {
158f94f5d71Spbrook     PS2KbdState *s = opaque;
159e7d93956Saurel32 
160fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
1617096a96dSRoy Tam     /* XXX: add support for scancode set 1 */
1627096a96dSRoy Tam     if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
1637096a96dSRoy Tam         if (keycode & 0x80) {
164f94f5d71Spbrook             ps2_queue(&s->common, 0xf0);
1657096a96dSRoy Tam         }
1667096a96dSRoy Tam         if (s->scancode_set == 2) {
167f94f5d71Spbrook             keycode = ps2_raw_keycode[keycode & 0x7f];
1687096a96dSRoy Tam         } else if (s->scancode_set == 3) {
1697096a96dSRoy Tam             keycode = ps2_raw_keycode_set3[keycode & 0x7f];
1707096a96dSRoy Tam         }
171f94f5d71Spbrook       }
1720e43e99cSbellard     ps2_queue(&s->common, keycode);
1730e43e99cSbellard }
1740e43e99cSbellard 
1750e43e99cSbellard uint32_t ps2_read_data(void *opaque)
1760e43e99cSbellard {
1770e43e99cSbellard     PS2State *s = (PS2State *)opaque;
1780e43e99cSbellard     PS2Queue *q;
1790e43e99cSbellard     int val, index;
1800e43e99cSbellard 
1810e43e99cSbellard     q = &s->queue;
1820e43e99cSbellard     if (q->count == 0) {
1830e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
1840e43e99cSbellard            (needed for EMM386) */
1850e43e99cSbellard         /* XXX: need a timer to do things correctly */
1860e43e99cSbellard         index = q->rptr - 1;
1870e43e99cSbellard         if (index < 0)
1880e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
1890e43e99cSbellard         val = q->data[index];
1900e43e99cSbellard     } else {
1910e43e99cSbellard         val = q->data[q->rptr];
1920e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
1930e43e99cSbellard             q->rptr = 0;
1940e43e99cSbellard         q->count--;
1950e43e99cSbellard         /* reading deasserts IRQ */
1960e43e99cSbellard         s->update_irq(s->update_arg, 0);
1970e43e99cSbellard         /* reassert IRQs if data left */
1980e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
1990e43e99cSbellard     }
2000e43e99cSbellard     return val;
2010e43e99cSbellard }
2020e43e99cSbellard 
2037f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
2047f540ab5SChristophe Fergeau {
2057f540ab5SChristophe Fergeau     s->ledstate = ledstate;
2067f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
2077f540ab5SChristophe Fergeau }
2087f540ab5SChristophe Fergeau 
2090e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
2100e43e99cSbellard {
2110e43e99cSbellard     s->scan_enabled = 1;
212e7d93956Saurel32     s->scancode_set = 2;
2137f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
2140e43e99cSbellard }
2150e43e99cSbellard 
2160e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
2170e43e99cSbellard {
2180e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
2190e43e99cSbellard 
2200e43e99cSbellard     switch(s->common.write_cmd) {
2210e43e99cSbellard     default:
2220e43e99cSbellard     case -1:
2230e43e99cSbellard         switch(val) {
2240e43e99cSbellard         case 0x00:
2250e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2260e43e99cSbellard             break;
2270e43e99cSbellard         case 0x05:
2280e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
2290e43e99cSbellard             break;
2300e43e99cSbellard         case KBD_CMD_GET_ID:
2310e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
232e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
23335c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
23435c4d671Saurel32             if (s->translate)
23535c4d671Saurel32                 ps2_queue(&s->common, 0x41);
23635c4d671Saurel32             else
23735c4d671Saurel32                 ps2_queue(&s->common, 0x83);
2380e43e99cSbellard             break;
2390e43e99cSbellard         case KBD_CMD_ECHO:
2400e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
2410e43e99cSbellard             break;
2420e43e99cSbellard         case KBD_CMD_ENABLE:
2430e43e99cSbellard             s->scan_enabled = 1;
2440e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2450e43e99cSbellard             break;
246e7d93956Saurel32         case KBD_CMD_SCANCODE:
2470e43e99cSbellard         case KBD_CMD_SET_LEDS:
2480e43e99cSbellard         case KBD_CMD_SET_RATE:
2490e43e99cSbellard             s->common.write_cmd = val;
2500e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2510e43e99cSbellard             break;
2520e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
2530e43e99cSbellard             ps2_reset_keyboard(s);
2540e43e99cSbellard             s->scan_enabled = 0;
2550e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2560e43e99cSbellard             break;
2570e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
2580e43e99cSbellard             ps2_reset_keyboard(s);
2590e43e99cSbellard             s->scan_enabled = 1;
2600e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2610e43e99cSbellard             break;
2620e43e99cSbellard         case KBD_CMD_RESET:
2630e43e99cSbellard             ps2_reset_keyboard(s);
2640e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2650e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
2660e43e99cSbellard             break;
2670e43e99cSbellard         default:
2680e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
2690e43e99cSbellard             break;
2700e43e99cSbellard         }
2710e43e99cSbellard         break;
272e7d93956Saurel32     case KBD_CMD_SCANCODE:
273e7d93956Saurel32         if (val == 0) {
274e7d93956Saurel32             if (s->scancode_set == 1)
275e7d93956Saurel32                 ps2_put_keycode(s, 0x43);
276e7d93956Saurel32             else if (s->scancode_set == 2)
277e7d93956Saurel32                 ps2_put_keycode(s, 0x41);
278e7d93956Saurel32             else if (s->scancode_set == 3)
279e7d93956Saurel32                 ps2_put_keycode(s, 0x3f);
280e7d93956Saurel32         } else {
281e7d93956Saurel32             if (val >= 1 && val <= 3)
282e7d93956Saurel32                 s->scancode_set = val;
283e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
284e7d93956Saurel32         }
285e7d93956Saurel32         s->common.write_cmd = -1;
286e7d93956Saurel32         break;
2870e43e99cSbellard     case KBD_CMD_SET_LEDS:
2887f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
2890e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
2900e43e99cSbellard         s->common.write_cmd = -1;
2910e43e99cSbellard         break;
2920e43e99cSbellard     case KBD_CMD_SET_RATE:
2930e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
2940e43e99cSbellard         s->common.write_cmd = -1;
2950e43e99cSbellard         break;
2960e43e99cSbellard     }
2970e43e99cSbellard }
2980e43e99cSbellard 
299f94f5d71Spbrook /* Set the scancode translation mode.
300f94f5d71Spbrook    0 = raw scancodes.
301f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
302f94f5d71Spbrook 
303f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
304f94f5d71Spbrook {
305f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
306f94f5d71Spbrook     s->translate = mode;
307f94f5d71Spbrook }
308f94f5d71Spbrook 
3090e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
3100e43e99cSbellard {
3110e43e99cSbellard     unsigned int b;
3120e43e99cSbellard     int dx1, dy1, dz1;
3130e43e99cSbellard 
3140e43e99cSbellard     dx1 = s->mouse_dx;
3150e43e99cSbellard     dy1 = s->mouse_dy;
3160e43e99cSbellard     dz1 = s->mouse_dz;
3170e43e99cSbellard     /* XXX: increase range to 8 bits ? */
3180e43e99cSbellard     if (dx1 > 127)
3190e43e99cSbellard         dx1 = 127;
3200e43e99cSbellard     else if (dx1 < -127)
3210e43e99cSbellard         dx1 = -127;
3220e43e99cSbellard     if (dy1 > 127)
3230e43e99cSbellard         dy1 = 127;
3240e43e99cSbellard     else if (dy1 < -127)
3250e43e99cSbellard         dy1 = -127;
3260e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
3270e43e99cSbellard     ps2_queue(&s->common, b);
3280e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
3290e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
3300e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
3310e43e99cSbellard     switch(s->mouse_type) {
3320e43e99cSbellard     default:
3330e43e99cSbellard         break;
3340e43e99cSbellard     case 3:
3350e43e99cSbellard         if (dz1 > 127)
3360e43e99cSbellard             dz1 = 127;
3370e43e99cSbellard         else if (dz1 < -127)
3380e43e99cSbellard                 dz1 = -127;
3390e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
3400e43e99cSbellard         break;
3410e43e99cSbellard     case 4:
3420e43e99cSbellard         if (dz1 > 7)
3430e43e99cSbellard             dz1 = 7;
3440e43e99cSbellard         else if (dz1 < -7)
3450e43e99cSbellard             dz1 = -7;
3460e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
3470e43e99cSbellard         ps2_queue(&s->common, b);
3480e43e99cSbellard         break;
3490e43e99cSbellard     }
3500e43e99cSbellard 
3510e43e99cSbellard     /* update deltas */
3520e43e99cSbellard     s->mouse_dx -= dx1;
3530e43e99cSbellard     s->mouse_dy -= dy1;
3540e43e99cSbellard     s->mouse_dz -= dz1;
3550e43e99cSbellard }
3560e43e99cSbellard 
3570e43e99cSbellard static void ps2_mouse_event(void *opaque,
3580e43e99cSbellard                             int dx, int dy, int dz, int buttons_state)
3590e43e99cSbellard {
3600e43e99cSbellard     PS2MouseState *s = opaque;
3610e43e99cSbellard 
3620e43e99cSbellard     /* check if deltas are recorded when disabled */
3630e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
3640e43e99cSbellard         return;
3650e43e99cSbellard 
3660e43e99cSbellard     s->mouse_dx += dx;
3670e43e99cSbellard     s->mouse_dy -= dy;
3680e43e99cSbellard     s->mouse_dz += dz;
3690e43e99cSbellard     /* XXX: SDL sometimes generates nul events: we delete them */
3700e43e99cSbellard     if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
3710e43e99cSbellard         s->mouse_buttons == buttons_state)
3720e43e99cSbellard 	return;
3730e43e99cSbellard     s->mouse_buttons = buttons_state;
3740e43e99cSbellard 
375fd214d18SGerd Hoffmann     if (buttons_state) {
376fd214d18SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
377fd214d18SGerd Hoffmann     }
378fd214d18SGerd Hoffmann 
379*2858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
380*2858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
3810e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
3820e43e99cSbellard                too big deltas */
3830e43e99cSbellard             ps2_mouse_send_packet(s);
3840e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
3850e43e99cSbellard                 break;
3860e43e99cSbellard         }
3870e43e99cSbellard     }
3880e43e99cSbellard }
3890e43e99cSbellard 
390548df2acSths void ps2_mouse_fake_event(void *opaque)
391548df2acSths {
392548df2acSths     ps2_mouse_event(opaque, 1, 0, 0, 0);
393548df2acSths }
394548df2acSths 
3950e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
3960e43e99cSbellard {
3970e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
3980e43e99cSbellard #ifdef DEBUG_MOUSE
3990e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
4000e43e99cSbellard #endif
4010e43e99cSbellard     switch(s->common.write_cmd) {
4020e43e99cSbellard     default:
4030e43e99cSbellard     case -1:
4040e43e99cSbellard         /* mouse command */
4050e43e99cSbellard         if (s->mouse_wrap) {
4060e43e99cSbellard             if (val == AUX_RESET_WRAP) {
4070e43e99cSbellard                 s->mouse_wrap = 0;
4080e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
4090e43e99cSbellard                 return;
4100e43e99cSbellard             } else if (val != AUX_RESET) {
4110e43e99cSbellard                 ps2_queue(&s->common, val);
4120e43e99cSbellard                 return;
4130e43e99cSbellard             }
4140e43e99cSbellard         }
4150e43e99cSbellard         switch(val) {
4160e43e99cSbellard         case AUX_SET_SCALE11:
4170e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
4180e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4190e43e99cSbellard             break;
4200e43e99cSbellard         case AUX_SET_SCALE21:
4210e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
4220e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4230e43e99cSbellard             break;
4240e43e99cSbellard         case AUX_SET_STREAM:
4250e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
4260e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4270e43e99cSbellard             break;
4280e43e99cSbellard         case AUX_SET_WRAP:
4290e43e99cSbellard             s->mouse_wrap = 1;
4300e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4310e43e99cSbellard             break;
4320e43e99cSbellard         case AUX_SET_REMOTE:
4330e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
4340e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4350e43e99cSbellard             break;
4360e43e99cSbellard         case AUX_GET_TYPE:
4370e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4380e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
4390e43e99cSbellard             break;
4400e43e99cSbellard         case AUX_SET_RES:
4410e43e99cSbellard         case AUX_SET_SAMPLE:
4420e43e99cSbellard             s->common.write_cmd = val;
4430e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4440e43e99cSbellard             break;
4450e43e99cSbellard         case AUX_GET_SCALE:
4460e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4470e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
4480e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
4490e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
4500e43e99cSbellard             break;
4510e43e99cSbellard         case AUX_POLL:
4520e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4530e43e99cSbellard             ps2_mouse_send_packet(s);
4540e43e99cSbellard             break;
4550e43e99cSbellard         case AUX_ENABLE_DEV:
4560e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
4570e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4580e43e99cSbellard             break;
4590e43e99cSbellard         case AUX_DISABLE_DEV:
4600e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
4610e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4620e43e99cSbellard             break;
4630e43e99cSbellard         case AUX_SET_DEFAULT:
4640e43e99cSbellard             s->mouse_sample_rate = 100;
4650e43e99cSbellard             s->mouse_resolution = 2;
4660e43e99cSbellard             s->mouse_status = 0;
4670e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4680e43e99cSbellard             break;
4690e43e99cSbellard         case AUX_RESET:
4700e43e99cSbellard             s->mouse_sample_rate = 100;
4710e43e99cSbellard             s->mouse_resolution = 2;
4720e43e99cSbellard             s->mouse_status = 0;
4730e43e99cSbellard             s->mouse_type = 0;
4740e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
4750e43e99cSbellard             ps2_queue(&s->common, 0xaa);
4760e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
4770e43e99cSbellard             break;
4780e43e99cSbellard         default:
4790e43e99cSbellard             break;
4800e43e99cSbellard         }
4810e43e99cSbellard         break;
4820e43e99cSbellard     case AUX_SET_SAMPLE:
4830e43e99cSbellard         s->mouse_sample_rate = val;
4840e43e99cSbellard         /* detect IMPS/2 or IMEX */
4850e43e99cSbellard         switch(s->mouse_detect_state) {
4860e43e99cSbellard         default:
4870e43e99cSbellard         case 0:
4880e43e99cSbellard             if (val == 200)
4890e43e99cSbellard                 s->mouse_detect_state = 1;
4900e43e99cSbellard             break;
4910e43e99cSbellard         case 1:
4920e43e99cSbellard             if (val == 100)
4930e43e99cSbellard                 s->mouse_detect_state = 2;
4940e43e99cSbellard             else if (val == 200)
4950e43e99cSbellard                 s->mouse_detect_state = 3;
4960e43e99cSbellard             else
4970e43e99cSbellard                 s->mouse_detect_state = 0;
4980e43e99cSbellard             break;
4990e43e99cSbellard         case 2:
5000e43e99cSbellard             if (val == 80)
5010e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
5020e43e99cSbellard             s->mouse_detect_state = 0;
5030e43e99cSbellard             break;
5040e43e99cSbellard         case 3:
5050e43e99cSbellard             if (val == 80)
5060e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
5070e43e99cSbellard             s->mouse_detect_state = 0;
5080e43e99cSbellard             break;
5090e43e99cSbellard         }
5100e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5110e43e99cSbellard         s->common.write_cmd = -1;
5120e43e99cSbellard         break;
5130e43e99cSbellard     case AUX_SET_RES:
5140e43e99cSbellard         s->mouse_resolution = val;
5150e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
5160e43e99cSbellard         s->common.write_cmd = -1;
5170e43e99cSbellard         break;
5180e43e99cSbellard     }
5190e43e99cSbellard }
5200e43e99cSbellard 
521ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
5220e43e99cSbellard {
5230e43e99cSbellard     PS2Queue *q;
5240e43e99cSbellard     s->write_cmd = -1;
5250e43e99cSbellard     q = &s->queue;
5260e43e99cSbellard     q->rptr = 0;
5270e43e99cSbellard     q->wptr = 0;
5280e43e99cSbellard     q->count = 0;
529deeccef3Saliguori     s->update_irq(s->update_arg, 0);
5300e43e99cSbellard }
5310e43e99cSbellard 
532*2858ab09SGonglei static void ps2_common_post_load(PS2State *s)
533*2858ab09SGonglei {
534*2858ab09SGonglei     PS2Queue *q = &s->queue;
535*2858ab09SGonglei     int size;
536*2858ab09SGonglei     int i;
537*2858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
538*2858ab09SGonglei 
539*2858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
540*2858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
541*2858ab09SGonglei 
542*2858ab09SGonglei     /* move the queue elements to the start of data array */
543*2858ab09SGonglei     if (size > 0) {
544*2858ab09SGonglei         for (i = 0; i < size; i++) {
545*2858ab09SGonglei             /* move the queue elements to the temporary buffer */
546*2858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
547*2858ab09SGonglei             if (++q->rptr == 256) {
548*2858ab09SGonglei                 q->rptr = 0;
549*2858ab09SGonglei             }
550*2858ab09SGonglei         }
551*2858ab09SGonglei         memcpy(q->data, tmp_data, size);
552*2858ab09SGonglei     }
553*2858ab09SGonglei     /* reset rptr/wptr/count */
554*2858ab09SGonglei     q->rptr = 0;
555*2858ab09SGonglei     q->wptr = size;
556*2858ab09SGonglei     q->count = size;
557*2858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
558*2858ab09SGonglei }
559*2858ab09SGonglei 
560ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
561ef74679aSDinesh Subhraveti {
562ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
563ef74679aSDinesh Subhraveti 
564ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
565ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
566ef74679aSDinesh Subhraveti     s->translate = 0;
567ef74679aSDinesh Subhraveti     s->scancode_set = 0;
568ef74679aSDinesh Subhraveti }
569ef74679aSDinesh Subhraveti 
570ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
571ef74679aSDinesh Subhraveti {
572ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
573ef74679aSDinesh Subhraveti 
574ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
575ef74679aSDinesh Subhraveti     s->mouse_status = 0;
576ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
577ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
578ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
579ef74679aSDinesh Subhraveti     s->mouse_type = 0;
580ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
581ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
582ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
583ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
584ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
585ef74679aSDinesh Subhraveti }
586ef74679aSDinesh Subhraveti 
587b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
588b31442c3SJuan Quintela     .name = "PS2 Common State",
589b31442c3SJuan Quintela     .version_id = 3,
590b31442c3SJuan Quintela     .minimum_version_id = 2,
591b31442c3SJuan Quintela     .minimum_version_id_old = 2,
592b31442c3SJuan Quintela     .fields      = (VMStateField []) {
593b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
594b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
595b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
596b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
597b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
598b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
5997783e9f0Spbrook     }
600b31442c3SJuan Quintela };
6017783e9f0Spbrook 
6027f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
6037f540ab5SChristophe Fergeau {
6047f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6057f540ab5SChristophe Fergeau 
6067f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
6077f540ab5SChristophe Fergeau }
6087f540ab5SChristophe Fergeau 
6097f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
6107f540ab5SChristophe Fergeau {
6117f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
6127f540ab5SChristophe Fergeau 
6137f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
6147f540ab5SChristophe Fergeau     return 0;
6157f540ab5SChristophe Fergeau }
6167f540ab5SChristophe Fergeau 
6177f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
6187f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
6197f540ab5SChristophe Fergeau     .version_id = 3,
6207f540ab5SChristophe Fergeau     .minimum_version_id = 2,
6217f540ab5SChristophe Fergeau     .minimum_version_id_old = 2,
6227f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
6237f540ab5SChristophe Fergeau     .fields      = (VMStateField []) {
6247f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
6257f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
6267f540ab5SChristophe Fergeau     }
6277f540ab5SChristophe Fergeau };
6287f540ab5SChristophe Fergeau 
629db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
6300e43e99cSbellard {
6310e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
632*2858ab09SGonglei     PS2State *ps2 = &s->common;
6330e43e99cSbellard 
634db596c53SJuan Quintela     if (version_id == 2)
635e7d93956Saurel32         s->scancode_set=2;
636*2858ab09SGonglei 
637*2858ab09SGonglei     ps2_common_post_load(ps2);
638*2858ab09SGonglei 
6390e43e99cSbellard     return 0;
6400e43e99cSbellard }
6410e43e99cSbellard 
642*2858ab09SGonglei static void ps2_kbd_pre_save(void *opaque)
643*2858ab09SGonglei {
644*2858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
645*2858ab09SGonglei     PS2State *ps2 = &s->common;
646*2858ab09SGonglei 
647*2858ab09SGonglei     ps2_common_post_load(ps2);
648*2858ab09SGonglei }
649*2858ab09SGonglei 
650b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
651b31442c3SJuan Quintela     .name = "ps2kbd",
652b31442c3SJuan Quintela     .version_id = 3,
653db596c53SJuan Quintela     .minimum_version_id = 2,
654b31442c3SJuan Quintela     .minimum_version_id_old = 2,
655db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
656*2858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
657b31442c3SJuan Quintela     .fields      = (VMStateField []) {
658b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
659b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
660b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
661b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
662b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
6637f540ab5SChristophe Fergeau     },
6647f540ab5SChristophe Fergeau     .subsections = (VMStateSubsection []) {
6657f540ab5SChristophe Fergeau         {
6667f540ab5SChristophe Fergeau             .vmsd = &vmstate_ps2_keyboard_ledstate,
6677f540ab5SChristophe Fergeau             .needed = ps2_keyboard_ledstate_needed,
6687f540ab5SChristophe Fergeau         }, {
6697f540ab5SChristophe Fergeau             /* empty */
6707f540ab5SChristophe Fergeau         }
6710e43e99cSbellard     }
672b31442c3SJuan Quintela };
673b31442c3SJuan Quintela 
674*2858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
675*2858ab09SGonglei {
676*2858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
677*2858ab09SGonglei     PS2State *ps2 = &s->common;
678*2858ab09SGonglei 
679*2858ab09SGonglei     ps2_common_post_load(ps2);
680*2858ab09SGonglei 
681*2858ab09SGonglei     return 0;
682*2858ab09SGonglei }
683*2858ab09SGonglei 
684*2858ab09SGonglei static void ps2_mouse_pre_save(void *opaque)
685*2858ab09SGonglei {
686*2858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
687*2858ab09SGonglei     PS2State *ps2 = &s->common;
688*2858ab09SGonglei 
689*2858ab09SGonglei     ps2_common_post_load(ps2);
690*2858ab09SGonglei }
691*2858ab09SGonglei 
692b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
693b31442c3SJuan Quintela     .name = "ps2mouse",
694b31442c3SJuan Quintela     .version_id = 2,
695b31442c3SJuan Quintela     .minimum_version_id = 2,
696b31442c3SJuan Quintela     .minimum_version_id_old = 2,
697*2858ab09SGonglei     .post_load = ps2_mouse_post_load,
698*2858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
699b31442c3SJuan Quintela     .fields      = (VMStateField []) {
700b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
701b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
702b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
703b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
704b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
705b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
706b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
707b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
708b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
709b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
710b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
711b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
712b31442c3SJuan Quintela     }
713b31442c3SJuan Quintela };
7140e43e99cSbellard 
7150e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
7160e43e99cSbellard {
7177267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
7180e43e99cSbellard 
7190e43e99cSbellard     s->common.update_irq = update_irq;
7200e43e99cSbellard     s->common.update_arg = update_arg;
721e7d93956Saurel32     s->scancode_set = 2;
7220be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
7230e43e99cSbellard     qemu_add_kbd_event_handler(ps2_put_keycode, s);
724ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
7250e43e99cSbellard     return s;
7260e43e99cSbellard }
7270e43e99cSbellard 
7280e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
7290e43e99cSbellard {
7307267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
7310e43e99cSbellard 
7320e43e99cSbellard     s->common.update_irq = update_irq;
7330e43e99cSbellard     s->common.update_arg = update_arg;
7340be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
735455204ebSths     qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
736ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
7370e43e99cSbellard     return s;
7380e43e99cSbellard }
739