149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * QEMU PS/2 keyboard/mouse emulation 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2003 Fabrice Bellard 549ab747fSPaolo Bonzini * 649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights 949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions: 1249ab747fSPaolo Bonzini * 1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software. 1549ab747fSPaolo Bonzini * 1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2249ab747fSPaolo Bonzini * THE SOFTWARE. 2349ab747fSPaolo Bonzini */ 240430891cSPeter Maydell #include "qemu/osdep.h" 25ec044a80SHervé Poussineau #include "qemu/log.h" 2649ab747fSPaolo Bonzini #include "hw/hw.h" 2749ab747fSPaolo Bonzini #include "hw/input/ps2.h" 2849ab747fSPaolo Bonzini #include "ui/console.h" 2966e6536eSGerd Hoffmann #include "ui/input.h" 3049ab747fSPaolo Bonzini #include "sysemu/sysemu.h" 3149ab747fSPaolo Bonzini 325edab03dSDon Koch #include "trace.h" 335edab03dSDon Koch 3449ab747fSPaolo Bonzini /* debug PC keyboard */ 3549ab747fSPaolo Bonzini //#define DEBUG_KBD 3649ab747fSPaolo Bonzini 3749ab747fSPaolo Bonzini /* debug PC keyboard : only mouse */ 3849ab747fSPaolo Bonzini //#define DEBUG_MOUSE 3949ab747fSPaolo Bonzini 4049ab747fSPaolo Bonzini /* Keyboard Commands */ 4149ab747fSPaolo Bonzini #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ 4249ab747fSPaolo Bonzini #define KBD_CMD_ECHO 0xEE 4349ab747fSPaolo Bonzini #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ 4449ab747fSPaolo Bonzini #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ 4549ab747fSPaolo Bonzini #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ 4649ab747fSPaolo Bonzini #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ 4749ab747fSPaolo Bonzini #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ 4849ab747fSPaolo Bonzini #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ 4949ab747fSPaolo Bonzini #define KBD_CMD_RESET 0xFF /* Reset */ 5049ab747fSPaolo Bonzini 5149ab747fSPaolo Bonzini /* Keyboard Replies */ 5249ab747fSPaolo Bonzini #define KBD_REPLY_POR 0xAA /* Power on reset */ 5349ab747fSPaolo Bonzini #define KBD_REPLY_ID 0xAB /* Keyboard ID */ 5449ab747fSPaolo Bonzini #define KBD_REPLY_ACK 0xFA /* Command ACK */ 5549ab747fSPaolo Bonzini #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ 5649ab747fSPaolo Bonzini 5749ab747fSPaolo Bonzini /* Mouse Commands */ 5849ab747fSPaolo Bonzini #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ 5949ab747fSPaolo Bonzini #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ 6049ab747fSPaolo Bonzini #define AUX_SET_RES 0xE8 /* Set resolution */ 6149ab747fSPaolo Bonzini #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ 6249ab747fSPaolo Bonzini #define AUX_SET_STREAM 0xEA /* Set stream mode */ 6349ab747fSPaolo Bonzini #define AUX_POLL 0xEB /* Poll */ 6449ab747fSPaolo Bonzini #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ 6549ab747fSPaolo Bonzini #define AUX_SET_WRAP 0xEE /* Set wrap mode */ 6649ab747fSPaolo Bonzini #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ 6749ab747fSPaolo Bonzini #define AUX_GET_TYPE 0xF2 /* Get type */ 6849ab747fSPaolo Bonzini #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ 6949ab747fSPaolo Bonzini #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ 7049ab747fSPaolo Bonzini #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ 7149ab747fSPaolo Bonzini #define AUX_SET_DEFAULT 0xF6 7249ab747fSPaolo Bonzini #define AUX_RESET 0xFF /* Reset aux device */ 7349ab747fSPaolo Bonzini #define AUX_ACK 0xFA /* Command byte ACK. */ 7449ab747fSPaolo Bonzini 7549ab747fSPaolo Bonzini #define MOUSE_STATUS_REMOTE 0x40 7649ab747fSPaolo Bonzini #define MOUSE_STATUS_ENABLED 0x20 7749ab747fSPaolo Bonzini #define MOUSE_STATUS_SCALE21 0x10 7849ab747fSPaolo Bonzini 792858ab09SGonglei #define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ 8049ab747fSPaolo Bonzini 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 8949ab747fSPaolo Bonzini typedef struct { 902858ab09SGonglei /* Keep the data array 256 bytes long, which compatibility 912858ab09SGonglei with older qemu versions. */ 922858ab09SGonglei uint8_t data[256]; 9349ab747fSPaolo Bonzini int rptr, wptr, count; 9449ab747fSPaolo Bonzini } PS2Queue; 9549ab747fSPaolo Bonzini 968498bb8dSGerd Hoffmann struct PS2State { 9749ab747fSPaolo Bonzini PS2Queue queue; 9849ab747fSPaolo Bonzini int32_t write_cmd; 9949ab747fSPaolo Bonzini void (*update_irq)(void *, int); 10049ab747fSPaolo Bonzini void *update_arg; 1018498bb8dSGerd Hoffmann }; 10249ab747fSPaolo Bonzini 10349ab747fSPaolo Bonzini typedef struct { 10449ab747fSPaolo Bonzini PS2State common; 10549ab747fSPaolo Bonzini int scan_enabled; 10649ab747fSPaolo Bonzini int translate; 10749ab747fSPaolo Bonzini int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ 10849ab747fSPaolo Bonzini int ledstate; 10957d5c005SHervé Poussineau bool need_high_bit; 110620775d1SDaniel P. Berrange unsigned int modifiers; /* bitmask of MOD_* constants above */ 11149ab747fSPaolo Bonzini } PS2KbdState; 11249ab747fSPaolo Bonzini 11349ab747fSPaolo Bonzini typedef struct { 11449ab747fSPaolo Bonzini PS2State common; 11549ab747fSPaolo Bonzini uint8_t mouse_status; 11649ab747fSPaolo Bonzini uint8_t mouse_resolution; 11749ab747fSPaolo Bonzini uint8_t mouse_sample_rate; 11849ab747fSPaolo Bonzini uint8_t mouse_wrap; 11949ab747fSPaolo Bonzini uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ 12049ab747fSPaolo Bonzini uint8_t mouse_detect_state; 12149ab747fSPaolo Bonzini int mouse_dx; /* current values, needed for 'poll' mode */ 12249ab747fSPaolo Bonzini int mouse_dy; 12349ab747fSPaolo Bonzini int mouse_dz; 12449ab747fSPaolo Bonzini uint8_t mouse_buttons; 12549ab747fSPaolo Bonzini } PS2MouseState; 12649ab747fSPaolo Bonzini 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 191*7abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 19249ab747fSPaolo Bonzini { 19349ab747fSPaolo Bonzini PS2Queue *q = &s->queue; 19449ab747fSPaolo Bonzini 195*7abe7eb2SGeoffrey McRae if (q->count == PS2_QUEUE_SIZE) { 19649ab747fSPaolo Bonzini return; 197*7abe7eb2SGeoffrey McRae } 198*7abe7eb2SGeoffrey McRae 19949ab747fSPaolo Bonzini q->data[q->wptr] = b; 20049ab747fSPaolo Bonzini if (++q->wptr == PS2_QUEUE_SIZE) 20149ab747fSPaolo Bonzini q->wptr = 0; 20249ab747fSPaolo Bonzini q->count++; 203*7abe7eb2SGeoffrey McRae } 204*7abe7eb2SGeoffrey McRae 205*7abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s) 206*7abe7eb2SGeoffrey McRae { 207*7abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 208*7abe7eb2SGeoffrey McRae } 209*7abe7eb2SGeoffrey McRae 210*7abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 211*7abe7eb2SGeoffrey McRae { 212*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 213*7abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 214*7abe7eb2SGeoffrey McRae } 215*7abe7eb2SGeoffrey McRae 216*7abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 217*7abe7eb2SGeoffrey McRae { 218*7abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 219*7abe7eb2SGeoffrey McRae return; 220*7abe7eb2SGeoffrey McRae } 221*7abe7eb2SGeoffrey McRae 222*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 223*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 224*7abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 225*7abe7eb2SGeoffrey McRae } 226*7abe7eb2SGeoffrey McRae 227*7abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 228*7abe7eb2SGeoffrey McRae { 229*7abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 230*7abe7eb2SGeoffrey McRae return; 231*7abe7eb2SGeoffrey McRae } 232*7abe7eb2SGeoffrey McRae 233*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 234*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 235*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 236*7abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 237*7abe7eb2SGeoffrey McRae } 238*7abe7eb2SGeoffrey McRae 239*7abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 240*7abe7eb2SGeoffrey McRae { 241*7abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 242*7abe7eb2SGeoffrey McRae return; 243*7abe7eb2SGeoffrey McRae } 244*7abe7eb2SGeoffrey McRae 245*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 246*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 247*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 248*7abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 24949ab747fSPaolo Bonzini s->update_irq(s->update_arg, 1); 25049ab747fSPaolo Bonzini } 25149ab747fSPaolo Bonzini 25257d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 25349ab747fSPaolo Bonzini static void ps2_put_keycode(void *opaque, int keycode) 25449ab747fSPaolo Bonzini { 25549ab747fSPaolo Bonzini PS2KbdState *s = opaque; 25649ab747fSPaolo Bonzini 2575edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 25849ab747fSPaolo Bonzini 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]); 26849ab747fSPaolo Bonzini } 26957d5c005SHervé Poussineau } else { 27049ab747fSPaolo Bonzini ps2_queue(&s->common, keycode); 27149ab747fSPaolo Bonzini } 27257d5c005SHervé Poussineau } 27349ab747fSPaolo Bonzini 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) 49349ab747fSPaolo Bonzini { 49449ab747fSPaolo Bonzini PS2Queue *q; 49549ab747fSPaolo Bonzini int val, index; 49649ab747fSPaolo Bonzini 4978498bb8dSGerd Hoffmann trace_ps2_read_data(s); 49849ab747fSPaolo Bonzini q = &s->queue; 49949ab747fSPaolo Bonzini if (q->count == 0) { 50049ab747fSPaolo Bonzini /* NOTE: if no data left, we return the last keyboard one 50149ab747fSPaolo Bonzini (needed for EMM386) */ 50249ab747fSPaolo Bonzini /* XXX: need a timer to do things correctly */ 50349ab747fSPaolo Bonzini index = q->rptr - 1; 50449ab747fSPaolo Bonzini if (index < 0) 50549ab747fSPaolo Bonzini index = PS2_QUEUE_SIZE - 1; 50649ab747fSPaolo Bonzini val = q->data[index]; 50749ab747fSPaolo Bonzini } else { 50849ab747fSPaolo Bonzini val = q->data[q->rptr]; 50949ab747fSPaolo Bonzini if (++q->rptr == PS2_QUEUE_SIZE) 51049ab747fSPaolo Bonzini q->rptr = 0; 51149ab747fSPaolo Bonzini q->count--; 51249ab747fSPaolo Bonzini /* reading deasserts IRQ */ 51349ab747fSPaolo Bonzini s->update_irq(s->update_arg, 0); 51449ab747fSPaolo Bonzini /* reassert IRQs if data left */ 51549ab747fSPaolo Bonzini s->update_irq(s->update_arg, q->count != 0); 51649ab747fSPaolo Bonzini } 51749ab747fSPaolo Bonzini return val; 51849ab747fSPaolo Bonzini } 51949ab747fSPaolo Bonzini 52049ab747fSPaolo Bonzini static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 52149ab747fSPaolo Bonzini { 5225edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 52349ab747fSPaolo Bonzini s->ledstate = ledstate; 52449ab747fSPaolo Bonzini kbd_put_ledstate(ledstate); 52549ab747fSPaolo Bonzini } 52649ab747fSPaolo Bonzini 52749ab747fSPaolo Bonzini static void ps2_reset_keyboard(PS2KbdState *s) 52849ab747fSPaolo Bonzini { 5295edab03dSDon Koch trace_ps2_reset_keyboard(s); 53049ab747fSPaolo Bonzini s->scan_enabled = 1; 53149ab747fSPaolo Bonzini s->scancode_set = 2; 5326e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 53349ab747fSPaolo Bonzini ps2_set_ledstate(s, 0); 53449ab747fSPaolo Bonzini } 53549ab747fSPaolo Bonzini 53649ab747fSPaolo Bonzini void ps2_write_keyboard(void *opaque, int val) 53749ab747fSPaolo Bonzini { 53849ab747fSPaolo Bonzini PS2KbdState *s = (PS2KbdState *)opaque; 53949ab747fSPaolo Bonzini 5405edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 54149ab747fSPaolo Bonzini switch(s->common.write_cmd) { 54249ab747fSPaolo Bonzini default: 54349ab747fSPaolo Bonzini case -1: 54449ab747fSPaolo Bonzini switch(val) { 54549ab747fSPaolo Bonzini case 0x00: 54649ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 54749ab747fSPaolo Bonzini break; 54849ab747fSPaolo Bonzini case 0x05: 54949ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_RESEND); 55049ab747fSPaolo Bonzini break; 55149ab747fSPaolo Bonzini case KBD_CMD_GET_ID: 55249ab747fSPaolo Bonzini /* We emulate a MF2 AT keyboard here */ 55349ab747fSPaolo Bonzini if (s->translate) 554*7abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 555*7abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 556*7abe7eb2SGeoffrey McRae KBD_REPLY_ID, 557*7abe7eb2SGeoffrey McRae 0x41); 55849ab747fSPaolo Bonzini else 559*7abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 560*7abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 561*7abe7eb2SGeoffrey McRae KBD_REPLY_ID, 562*7abe7eb2SGeoffrey McRae 0x83); 56349ab747fSPaolo Bonzini break; 56449ab747fSPaolo Bonzini case KBD_CMD_ECHO: 56549ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_CMD_ECHO); 56649ab747fSPaolo Bonzini break; 56749ab747fSPaolo Bonzini case KBD_CMD_ENABLE: 56849ab747fSPaolo Bonzini s->scan_enabled = 1; 56949ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 57049ab747fSPaolo Bonzini break; 57149ab747fSPaolo Bonzini case KBD_CMD_SCANCODE: 57249ab747fSPaolo Bonzini case KBD_CMD_SET_LEDS: 57349ab747fSPaolo Bonzini case KBD_CMD_SET_RATE: 57449ab747fSPaolo Bonzini s->common.write_cmd = val; 57549ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 57649ab747fSPaolo Bonzini break; 57749ab747fSPaolo Bonzini case KBD_CMD_RESET_DISABLE: 57849ab747fSPaolo Bonzini ps2_reset_keyboard(s); 57949ab747fSPaolo Bonzini s->scan_enabled = 0; 58049ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 58149ab747fSPaolo Bonzini break; 58249ab747fSPaolo Bonzini case KBD_CMD_RESET_ENABLE: 58349ab747fSPaolo Bonzini ps2_reset_keyboard(s); 58449ab747fSPaolo Bonzini s->scan_enabled = 1; 58549ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 58649ab747fSPaolo Bonzini break; 58749ab747fSPaolo Bonzini case KBD_CMD_RESET: 58849ab747fSPaolo Bonzini ps2_reset_keyboard(s); 589*7abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 590*7abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 591*7abe7eb2SGeoffrey McRae KBD_REPLY_POR); 59249ab747fSPaolo Bonzini break; 59349ab747fSPaolo Bonzini default: 59406b3611fSHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 59549ab747fSPaolo Bonzini break; 59649ab747fSPaolo Bonzini } 59749ab747fSPaolo Bonzini break; 59849ab747fSPaolo Bonzini case KBD_CMD_SCANCODE: 59949ab747fSPaolo Bonzini if (val == 0) { 600*7abe7eb2SGeoffrey 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); 603*7abe7eb2SGeoffrey McRae } 6044df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 60549ab747fSPaolo Bonzini s->scancode_set = val; 60649ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 6074df23b64SHervé Poussineau } else { 6084df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 60949ab747fSPaolo Bonzini } 61049ab747fSPaolo Bonzini s->common.write_cmd = -1; 61149ab747fSPaolo Bonzini break; 61249ab747fSPaolo Bonzini case KBD_CMD_SET_LEDS: 61349ab747fSPaolo Bonzini ps2_set_ledstate(s, val); 61449ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 61549ab747fSPaolo Bonzini s->common.write_cmd = -1; 61649ab747fSPaolo Bonzini break; 61749ab747fSPaolo Bonzini case KBD_CMD_SET_RATE: 61849ab747fSPaolo Bonzini ps2_queue(&s->common, KBD_REPLY_ACK); 61949ab747fSPaolo Bonzini s->common.write_cmd = -1; 62049ab747fSPaolo Bonzini break; 62149ab747fSPaolo Bonzini } 62249ab747fSPaolo Bonzini } 62349ab747fSPaolo Bonzini 62449ab747fSPaolo Bonzini /* Set the scancode translation mode. 62549ab747fSPaolo Bonzini 0 = raw scancodes. 62649ab747fSPaolo Bonzini 1 = translated scancodes (used by qemu internally). */ 62749ab747fSPaolo Bonzini 62849ab747fSPaolo Bonzini void ps2_keyboard_set_translation(void *opaque, int mode) 62949ab747fSPaolo Bonzini { 63049ab747fSPaolo Bonzini PS2KbdState *s = (PS2KbdState *)opaque; 6315edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 63249ab747fSPaolo Bonzini s->translate = mode; 63349ab747fSPaolo Bonzini } 63449ab747fSPaolo Bonzini 635*7abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 63649ab747fSPaolo Bonzini { 637*7abe7eb2SGeoffrey McRae const int needed = 3 + (s->mouse_type - 2); 63849ab747fSPaolo Bonzini unsigned int b; 63949ab747fSPaolo Bonzini int dx1, dy1, dz1; 64049ab747fSPaolo Bonzini 641*7abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { 642*7abe7eb2SGeoffrey McRae return 0; 643*7abe7eb2SGeoffrey McRae } 644*7abe7eb2SGeoffrey McRae 64549ab747fSPaolo Bonzini dx1 = s->mouse_dx; 64649ab747fSPaolo Bonzini dy1 = s->mouse_dy; 64749ab747fSPaolo Bonzini dz1 = s->mouse_dz; 64849ab747fSPaolo Bonzini /* XXX: increase range to 8 bits ? */ 64949ab747fSPaolo Bonzini if (dx1 > 127) 65049ab747fSPaolo Bonzini dx1 = 127; 65149ab747fSPaolo Bonzini else if (dx1 < -127) 65249ab747fSPaolo Bonzini dx1 = -127; 65349ab747fSPaolo Bonzini if (dy1 > 127) 65449ab747fSPaolo Bonzini dy1 = 127; 65549ab747fSPaolo Bonzini else if (dy1 < -127) 65649ab747fSPaolo Bonzini dy1 = -127; 65749ab747fSPaolo Bonzini b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 658*7abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 659*7abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dx1 & 0xff); 660*7abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dy1 & 0xff); 66149ab747fSPaolo Bonzini /* extra byte for IMPS/2 or IMEX */ 66249ab747fSPaolo Bonzini switch(s->mouse_type) { 66349ab747fSPaolo Bonzini default: 66449ab747fSPaolo Bonzini break; 66549ab747fSPaolo Bonzini case 3: 66649ab747fSPaolo Bonzini if (dz1 > 127) 66749ab747fSPaolo Bonzini dz1 = 127; 66849ab747fSPaolo Bonzini else if (dz1 < -127) 66949ab747fSPaolo Bonzini dz1 = -127; 670*7abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dz1 & 0xff); 67149ab747fSPaolo Bonzini break; 67249ab747fSPaolo Bonzini case 4: 67349ab747fSPaolo Bonzini if (dz1 > 7) 67449ab747fSPaolo Bonzini dz1 = 7; 67549ab747fSPaolo Bonzini else if (dz1 < -7) 67649ab747fSPaolo Bonzini dz1 = -7; 67749ab747fSPaolo Bonzini b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 678*7abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 67949ab747fSPaolo Bonzini break; 68049ab747fSPaolo Bonzini } 68149ab747fSPaolo Bonzini 682*7abe7eb2SGeoffrey McRae ps2_raise_irq(&s->common); 683*7abe7eb2SGeoffrey McRae 6845edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 68549ab747fSPaolo Bonzini /* update deltas */ 68649ab747fSPaolo Bonzini s->mouse_dx -= dx1; 68749ab747fSPaolo Bonzini s->mouse_dy -= dy1; 68849ab747fSPaolo Bonzini s->mouse_dz -= dz1; 689*7abe7eb2SGeoffrey McRae 690*7abe7eb2SGeoffrey McRae return 1; 69149ab747fSPaolo Bonzini } 69249ab747fSPaolo Bonzini 6932a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 6942a766d29SGerd Hoffmann InputEvent *evt) 69549ab747fSPaolo Bonzini { 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; 70649ab747fSPaolo Bonzini 70749ab747fSPaolo Bonzini /* check if deltas are recorded when disabled */ 70849ab747fSPaolo Bonzini if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 70949ab747fSPaolo Bonzini return; 71049ab747fSPaolo Bonzini 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; 72049ab747fSPaolo Bonzini 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 } 73949ab747fSPaolo Bonzini } 74049ab747fSPaolo Bonzini 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)) { 75449ab747fSPaolo Bonzini /* if not remote, send event. Multiple events are sent if 75549ab747fSPaolo Bonzini too big deltas */ 756*7abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 75749ab747fSPaolo Bonzini if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 75849ab747fSPaolo Bonzini break; 75949ab747fSPaolo Bonzini } 76049ab747fSPaolo Bonzini } 76149ab747fSPaolo Bonzini } 76249ab747fSPaolo Bonzini 76349ab747fSPaolo Bonzini void ps2_mouse_fake_event(void *opaque) 76449ab747fSPaolo Bonzini { 7652a766d29SGerd Hoffmann PS2MouseState *s = opaque; 7665edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 7672a766d29SGerd Hoffmann s->mouse_dx++; 7682a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 76949ab747fSPaolo Bonzini } 77049ab747fSPaolo Bonzini 77149ab747fSPaolo Bonzini void ps2_write_mouse(void *opaque, int val) 77249ab747fSPaolo Bonzini { 77349ab747fSPaolo Bonzini PS2MouseState *s = (PS2MouseState *)opaque; 7745edab03dSDon Koch 7755edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 77649ab747fSPaolo Bonzini #ifdef DEBUG_MOUSE 77749ab747fSPaolo Bonzini printf("kbd: write mouse 0x%02x\n", val); 77849ab747fSPaolo Bonzini #endif 77949ab747fSPaolo Bonzini switch(s->common.write_cmd) { 78049ab747fSPaolo Bonzini default: 78149ab747fSPaolo Bonzini case -1: 78249ab747fSPaolo Bonzini /* mouse command */ 78349ab747fSPaolo Bonzini if (s->mouse_wrap) { 78449ab747fSPaolo Bonzini if (val == AUX_RESET_WRAP) { 78549ab747fSPaolo Bonzini s->mouse_wrap = 0; 78649ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 78749ab747fSPaolo Bonzini return; 78849ab747fSPaolo Bonzini } else if (val != AUX_RESET) { 78949ab747fSPaolo Bonzini ps2_queue(&s->common, val); 79049ab747fSPaolo Bonzini return; 79149ab747fSPaolo Bonzini } 79249ab747fSPaolo Bonzini } 79349ab747fSPaolo Bonzini switch(val) { 79449ab747fSPaolo Bonzini case AUX_SET_SCALE11: 79549ab747fSPaolo Bonzini s->mouse_status &= ~MOUSE_STATUS_SCALE21; 79649ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 79749ab747fSPaolo Bonzini break; 79849ab747fSPaolo Bonzini case AUX_SET_SCALE21: 79949ab747fSPaolo Bonzini s->mouse_status |= MOUSE_STATUS_SCALE21; 80049ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 80149ab747fSPaolo Bonzini break; 80249ab747fSPaolo Bonzini case AUX_SET_STREAM: 80349ab747fSPaolo Bonzini s->mouse_status &= ~MOUSE_STATUS_REMOTE; 80449ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 80549ab747fSPaolo Bonzini break; 80649ab747fSPaolo Bonzini case AUX_SET_WRAP: 80749ab747fSPaolo Bonzini s->mouse_wrap = 1; 80849ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 80949ab747fSPaolo Bonzini break; 81049ab747fSPaolo Bonzini case AUX_SET_REMOTE: 81149ab747fSPaolo Bonzini s->mouse_status |= MOUSE_STATUS_REMOTE; 81249ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 81349ab747fSPaolo Bonzini break; 81449ab747fSPaolo Bonzini case AUX_GET_TYPE: 815*7abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 816*7abe7eb2SGeoffrey McRae AUX_ACK, 817*7abe7eb2SGeoffrey McRae s->mouse_type); 81849ab747fSPaolo Bonzini break; 81949ab747fSPaolo Bonzini case AUX_SET_RES: 82049ab747fSPaolo Bonzini case AUX_SET_SAMPLE: 82149ab747fSPaolo Bonzini s->common.write_cmd = val; 82249ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 82349ab747fSPaolo Bonzini break; 82449ab747fSPaolo Bonzini case AUX_GET_SCALE: 825*7abe7eb2SGeoffrey McRae ps2_queue_4(&s->common, 826*7abe7eb2SGeoffrey McRae AUX_ACK, 827*7abe7eb2SGeoffrey McRae s->mouse_status, 828*7abe7eb2SGeoffrey McRae s->mouse_resolution, 829*7abe7eb2SGeoffrey McRae s->mouse_sample_rate); 83049ab747fSPaolo Bonzini break; 83149ab747fSPaolo Bonzini case AUX_POLL: 83249ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 83349ab747fSPaolo Bonzini ps2_mouse_send_packet(s); 83449ab747fSPaolo Bonzini break; 83549ab747fSPaolo Bonzini case AUX_ENABLE_DEV: 83649ab747fSPaolo Bonzini s->mouse_status |= MOUSE_STATUS_ENABLED; 83749ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 83849ab747fSPaolo Bonzini break; 83949ab747fSPaolo Bonzini case AUX_DISABLE_DEV: 84049ab747fSPaolo Bonzini s->mouse_status &= ~MOUSE_STATUS_ENABLED; 84149ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 84249ab747fSPaolo Bonzini break; 84349ab747fSPaolo Bonzini case AUX_SET_DEFAULT: 84449ab747fSPaolo Bonzini s->mouse_sample_rate = 100; 84549ab747fSPaolo Bonzini s->mouse_resolution = 2; 84649ab747fSPaolo Bonzini s->mouse_status = 0; 84749ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 84849ab747fSPaolo Bonzini break; 84949ab747fSPaolo Bonzini case AUX_RESET: 85049ab747fSPaolo Bonzini s->mouse_sample_rate = 100; 85149ab747fSPaolo Bonzini s->mouse_resolution = 2; 85249ab747fSPaolo Bonzini s->mouse_status = 0; 85349ab747fSPaolo Bonzini s->mouse_type = 0; 854143c04c7SGeoffrey McRae ps2_reset_queue(&s->common); 855*7abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 856*7abe7eb2SGeoffrey McRae AUX_ACK, 857*7abe7eb2SGeoffrey McRae 0xaa, 858*7abe7eb2SGeoffrey McRae s->mouse_type); 85949ab747fSPaolo Bonzini break; 86049ab747fSPaolo Bonzini default: 86149ab747fSPaolo Bonzini break; 86249ab747fSPaolo Bonzini } 86349ab747fSPaolo Bonzini break; 86449ab747fSPaolo Bonzini case AUX_SET_SAMPLE: 86549ab747fSPaolo Bonzini s->mouse_sample_rate = val; 86649ab747fSPaolo Bonzini /* detect IMPS/2 or IMEX */ 86749ab747fSPaolo Bonzini switch(s->mouse_detect_state) { 86849ab747fSPaolo Bonzini default: 86949ab747fSPaolo Bonzini case 0: 87049ab747fSPaolo Bonzini if (val == 200) 87149ab747fSPaolo Bonzini s->mouse_detect_state = 1; 87249ab747fSPaolo Bonzini break; 87349ab747fSPaolo Bonzini case 1: 87449ab747fSPaolo Bonzini if (val == 100) 87549ab747fSPaolo Bonzini s->mouse_detect_state = 2; 87649ab747fSPaolo Bonzini else if (val == 200) 87749ab747fSPaolo Bonzini s->mouse_detect_state = 3; 87849ab747fSPaolo Bonzini else 87949ab747fSPaolo Bonzini s->mouse_detect_state = 0; 88049ab747fSPaolo Bonzini break; 88149ab747fSPaolo Bonzini case 2: 88249ab747fSPaolo Bonzini if (val == 80) 88349ab747fSPaolo Bonzini s->mouse_type = 3; /* IMPS/2 */ 88449ab747fSPaolo Bonzini s->mouse_detect_state = 0; 88549ab747fSPaolo Bonzini break; 88649ab747fSPaolo Bonzini case 3: 88749ab747fSPaolo Bonzini if (val == 80) 88849ab747fSPaolo Bonzini s->mouse_type = 4; /* IMEX */ 88949ab747fSPaolo Bonzini s->mouse_detect_state = 0; 89049ab747fSPaolo Bonzini break; 89149ab747fSPaolo Bonzini } 89249ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 89349ab747fSPaolo Bonzini s->common.write_cmd = -1; 89449ab747fSPaolo Bonzini break; 89549ab747fSPaolo Bonzini case AUX_SET_RES: 89649ab747fSPaolo Bonzini s->mouse_resolution = val; 89749ab747fSPaolo Bonzini ps2_queue(&s->common, AUX_ACK); 89849ab747fSPaolo Bonzini s->common.write_cmd = -1; 89949ab747fSPaolo Bonzini break; 90049ab747fSPaolo Bonzini } 90149ab747fSPaolo Bonzini } 90249ab747fSPaolo Bonzini 90349ab747fSPaolo Bonzini static void ps2_common_reset(PS2State *s) 90449ab747fSPaolo Bonzini { 90549ab747fSPaolo Bonzini s->write_cmd = -1; 906954ee55bSGerd Hoffmann ps2_reset_queue(s); 90749ab747fSPaolo Bonzini s->update_irq(s->update_arg, 0); 90849ab747fSPaolo Bonzini } 90949ab747fSPaolo Bonzini 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; 9302858ab09SGonglei q->wptr = size; 9312858ab09SGonglei q->count = size; 9322858ab09SGonglei s->update_irq(s->update_arg, q->count != 0); 9332858ab09SGonglei } 9342858ab09SGonglei 93549ab747fSPaolo Bonzini static void ps2_kbd_reset(void *opaque) 93649ab747fSPaolo Bonzini { 93749ab747fSPaolo Bonzini PS2KbdState *s = (PS2KbdState *) opaque; 93849ab747fSPaolo Bonzini 9395edab03dSDon Koch trace_ps2_kbd_reset(opaque); 94049ab747fSPaolo Bonzini ps2_common_reset(&s->common); 94149ab747fSPaolo Bonzini s->scan_enabled = 0; 94249ab747fSPaolo Bonzini s->translate = 0; 943089adafdSHervé Poussineau s->scancode_set = 2; 944620775d1SDaniel P. Berrange s->modifiers = 0; 94549ab747fSPaolo Bonzini } 94649ab747fSPaolo Bonzini 94749ab747fSPaolo Bonzini static void ps2_mouse_reset(void *opaque) 94849ab747fSPaolo Bonzini { 94949ab747fSPaolo Bonzini PS2MouseState *s = (PS2MouseState *) opaque; 95049ab747fSPaolo Bonzini 9515edab03dSDon Koch trace_ps2_mouse_reset(opaque); 95249ab747fSPaolo Bonzini ps2_common_reset(&s->common); 95349ab747fSPaolo Bonzini s->mouse_status = 0; 95449ab747fSPaolo Bonzini s->mouse_resolution = 0; 95549ab747fSPaolo Bonzini s->mouse_sample_rate = 0; 95649ab747fSPaolo Bonzini s->mouse_wrap = 0; 95749ab747fSPaolo Bonzini s->mouse_type = 0; 95849ab747fSPaolo Bonzini s->mouse_detect_state = 0; 95949ab747fSPaolo Bonzini s->mouse_dx = 0; 96049ab747fSPaolo Bonzini s->mouse_dy = 0; 96149ab747fSPaolo Bonzini s->mouse_dz = 0; 96249ab747fSPaolo Bonzini s->mouse_buttons = 0; 96349ab747fSPaolo Bonzini } 96449ab747fSPaolo Bonzini 96549ab747fSPaolo Bonzini static const VMStateDescription vmstate_ps2_common = { 96649ab747fSPaolo Bonzini .name = "PS2 Common State", 96749ab747fSPaolo Bonzini .version_id = 3, 96849ab747fSPaolo Bonzini .minimum_version_id = 2, 96949ab747fSPaolo Bonzini .fields = (VMStateField[]) { 97049ab747fSPaolo Bonzini VMSTATE_INT32(write_cmd, PS2State), 97149ab747fSPaolo Bonzini VMSTATE_INT32(queue.rptr, PS2State), 97249ab747fSPaolo Bonzini VMSTATE_INT32(queue.wptr, PS2State), 97349ab747fSPaolo Bonzini VMSTATE_INT32(queue.count, PS2State), 97449ab747fSPaolo Bonzini VMSTATE_BUFFER(queue.data, PS2State), 97549ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 97649ab747fSPaolo Bonzini } 97749ab747fSPaolo Bonzini }; 97849ab747fSPaolo Bonzini 97949ab747fSPaolo Bonzini static bool ps2_keyboard_ledstate_needed(void *opaque) 98049ab747fSPaolo Bonzini { 98149ab747fSPaolo Bonzini PS2KbdState *s = opaque; 98249ab747fSPaolo Bonzini 98349ab747fSPaolo Bonzini return s->ledstate != 0; /* 0 is default state */ 98449ab747fSPaolo Bonzini } 98549ab747fSPaolo Bonzini 98649ab747fSPaolo Bonzini static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 98749ab747fSPaolo Bonzini { 98849ab747fSPaolo Bonzini PS2KbdState *s = opaque; 98949ab747fSPaolo Bonzini 99049ab747fSPaolo Bonzini kbd_put_ledstate(s->ledstate); 99149ab747fSPaolo Bonzini return 0; 99249ab747fSPaolo Bonzini } 99349ab747fSPaolo Bonzini 99449ab747fSPaolo Bonzini static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 99549ab747fSPaolo Bonzini .name = "ps2kbd/ledstate", 99649ab747fSPaolo Bonzini .version_id = 3, 99749ab747fSPaolo Bonzini .minimum_version_id = 2, 99849ab747fSPaolo Bonzini .post_load = ps2_kbd_ledstate_post_load, 9995cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 100049ab747fSPaolo Bonzini .fields = (VMStateField[]) { 100149ab747fSPaolo Bonzini VMSTATE_INT32(ledstate, PS2KbdState), 100249ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 100349ab747fSPaolo Bonzini } 100449ab747fSPaolo Bonzini }; 100549ab747fSPaolo Bonzini 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 102349ab747fSPaolo Bonzini static int ps2_kbd_post_load(void* opaque, int version_id) 102449ab747fSPaolo Bonzini { 102549ab747fSPaolo Bonzini PS2KbdState *s = (PS2KbdState*)opaque; 10262858ab09SGonglei PS2State *ps2 = &s->common; 102749ab747fSPaolo Bonzini 102849ab747fSPaolo Bonzini if (version_id == 2) 102949ab747fSPaolo Bonzini s->scancode_set=2; 10302858ab09SGonglei 10312858ab09SGonglei ps2_common_post_load(ps2); 10322858ab09SGonglei 103349ab747fSPaolo Bonzini return 0; 103449ab747fSPaolo Bonzini } 103549ab747fSPaolo Bonzini 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 104649ab747fSPaolo Bonzini static const VMStateDescription vmstate_ps2_keyboard = { 104749ab747fSPaolo Bonzini .name = "ps2kbd", 104849ab747fSPaolo Bonzini .version_id = 3, 104949ab747fSPaolo Bonzini .minimum_version_id = 2, 105049ab747fSPaolo Bonzini .post_load = ps2_kbd_post_load, 10512858ab09SGonglei .pre_save = ps2_kbd_pre_save, 105249ab747fSPaolo Bonzini .fields = (VMStateField[]) { 105349ab747fSPaolo Bonzini VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 105449ab747fSPaolo Bonzini VMSTATE_INT32(scan_enabled, PS2KbdState), 105549ab747fSPaolo Bonzini VMSTATE_INT32(translate, PS2KbdState), 105649ab747fSPaolo Bonzini VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 105749ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 105849ab747fSPaolo Bonzini }, 10595cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 10605cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 106157d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 10625cd8cadaSJuan Quintela NULL 106349ab747fSPaolo Bonzini } 106449ab747fSPaolo Bonzini }; 106549ab747fSPaolo Bonzini 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 108649ab747fSPaolo Bonzini static const VMStateDescription vmstate_ps2_mouse = { 108749ab747fSPaolo Bonzini .name = "ps2mouse", 108849ab747fSPaolo Bonzini .version_id = 2, 108949ab747fSPaolo Bonzini .minimum_version_id = 2, 10902858ab09SGonglei .post_load = ps2_mouse_post_load, 10912858ab09SGonglei .pre_save = ps2_mouse_pre_save, 109249ab747fSPaolo Bonzini .fields = (VMStateField[]) { 109349ab747fSPaolo Bonzini VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 109449ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_status, PS2MouseState), 109549ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_resolution, PS2MouseState), 109649ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 109749ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_wrap, PS2MouseState), 109849ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_type, PS2MouseState), 109949ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 110049ab747fSPaolo Bonzini VMSTATE_INT32(mouse_dx, PS2MouseState), 110149ab747fSPaolo Bonzini VMSTATE_INT32(mouse_dy, PS2MouseState), 110249ab747fSPaolo Bonzini VMSTATE_INT32(mouse_dz, PS2MouseState), 110349ab747fSPaolo Bonzini VMSTATE_UINT8(mouse_buttons, PS2MouseState), 110449ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 110549ab747fSPaolo Bonzini } 110649ab747fSPaolo Bonzini }; 110749ab747fSPaolo Bonzini 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 111449ab747fSPaolo Bonzini void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 111549ab747fSPaolo Bonzini { 111649ab747fSPaolo Bonzini PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 111749ab747fSPaolo Bonzini 11185edab03dSDon Koch trace_ps2_kbd_init(s); 111949ab747fSPaolo Bonzini s->common.update_irq = update_irq; 112049ab747fSPaolo Bonzini s->common.update_arg = update_arg; 112149ab747fSPaolo Bonzini s->scancode_set = 2; 112249ab747fSPaolo Bonzini vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 112366e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 112466e6536eSGerd Hoffmann &ps2_keyboard_handler); 112549ab747fSPaolo Bonzini qemu_register_reset(ps2_kbd_reset, s); 112649ab747fSPaolo Bonzini return s; 112749ab747fSPaolo Bonzini } 112849ab747fSPaolo Bonzini 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 113649ab747fSPaolo Bonzini void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 113749ab747fSPaolo Bonzini { 113849ab747fSPaolo Bonzini PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 113949ab747fSPaolo Bonzini 11405edab03dSDon Koch trace_ps2_mouse_init(s); 114149ab747fSPaolo Bonzini s->common.update_irq = update_irq; 114249ab747fSPaolo Bonzini s->common.update_arg = update_arg; 114349ab747fSPaolo Bonzini vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 11442a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 11452a766d29SGerd Hoffmann &ps2_mouse_handler); 114649ab747fSPaolo Bonzini qemu_register_reset(ps2_mouse_reset, s); 114749ab747fSPaolo Bonzini return s; 114849ab747fSPaolo Bonzini } 1149