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