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 1918498bb8dSGerd Hoffmann void ps2_queue(PS2State *s, int b) 1920e43e99cSbellard { 1930e43e99cSbellard PS2Queue *q = &s->queue; 1940e43e99cSbellard 1952858ab09SGonglei if (q->count >= PS2_QUEUE_SIZE - 1) 1960e43e99cSbellard return; 1970e43e99cSbellard q->data[q->wptr] = b; 1980e43e99cSbellard if (++q->wptr == PS2_QUEUE_SIZE) 1990e43e99cSbellard q->wptr = 0; 2000e43e99cSbellard q->count++; 2010e43e99cSbellard s->update_irq(s->update_arg, 1); 2020e43e99cSbellard } 2030e43e99cSbellard 20457d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 2050e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 2060e43e99cSbellard { 207f94f5d71Spbrook PS2KbdState *s = opaque; 208e7d93956Saurel32 2095edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 210fd214d18SGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 21157d5c005SHervé Poussineau 21257d5c005SHervé Poussineau if (s->translate) { 21357d5c005SHervé Poussineau if (keycode == 0xf0) { 21457d5c005SHervé Poussineau s->need_high_bit = true; 21557d5c005SHervé Poussineau } else if (s->need_high_bit) { 21657d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode] | 0x80); 21757d5c005SHervé Poussineau s->need_high_bit = false; 21857d5c005SHervé Poussineau } else { 21957d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode]); 2207096a96dSRoy Tam } 22157d5c005SHervé Poussineau } else { 2220e43e99cSbellard ps2_queue(&s->common, keycode); 2230e43e99cSbellard } 22457d5c005SHervé Poussineau } 2250e43e99cSbellard 22666e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 22766e6536eSGerd Hoffmann InputEvent *evt) 22866e6536eSGerd Hoffmann { 22966e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 23032bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 2318c10e0baSHervé Poussineau int qcode; 232*ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 233620775d1SDaniel P. Berrange int mod; 23466e6536eSGerd Hoffmann 23566e6536eSGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 2368c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 2378c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 23857d5c005SHervé Poussineau 239620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 240620775d1SDaniel P. Berrange trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers); 241620775d1SDaniel P. Berrange if (key->down) { 242620775d1SDaniel P. Berrange s->modifiers |= mod; 243620775d1SDaniel P. Berrange } else { 244620775d1SDaniel P. Berrange s->modifiers &= ~mod; 245620775d1SDaniel P. Berrange } 246620775d1SDaniel P. Berrange 2478c10e0baSHervé Poussineau if (s->scancode_set == 1) { 2488c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 24929fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 25029fd23a5SDaniel P. Berrange if (key->down) { 25129fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 25229fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 25329fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 25429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 25529fd23a5SDaniel P. Berrange } 25629fd23a5SDaniel P. Berrange } else { 2578c10e0baSHervé Poussineau if (key->down) { 2588c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 2598c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 2608c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 261927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 2628c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 2638c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 2648c10e0baSHervé Poussineau } 26529fd23a5SDaniel P. Berrange } 2668c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 267620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 268620775d1SDaniel P. Berrange if (key->down) { 269620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 270620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 271620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 272620775d1SDaniel P. Berrange } else { 273620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 274620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 275620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 276620775d1SDaniel P. Berrange } 277620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 278620775d1SDaniel P. Berrange if (key->down) { 279620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 280620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 281620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 282620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 283620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 284620775d1SDaniel P. Berrange } else { 285620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 286620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 287620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 288620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 289620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 290620775d1SDaniel P. Berrange } 2918f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 2928f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 2938f63458fSDaniel P. Berrange if (key->down) { 2948f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 2958f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 2968f63458fSDaniel P. Berrange } else { 2978f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 2988f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 2998f63458fSDaniel P. Berrange } 300620775d1SDaniel P. Berrange } else { 3018c10e0baSHervé Poussineau if (key->down) { 3028c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3038c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 3048c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3058c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 3068c10e0baSHervé Poussineau } else { 3078c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3088c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 3098c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3108c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 3118c10e0baSHervé Poussineau } 312620775d1SDaniel P. Berrange } 3138c10e0baSHervé Poussineau } else { 314*ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset1_len) 315*ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 3168c10e0baSHervé Poussineau if (keycode) { 3178c10e0baSHervé Poussineau if (keycode & 0xff00) { 3188c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 3198c10e0baSHervé Poussineau } 3208c10e0baSHervé Poussineau if (!key->down) { 3218c10e0baSHervé Poussineau keycode |= 0x80; 3228c10e0baSHervé Poussineau } 3238c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 3248c10e0baSHervé Poussineau } else { 325ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 326ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 3278c10e0baSHervé Poussineau } 3288c10e0baSHervé Poussineau } 3298c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 3308c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 33129fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 33229fd23a5SDaniel P. Berrange if (key->down) { 33329fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 33429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 33529fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 33629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 33729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 33829fd23a5SDaniel P. Berrange } 33929fd23a5SDaniel P. Berrange } else { 3408c10e0baSHervé Poussineau if (key->down) { 3418c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3428c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 3438c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 3448c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3458c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 3468c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 3478c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 3488c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 3498c10e0baSHervé Poussineau } 35029fd23a5SDaniel P. Berrange } 3518c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 352620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 353620775d1SDaniel P. Berrange if (key->down) { 354620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 355620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 356620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 357620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 358620775d1SDaniel P. Berrange } else { 359620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 360620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 361620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 362620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 363620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 364620775d1SDaniel P. Berrange } 365620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 366620775d1SDaniel P. Berrange if (key->down) { 367620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 368620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 369620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 370620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 371620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 372620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 373620775d1SDaniel P. Berrange } else { 374620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 375620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 376620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 377620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 378620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 379620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 380620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 381620775d1SDaniel P. Berrange } 3828f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 3838f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 3848f63458fSDaniel P. Berrange if (key->down) { 3858f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3868f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 3878f63458fSDaniel P. Berrange } else { 3888f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3898f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 3908f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 3918f63458fSDaniel P. Berrange } 392620775d1SDaniel P. Berrange } else { 3938c10e0baSHervé Poussineau if (key->down) { 3948c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3958c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 3968c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3978c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 3988c10e0baSHervé Poussineau } else { 3998c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4008c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4018c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4028c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4038c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4048c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4058c10e0baSHervé Poussineau } 406620775d1SDaniel P. Berrange } 4078c10e0baSHervé Poussineau } else { 408*ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset2_len) 409*ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 4108c10e0baSHervé Poussineau if (keycode) { 4118c10e0baSHervé Poussineau if (keycode & 0xff00) { 4128c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4138c10e0baSHervé Poussineau } 4148c10e0baSHervé Poussineau if (!key->down) { 4158c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4168c10e0baSHervé Poussineau } 4178c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 41857d5c005SHervé Poussineau } else { 419ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 420ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 42157d5c005SHervé Poussineau } 42257d5c005SHervé Poussineau } 42357d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 424*ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset3_len) 425*ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 4268c10e0baSHervé Poussineau if (keycode) { 4278c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 4288c10e0baSHervé Poussineau if (!key->down) { 4298c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 43057d5c005SHervé Poussineau } 43157d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 4328c10e0baSHervé Poussineau } else { 433ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 434ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 4358c10e0baSHervé Poussineau } 43666e6536eSGerd Hoffmann } 43766e6536eSGerd Hoffmann } 43866e6536eSGerd Hoffmann 4398498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 4400e43e99cSbellard { 4410e43e99cSbellard PS2Queue *q; 4420e43e99cSbellard int val, index; 4430e43e99cSbellard 4448498bb8dSGerd Hoffmann trace_ps2_read_data(s); 4450e43e99cSbellard q = &s->queue; 4460e43e99cSbellard if (q->count == 0) { 4470e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 4480e43e99cSbellard (needed for EMM386) */ 4490e43e99cSbellard /* XXX: need a timer to do things correctly */ 4500e43e99cSbellard index = q->rptr - 1; 4510e43e99cSbellard if (index < 0) 4520e43e99cSbellard index = PS2_QUEUE_SIZE - 1; 4530e43e99cSbellard val = q->data[index]; 4540e43e99cSbellard } else { 4550e43e99cSbellard val = q->data[q->rptr]; 4560e43e99cSbellard if (++q->rptr == PS2_QUEUE_SIZE) 4570e43e99cSbellard q->rptr = 0; 4580e43e99cSbellard q->count--; 4590e43e99cSbellard /* reading deasserts IRQ */ 4600e43e99cSbellard s->update_irq(s->update_arg, 0); 4610e43e99cSbellard /* reassert IRQs if data left */ 4620e43e99cSbellard s->update_irq(s->update_arg, q->count != 0); 4630e43e99cSbellard } 4640e43e99cSbellard return val; 4650e43e99cSbellard } 4660e43e99cSbellard 4677f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 4687f540ab5SChristophe Fergeau { 4695edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 4707f540ab5SChristophe Fergeau s->ledstate = ledstate; 4717f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 4727f540ab5SChristophe Fergeau } 4737f540ab5SChristophe Fergeau 4740e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 4750e43e99cSbellard { 4765edab03dSDon Koch trace_ps2_reset_keyboard(s); 4770e43e99cSbellard s->scan_enabled = 1; 478e7d93956Saurel32 s->scancode_set = 2; 4796e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 4807f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 4810e43e99cSbellard } 4820e43e99cSbellard 4830e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 4840e43e99cSbellard { 4850e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 4860e43e99cSbellard 4875edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 4880e43e99cSbellard switch(s->common.write_cmd) { 4890e43e99cSbellard default: 4900e43e99cSbellard case -1: 4910e43e99cSbellard switch(val) { 4920e43e99cSbellard case 0x00: 4930e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 4940e43e99cSbellard break; 4950e43e99cSbellard case 0x05: 4960e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_RESEND); 4970e43e99cSbellard break; 4980e43e99cSbellard case KBD_CMD_GET_ID: 4990e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 500e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 50135c4d671Saurel32 ps2_queue(&s->common, KBD_REPLY_ID); 50235c4d671Saurel32 if (s->translate) 50335c4d671Saurel32 ps2_queue(&s->common, 0x41); 50435c4d671Saurel32 else 50535c4d671Saurel32 ps2_queue(&s->common, 0x83); 5060e43e99cSbellard break; 5070e43e99cSbellard case KBD_CMD_ECHO: 5080e43e99cSbellard ps2_queue(&s->common, KBD_CMD_ECHO); 5090e43e99cSbellard break; 5100e43e99cSbellard case KBD_CMD_ENABLE: 5110e43e99cSbellard s->scan_enabled = 1; 5120e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5130e43e99cSbellard break; 514e7d93956Saurel32 case KBD_CMD_SCANCODE: 5150e43e99cSbellard case KBD_CMD_SET_LEDS: 5160e43e99cSbellard case KBD_CMD_SET_RATE: 5170e43e99cSbellard s->common.write_cmd = val; 5180e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5190e43e99cSbellard break; 5200e43e99cSbellard case KBD_CMD_RESET_DISABLE: 5210e43e99cSbellard ps2_reset_keyboard(s); 5220e43e99cSbellard s->scan_enabled = 0; 5230e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5240e43e99cSbellard break; 5250e43e99cSbellard case KBD_CMD_RESET_ENABLE: 5260e43e99cSbellard ps2_reset_keyboard(s); 5270e43e99cSbellard s->scan_enabled = 1; 5280e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5290e43e99cSbellard break; 5300e43e99cSbellard case KBD_CMD_RESET: 5310e43e99cSbellard ps2_reset_keyboard(s); 5320e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5330e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_POR); 5340e43e99cSbellard break; 5350e43e99cSbellard default: 53606b3611fSHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 5370e43e99cSbellard break; 5380e43e99cSbellard } 5390e43e99cSbellard break; 540e7d93956Saurel32 case KBD_CMD_SCANCODE: 541e7d93956Saurel32 if (val == 0) { 5424df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_ACK); 54357d5c005SHervé Poussineau ps2_put_keycode(s, s->scancode_set); 5444df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 545e7d93956Saurel32 s->scancode_set = val; 546e7d93956Saurel32 ps2_queue(&s->common, KBD_REPLY_ACK); 5474df23b64SHervé Poussineau } else { 5484df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 549e7d93956Saurel32 } 550e7d93956Saurel32 s->common.write_cmd = -1; 551e7d93956Saurel32 break; 5520e43e99cSbellard case KBD_CMD_SET_LEDS: 5537f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 5540e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5550e43e99cSbellard s->common.write_cmd = -1; 5560e43e99cSbellard break; 5570e43e99cSbellard case KBD_CMD_SET_RATE: 5580e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5590e43e99cSbellard s->common.write_cmd = -1; 5600e43e99cSbellard break; 5610e43e99cSbellard } 5620e43e99cSbellard } 5630e43e99cSbellard 564f94f5d71Spbrook /* Set the scancode translation mode. 565f94f5d71Spbrook 0 = raw scancodes. 566f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 567f94f5d71Spbrook 568f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 569f94f5d71Spbrook { 570f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 5715edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 572f94f5d71Spbrook s->translate = mode; 573f94f5d71Spbrook } 574f94f5d71Spbrook 5750e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s) 5760e43e99cSbellard { 5770e43e99cSbellard unsigned int b; 5780e43e99cSbellard int dx1, dy1, dz1; 5790e43e99cSbellard 5800e43e99cSbellard dx1 = s->mouse_dx; 5810e43e99cSbellard dy1 = s->mouse_dy; 5820e43e99cSbellard dz1 = s->mouse_dz; 5830e43e99cSbellard /* XXX: increase range to 8 bits ? */ 5840e43e99cSbellard if (dx1 > 127) 5850e43e99cSbellard dx1 = 127; 5860e43e99cSbellard else if (dx1 < -127) 5870e43e99cSbellard dx1 = -127; 5880e43e99cSbellard if (dy1 > 127) 5890e43e99cSbellard dy1 = 127; 5900e43e99cSbellard else if (dy1 < -127) 5910e43e99cSbellard dy1 = -127; 5920e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 5930e43e99cSbellard ps2_queue(&s->common, b); 5940e43e99cSbellard ps2_queue(&s->common, dx1 & 0xff); 5950e43e99cSbellard ps2_queue(&s->common, dy1 & 0xff); 5960e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 5970e43e99cSbellard switch(s->mouse_type) { 5980e43e99cSbellard default: 5990e43e99cSbellard break; 6000e43e99cSbellard case 3: 6010e43e99cSbellard if (dz1 > 127) 6020e43e99cSbellard dz1 = 127; 6030e43e99cSbellard else if (dz1 < -127) 6040e43e99cSbellard dz1 = -127; 6050e43e99cSbellard ps2_queue(&s->common, dz1 & 0xff); 6060e43e99cSbellard break; 6070e43e99cSbellard case 4: 6080e43e99cSbellard if (dz1 > 7) 6090e43e99cSbellard dz1 = 7; 6100e43e99cSbellard else if (dz1 < -7) 6110e43e99cSbellard dz1 = -7; 6120e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 6130e43e99cSbellard ps2_queue(&s->common, b); 6140e43e99cSbellard break; 6150e43e99cSbellard } 6160e43e99cSbellard 6175edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 6180e43e99cSbellard /* update deltas */ 6190e43e99cSbellard s->mouse_dx -= dx1; 6200e43e99cSbellard s->mouse_dy -= dy1; 6210e43e99cSbellard s->mouse_dz -= dz1; 6220e43e99cSbellard } 6230e43e99cSbellard 6242a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 6252a766d29SGerd Hoffmann InputEvent *evt) 6260e43e99cSbellard { 6277fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 6288b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 6298b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 6308b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 6318b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 6328b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 6332a766d29SGerd Hoffmann }; 6342a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 635b5a1b443SEric Blake InputMoveEvent *move; 636b5a1b443SEric Blake InputBtnEvent *btn; 6370e43e99cSbellard 6380e43e99cSbellard /* check if deltas are recorded when disabled */ 6390e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 6400e43e99cSbellard return; 6410e43e99cSbellard 642568c73a4SEric Blake switch (evt->type) { 6432a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 64432bafa8fSEric Blake move = evt->u.rel.data; 645b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 646b5a1b443SEric Blake s->mouse_dx += move->value; 647b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 648b5a1b443SEric Blake s->mouse_dy -= move->value; 6492a766d29SGerd Hoffmann } 6502a766d29SGerd Hoffmann break; 6510e43e99cSbellard 6522a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 65332bafa8fSEric Blake btn = evt->u.btn.data; 654b5a1b443SEric Blake if (btn->down) { 655b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 656b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 6572a766d29SGerd Hoffmann s->mouse_dz--; 658b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 6592a766d29SGerd Hoffmann s->mouse_dz++; 6602a766d29SGerd Hoffmann } 6612a766d29SGerd Hoffmann } else { 662b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 6632a766d29SGerd Hoffmann } 6642a766d29SGerd Hoffmann break; 6652a766d29SGerd Hoffmann 6662a766d29SGerd Hoffmann default: 6672a766d29SGerd Hoffmann /* keep gcc happy */ 6682a766d29SGerd Hoffmann break; 6692a766d29SGerd Hoffmann } 670fd214d18SGerd Hoffmann } 671fd214d18SGerd Hoffmann 6722a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 6732a766d29SGerd Hoffmann { 6742a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 6752a766d29SGerd Hoffmann 6762a766d29SGerd Hoffmann if (s->mouse_buttons) { 6772a766d29SGerd Hoffmann qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); 6782a766d29SGerd Hoffmann } 6792858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 6802858ab09SGonglei while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { 6810e43e99cSbellard /* if not remote, send event. Multiple events are sent if 6820e43e99cSbellard too big deltas */ 6830e43e99cSbellard ps2_mouse_send_packet(s); 6840e43e99cSbellard if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 6850e43e99cSbellard break; 6860e43e99cSbellard } 6870e43e99cSbellard } 6880e43e99cSbellard } 6890e43e99cSbellard 690548df2acSths void ps2_mouse_fake_event(void *opaque) 691548df2acSths { 6922a766d29SGerd Hoffmann PS2MouseState *s = opaque; 6935edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 6942a766d29SGerd Hoffmann s->mouse_dx++; 6952a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 696548df2acSths } 697548df2acSths 6980e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 6990e43e99cSbellard { 7000e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 7015edab03dSDon Koch 7025edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 7030e43e99cSbellard #ifdef DEBUG_MOUSE 7040e43e99cSbellard printf("kbd: write mouse 0x%02x\n", val); 7050e43e99cSbellard #endif 7060e43e99cSbellard switch(s->common.write_cmd) { 7070e43e99cSbellard default: 7080e43e99cSbellard case -1: 7090e43e99cSbellard /* mouse command */ 7100e43e99cSbellard if (s->mouse_wrap) { 7110e43e99cSbellard if (val == AUX_RESET_WRAP) { 7120e43e99cSbellard s->mouse_wrap = 0; 7130e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7140e43e99cSbellard return; 7150e43e99cSbellard } else if (val != AUX_RESET) { 7160e43e99cSbellard ps2_queue(&s->common, val); 7170e43e99cSbellard return; 7180e43e99cSbellard } 7190e43e99cSbellard } 7200e43e99cSbellard switch(val) { 7210e43e99cSbellard case AUX_SET_SCALE11: 7220e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 7230e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7240e43e99cSbellard break; 7250e43e99cSbellard case AUX_SET_SCALE21: 7260e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 7270e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7280e43e99cSbellard break; 7290e43e99cSbellard case AUX_SET_STREAM: 7300e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 7310e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7320e43e99cSbellard break; 7330e43e99cSbellard case AUX_SET_WRAP: 7340e43e99cSbellard s->mouse_wrap = 1; 7350e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7360e43e99cSbellard break; 7370e43e99cSbellard case AUX_SET_REMOTE: 7380e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 7390e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7400e43e99cSbellard break; 7410e43e99cSbellard case AUX_GET_TYPE: 7420e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7430e43e99cSbellard ps2_queue(&s->common, s->mouse_type); 7440e43e99cSbellard break; 7450e43e99cSbellard case AUX_SET_RES: 7460e43e99cSbellard case AUX_SET_SAMPLE: 7470e43e99cSbellard s->common.write_cmd = val; 7480e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7490e43e99cSbellard break; 7500e43e99cSbellard case AUX_GET_SCALE: 7510e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7520e43e99cSbellard ps2_queue(&s->common, s->mouse_status); 7530e43e99cSbellard ps2_queue(&s->common, s->mouse_resolution); 7540e43e99cSbellard ps2_queue(&s->common, s->mouse_sample_rate); 7550e43e99cSbellard break; 7560e43e99cSbellard case AUX_POLL: 7570e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7580e43e99cSbellard ps2_mouse_send_packet(s); 7590e43e99cSbellard break; 7600e43e99cSbellard case AUX_ENABLE_DEV: 7610e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 7620e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7630e43e99cSbellard break; 7640e43e99cSbellard case AUX_DISABLE_DEV: 7650e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 7660e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7670e43e99cSbellard break; 7680e43e99cSbellard case AUX_SET_DEFAULT: 7690e43e99cSbellard s->mouse_sample_rate = 100; 7700e43e99cSbellard s->mouse_resolution = 2; 7710e43e99cSbellard s->mouse_status = 0; 7720e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7730e43e99cSbellard break; 7740e43e99cSbellard case AUX_RESET: 7750e43e99cSbellard s->mouse_sample_rate = 100; 7760e43e99cSbellard s->mouse_resolution = 2; 7770e43e99cSbellard s->mouse_status = 0; 7780e43e99cSbellard s->mouse_type = 0; 7790e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7800e43e99cSbellard ps2_queue(&s->common, 0xaa); 7810e43e99cSbellard ps2_queue(&s->common, s->mouse_type); 7820e43e99cSbellard break; 7830e43e99cSbellard default: 7840e43e99cSbellard break; 7850e43e99cSbellard } 7860e43e99cSbellard break; 7870e43e99cSbellard case AUX_SET_SAMPLE: 7880e43e99cSbellard s->mouse_sample_rate = val; 7890e43e99cSbellard /* detect IMPS/2 or IMEX */ 7900e43e99cSbellard switch(s->mouse_detect_state) { 7910e43e99cSbellard default: 7920e43e99cSbellard case 0: 7930e43e99cSbellard if (val == 200) 7940e43e99cSbellard s->mouse_detect_state = 1; 7950e43e99cSbellard break; 7960e43e99cSbellard case 1: 7970e43e99cSbellard if (val == 100) 7980e43e99cSbellard s->mouse_detect_state = 2; 7990e43e99cSbellard else if (val == 200) 8000e43e99cSbellard s->mouse_detect_state = 3; 8010e43e99cSbellard else 8020e43e99cSbellard s->mouse_detect_state = 0; 8030e43e99cSbellard break; 8040e43e99cSbellard case 2: 8050e43e99cSbellard if (val == 80) 8060e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 8070e43e99cSbellard s->mouse_detect_state = 0; 8080e43e99cSbellard break; 8090e43e99cSbellard case 3: 8100e43e99cSbellard if (val == 80) 8110e43e99cSbellard s->mouse_type = 4; /* IMEX */ 8120e43e99cSbellard s->mouse_detect_state = 0; 8130e43e99cSbellard break; 8140e43e99cSbellard } 8150e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8160e43e99cSbellard s->common.write_cmd = -1; 8170e43e99cSbellard break; 8180e43e99cSbellard case AUX_SET_RES: 8190e43e99cSbellard s->mouse_resolution = val; 8200e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8210e43e99cSbellard s->common.write_cmd = -1; 8220e43e99cSbellard break; 8230e43e99cSbellard } 8240e43e99cSbellard } 8250e43e99cSbellard 826ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 8270e43e99cSbellard { 8280e43e99cSbellard s->write_cmd = -1; 829954ee55bSGerd Hoffmann ps2_reset_queue(s); 830deeccef3Saliguori s->update_irq(s->update_arg, 0); 8310e43e99cSbellard } 8320e43e99cSbellard 8332858ab09SGonglei static void ps2_common_post_load(PS2State *s) 8342858ab09SGonglei { 8352858ab09SGonglei PS2Queue *q = &s->queue; 836802cbcb7SPrasad J Pandit uint8_t i, size; 837802cbcb7SPrasad J Pandit uint8_t tmp_data[PS2_QUEUE_SIZE]; 8382858ab09SGonglei 8392858ab09SGonglei /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ 840802cbcb7SPrasad J Pandit size = (q->count < 0 || q->count > PS2_QUEUE_SIZE) ? 0 : q->count; 8412858ab09SGonglei 8422858ab09SGonglei /* move the queue elements to the start of data array */ 8432858ab09SGonglei for (i = 0; i < size; i++) { 844802cbcb7SPrasad J Pandit if (q->rptr < 0 || q->rptr >= sizeof(q->data)) { 8452858ab09SGonglei q->rptr = 0; 8462858ab09SGonglei } 847802cbcb7SPrasad J Pandit tmp_data[i] = q->data[q->rptr++]; 8482858ab09SGonglei } 8492858ab09SGonglei memcpy(q->data, tmp_data, size); 850802cbcb7SPrasad J Pandit 8512858ab09SGonglei /* reset rptr/wptr/count */ 8522858ab09SGonglei q->rptr = 0; 8532858ab09SGonglei q->wptr = size; 8542858ab09SGonglei q->count = size; 8552858ab09SGonglei s->update_irq(s->update_arg, q->count != 0); 8562858ab09SGonglei } 8572858ab09SGonglei 858ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 859ef74679aSDinesh Subhraveti { 860ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 861ef74679aSDinesh Subhraveti 8625edab03dSDon Koch trace_ps2_kbd_reset(opaque); 863ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 864ef74679aSDinesh Subhraveti s->scan_enabled = 0; 865ef74679aSDinesh Subhraveti s->translate = 0; 866089adafdSHervé Poussineau s->scancode_set = 2; 867620775d1SDaniel P. Berrange s->modifiers = 0; 868ef74679aSDinesh Subhraveti } 869ef74679aSDinesh Subhraveti 870ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 871ef74679aSDinesh Subhraveti { 872ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 873ef74679aSDinesh Subhraveti 8745edab03dSDon Koch trace_ps2_mouse_reset(opaque); 875ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 876ef74679aSDinesh Subhraveti s->mouse_status = 0; 877ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 878ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 879ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 880ef74679aSDinesh Subhraveti s->mouse_type = 0; 881ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 882ef74679aSDinesh Subhraveti s->mouse_dx = 0; 883ef74679aSDinesh Subhraveti s->mouse_dy = 0; 884ef74679aSDinesh Subhraveti s->mouse_dz = 0; 885ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 886ef74679aSDinesh Subhraveti } 887ef74679aSDinesh Subhraveti 888b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 889b31442c3SJuan Quintela .name = "PS2 Common State", 890b31442c3SJuan Quintela .version_id = 3, 891b31442c3SJuan Quintela .minimum_version_id = 2, 892b31442c3SJuan Quintela .fields = (VMStateField[]) { 893b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 894b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 895b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 896b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 897b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 898b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 8997783e9f0Spbrook } 900b31442c3SJuan Quintela }; 9017783e9f0Spbrook 9027f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 9037f540ab5SChristophe Fergeau { 9047f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 9057f540ab5SChristophe Fergeau 9067f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 9077f540ab5SChristophe Fergeau } 9087f540ab5SChristophe Fergeau 9097f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 9107f540ab5SChristophe Fergeau { 9117f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 9127f540ab5SChristophe Fergeau 9137f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 9147f540ab5SChristophe Fergeau return 0; 9157f540ab5SChristophe Fergeau } 9167f540ab5SChristophe Fergeau 9177f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 9187f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 9197f540ab5SChristophe Fergeau .version_id = 3, 9207f540ab5SChristophe Fergeau .minimum_version_id = 2, 9217f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 9225cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 9237f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 9247f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 9257f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 9267f540ab5SChristophe Fergeau } 9277f540ab5SChristophe Fergeau }; 9287f540ab5SChristophe Fergeau 92957d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 93057d5c005SHervé Poussineau { 93157d5c005SHervé Poussineau PS2KbdState *s = opaque; 93257d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 93357d5c005SHervé Poussineau } 93457d5c005SHervé Poussineau 93557d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 93657d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 93757d5c005SHervé Poussineau .version_id = 1, 93857d5c005SHervé Poussineau .minimum_version_id = 1, 93957d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 94057d5c005SHervé Poussineau .fields = (VMStateField[]) { 94157d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 94257d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 94357d5c005SHervé Poussineau } 94457d5c005SHervé Poussineau }; 94557d5c005SHervé Poussineau 946db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 9470e43e99cSbellard { 9480e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 9492858ab09SGonglei PS2State *ps2 = &s->common; 9500e43e99cSbellard 951db596c53SJuan Quintela if (version_id == 2) 952e7d93956Saurel32 s->scancode_set=2; 9532858ab09SGonglei 9542858ab09SGonglei ps2_common_post_load(ps2); 9552858ab09SGonglei 9560e43e99cSbellard return 0; 9570e43e99cSbellard } 9580e43e99cSbellard 95944b1ff31SDr. David Alan Gilbert static int ps2_kbd_pre_save(void *opaque) 9602858ab09SGonglei { 9612858ab09SGonglei PS2KbdState *s = (PS2KbdState *)opaque; 9622858ab09SGonglei PS2State *ps2 = &s->common; 9632858ab09SGonglei 9642858ab09SGonglei ps2_common_post_load(ps2); 96544b1ff31SDr. David Alan Gilbert 96644b1ff31SDr. David Alan Gilbert return 0; 9672858ab09SGonglei } 9682858ab09SGonglei 969b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 970b31442c3SJuan Quintela .name = "ps2kbd", 971b31442c3SJuan Quintela .version_id = 3, 972db596c53SJuan Quintela .minimum_version_id = 2, 973db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 9742858ab09SGonglei .pre_save = ps2_kbd_pre_save, 975b31442c3SJuan Quintela .fields = (VMStateField[]) { 976b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 977b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 978b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 979b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 980b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 9817f540ab5SChristophe Fergeau }, 9825cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 9835cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 98457d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 9855cd8cadaSJuan Quintela NULL 9860e43e99cSbellard } 987b31442c3SJuan Quintela }; 988b31442c3SJuan Quintela 9892858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 9902858ab09SGonglei { 9912858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 9922858ab09SGonglei PS2State *ps2 = &s->common; 9932858ab09SGonglei 9942858ab09SGonglei ps2_common_post_load(ps2); 9952858ab09SGonglei 9962858ab09SGonglei return 0; 9972858ab09SGonglei } 9982858ab09SGonglei 99944b1ff31SDr. David Alan Gilbert static int ps2_mouse_pre_save(void *opaque) 10002858ab09SGonglei { 10012858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 10022858ab09SGonglei PS2State *ps2 = &s->common; 10032858ab09SGonglei 10042858ab09SGonglei ps2_common_post_load(ps2); 100544b1ff31SDr. David Alan Gilbert 100644b1ff31SDr. David Alan Gilbert return 0; 10072858ab09SGonglei } 10082858ab09SGonglei 1009b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1010b31442c3SJuan Quintela .name = "ps2mouse", 1011b31442c3SJuan Quintela .version_id = 2, 1012b31442c3SJuan Quintela .minimum_version_id = 2, 10132858ab09SGonglei .post_load = ps2_mouse_post_load, 10142858ab09SGonglei .pre_save = ps2_mouse_pre_save, 1015b31442c3SJuan Quintela .fields = (VMStateField[]) { 1016b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 1017b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1018b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1019b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1020b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1021b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1022b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1023b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1024b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1025b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1026b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1027b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1028b31442c3SJuan Quintela } 1029b31442c3SJuan Quintela }; 10300e43e99cSbellard 103166e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 103266e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 103366e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 103466e6536eSGerd Hoffmann .event = ps2_keyboard_event, 103566e6536eSGerd Hoffmann }; 103666e6536eSGerd Hoffmann 10370e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 10380e43e99cSbellard { 10397267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 10400e43e99cSbellard 10415edab03dSDon Koch trace_ps2_kbd_init(s); 10420e43e99cSbellard s->common.update_irq = update_irq; 10430e43e99cSbellard s->common.update_arg = update_arg; 1044e7d93956Saurel32 s->scancode_set = 2; 10450be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 104666e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 104766e6536eSGerd Hoffmann &ps2_keyboard_handler); 1048ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 10490e43e99cSbellard return s; 10500e43e99cSbellard } 10510e43e99cSbellard 10522a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 10532a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 10542a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 10552a766d29SGerd Hoffmann .event = ps2_mouse_event, 10562a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 10572a766d29SGerd Hoffmann }; 10582a766d29SGerd Hoffmann 10590e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 10600e43e99cSbellard { 10617267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 10620e43e99cSbellard 10635edab03dSDon Koch trace_ps2_mouse_init(s); 10640e43e99cSbellard s->common.update_irq = update_irq; 10650e43e99cSbellard s->common.update_arg = update_arg; 10660be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 10672a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 10682a766d29SGerd Hoffmann &ps2_mouse_handler); 1069ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 10700e43e99cSbellard return s; 10710e43e99cSbellard } 1072