10e43e99cSbellard /* 20e43e99cSbellard * QEMU PS/2 keyboard/mouse emulation 30e43e99cSbellard * 40e43e99cSbellard * Copyright (c) 2003 Fabrice Bellard 50e43e99cSbellard * 60e43e99cSbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 70e43e99cSbellard * of this software and associated documentation files (the "Software"), to deal 80e43e99cSbellard * in the Software without restriction, including without limitation the rights 90e43e99cSbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 100e43e99cSbellard * copies of the Software, and to permit persons to whom the Software is 110e43e99cSbellard * furnished to do so, subject to the following conditions: 120e43e99cSbellard * 130e43e99cSbellard * The above copyright notice and this permission notice shall be included in 140e43e99cSbellard * all copies or substantial portions of the Software. 150e43e99cSbellard * 160e43e99cSbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 170e43e99cSbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 180e43e99cSbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 190e43e99cSbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 200e43e99cSbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 210e43e99cSbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 220e43e99cSbellard * THE SOFTWARE. 230e43e99cSbellard */ 240430891cSPeter Maydell #include "qemu/osdep.h" 2583c9f4caSPaolo Bonzini #include "hw/hw.h" 260d09e41aSPaolo Bonzini #include "hw/input/ps2.h" 2728ecbaeeSPaolo Bonzini #include "ui/console.h" 2866e6536eSGerd Hoffmann #include "ui/input.h" 299c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 300e43e99cSbellard 315edab03dSDon Koch #include "trace.h" 325edab03dSDon Koch 330e43e99cSbellard /* debug PC keyboard */ 340e43e99cSbellard //#define DEBUG_KBD 350e43e99cSbellard 360e43e99cSbellard /* debug PC keyboard : only mouse */ 370e43e99cSbellard //#define DEBUG_MOUSE 380e43e99cSbellard 390e43e99cSbellard /* Keyboard Commands */ 400e43e99cSbellard #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ 410e43e99cSbellard #define KBD_CMD_ECHO 0xEE 42e7d93956Saurel32 #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ 430e43e99cSbellard #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ 440e43e99cSbellard #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ 450e43e99cSbellard #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ 460e43e99cSbellard #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ 470e43e99cSbellard #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ 480e43e99cSbellard #define KBD_CMD_RESET 0xFF /* Reset */ 490e43e99cSbellard 500e43e99cSbellard /* Keyboard Replies */ 510e43e99cSbellard #define KBD_REPLY_POR 0xAA /* Power on reset */ 5235c4d671Saurel32 #define KBD_REPLY_ID 0xAB /* Keyboard ID */ 530e43e99cSbellard #define KBD_REPLY_ACK 0xFA /* Command ACK */ 540e43e99cSbellard #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ 550e43e99cSbellard 560e43e99cSbellard /* Mouse Commands */ 570e43e99cSbellard #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ 580e43e99cSbellard #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ 590e43e99cSbellard #define AUX_SET_RES 0xE8 /* Set resolution */ 600e43e99cSbellard #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ 610e43e99cSbellard #define AUX_SET_STREAM 0xEA /* Set stream mode */ 620e43e99cSbellard #define AUX_POLL 0xEB /* Poll */ 630e43e99cSbellard #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ 640e43e99cSbellard #define AUX_SET_WRAP 0xEE /* Set wrap mode */ 650e43e99cSbellard #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ 660e43e99cSbellard #define AUX_GET_TYPE 0xF2 /* Get type */ 670e43e99cSbellard #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ 680e43e99cSbellard #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ 690e43e99cSbellard #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ 700e43e99cSbellard #define AUX_SET_DEFAULT 0xF6 710e43e99cSbellard #define AUX_RESET 0xFF /* Reset aux device */ 720e43e99cSbellard #define AUX_ACK 0xFA /* Command byte ACK. */ 730e43e99cSbellard 740e43e99cSbellard #define MOUSE_STATUS_REMOTE 0x40 750e43e99cSbellard #define MOUSE_STATUS_ENABLED 0x20 760e43e99cSbellard #define MOUSE_STATUS_SCALE21 0x10 770e43e99cSbellard 782858ab09SGonglei #define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ 790e43e99cSbellard 800e43e99cSbellard typedef struct { 812858ab09SGonglei /* Keep the data array 256 bytes long, which compatibility 822858ab09SGonglei with older qemu versions. */ 832858ab09SGonglei uint8_t data[256]; 840e43e99cSbellard int rptr, wptr, count; 850e43e99cSbellard } PS2Queue; 860e43e99cSbellard 870e43e99cSbellard typedef struct { 880e43e99cSbellard PS2Queue queue; 890e43e99cSbellard int32_t write_cmd; 900e43e99cSbellard void (*update_irq)(void *, int); 910e43e99cSbellard void *update_arg; 920e43e99cSbellard } PS2State; 930e43e99cSbellard 940e43e99cSbellard typedef struct { 950e43e99cSbellard PS2State common; 960e43e99cSbellard int scan_enabled; 975cbdb3a3SStefan Weil /* QEMU uses translated PC scancodes internally. To avoid multiple 98f94f5d71Spbrook conversions we do the translation (if any) in the PS/2 emulation 99f94f5d71Spbrook not the keyboard controller. */ 100f94f5d71Spbrook int translate; 101e7d93956Saurel32 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ 1027f540ab5SChristophe Fergeau int ledstate; 1030e43e99cSbellard } PS2KbdState; 1040e43e99cSbellard 1050e43e99cSbellard typedef struct { 1060e43e99cSbellard PS2State common; 1070e43e99cSbellard uint8_t mouse_status; 1080e43e99cSbellard uint8_t mouse_resolution; 1090e43e99cSbellard uint8_t mouse_sample_rate; 1100e43e99cSbellard uint8_t mouse_wrap; 1110e43e99cSbellard uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ 1120e43e99cSbellard uint8_t mouse_detect_state; 1130e43e99cSbellard int mouse_dx; /* current values, needed for 'poll' mode */ 1140e43e99cSbellard int mouse_dy; 1150e43e99cSbellard int mouse_dz; 1160e43e99cSbellard uint8_t mouse_buttons; 1170e43e99cSbellard } PS2MouseState; 1180e43e99cSbellard 119f94f5d71Spbrook /* Table to convert from PC scancodes to raw scancodes. */ 120f94f5d71Spbrook static const unsigned char ps2_raw_keycode[128] = { 121f94f5d71Spbrook 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13, 122f94f5d71Spbrook 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, 123f94f5d71Spbrook 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, 124f94f5d71Spbrook 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3, 125f94f5d71Spbrook 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105, 126f94f5d71Spbrook 114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63, 127f94f5d71Spbrook 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111, 128f94f5d71Spbrook 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 129f94f5d71Spbrook }; 1307096a96dSRoy Tam static const unsigned char ps2_raw_keycode_set3[128] = { 1317096a96dSRoy Tam 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13, 1327096a96dSRoy Tam 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27, 1337096a96dSRoy Tam 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42, 1347096a96dSRoy Tam 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39, 1357096a96dSRoy Tam 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105, 1367096a96dSRoy Tam 114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63, 1377096a96dSRoy Tam 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111, 1387096a96dSRoy Tam 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110 1397096a96dSRoy Tam }; 140f94f5d71Spbrook 1410e43e99cSbellard void ps2_queue(void *opaque, int b) 1420e43e99cSbellard { 1430e43e99cSbellard PS2State *s = (PS2State *)opaque; 1440e43e99cSbellard PS2Queue *q = &s->queue; 1450e43e99cSbellard 1462858ab09SGonglei if (q->count >= PS2_QUEUE_SIZE - 1) 1470e43e99cSbellard return; 1480e43e99cSbellard q->data[q->wptr] = b; 1490e43e99cSbellard if (++q->wptr == PS2_QUEUE_SIZE) 1500e43e99cSbellard q->wptr = 0; 1510e43e99cSbellard q->count++; 1520e43e99cSbellard s->update_irq(s->update_arg, 1); 1530e43e99cSbellard } 1540e43e99cSbellard 15535c4d671Saurel32 /* 15635c4d671Saurel32 keycode is expressed as follow: 15735c4d671Saurel32 bit 7 - 0 key pressed, 1 = key released 15835c4d671Saurel32 bits 6-0 - translated scancode set 2 15935c4d671Saurel32 */ 1600e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 1610e43e99cSbellard { 162f94f5d71Spbrook PS2KbdState *s = opaque; 163e7d93956Saurel32 1645edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 165fd214d18SGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 1667096a96dSRoy Tam /* XXX: add support for scancode set 1 */ 1677096a96dSRoy Tam if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) { 1687096a96dSRoy Tam if (keycode & 0x80) { 169f94f5d71Spbrook ps2_queue(&s->common, 0xf0); 1707096a96dSRoy Tam } 1717096a96dSRoy Tam if (s->scancode_set == 2) { 172f94f5d71Spbrook keycode = ps2_raw_keycode[keycode & 0x7f]; 1737096a96dSRoy Tam } else if (s->scancode_set == 3) { 1747096a96dSRoy Tam keycode = ps2_raw_keycode_set3[keycode & 0x7f]; 1757096a96dSRoy Tam } 176f94f5d71Spbrook } 1770e43e99cSbellard ps2_queue(&s->common, keycode); 1780e43e99cSbellard } 1790e43e99cSbellard 18066e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 18166e6536eSGerd Hoffmann InputEvent *evt) 18266e6536eSGerd Hoffmann { 18366e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 18466e6536eSGerd Hoffmann int scancodes[3], i, count; 185*32bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 18666e6536eSGerd Hoffmann 18766e6536eSGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 188b5a1b443SEric Blake count = qemu_input_key_value_to_scancode(key->key, 189b5a1b443SEric Blake key->down, 19066e6536eSGerd Hoffmann scancodes); 19166e6536eSGerd Hoffmann for (i = 0; i < count; i++) { 19266e6536eSGerd Hoffmann ps2_put_keycode(s, scancodes[i]); 19366e6536eSGerd Hoffmann } 19466e6536eSGerd Hoffmann } 19566e6536eSGerd Hoffmann 1960e43e99cSbellard uint32_t ps2_read_data(void *opaque) 1970e43e99cSbellard { 1980e43e99cSbellard PS2State *s = (PS2State *)opaque; 1990e43e99cSbellard PS2Queue *q; 2000e43e99cSbellard int val, index; 2010e43e99cSbellard 2025edab03dSDon Koch trace_ps2_read_data(opaque); 2030e43e99cSbellard q = &s->queue; 2040e43e99cSbellard if (q->count == 0) { 2050e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 2060e43e99cSbellard (needed for EMM386) */ 2070e43e99cSbellard /* XXX: need a timer to do things correctly */ 2080e43e99cSbellard index = q->rptr - 1; 2090e43e99cSbellard if (index < 0) 2100e43e99cSbellard index = PS2_QUEUE_SIZE - 1; 2110e43e99cSbellard val = q->data[index]; 2120e43e99cSbellard } else { 2130e43e99cSbellard val = q->data[q->rptr]; 2140e43e99cSbellard if (++q->rptr == PS2_QUEUE_SIZE) 2150e43e99cSbellard q->rptr = 0; 2160e43e99cSbellard q->count--; 2170e43e99cSbellard /* reading deasserts IRQ */ 2180e43e99cSbellard s->update_irq(s->update_arg, 0); 2190e43e99cSbellard /* reassert IRQs if data left */ 2200e43e99cSbellard s->update_irq(s->update_arg, q->count != 0); 2210e43e99cSbellard } 2220e43e99cSbellard return val; 2230e43e99cSbellard } 2240e43e99cSbellard 2257f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 2267f540ab5SChristophe Fergeau { 2275edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 2287f540ab5SChristophe Fergeau s->ledstate = ledstate; 2297f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 2307f540ab5SChristophe Fergeau } 2317f540ab5SChristophe Fergeau 2320e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 2330e43e99cSbellard { 2345edab03dSDon Koch trace_ps2_reset_keyboard(s); 2350e43e99cSbellard s->scan_enabled = 1; 236e7d93956Saurel32 s->scancode_set = 2; 2377f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 2380e43e99cSbellard } 2390e43e99cSbellard 2400e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 2410e43e99cSbellard { 2420e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 2430e43e99cSbellard 2445edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 2450e43e99cSbellard switch(s->common.write_cmd) { 2460e43e99cSbellard default: 2470e43e99cSbellard case -1: 2480e43e99cSbellard switch(val) { 2490e43e99cSbellard case 0x00: 2500e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2510e43e99cSbellard break; 2520e43e99cSbellard case 0x05: 2530e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_RESEND); 2540e43e99cSbellard break; 2550e43e99cSbellard case KBD_CMD_GET_ID: 2560e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 257e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 25835c4d671Saurel32 ps2_queue(&s->common, KBD_REPLY_ID); 25935c4d671Saurel32 if (s->translate) 26035c4d671Saurel32 ps2_queue(&s->common, 0x41); 26135c4d671Saurel32 else 26235c4d671Saurel32 ps2_queue(&s->common, 0x83); 2630e43e99cSbellard break; 2640e43e99cSbellard case KBD_CMD_ECHO: 2650e43e99cSbellard ps2_queue(&s->common, KBD_CMD_ECHO); 2660e43e99cSbellard break; 2670e43e99cSbellard case KBD_CMD_ENABLE: 2680e43e99cSbellard s->scan_enabled = 1; 2690e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2700e43e99cSbellard break; 271e7d93956Saurel32 case KBD_CMD_SCANCODE: 2720e43e99cSbellard case KBD_CMD_SET_LEDS: 2730e43e99cSbellard case KBD_CMD_SET_RATE: 2740e43e99cSbellard s->common.write_cmd = val; 2750e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2760e43e99cSbellard break; 2770e43e99cSbellard case KBD_CMD_RESET_DISABLE: 2780e43e99cSbellard ps2_reset_keyboard(s); 2790e43e99cSbellard s->scan_enabled = 0; 2800e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2810e43e99cSbellard break; 2820e43e99cSbellard case KBD_CMD_RESET_ENABLE: 2830e43e99cSbellard ps2_reset_keyboard(s); 2840e43e99cSbellard s->scan_enabled = 1; 2850e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2860e43e99cSbellard break; 2870e43e99cSbellard case KBD_CMD_RESET: 2880e43e99cSbellard ps2_reset_keyboard(s); 2890e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2900e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_POR); 2910e43e99cSbellard break; 2920e43e99cSbellard default: 2930e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 2940e43e99cSbellard break; 2950e43e99cSbellard } 2960e43e99cSbellard break; 297e7d93956Saurel32 case KBD_CMD_SCANCODE: 298e7d93956Saurel32 if (val == 0) { 299e7d93956Saurel32 if (s->scancode_set == 1) 300e7d93956Saurel32 ps2_put_keycode(s, 0x43); 301e7d93956Saurel32 else if (s->scancode_set == 2) 302e7d93956Saurel32 ps2_put_keycode(s, 0x41); 303e7d93956Saurel32 else if (s->scancode_set == 3) 304e7d93956Saurel32 ps2_put_keycode(s, 0x3f); 305e7d93956Saurel32 } else { 306e7d93956Saurel32 if (val >= 1 && val <= 3) 307e7d93956Saurel32 s->scancode_set = val; 308e7d93956Saurel32 ps2_queue(&s->common, KBD_REPLY_ACK); 309e7d93956Saurel32 } 310e7d93956Saurel32 s->common.write_cmd = -1; 311e7d93956Saurel32 break; 3120e43e99cSbellard case KBD_CMD_SET_LEDS: 3137f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 3140e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 3150e43e99cSbellard s->common.write_cmd = -1; 3160e43e99cSbellard break; 3170e43e99cSbellard case KBD_CMD_SET_RATE: 3180e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 3190e43e99cSbellard s->common.write_cmd = -1; 3200e43e99cSbellard break; 3210e43e99cSbellard } 3220e43e99cSbellard } 3230e43e99cSbellard 324f94f5d71Spbrook /* Set the scancode translation mode. 325f94f5d71Spbrook 0 = raw scancodes. 326f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 327f94f5d71Spbrook 328f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 329f94f5d71Spbrook { 330f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 3315edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 332f94f5d71Spbrook s->translate = mode; 333f94f5d71Spbrook } 334f94f5d71Spbrook 3350e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s) 3360e43e99cSbellard { 3370e43e99cSbellard unsigned int b; 3380e43e99cSbellard int dx1, dy1, dz1; 3390e43e99cSbellard 3400e43e99cSbellard dx1 = s->mouse_dx; 3410e43e99cSbellard dy1 = s->mouse_dy; 3420e43e99cSbellard dz1 = s->mouse_dz; 3430e43e99cSbellard /* XXX: increase range to 8 bits ? */ 3440e43e99cSbellard if (dx1 > 127) 3450e43e99cSbellard dx1 = 127; 3460e43e99cSbellard else if (dx1 < -127) 3470e43e99cSbellard dx1 = -127; 3480e43e99cSbellard if (dy1 > 127) 3490e43e99cSbellard dy1 = 127; 3500e43e99cSbellard else if (dy1 < -127) 3510e43e99cSbellard dy1 = -127; 3520e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 3530e43e99cSbellard ps2_queue(&s->common, b); 3540e43e99cSbellard ps2_queue(&s->common, dx1 & 0xff); 3550e43e99cSbellard ps2_queue(&s->common, dy1 & 0xff); 3560e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 3570e43e99cSbellard switch(s->mouse_type) { 3580e43e99cSbellard default: 3590e43e99cSbellard break; 3600e43e99cSbellard case 3: 3610e43e99cSbellard if (dz1 > 127) 3620e43e99cSbellard dz1 = 127; 3630e43e99cSbellard else if (dz1 < -127) 3640e43e99cSbellard dz1 = -127; 3650e43e99cSbellard ps2_queue(&s->common, dz1 & 0xff); 3660e43e99cSbellard break; 3670e43e99cSbellard case 4: 3680e43e99cSbellard if (dz1 > 7) 3690e43e99cSbellard dz1 = 7; 3700e43e99cSbellard else if (dz1 < -7) 3710e43e99cSbellard dz1 = -7; 3720e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 3730e43e99cSbellard ps2_queue(&s->common, b); 3740e43e99cSbellard break; 3750e43e99cSbellard } 3760e43e99cSbellard 3775edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 3780e43e99cSbellard /* update deltas */ 3790e43e99cSbellard s->mouse_dx -= dx1; 3800e43e99cSbellard s->mouse_dy -= dy1; 3810e43e99cSbellard s->mouse_dz -= dz1; 3820e43e99cSbellard } 3830e43e99cSbellard 3842a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 3852a766d29SGerd Hoffmann InputEvent *evt) 3860e43e99cSbellard { 3877fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 3882a766d29SGerd Hoffmann [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, 3892a766d29SGerd Hoffmann [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, 3902a766d29SGerd Hoffmann [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, 3912a766d29SGerd Hoffmann }; 3922a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 393b5a1b443SEric Blake InputMoveEvent *move; 394b5a1b443SEric Blake InputBtnEvent *btn; 3950e43e99cSbellard 3960e43e99cSbellard /* check if deltas are recorded when disabled */ 3970e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 3980e43e99cSbellard return; 3990e43e99cSbellard 400568c73a4SEric Blake switch (evt->type) { 4012a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 402*32bafa8fSEric Blake move = evt->u.rel.data; 403b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 404b5a1b443SEric Blake s->mouse_dx += move->value; 405b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 406b5a1b443SEric Blake s->mouse_dy -= move->value; 4072a766d29SGerd Hoffmann } 4082a766d29SGerd Hoffmann break; 4090e43e99cSbellard 4102a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 411*32bafa8fSEric Blake btn = evt->u.btn.data; 412b5a1b443SEric Blake if (btn->down) { 413b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 414b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 4152a766d29SGerd Hoffmann s->mouse_dz--; 416b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 4172a766d29SGerd Hoffmann s->mouse_dz++; 4182a766d29SGerd Hoffmann } 4192a766d29SGerd Hoffmann } else { 420b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 4212a766d29SGerd Hoffmann } 4222a766d29SGerd Hoffmann break; 4232a766d29SGerd Hoffmann 4242a766d29SGerd Hoffmann default: 4252a766d29SGerd Hoffmann /* keep gcc happy */ 4262a766d29SGerd Hoffmann break; 4272a766d29SGerd Hoffmann } 428fd214d18SGerd Hoffmann } 429fd214d18SGerd Hoffmann 4302a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 4312a766d29SGerd Hoffmann { 4322a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 4332a766d29SGerd Hoffmann 4342a766d29SGerd Hoffmann if (s->mouse_buttons) { 4352a766d29SGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 4362a766d29SGerd Hoffmann } 4372858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 4382858ab09SGonglei while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { 4390e43e99cSbellard /* if not remote, send event. Multiple events are sent if 4400e43e99cSbellard too big deltas */ 4410e43e99cSbellard ps2_mouse_send_packet(s); 4420e43e99cSbellard if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 4430e43e99cSbellard break; 4440e43e99cSbellard } 4450e43e99cSbellard } 4460e43e99cSbellard } 4470e43e99cSbellard 448548df2acSths void ps2_mouse_fake_event(void *opaque) 449548df2acSths { 4502a766d29SGerd Hoffmann PS2MouseState *s = opaque; 4515edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 4522a766d29SGerd Hoffmann s->mouse_dx++; 4532a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 454548df2acSths } 455548df2acSths 4560e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 4570e43e99cSbellard { 4580e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 4595edab03dSDon Koch 4605edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 4610e43e99cSbellard #ifdef DEBUG_MOUSE 4620e43e99cSbellard printf("kbd: write mouse 0x%02x\n", val); 4630e43e99cSbellard #endif 4640e43e99cSbellard switch(s->common.write_cmd) { 4650e43e99cSbellard default: 4660e43e99cSbellard case -1: 4670e43e99cSbellard /* mouse command */ 4680e43e99cSbellard if (s->mouse_wrap) { 4690e43e99cSbellard if (val == AUX_RESET_WRAP) { 4700e43e99cSbellard s->mouse_wrap = 0; 4710e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 4720e43e99cSbellard return; 4730e43e99cSbellard } else if (val != AUX_RESET) { 4740e43e99cSbellard ps2_queue(&s->common, val); 4750e43e99cSbellard return; 4760e43e99cSbellard } 4770e43e99cSbellard } 4780e43e99cSbellard switch(val) { 4790e43e99cSbellard case AUX_SET_SCALE11: 4800e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 4810e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 4820e43e99cSbellard break; 4830e43e99cSbellard case AUX_SET_SCALE21: 4840e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 4850e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 4860e43e99cSbellard break; 4870e43e99cSbellard case AUX_SET_STREAM: 4880e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 4890e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 4900e43e99cSbellard break; 4910e43e99cSbellard case AUX_SET_WRAP: 4920e43e99cSbellard s->mouse_wrap = 1; 4930e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 4940e43e99cSbellard break; 4950e43e99cSbellard case AUX_SET_REMOTE: 4960e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 4970e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 4980e43e99cSbellard break; 4990e43e99cSbellard case AUX_GET_TYPE: 5000e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5010e43e99cSbellard ps2_queue(&s->common, s->mouse_type); 5020e43e99cSbellard break; 5030e43e99cSbellard case AUX_SET_RES: 5040e43e99cSbellard case AUX_SET_SAMPLE: 5050e43e99cSbellard s->common.write_cmd = val; 5060e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5070e43e99cSbellard break; 5080e43e99cSbellard case AUX_GET_SCALE: 5090e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5100e43e99cSbellard ps2_queue(&s->common, s->mouse_status); 5110e43e99cSbellard ps2_queue(&s->common, s->mouse_resolution); 5120e43e99cSbellard ps2_queue(&s->common, s->mouse_sample_rate); 5130e43e99cSbellard break; 5140e43e99cSbellard case AUX_POLL: 5150e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5160e43e99cSbellard ps2_mouse_send_packet(s); 5170e43e99cSbellard break; 5180e43e99cSbellard case AUX_ENABLE_DEV: 5190e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 5200e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5210e43e99cSbellard break; 5220e43e99cSbellard case AUX_DISABLE_DEV: 5230e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 5240e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5250e43e99cSbellard break; 5260e43e99cSbellard case AUX_SET_DEFAULT: 5270e43e99cSbellard s->mouse_sample_rate = 100; 5280e43e99cSbellard s->mouse_resolution = 2; 5290e43e99cSbellard s->mouse_status = 0; 5300e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5310e43e99cSbellard break; 5320e43e99cSbellard case AUX_RESET: 5330e43e99cSbellard s->mouse_sample_rate = 100; 5340e43e99cSbellard s->mouse_resolution = 2; 5350e43e99cSbellard s->mouse_status = 0; 5360e43e99cSbellard s->mouse_type = 0; 5370e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5380e43e99cSbellard ps2_queue(&s->common, 0xaa); 5390e43e99cSbellard ps2_queue(&s->common, s->mouse_type); 5400e43e99cSbellard break; 5410e43e99cSbellard default: 5420e43e99cSbellard break; 5430e43e99cSbellard } 5440e43e99cSbellard break; 5450e43e99cSbellard case AUX_SET_SAMPLE: 5460e43e99cSbellard s->mouse_sample_rate = val; 5470e43e99cSbellard /* detect IMPS/2 or IMEX */ 5480e43e99cSbellard switch(s->mouse_detect_state) { 5490e43e99cSbellard default: 5500e43e99cSbellard case 0: 5510e43e99cSbellard if (val == 200) 5520e43e99cSbellard s->mouse_detect_state = 1; 5530e43e99cSbellard break; 5540e43e99cSbellard case 1: 5550e43e99cSbellard if (val == 100) 5560e43e99cSbellard s->mouse_detect_state = 2; 5570e43e99cSbellard else if (val == 200) 5580e43e99cSbellard s->mouse_detect_state = 3; 5590e43e99cSbellard else 5600e43e99cSbellard s->mouse_detect_state = 0; 5610e43e99cSbellard break; 5620e43e99cSbellard case 2: 5630e43e99cSbellard if (val == 80) 5640e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 5650e43e99cSbellard s->mouse_detect_state = 0; 5660e43e99cSbellard break; 5670e43e99cSbellard case 3: 5680e43e99cSbellard if (val == 80) 5690e43e99cSbellard s->mouse_type = 4; /* IMEX */ 5700e43e99cSbellard s->mouse_detect_state = 0; 5710e43e99cSbellard break; 5720e43e99cSbellard } 5730e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5740e43e99cSbellard s->common.write_cmd = -1; 5750e43e99cSbellard break; 5760e43e99cSbellard case AUX_SET_RES: 5770e43e99cSbellard s->mouse_resolution = val; 5780e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 5790e43e99cSbellard s->common.write_cmd = -1; 5800e43e99cSbellard break; 5810e43e99cSbellard } 5820e43e99cSbellard } 5830e43e99cSbellard 584ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 5850e43e99cSbellard { 5860e43e99cSbellard PS2Queue *q; 5870e43e99cSbellard s->write_cmd = -1; 5880e43e99cSbellard q = &s->queue; 5890e43e99cSbellard q->rptr = 0; 5900e43e99cSbellard q->wptr = 0; 5910e43e99cSbellard q->count = 0; 592deeccef3Saliguori s->update_irq(s->update_arg, 0); 5930e43e99cSbellard } 5940e43e99cSbellard 5952858ab09SGonglei static void ps2_common_post_load(PS2State *s) 5962858ab09SGonglei { 5972858ab09SGonglei PS2Queue *q = &s->queue; 5982858ab09SGonglei int size; 5992858ab09SGonglei int i; 6002858ab09SGonglei int tmp_data[PS2_QUEUE_SIZE]; 6012858ab09SGonglei 6022858ab09SGonglei /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ 6032858ab09SGonglei size = q->count > PS2_QUEUE_SIZE ? 0 : q->count; 6042858ab09SGonglei 6052858ab09SGonglei /* move the queue elements to the start of data array */ 6062858ab09SGonglei if (size > 0) { 6072858ab09SGonglei for (i = 0; i < size; i++) { 6082858ab09SGonglei /* move the queue elements to the temporary buffer */ 6092858ab09SGonglei tmp_data[i] = q->data[q->rptr]; 6102858ab09SGonglei if (++q->rptr == 256) { 6112858ab09SGonglei q->rptr = 0; 6122858ab09SGonglei } 6132858ab09SGonglei } 6142858ab09SGonglei memcpy(q->data, tmp_data, size); 6152858ab09SGonglei } 6162858ab09SGonglei /* reset rptr/wptr/count */ 6172858ab09SGonglei q->rptr = 0; 6182858ab09SGonglei q->wptr = size; 6192858ab09SGonglei q->count = size; 6202858ab09SGonglei s->update_irq(s->update_arg, q->count != 0); 6212858ab09SGonglei } 6222858ab09SGonglei 623ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 624ef74679aSDinesh Subhraveti { 625ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 626ef74679aSDinesh Subhraveti 6275edab03dSDon Koch trace_ps2_kbd_reset(opaque); 628ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 629ef74679aSDinesh Subhraveti s->scan_enabled = 0; 630ef74679aSDinesh Subhraveti s->translate = 0; 631ef74679aSDinesh Subhraveti s->scancode_set = 0; 632ef74679aSDinesh Subhraveti } 633ef74679aSDinesh Subhraveti 634ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 635ef74679aSDinesh Subhraveti { 636ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 637ef74679aSDinesh Subhraveti 6385edab03dSDon Koch trace_ps2_mouse_reset(opaque); 639ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 640ef74679aSDinesh Subhraveti s->mouse_status = 0; 641ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 642ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 643ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 644ef74679aSDinesh Subhraveti s->mouse_type = 0; 645ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 646ef74679aSDinesh Subhraveti s->mouse_dx = 0; 647ef74679aSDinesh Subhraveti s->mouse_dy = 0; 648ef74679aSDinesh Subhraveti s->mouse_dz = 0; 649ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 650ef74679aSDinesh Subhraveti } 651ef74679aSDinesh Subhraveti 652b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 653b31442c3SJuan Quintela .name = "PS2 Common State", 654b31442c3SJuan Quintela .version_id = 3, 655b31442c3SJuan Quintela .minimum_version_id = 2, 656b31442c3SJuan Quintela .fields = (VMStateField[]) { 657b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 658b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 659b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 660b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 661b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 662b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 6637783e9f0Spbrook } 664b31442c3SJuan Quintela }; 6657783e9f0Spbrook 6667f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 6677f540ab5SChristophe Fergeau { 6687f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 6697f540ab5SChristophe Fergeau 6707f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 6717f540ab5SChristophe Fergeau } 6727f540ab5SChristophe Fergeau 6737f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 6747f540ab5SChristophe Fergeau { 6757f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 6767f540ab5SChristophe Fergeau 6777f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 6787f540ab5SChristophe Fergeau return 0; 6797f540ab5SChristophe Fergeau } 6807f540ab5SChristophe Fergeau 6817f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 6827f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 6837f540ab5SChristophe Fergeau .version_id = 3, 6847f540ab5SChristophe Fergeau .minimum_version_id = 2, 6857f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 6865cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 6877f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 6887f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 6897f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 6907f540ab5SChristophe Fergeau } 6917f540ab5SChristophe Fergeau }; 6927f540ab5SChristophe Fergeau 693db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 6940e43e99cSbellard { 6950e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 6962858ab09SGonglei PS2State *ps2 = &s->common; 6970e43e99cSbellard 698db596c53SJuan Quintela if (version_id == 2) 699e7d93956Saurel32 s->scancode_set=2; 7002858ab09SGonglei 7012858ab09SGonglei ps2_common_post_load(ps2); 7022858ab09SGonglei 7030e43e99cSbellard return 0; 7040e43e99cSbellard } 7050e43e99cSbellard 7062858ab09SGonglei static void ps2_kbd_pre_save(void *opaque) 7072858ab09SGonglei { 7082858ab09SGonglei PS2KbdState *s = (PS2KbdState *)opaque; 7092858ab09SGonglei PS2State *ps2 = &s->common; 7102858ab09SGonglei 7112858ab09SGonglei ps2_common_post_load(ps2); 7122858ab09SGonglei } 7132858ab09SGonglei 714b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 715b31442c3SJuan Quintela .name = "ps2kbd", 716b31442c3SJuan Quintela .version_id = 3, 717db596c53SJuan Quintela .minimum_version_id = 2, 718db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 7192858ab09SGonglei .pre_save = ps2_kbd_pre_save, 720b31442c3SJuan Quintela .fields = (VMStateField[]) { 721b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 722b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 723b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 724b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 725b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 7267f540ab5SChristophe Fergeau }, 7275cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 7285cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 7295cd8cadaSJuan Quintela NULL 7300e43e99cSbellard } 731b31442c3SJuan Quintela }; 732b31442c3SJuan Quintela 7332858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 7342858ab09SGonglei { 7352858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 7362858ab09SGonglei PS2State *ps2 = &s->common; 7372858ab09SGonglei 7382858ab09SGonglei ps2_common_post_load(ps2); 7392858ab09SGonglei 7402858ab09SGonglei return 0; 7412858ab09SGonglei } 7422858ab09SGonglei 7432858ab09SGonglei static void ps2_mouse_pre_save(void *opaque) 7442858ab09SGonglei { 7452858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 7462858ab09SGonglei PS2State *ps2 = &s->common; 7472858ab09SGonglei 7482858ab09SGonglei ps2_common_post_load(ps2); 7492858ab09SGonglei } 7502858ab09SGonglei 751b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 752b31442c3SJuan Quintela .name = "ps2mouse", 753b31442c3SJuan Quintela .version_id = 2, 754b31442c3SJuan Quintela .minimum_version_id = 2, 7552858ab09SGonglei .post_load = ps2_mouse_post_load, 7562858ab09SGonglei .pre_save = ps2_mouse_pre_save, 757b31442c3SJuan Quintela .fields = (VMStateField[]) { 758b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 759b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 760b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 761b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 762b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 763b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 764b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 765b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 766b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 767b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 768b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 769b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 770b31442c3SJuan Quintela } 771b31442c3SJuan Quintela }; 7720e43e99cSbellard 77366e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 77466e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 77566e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 77666e6536eSGerd Hoffmann .event = ps2_keyboard_event, 77766e6536eSGerd Hoffmann }; 77866e6536eSGerd Hoffmann 7790e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 7800e43e99cSbellard { 7817267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 7820e43e99cSbellard 7835edab03dSDon Koch trace_ps2_kbd_init(s); 7840e43e99cSbellard s->common.update_irq = update_irq; 7850e43e99cSbellard s->common.update_arg = update_arg; 786e7d93956Saurel32 s->scancode_set = 2; 7870be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 78866e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 78966e6536eSGerd Hoffmann &ps2_keyboard_handler); 790ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 7910e43e99cSbellard return s; 7920e43e99cSbellard } 7930e43e99cSbellard 7942a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 7952a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 7962a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 7972a766d29SGerd Hoffmann .event = ps2_mouse_event, 7982a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 7992a766d29SGerd Hoffmann }; 8002a766d29SGerd Hoffmann 8010e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 8020e43e99cSbellard { 8037267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 8040e43e99cSbellard 8055edab03dSDon Koch trace_ps2_mouse_init(s); 8060e43e99cSbellard s->common.update_irq = update_irq; 8070e43e99cSbellard s->common.update_arg = update_arg; 8080be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 8092a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 8102a766d29SGerd Hoffmann &ps2_mouse_handler); 811ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 8120e43e99cSbellard return s; 8130e43e99cSbellard } 814