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" 25ec044a80SHervé Poussineau #include "qemu/log.h" 2683c9f4caSPaolo Bonzini #include "hw/hw.h" 270d09e41aSPaolo Bonzini #include "hw/input/ps2.h" 2828ecbaeeSPaolo Bonzini #include "ui/console.h" 2966e6536eSGerd Hoffmann #include "ui/input.h" 309c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 310e43e99cSbellard 325edab03dSDon Koch #include "trace.h" 335edab03dSDon Koch 340e43e99cSbellard /* debug PC keyboard */ 350e43e99cSbellard //#define DEBUG_KBD 360e43e99cSbellard 370e43e99cSbellard /* debug PC keyboard : only mouse */ 380e43e99cSbellard //#define DEBUG_MOUSE 390e43e99cSbellard 400e43e99cSbellard /* Keyboard Commands */ 410e43e99cSbellard #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ 420e43e99cSbellard #define KBD_CMD_ECHO 0xEE 43e7d93956Saurel32 #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ 440e43e99cSbellard #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ 450e43e99cSbellard #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ 460e43e99cSbellard #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ 470e43e99cSbellard #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ 480e43e99cSbellard #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ 490e43e99cSbellard #define KBD_CMD_RESET 0xFF /* Reset */ 500e43e99cSbellard 510e43e99cSbellard /* Keyboard Replies */ 520e43e99cSbellard #define KBD_REPLY_POR 0xAA /* Power on reset */ 5335c4d671Saurel32 #define KBD_REPLY_ID 0xAB /* Keyboard ID */ 540e43e99cSbellard #define KBD_REPLY_ACK 0xFA /* Command ACK */ 550e43e99cSbellard #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ 560e43e99cSbellard 570e43e99cSbellard /* Mouse Commands */ 580e43e99cSbellard #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ 590e43e99cSbellard #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ 600e43e99cSbellard #define AUX_SET_RES 0xE8 /* Set resolution */ 610e43e99cSbellard #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ 620e43e99cSbellard #define AUX_SET_STREAM 0xEA /* Set stream mode */ 630e43e99cSbellard #define AUX_POLL 0xEB /* Poll */ 640e43e99cSbellard #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ 650e43e99cSbellard #define AUX_SET_WRAP 0xEE /* Set wrap mode */ 660e43e99cSbellard #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ 670e43e99cSbellard #define AUX_GET_TYPE 0xF2 /* Get type */ 680e43e99cSbellard #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ 690e43e99cSbellard #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ 700e43e99cSbellard #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ 710e43e99cSbellard #define AUX_SET_DEFAULT 0xF6 720e43e99cSbellard #define AUX_RESET 0xFF /* Reset aux device */ 730e43e99cSbellard #define AUX_ACK 0xFA /* Command byte ACK. */ 740e43e99cSbellard 750e43e99cSbellard #define MOUSE_STATUS_REMOTE 0x40 760e43e99cSbellard #define MOUSE_STATUS_ENABLED 0x20 770e43e99cSbellard #define MOUSE_STATUS_SCALE21 0x10 780e43e99cSbellard 792858ab09SGonglei #define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ 800e43e99cSbellard 81620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */ 82620775d1SDaniel P. Berrange #define MOD_CTRL_L (1 << 0) 83620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1) 84620775d1SDaniel P. Berrange #define MOD_ALT_L (1 << 2) 85620775d1SDaniel P. Berrange #define MOD_CTRL_R (1 << 3) 86620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4) 87620775d1SDaniel P. Berrange #define MOD_ALT_R (1 << 5) 88620775d1SDaniel P. Berrange 890e43e99cSbellard typedef struct { 902858ab09SGonglei /* Keep the data array 256 bytes long, which compatibility 912858ab09SGonglei with older qemu versions. */ 922858ab09SGonglei uint8_t data[256]; 930e43e99cSbellard int rptr, wptr, count; 940e43e99cSbellard } PS2Queue; 950e43e99cSbellard 968498bb8dSGerd Hoffmann struct PS2State { 970e43e99cSbellard PS2Queue queue; 980e43e99cSbellard int32_t write_cmd; 990e43e99cSbellard void (*update_irq)(void *, int); 1000e43e99cSbellard void *update_arg; 1018498bb8dSGerd Hoffmann }; 1020e43e99cSbellard 1030e43e99cSbellard typedef struct { 1040e43e99cSbellard PS2State common; 1050e43e99cSbellard int scan_enabled; 106f94f5d71Spbrook int translate; 107e7d93956Saurel32 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ 1087f540ab5SChristophe Fergeau int ledstate; 10957d5c005SHervé Poussineau bool need_high_bit; 110620775d1SDaniel P. Berrange unsigned int modifiers; /* bitmask of MOD_* constants above */ 1110e43e99cSbellard } PS2KbdState; 1120e43e99cSbellard 1130e43e99cSbellard typedef struct { 1140e43e99cSbellard PS2State common; 1150e43e99cSbellard uint8_t mouse_status; 1160e43e99cSbellard uint8_t mouse_resolution; 1170e43e99cSbellard uint8_t mouse_sample_rate; 1180e43e99cSbellard uint8_t mouse_wrap; 1190e43e99cSbellard uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ 1200e43e99cSbellard uint8_t mouse_detect_state; 1210e43e99cSbellard int mouse_dx; /* current values, needed for 'poll' mode */ 1220e43e99cSbellard int mouse_dy; 1230e43e99cSbellard int mouse_dz; 1240e43e99cSbellard uint8_t mouse_buttons; 1250e43e99cSbellard } PS2MouseState; 1260e43e99cSbellard 12757d5c005SHervé Poussineau static uint8_t translate_table[256] = { 12857d5c005SHervé Poussineau 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 12957d5c005SHervé Poussineau 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 13057d5c005SHervé Poussineau 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 13157d5c005SHervé Poussineau 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 13257d5c005SHervé Poussineau 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 13357d5c005SHervé Poussineau 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 13457d5c005SHervé Poussineau 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 13557d5c005SHervé Poussineau 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 13657d5c005SHervé Poussineau 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 13757d5c005SHervé Poussineau 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 13857d5c005SHervé Poussineau 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 13957d5c005SHervé Poussineau 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 14057d5c005SHervé Poussineau 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 14157d5c005SHervé Poussineau 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 14257d5c005SHervé Poussineau 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 14357d5c005SHervé Poussineau 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 14457d5c005SHervé Poussineau 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 14557d5c005SHervé Poussineau 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 14657d5c005SHervé Poussineau 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 14757d5c005SHervé Poussineau 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 14857d5c005SHervé Poussineau 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 14957d5c005SHervé Poussineau 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 15057d5c005SHervé Poussineau 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 15157d5c005SHervé Poussineau 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 15257d5c005SHervé Poussineau 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 15357d5c005SHervé Poussineau 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 15457d5c005SHervé Poussineau 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 15557d5c005SHervé Poussineau 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 15657d5c005SHervé Poussineau 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 15757d5c005SHervé Poussineau 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 15857d5c005SHervé Poussineau 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 15957d5c005SHervé Poussineau 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 16057d5c005SHervé Poussineau }; 16157d5c005SHervé Poussineau 162620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key) 163620775d1SDaniel P. Berrange { 164620775d1SDaniel P. Berrange switch (key) { 165620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL: 166620775d1SDaniel P. Berrange return MOD_CTRL_L; 167620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL_R: 168620775d1SDaniel P. Berrange return MOD_CTRL_R; 169620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT: 170620775d1SDaniel P. Berrange return MOD_SHIFT_L; 171620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT_R: 172620775d1SDaniel P. Berrange return MOD_SHIFT_R; 173620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT: 174620775d1SDaniel P. Berrange return MOD_ALT_L; 175620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT_R: 176620775d1SDaniel P. Berrange return MOD_ALT_R; 177620775d1SDaniel P. Berrange default: 178620775d1SDaniel P. Berrange return 0; 179620775d1SDaniel P. Berrange } 180620775d1SDaniel P. Berrange } 181620775d1SDaniel P. Berrange 182954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s) 183954ee55bSGerd Hoffmann { 184954ee55bSGerd Hoffmann PS2Queue *q = &s->queue; 185954ee55bSGerd Hoffmann 186954ee55bSGerd Hoffmann q->rptr = 0; 187954ee55bSGerd Hoffmann q->wptr = 0; 188954ee55bSGerd Hoffmann q->count = 0; 189954ee55bSGerd Hoffmann } 190954ee55bSGerd Hoffmann 1917abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 1920e43e99cSbellard { 1930e43e99cSbellard PS2Queue *q = &s->queue; 1940e43e99cSbellard 1957abe7eb2SGeoffrey McRae if (q->count == PS2_QUEUE_SIZE) { 1960e43e99cSbellard return; 1977abe7eb2SGeoffrey McRae } 1987abe7eb2SGeoffrey McRae 1990e43e99cSbellard q->data[q->wptr] = b; 2000e43e99cSbellard if (++q->wptr == PS2_QUEUE_SIZE) 2010e43e99cSbellard q->wptr = 0; 2020e43e99cSbellard q->count++; 2037abe7eb2SGeoffrey McRae } 2047abe7eb2SGeoffrey McRae 2057abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s) 2067abe7eb2SGeoffrey McRae { 2077abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2087abe7eb2SGeoffrey McRae } 2097abe7eb2SGeoffrey McRae 2107abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 2117abe7eb2SGeoffrey McRae { 2127abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 2137abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2147abe7eb2SGeoffrey McRae } 2157abe7eb2SGeoffrey McRae 2167abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 2177abe7eb2SGeoffrey McRae { 2187abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 2197abe7eb2SGeoffrey McRae return; 2207abe7eb2SGeoffrey McRae } 2217abe7eb2SGeoffrey McRae 2227abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2237abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2247abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2257abe7eb2SGeoffrey McRae } 2267abe7eb2SGeoffrey McRae 2277abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 2287abe7eb2SGeoffrey McRae { 2297abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 2307abe7eb2SGeoffrey McRae return; 2317abe7eb2SGeoffrey McRae } 2327abe7eb2SGeoffrey McRae 2337abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2347abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2357abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2367abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2377abe7eb2SGeoffrey McRae } 2387abe7eb2SGeoffrey McRae 2397abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 2407abe7eb2SGeoffrey McRae { 2417abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 2427abe7eb2SGeoffrey McRae return; 2437abe7eb2SGeoffrey McRae } 2447abe7eb2SGeoffrey McRae 2457abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2467abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2477abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2487abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 2490e43e99cSbellard s->update_irq(s->update_arg, 1); 2500e43e99cSbellard } 2510e43e99cSbellard 25257d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 2530e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 2540e43e99cSbellard { 255f94f5d71Spbrook PS2KbdState *s = opaque; 256e7d93956Saurel32 2575edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 258fd214d18SGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 25957d5c005SHervé Poussineau 26057d5c005SHervé Poussineau if (s->translate) { 26157d5c005SHervé Poussineau if (keycode == 0xf0) { 26257d5c005SHervé Poussineau s->need_high_bit = true; 26357d5c005SHervé Poussineau } else if (s->need_high_bit) { 26457d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode] | 0x80); 26557d5c005SHervé Poussineau s->need_high_bit = false; 26657d5c005SHervé Poussineau } else { 26757d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode]); 2687096a96dSRoy Tam } 26957d5c005SHervé Poussineau } else { 2700e43e99cSbellard ps2_queue(&s->common, keycode); 2710e43e99cSbellard } 27257d5c005SHervé Poussineau } 2730e43e99cSbellard 27466e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 27566e6536eSGerd Hoffmann InputEvent *evt) 27666e6536eSGerd Hoffmann { 27766e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 27832bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 2798c10e0baSHervé Poussineau int qcode; 280ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 281620775d1SDaniel P. Berrange int mod; 28266e6536eSGerd Hoffmann 283143c04c7SGeoffrey McRae /* do not process events while disabled to prevent stream corruption */ 284143c04c7SGeoffrey McRae if (!s->scan_enabled) { 285143c04c7SGeoffrey McRae return; 286143c04c7SGeoffrey McRae } 287143c04c7SGeoffrey McRae 28866e6536eSGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 2898c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 2908c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 29157d5c005SHervé Poussineau 292620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 293620775d1SDaniel P. Berrange trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers); 294620775d1SDaniel P. Berrange if (key->down) { 295620775d1SDaniel P. Berrange s->modifiers |= mod; 296620775d1SDaniel P. Berrange } else { 297620775d1SDaniel P. Berrange s->modifiers &= ~mod; 298620775d1SDaniel P. Berrange } 299620775d1SDaniel P. Berrange 3008c10e0baSHervé Poussineau if (s->scancode_set == 1) { 3018c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 30229fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 30329fd23a5SDaniel P. Berrange if (key->down) { 30429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 30529fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 30629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 30729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 30829fd23a5SDaniel P. Berrange } 30929fd23a5SDaniel P. Berrange } else { 3108c10e0baSHervé Poussineau if (key->down) { 3118c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3128c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 3138c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 314927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 3158c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 3168c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 3178c10e0baSHervé Poussineau } 31829fd23a5SDaniel P. Berrange } 3198c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 320620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 321620775d1SDaniel P. Berrange if (key->down) { 322620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 323620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 324620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 325620775d1SDaniel P. Berrange } else { 326620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 327620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 328620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 329620775d1SDaniel P. Berrange } 330620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 331620775d1SDaniel P. Berrange if (key->down) { 332620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 333620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 334620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 335620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 336620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 337620775d1SDaniel P. Berrange } else { 338620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 339620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 340620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 341620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 342620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 343620775d1SDaniel P. Berrange } 3448f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 3458f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 3468f63458fSDaniel P. Berrange if (key->down) { 3478f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3488f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 3498f63458fSDaniel P. Berrange } else { 3508f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3518f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 3528f63458fSDaniel P. Berrange } 353620775d1SDaniel P. Berrange } else { 3548c10e0baSHervé Poussineau if (key->down) { 3558c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3568c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 3578c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3588c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 3598c10e0baSHervé Poussineau } else { 3608c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3618c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 3628c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3638c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 3648c10e0baSHervé Poussineau } 365620775d1SDaniel P. Berrange } 3668c10e0baSHervé Poussineau } else { 367ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset1_len) 368ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 3698c10e0baSHervé Poussineau if (keycode) { 3708c10e0baSHervé Poussineau if (keycode & 0xff00) { 3718c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 3728c10e0baSHervé Poussineau } 3738c10e0baSHervé Poussineau if (!key->down) { 3748c10e0baSHervé Poussineau keycode |= 0x80; 3758c10e0baSHervé Poussineau } 3768c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 3778c10e0baSHervé Poussineau } else { 378ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 379ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 3808c10e0baSHervé Poussineau } 3818c10e0baSHervé Poussineau } 3828c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 3838c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 38429fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 38529fd23a5SDaniel P. Berrange if (key->down) { 38629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 38729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 38829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 38929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 39029fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 39129fd23a5SDaniel P. Berrange } 39229fd23a5SDaniel P. Berrange } else { 3938c10e0baSHervé Poussineau if (key->down) { 3948c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3958c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 3968c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 3978c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3988c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 3998c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4008c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4018c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4028c10e0baSHervé Poussineau } 40329fd23a5SDaniel P. Berrange } 4048c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 405620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 406620775d1SDaniel P. Berrange if (key->down) { 407620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 408620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 409620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 410620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 411620775d1SDaniel P. Berrange } else { 412620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 413620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 414620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 415620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 416620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 417620775d1SDaniel P. Berrange } 418620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 419620775d1SDaniel P. Berrange if (key->down) { 420620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 421620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 422620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 423620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 424620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 425620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 426620775d1SDaniel P. Berrange } else { 427620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 428620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 429620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 430620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 431620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 432620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 433620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 434620775d1SDaniel P. Berrange } 4358f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 4368f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 4378f63458fSDaniel P. Berrange if (key->down) { 4388f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4398f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4408f63458fSDaniel P. Berrange } else { 4418f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4428f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 4438f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4448f63458fSDaniel P. Berrange } 445620775d1SDaniel P. Berrange } else { 4468c10e0baSHervé Poussineau if (key->down) { 4478c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4488c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4498c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4508c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4518c10e0baSHervé Poussineau } else { 4528c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4538c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4548c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4558c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4568c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4578c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4588c10e0baSHervé Poussineau } 459620775d1SDaniel P. Berrange } 4608c10e0baSHervé Poussineau } else { 461ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset2_len) 462ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 4638c10e0baSHervé Poussineau if (keycode) { 4648c10e0baSHervé Poussineau if (keycode & 0xff00) { 4658c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4668c10e0baSHervé Poussineau } 4678c10e0baSHervé Poussineau if (!key->down) { 4688c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4698c10e0baSHervé Poussineau } 4708c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 47157d5c005SHervé Poussineau } else { 472ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 473ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 47457d5c005SHervé Poussineau } 47557d5c005SHervé Poussineau } 47657d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 477ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset3_len) 478ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 4798c10e0baSHervé Poussineau if (keycode) { 4808c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 4818c10e0baSHervé Poussineau if (!key->down) { 4828c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 48357d5c005SHervé Poussineau } 48457d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 4858c10e0baSHervé Poussineau } else { 486ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 487ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 4888c10e0baSHervé Poussineau } 48966e6536eSGerd Hoffmann } 49066e6536eSGerd Hoffmann } 49166e6536eSGerd Hoffmann 4928498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 4930e43e99cSbellard { 4940e43e99cSbellard PS2Queue *q; 4950e43e99cSbellard int val, index; 4960e43e99cSbellard 4978498bb8dSGerd Hoffmann trace_ps2_read_data(s); 4980e43e99cSbellard q = &s->queue; 4990e43e99cSbellard if (q->count == 0) { 5000e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 5010e43e99cSbellard (needed for EMM386) */ 5020e43e99cSbellard /* XXX: need a timer to do things correctly */ 5030e43e99cSbellard index = q->rptr - 1; 5040e43e99cSbellard if (index < 0) 5050e43e99cSbellard index = PS2_QUEUE_SIZE - 1; 5060e43e99cSbellard val = q->data[index]; 5070e43e99cSbellard } else { 5080e43e99cSbellard val = q->data[q->rptr]; 5090e43e99cSbellard if (++q->rptr == PS2_QUEUE_SIZE) 5100e43e99cSbellard q->rptr = 0; 5110e43e99cSbellard q->count--; 5120e43e99cSbellard /* reading deasserts IRQ */ 5130e43e99cSbellard s->update_irq(s->update_arg, 0); 5140e43e99cSbellard /* reassert IRQs if data left */ 5150e43e99cSbellard s->update_irq(s->update_arg, q->count != 0); 5160e43e99cSbellard } 5170e43e99cSbellard return val; 5180e43e99cSbellard } 5190e43e99cSbellard 5207f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 5217f540ab5SChristophe Fergeau { 5225edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 5237f540ab5SChristophe Fergeau s->ledstate = ledstate; 5247f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 5257f540ab5SChristophe Fergeau } 5267f540ab5SChristophe Fergeau 5270e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 5280e43e99cSbellard { 5295edab03dSDon Koch trace_ps2_reset_keyboard(s); 5300e43e99cSbellard s->scan_enabled = 1; 531e7d93956Saurel32 s->scancode_set = 2; 5326e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 5337f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 5340e43e99cSbellard } 5350e43e99cSbellard 5360e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 5370e43e99cSbellard { 5380e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 5390e43e99cSbellard 5405edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 5410e43e99cSbellard switch(s->common.write_cmd) { 5420e43e99cSbellard default: 5430e43e99cSbellard case -1: 5440e43e99cSbellard switch(val) { 5450e43e99cSbellard case 0x00: 5460e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5470e43e99cSbellard break; 5480e43e99cSbellard case 0x05: 5490e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_RESEND); 5500e43e99cSbellard break; 5510e43e99cSbellard case KBD_CMD_GET_ID: 552e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 55335c4d671Saurel32 if (s->translate) 5547abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 5557abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5567abe7eb2SGeoffrey McRae KBD_REPLY_ID, 5577abe7eb2SGeoffrey McRae 0x41); 55835c4d671Saurel32 else 5597abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 5607abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5617abe7eb2SGeoffrey McRae KBD_REPLY_ID, 5627abe7eb2SGeoffrey McRae 0x83); 5630e43e99cSbellard break; 5640e43e99cSbellard case KBD_CMD_ECHO: 5650e43e99cSbellard ps2_queue(&s->common, KBD_CMD_ECHO); 5660e43e99cSbellard break; 5670e43e99cSbellard case KBD_CMD_ENABLE: 5680e43e99cSbellard s->scan_enabled = 1; 5690e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5700e43e99cSbellard break; 571e7d93956Saurel32 case KBD_CMD_SCANCODE: 5720e43e99cSbellard case KBD_CMD_SET_LEDS: 5730e43e99cSbellard case KBD_CMD_SET_RATE: 5740e43e99cSbellard s->common.write_cmd = val; 5750e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5760e43e99cSbellard break; 5770e43e99cSbellard case KBD_CMD_RESET_DISABLE: 5780e43e99cSbellard ps2_reset_keyboard(s); 5790e43e99cSbellard s->scan_enabled = 0; 5800e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5810e43e99cSbellard break; 5820e43e99cSbellard case KBD_CMD_RESET_ENABLE: 5830e43e99cSbellard ps2_reset_keyboard(s); 5840e43e99cSbellard s->scan_enabled = 1; 5850e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5860e43e99cSbellard break; 5870e43e99cSbellard case KBD_CMD_RESET: 5880e43e99cSbellard ps2_reset_keyboard(s); 5897abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 5907abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5917abe7eb2SGeoffrey McRae KBD_REPLY_POR); 5920e43e99cSbellard break; 5930e43e99cSbellard default: 59406b3611fSHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 5950e43e99cSbellard break; 5960e43e99cSbellard } 5970e43e99cSbellard break; 598e7d93956Saurel32 case KBD_CMD_SCANCODE: 599e7d93956Saurel32 if (val == 0) { 6007abe7eb2SGeoffrey McRae if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) { 6014df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_ACK); 60257d5c005SHervé Poussineau ps2_put_keycode(s, s->scancode_set); 6037abe7eb2SGeoffrey McRae } 6044df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 605e7d93956Saurel32 s->scancode_set = val; 606e7d93956Saurel32 ps2_queue(&s->common, KBD_REPLY_ACK); 6074df23b64SHervé Poussineau } else { 6084df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 609e7d93956Saurel32 } 610e7d93956Saurel32 s->common.write_cmd = -1; 611e7d93956Saurel32 break; 6120e43e99cSbellard case KBD_CMD_SET_LEDS: 6137f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 6140e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6150e43e99cSbellard s->common.write_cmd = -1; 6160e43e99cSbellard break; 6170e43e99cSbellard case KBD_CMD_SET_RATE: 6180e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6190e43e99cSbellard s->common.write_cmd = -1; 6200e43e99cSbellard break; 6210e43e99cSbellard } 6220e43e99cSbellard } 6230e43e99cSbellard 624f94f5d71Spbrook /* Set the scancode translation mode. 625f94f5d71Spbrook 0 = raw scancodes. 626f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 627f94f5d71Spbrook 628f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 629f94f5d71Spbrook { 630f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 6315edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 632f94f5d71Spbrook s->translate = mode; 633f94f5d71Spbrook } 634f94f5d71Spbrook 6357abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 6360e43e99cSbellard { 6377abe7eb2SGeoffrey McRae const int needed = 3 + (s->mouse_type - 2); 6380e43e99cSbellard unsigned int b; 6390e43e99cSbellard int dx1, dy1, dz1; 6400e43e99cSbellard 6417abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { 6427abe7eb2SGeoffrey McRae return 0; 6437abe7eb2SGeoffrey McRae } 6447abe7eb2SGeoffrey McRae 6450e43e99cSbellard dx1 = s->mouse_dx; 6460e43e99cSbellard dy1 = s->mouse_dy; 6470e43e99cSbellard dz1 = s->mouse_dz; 6480e43e99cSbellard /* XXX: increase range to 8 bits ? */ 6490e43e99cSbellard if (dx1 > 127) 6500e43e99cSbellard dx1 = 127; 6510e43e99cSbellard else if (dx1 < -127) 6520e43e99cSbellard dx1 = -127; 6530e43e99cSbellard if (dy1 > 127) 6540e43e99cSbellard dy1 = 127; 6550e43e99cSbellard else if (dy1 < -127) 6560e43e99cSbellard dy1 = -127; 6570e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 6587abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 6597abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dx1 & 0xff); 6607abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dy1 & 0xff); 6610e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 6620e43e99cSbellard switch(s->mouse_type) { 6630e43e99cSbellard default: 6640e43e99cSbellard break; 6650e43e99cSbellard case 3: 6660e43e99cSbellard if (dz1 > 127) 6670e43e99cSbellard dz1 = 127; 6680e43e99cSbellard else if (dz1 < -127) 6690e43e99cSbellard dz1 = -127; 6707abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dz1 & 0xff); 6710e43e99cSbellard break; 6720e43e99cSbellard case 4: 6730e43e99cSbellard if (dz1 > 7) 6740e43e99cSbellard dz1 = 7; 6750e43e99cSbellard else if (dz1 < -7) 6760e43e99cSbellard dz1 = -7; 6770e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 6787abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 6790e43e99cSbellard break; 6800e43e99cSbellard } 6810e43e99cSbellard 6827abe7eb2SGeoffrey McRae ps2_raise_irq(&s->common); 6837abe7eb2SGeoffrey McRae 6845edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 6850e43e99cSbellard /* update deltas */ 6860e43e99cSbellard s->mouse_dx -= dx1; 6870e43e99cSbellard s->mouse_dy -= dy1; 6880e43e99cSbellard s->mouse_dz -= dz1; 6897abe7eb2SGeoffrey McRae 6907abe7eb2SGeoffrey McRae return 1; 6910e43e99cSbellard } 6920e43e99cSbellard 6932a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 6942a766d29SGerd Hoffmann InputEvent *evt) 6950e43e99cSbellard { 6967fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 6978b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 6988b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 6998b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 7008b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 7018b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 7022a766d29SGerd Hoffmann }; 7032a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 704b5a1b443SEric Blake InputMoveEvent *move; 705b5a1b443SEric Blake InputBtnEvent *btn; 7060e43e99cSbellard 7070e43e99cSbellard /* check if deltas are recorded when disabled */ 7080e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 7090e43e99cSbellard return; 7100e43e99cSbellard 711568c73a4SEric Blake switch (evt->type) { 7122a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 71332bafa8fSEric Blake move = evt->u.rel.data; 714b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 715b5a1b443SEric Blake s->mouse_dx += move->value; 716b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 717b5a1b443SEric Blake s->mouse_dy -= move->value; 7182a766d29SGerd Hoffmann } 7192a766d29SGerd Hoffmann break; 7200e43e99cSbellard 7212a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 72232bafa8fSEric Blake btn = evt->u.btn.data; 723b5a1b443SEric Blake if (btn->down) { 724b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 725b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 7262a766d29SGerd Hoffmann s->mouse_dz--; 727b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 7282a766d29SGerd Hoffmann s->mouse_dz++; 7292a766d29SGerd Hoffmann } 7302a766d29SGerd Hoffmann } else { 731b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 7322a766d29SGerd Hoffmann } 7332a766d29SGerd Hoffmann break; 7342a766d29SGerd Hoffmann 7352a766d29SGerd Hoffmann default: 7362a766d29SGerd Hoffmann /* keep gcc happy */ 7372a766d29SGerd Hoffmann break; 7382a766d29SGerd Hoffmann } 739fd214d18SGerd Hoffmann } 740fd214d18SGerd Hoffmann 7412a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 7422a766d29SGerd Hoffmann { 7432a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 7442a766d29SGerd Hoffmann 745143c04c7SGeoffrey McRae /* do not sync while disabled to prevent stream corruption */ 746143c04c7SGeoffrey McRae if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 747143c04c7SGeoffrey McRae return; 748143c04c7SGeoffrey McRae } 749143c04c7SGeoffrey McRae 7502a766d29SGerd Hoffmann if (s->mouse_buttons) { 7512a766d29SGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 7522a766d29SGerd Hoffmann } 7532858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 7540e43e99cSbellard /* if not remote, send event. Multiple events are sent if 7550e43e99cSbellard too big deltas */ 7567abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 7570e43e99cSbellard if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 7580e43e99cSbellard break; 7590e43e99cSbellard } 7600e43e99cSbellard } 7610e43e99cSbellard } 7620e43e99cSbellard 763548df2acSths void ps2_mouse_fake_event(void *opaque) 764548df2acSths { 7652a766d29SGerd Hoffmann PS2MouseState *s = opaque; 7665edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 7672a766d29SGerd Hoffmann s->mouse_dx++; 7682a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 769548df2acSths } 770548df2acSths 7710e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 7720e43e99cSbellard { 7730e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 7745edab03dSDon Koch 7755edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 7760e43e99cSbellard #ifdef DEBUG_MOUSE 7770e43e99cSbellard printf("kbd: write mouse 0x%02x\n", val); 7780e43e99cSbellard #endif 7790e43e99cSbellard switch(s->common.write_cmd) { 7800e43e99cSbellard default: 7810e43e99cSbellard case -1: 7820e43e99cSbellard /* mouse command */ 7830e43e99cSbellard if (s->mouse_wrap) { 7840e43e99cSbellard if (val == AUX_RESET_WRAP) { 7850e43e99cSbellard s->mouse_wrap = 0; 7860e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7870e43e99cSbellard return; 7880e43e99cSbellard } else if (val != AUX_RESET) { 7890e43e99cSbellard ps2_queue(&s->common, val); 7900e43e99cSbellard return; 7910e43e99cSbellard } 7920e43e99cSbellard } 7930e43e99cSbellard switch(val) { 7940e43e99cSbellard case AUX_SET_SCALE11: 7950e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 7960e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7970e43e99cSbellard break; 7980e43e99cSbellard case AUX_SET_SCALE21: 7990e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 8000e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8010e43e99cSbellard break; 8020e43e99cSbellard case AUX_SET_STREAM: 8030e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 8040e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8050e43e99cSbellard break; 8060e43e99cSbellard case AUX_SET_WRAP: 8070e43e99cSbellard s->mouse_wrap = 1; 8080e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8090e43e99cSbellard break; 8100e43e99cSbellard case AUX_SET_REMOTE: 8110e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 8120e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8130e43e99cSbellard break; 8140e43e99cSbellard case AUX_GET_TYPE: 8157abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 8167abe7eb2SGeoffrey McRae AUX_ACK, 8177abe7eb2SGeoffrey McRae s->mouse_type); 8180e43e99cSbellard break; 8190e43e99cSbellard case AUX_SET_RES: 8200e43e99cSbellard case AUX_SET_SAMPLE: 8210e43e99cSbellard s->common.write_cmd = val; 8220e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8230e43e99cSbellard break; 8240e43e99cSbellard case AUX_GET_SCALE: 8257abe7eb2SGeoffrey McRae ps2_queue_4(&s->common, 8267abe7eb2SGeoffrey McRae AUX_ACK, 8277abe7eb2SGeoffrey McRae s->mouse_status, 8287abe7eb2SGeoffrey McRae s->mouse_resolution, 8297abe7eb2SGeoffrey McRae s->mouse_sample_rate); 8300e43e99cSbellard break; 8310e43e99cSbellard case AUX_POLL: 8320e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8330e43e99cSbellard ps2_mouse_send_packet(s); 8340e43e99cSbellard break; 8350e43e99cSbellard case AUX_ENABLE_DEV: 8360e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 8370e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8380e43e99cSbellard break; 8390e43e99cSbellard case AUX_DISABLE_DEV: 8400e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 8410e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8420e43e99cSbellard break; 8430e43e99cSbellard case AUX_SET_DEFAULT: 8440e43e99cSbellard s->mouse_sample_rate = 100; 8450e43e99cSbellard s->mouse_resolution = 2; 8460e43e99cSbellard s->mouse_status = 0; 8470e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8480e43e99cSbellard break; 8490e43e99cSbellard case AUX_RESET: 8500e43e99cSbellard s->mouse_sample_rate = 100; 8510e43e99cSbellard s->mouse_resolution = 2; 8520e43e99cSbellard s->mouse_status = 0; 8530e43e99cSbellard s->mouse_type = 0; 854143c04c7SGeoffrey McRae ps2_reset_queue(&s->common); 8557abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 8567abe7eb2SGeoffrey McRae AUX_ACK, 8577abe7eb2SGeoffrey McRae 0xaa, 8587abe7eb2SGeoffrey McRae s->mouse_type); 8590e43e99cSbellard break; 8600e43e99cSbellard default: 8610e43e99cSbellard break; 8620e43e99cSbellard } 8630e43e99cSbellard break; 8640e43e99cSbellard case AUX_SET_SAMPLE: 8650e43e99cSbellard s->mouse_sample_rate = val; 8660e43e99cSbellard /* detect IMPS/2 or IMEX */ 8670e43e99cSbellard switch(s->mouse_detect_state) { 8680e43e99cSbellard default: 8690e43e99cSbellard case 0: 8700e43e99cSbellard if (val == 200) 8710e43e99cSbellard s->mouse_detect_state = 1; 8720e43e99cSbellard break; 8730e43e99cSbellard case 1: 8740e43e99cSbellard if (val == 100) 8750e43e99cSbellard s->mouse_detect_state = 2; 8760e43e99cSbellard else if (val == 200) 8770e43e99cSbellard s->mouse_detect_state = 3; 8780e43e99cSbellard else 8790e43e99cSbellard s->mouse_detect_state = 0; 8800e43e99cSbellard break; 8810e43e99cSbellard case 2: 8820e43e99cSbellard if (val == 80) 8830e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 8840e43e99cSbellard s->mouse_detect_state = 0; 8850e43e99cSbellard break; 8860e43e99cSbellard case 3: 8870e43e99cSbellard if (val == 80) 8880e43e99cSbellard s->mouse_type = 4; /* IMEX */ 8890e43e99cSbellard s->mouse_detect_state = 0; 8900e43e99cSbellard break; 8910e43e99cSbellard } 8920e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8930e43e99cSbellard s->common.write_cmd = -1; 8940e43e99cSbellard break; 8950e43e99cSbellard case AUX_SET_RES: 8960e43e99cSbellard s->mouse_resolution = val; 8970e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8980e43e99cSbellard s->common.write_cmd = -1; 8990e43e99cSbellard break; 9000e43e99cSbellard } 9010e43e99cSbellard } 9020e43e99cSbellard 903ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 9040e43e99cSbellard { 9050e43e99cSbellard s->write_cmd = -1; 906954ee55bSGerd Hoffmann ps2_reset_queue(s); 907deeccef3Saliguori s->update_irq(s->update_arg, 0); 9080e43e99cSbellard } 9090e43e99cSbellard 9102858ab09SGonglei static void ps2_common_post_load(PS2State *s) 9112858ab09SGonglei { 9122858ab09SGonglei PS2Queue *q = &s->queue; 913802cbcb7SPrasad J Pandit uint8_t i, size; 914802cbcb7SPrasad J Pandit uint8_t tmp_data[PS2_QUEUE_SIZE]; 9152858ab09SGonglei 9162858ab09SGonglei /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ 917802cbcb7SPrasad J Pandit size = (q->count < 0 || q->count > PS2_QUEUE_SIZE) ? 0 : q->count; 9182858ab09SGonglei 9192858ab09SGonglei /* move the queue elements to the start of data array */ 9202858ab09SGonglei for (i = 0; i < size; i++) { 921802cbcb7SPrasad J Pandit if (q->rptr < 0 || q->rptr >= sizeof(q->data)) { 9222858ab09SGonglei q->rptr = 0; 9232858ab09SGonglei } 924802cbcb7SPrasad J Pandit tmp_data[i] = q->data[q->rptr++]; 9252858ab09SGonglei } 9262858ab09SGonglei memcpy(q->data, tmp_data, size); 927802cbcb7SPrasad J Pandit 9282858ab09SGonglei /* reset rptr/wptr/count */ 9292858ab09SGonglei q->rptr = 0; 930*b55a06dfSliujunjie q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size; 9312858ab09SGonglei q->count = size; 9322858ab09SGonglei s->update_irq(s->update_arg, q->count != 0); 9332858ab09SGonglei } 9342858ab09SGonglei 935ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 936ef74679aSDinesh Subhraveti { 937ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 938ef74679aSDinesh Subhraveti 9395edab03dSDon Koch trace_ps2_kbd_reset(opaque); 940ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 941ef74679aSDinesh Subhraveti s->scan_enabled = 0; 942ef74679aSDinesh Subhraveti s->translate = 0; 943089adafdSHervé Poussineau s->scancode_set = 2; 944620775d1SDaniel P. Berrange s->modifiers = 0; 945ef74679aSDinesh Subhraveti } 946ef74679aSDinesh Subhraveti 947ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 948ef74679aSDinesh Subhraveti { 949ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 950ef74679aSDinesh Subhraveti 9515edab03dSDon Koch trace_ps2_mouse_reset(opaque); 952ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 953ef74679aSDinesh Subhraveti s->mouse_status = 0; 954ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 955ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 956ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 957ef74679aSDinesh Subhraveti s->mouse_type = 0; 958ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 959ef74679aSDinesh Subhraveti s->mouse_dx = 0; 960ef74679aSDinesh Subhraveti s->mouse_dy = 0; 961ef74679aSDinesh Subhraveti s->mouse_dz = 0; 962ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 963ef74679aSDinesh Subhraveti } 964ef74679aSDinesh Subhraveti 965b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 966b31442c3SJuan Quintela .name = "PS2 Common State", 967b31442c3SJuan Quintela .version_id = 3, 968b31442c3SJuan Quintela .minimum_version_id = 2, 969b31442c3SJuan Quintela .fields = (VMStateField[]) { 970b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 971b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 972b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 973b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 974b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 975b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 9767783e9f0Spbrook } 977b31442c3SJuan Quintela }; 9787783e9f0Spbrook 9797f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 9807f540ab5SChristophe Fergeau { 9817f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 9827f540ab5SChristophe Fergeau 9837f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 9847f540ab5SChristophe Fergeau } 9857f540ab5SChristophe Fergeau 9867f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 9877f540ab5SChristophe Fergeau { 9887f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 9897f540ab5SChristophe Fergeau 9907f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 9917f540ab5SChristophe Fergeau return 0; 9927f540ab5SChristophe Fergeau } 9937f540ab5SChristophe Fergeau 9947f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 9957f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 9967f540ab5SChristophe Fergeau .version_id = 3, 9977f540ab5SChristophe Fergeau .minimum_version_id = 2, 9987f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 9995cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 10007f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 10017f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 10027f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 10037f540ab5SChristophe Fergeau } 10047f540ab5SChristophe Fergeau }; 10057f540ab5SChristophe Fergeau 100657d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 100757d5c005SHervé Poussineau { 100857d5c005SHervé Poussineau PS2KbdState *s = opaque; 100957d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 101057d5c005SHervé Poussineau } 101157d5c005SHervé Poussineau 101257d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 101357d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 101457d5c005SHervé Poussineau .version_id = 1, 101557d5c005SHervé Poussineau .minimum_version_id = 1, 101657d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 101757d5c005SHervé Poussineau .fields = (VMStateField[]) { 101857d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 101957d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 102057d5c005SHervé Poussineau } 102157d5c005SHervé Poussineau }; 102257d5c005SHervé Poussineau 1023db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 10240e43e99cSbellard { 10250e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 10262858ab09SGonglei PS2State *ps2 = &s->common; 10270e43e99cSbellard 1028db596c53SJuan Quintela if (version_id == 2) 1029e7d93956Saurel32 s->scancode_set=2; 10302858ab09SGonglei 10312858ab09SGonglei ps2_common_post_load(ps2); 10322858ab09SGonglei 10330e43e99cSbellard return 0; 10340e43e99cSbellard } 10350e43e99cSbellard 103644b1ff31SDr. David Alan Gilbert static int ps2_kbd_pre_save(void *opaque) 10372858ab09SGonglei { 10382858ab09SGonglei PS2KbdState *s = (PS2KbdState *)opaque; 10392858ab09SGonglei PS2State *ps2 = &s->common; 10402858ab09SGonglei 10412858ab09SGonglei ps2_common_post_load(ps2); 104244b1ff31SDr. David Alan Gilbert 104344b1ff31SDr. David Alan Gilbert return 0; 10442858ab09SGonglei } 10452858ab09SGonglei 1046b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 1047b31442c3SJuan Quintela .name = "ps2kbd", 1048b31442c3SJuan Quintela .version_id = 3, 1049db596c53SJuan Quintela .minimum_version_id = 2, 1050db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 10512858ab09SGonglei .pre_save = ps2_kbd_pre_save, 1052b31442c3SJuan Quintela .fields = (VMStateField[]) { 1053b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 1054b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 1055b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 1056b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 1057b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 10587f540ab5SChristophe Fergeau }, 10595cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 10605cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 106157d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 10625cd8cadaSJuan Quintela NULL 10630e43e99cSbellard } 1064b31442c3SJuan Quintela }; 1065b31442c3SJuan Quintela 10662858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 10672858ab09SGonglei { 10682858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 10692858ab09SGonglei PS2State *ps2 = &s->common; 10702858ab09SGonglei 10712858ab09SGonglei ps2_common_post_load(ps2); 10722858ab09SGonglei 10732858ab09SGonglei return 0; 10742858ab09SGonglei } 10752858ab09SGonglei 107644b1ff31SDr. David Alan Gilbert static int ps2_mouse_pre_save(void *opaque) 10772858ab09SGonglei { 10782858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 10792858ab09SGonglei PS2State *ps2 = &s->common; 10802858ab09SGonglei 10812858ab09SGonglei ps2_common_post_load(ps2); 108244b1ff31SDr. David Alan Gilbert 108344b1ff31SDr. David Alan Gilbert return 0; 10842858ab09SGonglei } 10852858ab09SGonglei 1086b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1087b31442c3SJuan Quintela .name = "ps2mouse", 1088b31442c3SJuan Quintela .version_id = 2, 1089b31442c3SJuan Quintela .minimum_version_id = 2, 10902858ab09SGonglei .post_load = ps2_mouse_post_load, 10912858ab09SGonglei .pre_save = ps2_mouse_pre_save, 1092b31442c3SJuan Quintela .fields = (VMStateField[]) { 1093b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 1094b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1095b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1096b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1097b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1098b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1099b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1100b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1101b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1102b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1103b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1104b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1105b31442c3SJuan Quintela } 1106b31442c3SJuan Quintela }; 11070e43e99cSbellard 110866e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 110966e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 111066e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 111166e6536eSGerd Hoffmann .event = ps2_keyboard_event, 111266e6536eSGerd Hoffmann }; 111366e6536eSGerd Hoffmann 11140e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 11150e43e99cSbellard { 11167267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 11170e43e99cSbellard 11185edab03dSDon Koch trace_ps2_kbd_init(s); 11190e43e99cSbellard s->common.update_irq = update_irq; 11200e43e99cSbellard s->common.update_arg = update_arg; 1121e7d93956Saurel32 s->scancode_set = 2; 11220be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 112366e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 112466e6536eSGerd Hoffmann &ps2_keyboard_handler); 1125ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 11260e43e99cSbellard return s; 11270e43e99cSbellard } 11280e43e99cSbellard 11292a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 11302a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 11312a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 11322a766d29SGerd Hoffmann .event = ps2_mouse_event, 11332a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 11342a766d29SGerd Hoffmann }; 11352a766d29SGerd Hoffmann 11360e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 11370e43e99cSbellard { 11387267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 11390e43e99cSbellard 11405edab03dSDon Koch trace_ps2_mouse_init(s); 11410e43e99cSbellard s->common.update_irq = update_irq; 11420e43e99cSbellard s->common.update_arg = update_arg; 11430be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 11442a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 11452a766d29SGerd Hoffmann &ps2_mouse_handler); 1146ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 11470e43e99cSbellard return s; 11480e43e99cSbellard } 1149