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 */ 2471e8a915SMarkus Armbruster 250430891cSPeter Maydell #include "qemu/osdep.h" 26ec044a80SHervé Poussineau #include "qemu/log.h" 270d09e41aSPaolo Bonzini #include "hw/input/ps2.h" 28d6454270SMarkus Armbruster #include "migration/vmstate.h" 2928ecbaeeSPaolo Bonzini #include "ui/console.h" 3066e6536eSGerd Hoffmann #include "ui/input.h" 3171e8a915SMarkus Armbruster #include "sysemu/reset.h" 3254d31236SMarkus Armbruster #include "sysemu/runstate.h" 330e43e99cSbellard 345edab03dSDon Koch #include "trace.h" 355edab03dSDon Koch 360e43e99cSbellard /* debug PC keyboard */ 370e43e99cSbellard //#define DEBUG_KBD 380e43e99cSbellard 390e43e99cSbellard /* debug PC keyboard : only mouse */ 400e43e99cSbellard //#define DEBUG_MOUSE 410e43e99cSbellard 420e43e99cSbellard /* Keyboard Commands */ 430e43e99cSbellard #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ 440e43e99cSbellard #define KBD_CMD_ECHO 0xEE 45e7d93956Saurel32 #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ 460e43e99cSbellard #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ 470e43e99cSbellard #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ 480e43e99cSbellard #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ 490e43e99cSbellard #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ 500e43e99cSbellard #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ 510e43e99cSbellard #define KBD_CMD_RESET 0xFF /* Reset */ 52*c56b6209SSven Schnelle #define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */ 53*c56b6209SSven Schnelle #define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */ 540e43e99cSbellard 550e43e99cSbellard /* Keyboard Replies */ 560e43e99cSbellard #define KBD_REPLY_POR 0xAA /* Power on reset */ 5735c4d671Saurel32 #define KBD_REPLY_ID 0xAB /* Keyboard ID */ 580e43e99cSbellard #define KBD_REPLY_ACK 0xFA /* Command ACK */ 590e43e99cSbellard #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ 600e43e99cSbellard 610e43e99cSbellard /* Mouse Commands */ 620e43e99cSbellard #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ 630e43e99cSbellard #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ 640e43e99cSbellard #define AUX_SET_RES 0xE8 /* Set resolution */ 650e43e99cSbellard #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ 660e43e99cSbellard #define AUX_SET_STREAM 0xEA /* Set stream mode */ 670e43e99cSbellard #define AUX_POLL 0xEB /* Poll */ 680e43e99cSbellard #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ 690e43e99cSbellard #define AUX_SET_WRAP 0xEE /* Set wrap mode */ 700e43e99cSbellard #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ 710e43e99cSbellard #define AUX_GET_TYPE 0xF2 /* Get type */ 720e43e99cSbellard #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ 730e43e99cSbellard #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ 740e43e99cSbellard #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ 750e43e99cSbellard #define AUX_SET_DEFAULT 0xF6 760e43e99cSbellard #define AUX_RESET 0xFF /* Reset aux device */ 770e43e99cSbellard #define AUX_ACK 0xFA /* Command byte ACK. */ 780e43e99cSbellard 790e43e99cSbellard #define MOUSE_STATUS_REMOTE 0x40 800e43e99cSbellard #define MOUSE_STATUS_ENABLED 0x20 810e43e99cSbellard #define MOUSE_STATUS_SCALE21 0x10 820e43e99cSbellard 832858ab09SGonglei #define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ 840e43e99cSbellard 85620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */ 86620775d1SDaniel P. Berrange #define MOD_CTRL_L (1 << 0) 87620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1) 88620775d1SDaniel P. Berrange #define MOD_ALT_L (1 << 2) 89620775d1SDaniel P. Berrange #define MOD_CTRL_R (1 << 3) 90620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4) 91620775d1SDaniel P. Berrange #define MOD_ALT_R (1 << 5) 92620775d1SDaniel P. Berrange 930e43e99cSbellard typedef struct { 942858ab09SGonglei /* Keep the data array 256 bytes long, which compatibility 952858ab09SGonglei with older qemu versions. */ 962858ab09SGonglei uint8_t data[256]; 970e43e99cSbellard int rptr, wptr, count; 980e43e99cSbellard } PS2Queue; 990e43e99cSbellard 1008498bb8dSGerd Hoffmann struct PS2State { 1010e43e99cSbellard PS2Queue queue; 1020e43e99cSbellard int32_t write_cmd; 1030e43e99cSbellard void (*update_irq)(void *, int); 1040e43e99cSbellard void *update_arg; 1058498bb8dSGerd Hoffmann }; 1060e43e99cSbellard 1070e43e99cSbellard typedef struct { 1080e43e99cSbellard PS2State common; 1090e43e99cSbellard int scan_enabled; 110f94f5d71Spbrook int translate; 111e7d93956Saurel32 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ 1127f540ab5SChristophe Fergeau int ledstate; 11357d5c005SHervé Poussineau bool need_high_bit; 114620775d1SDaniel P. Berrange unsigned int modifiers; /* bitmask of MOD_* constants above */ 1150e43e99cSbellard } PS2KbdState; 1160e43e99cSbellard 1170e43e99cSbellard typedef struct { 1180e43e99cSbellard PS2State common; 1190e43e99cSbellard uint8_t mouse_status; 1200e43e99cSbellard uint8_t mouse_resolution; 1210e43e99cSbellard uint8_t mouse_sample_rate; 1220e43e99cSbellard uint8_t mouse_wrap; 1230e43e99cSbellard uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ 1240e43e99cSbellard uint8_t mouse_detect_state; 1250e43e99cSbellard int mouse_dx; /* current values, needed for 'poll' mode */ 1260e43e99cSbellard int mouse_dy; 1270e43e99cSbellard int mouse_dz; 1280e43e99cSbellard uint8_t mouse_buttons; 1290e43e99cSbellard } PS2MouseState; 1300e43e99cSbellard 13157d5c005SHervé Poussineau static uint8_t translate_table[256] = { 13257d5c005SHervé Poussineau 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 13357d5c005SHervé Poussineau 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 13457d5c005SHervé Poussineau 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 13557d5c005SHervé Poussineau 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 13657d5c005SHervé Poussineau 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 13757d5c005SHervé Poussineau 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 13857d5c005SHervé Poussineau 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 13957d5c005SHervé Poussineau 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 14057d5c005SHervé Poussineau 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 14157d5c005SHervé Poussineau 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 14257d5c005SHervé Poussineau 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 14357d5c005SHervé Poussineau 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 14457d5c005SHervé Poussineau 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 14557d5c005SHervé Poussineau 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 14657d5c005SHervé Poussineau 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 14757d5c005SHervé Poussineau 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 14857d5c005SHervé Poussineau 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 14957d5c005SHervé Poussineau 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 15057d5c005SHervé Poussineau 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 15157d5c005SHervé Poussineau 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 15257d5c005SHervé Poussineau 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 15357d5c005SHervé Poussineau 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 15457d5c005SHervé Poussineau 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 15557d5c005SHervé Poussineau 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 15657d5c005SHervé Poussineau 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 15757d5c005SHervé Poussineau 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 15857d5c005SHervé Poussineau 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 15957d5c005SHervé Poussineau 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 16057d5c005SHervé Poussineau 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 16157d5c005SHervé Poussineau 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 16257d5c005SHervé Poussineau 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 16357d5c005SHervé Poussineau 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 16457d5c005SHervé Poussineau }; 16557d5c005SHervé Poussineau 166620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key) 167620775d1SDaniel P. Berrange { 168620775d1SDaniel P. Berrange switch (key) { 169620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL: 170620775d1SDaniel P. Berrange return MOD_CTRL_L; 171620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL_R: 172620775d1SDaniel P. Berrange return MOD_CTRL_R; 173620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT: 174620775d1SDaniel P. Berrange return MOD_SHIFT_L; 175620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT_R: 176620775d1SDaniel P. Berrange return MOD_SHIFT_R; 177620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT: 178620775d1SDaniel P. Berrange return MOD_ALT_L; 179620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT_R: 180620775d1SDaniel P. Berrange return MOD_ALT_R; 181620775d1SDaniel P. Berrange default: 182620775d1SDaniel P. Berrange return 0; 183620775d1SDaniel P. Berrange } 184620775d1SDaniel P. Berrange } 185620775d1SDaniel P. Berrange 186954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s) 187954ee55bSGerd Hoffmann { 188954ee55bSGerd Hoffmann PS2Queue *q = &s->queue; 189954ee55bSGerd Hoffmann 190954ee55bSGerd Hoffmann q->rptr = 0; 191954ee55bSGerd Hoffmann q->wptr = 0; 192954ee55bSGerd Hoffmann q->count = 0; 193954ee55bSGerd Hoffmann } 194954ee55bSGerd Hoffmann 1957abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 1960e43e99cSbellard { 1970e43e99cSbellard PS2Queue *q = &s->queue; 1980e43e99cSbellard 1997abe7eb2SGeoffrey McRae if (q->count == PS2_QUEUE_SIZE) { 2000e43e99cSbellard return; 2017abe7eb2SGeoffrey McRae } 2027abe7eb2SGeoffrey McRae 2030e43e99cSbellard q->data[q->wptr] = b; 2040e43e99cSbellard if (++q->wptr == PS2_QUEUE_SIZE) 2050e43e99cSbellard q->wptr = 0; 2060e43e99cSbellard q->count++; 2077abe7eb2SGeoffrey McRae } 2087abe7eb2SGeoffrey McRae 2097abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s) 2107abe7eb2SGeoffrey McRae { 2117abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2127abe7eb2SGeoffrey McRae } 2137abe7eb2SGeoffrey McRae 2147abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 2157abe7eb2SGeoffrey McRae { 2167abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 2177abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2187abe7eb2SGeoffrey McRae } 2197abe7eb2SGeoffrey McRae 2207abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 2217abe7eb2SGeoffrey McRae { 2227abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 2237abe7eb2SGeoffrey McRae return; 2247abe7eb2SGeoffrey McRae } 2257abe7eb2SGeoffrey McRae 2267abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2277abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2287abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2297abe7eb2SGeoffrey McRae } 2307abe7eb2SGeoffrey McRae 2317abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 2327abe7eb2SGeoffrey McRae { 2337abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 2347abe7eb2SGeoffrey McRae return; 2357abe7eb2SGeoffrey McRae } 2367abe7eb2SGeoffrey McRae 2377abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2387abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2397abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2407abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2417abe7eb2SGeoffrey McRae } 2427abe7eb2SGeoffrey McRae 2437abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 2447abe7eb2SGeoffrey McRae { 2457abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 2467abe7eb2SGeoffrey McRae return; 2477abe7eb2SGeoffrey McRae } 2487abe7eb2SGeoffrey McRae 2497abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2507abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2517abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2527abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 2530e43e99cSbellard s->update_irq(s->update_arg, 1); 2540e43e99cSbellard } 2550e43e99cSbellard 25657d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 2570e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 2580e43e99cSbellard { 259f94f5d71Spbrook PS2KbdState *s = opaque; 260e7d93956Saurel32 2615edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 262fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 26357d5c005SHervé Poussineau 26457d5c005SHervé Poussineau if (s->translate) { 26557d5c005SHervé Poussineau if (keycode == 0xf0) { 26657d5c005SHervé Poussineau s->need_high_bit = true; 26757d5c005SHervé Poussineau } else if (s->need_high_bit) { 26857d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode] | 0x80); 26957d5c005SHervé Poussineau s->need_high_bit = false; 27057d5c005SHervé Poussineau } else { 27157d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode]); 2727096a96dSRoy Tam } 27357d5c005SHervé Poussineau } else { 2740e43e99cSbellard ps2_queue(&s->common, keycode); 2750e43e99cSbellard } 27657d5c005SHervé Poussineau } 2770e43e99cSbellard 27866e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 27966e6536eSGerd Hoffmann InputEvent *evt) 28066e6536eSGerd Hoffmann { 28166e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 28232bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 2838c10e0baSHervé Poussineau int qcode; 284ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 285620775d1SDaniel P. Berrange int mod; 28666e6536eSGerd Hoffmann 287143c04c7SGeoffrey McRae /* do not process events while disabled to prevent stream corruption */ 288143c04c7SGeoffrey McRae if (!s->scan_enabled) { 289143c04c7SGeoffrey McRae return; 290143c04c7SGeoffrey McRae } 291143c04c7SGeoffrey McRae 292fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 2938c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 2948c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 29557d5c005SHervé Poussineau 296620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 297620775d1SDaniel P. Berrange trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers); 298620775d1SDaniel P. Berrange if (key->down) { 299620775d1SDaniel P. Berrange s->modifiers |= mod; 300620775d1SDaniel P. Berrange } else { 301620775d1SDaniel P. Berrange s->modifiers &= ~mod; 302620775d1SDaniel P. Berrange } 303620775d1SDaniel P. Berrange 3048c10e0baSHervé Poussineau if (s->scancode_set == 1) { 3058c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 30629fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 30729fd23a5SDaniel P. Berrange if (key->down) { 30829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 30929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 31029fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 31129fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 31229fd23a5SDaniel P. Berrange } 31329fd23a5SDaniel P. Berrange } else { 3148c10e0baSHervé Poussineau if (key->down) { 3158c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3168c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 3178c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 318927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 3198c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 3208c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 3218c10e0baSHervé Poussineau } 32229fd23a5SDaniel P. Berrange } 3238c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 324620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 325620775d1SDaniel P. Berrange if (key->down) { 326620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 327620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 328620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 329620775d1SDaniel P. Berrange } else { 330620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 331620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 332620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 333620775d1SDaniel P. Berrange } 334620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 335620775d1SDaniel P. Berrange if (key->down) { 336620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 337620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 338620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 339620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 340620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 341620775d1SDaniel P. Berrange } else { 342620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 343620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 344620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 345620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 346620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 347620775d1SDaniel P. Berrange } 3488f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 3498f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 3508f63458fSDaniel P. Berrange if (key->down) { 3518f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3528f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 3538f63458fSDaniel P. Berrange } else { 3548f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3558f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 3568f63458fSDaniel P. Berrange } 357620775d1SDaniel P. Berrange } else { 3588c10e0baSHervé Poussineau if (key->down) { 3598c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3608c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 3618c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3628c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 3638c10e0baSHervé Poussineau } else { 3648c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3658c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 3668c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3678c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 3688c10e0baSHervé Poussineau } 369620775d1SDaniel P. Berrange } 3708c10e0baSHervé Poussineau } else { 371ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset1_len) 372ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 3738c10e0baSHervé Poussineau if (keycode) { 3748c10e0baSHervé Poussineau if (keycode & 0xff00) { 3758c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 3768c10e0baSHervé Poussineau } 3778c10e0baSHervé Poussineau if (!key->down) { 3788c10e0baSHervé Poussineau keycode |= 0x80; 3798c10e0baSHervé Poussineau } 3808c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 3818c10e0baSHervé Poussineau } else { 382ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 383ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 3848c10e0baSHervé Poussineau } 3858c10e0baSHervé Poussineau } 3868c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 3878c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 38829fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 38929fd23a5SDaniel P. Berrange if (key->down) { 39029fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 39129fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 39229fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 39329fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 39429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 39529fd23a5SDaniel P. Berrange } 39629fd23a5SDaniel P. Berrange } else { 3978c10e0baSHervé Poussineau if (key->down) { 3988c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3998c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4008c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4018c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4028c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4038c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4048c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4058c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4068c10e0baSHervé Poussineau } 40729fd23a5SDaniel P. Berrange } 4088c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 409620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 410620775d1SDaniel P. Berrange if (key->down) { 411620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 412620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 413620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 414620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 415620775d1SDaniel P. Berrange } else { 416620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 417620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 418620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 419620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 420620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 421620775d1SDaniel P. Berrange } 422620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 423620775d1SDaniel P. Berrange if (key->down) { 424620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 425620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 426620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 427620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 428620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 429620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 430620775d1SDaniel P. Berrange } else { 431620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 432620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 433620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 434620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 435620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 436620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 437620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 438620775d1SDaniel P. Berrange } 4398f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 4408f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 4418f63458fSDaniel P. Berrange if (key->down) { 4428f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4438f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4448f63458fSDaniel P. Berrange } else { 4458f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4468f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 4478f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4488f63458fSDaniel P. Berrange } 449620775d1SDaniel P. Berrange } else { 4508c10e0baSHervé Poussineau if (key->down) { 4518c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4528c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4538c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4548c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4558c10e0baSHervé Poussineau } else { 4568c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4578c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4588c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4598c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4608c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4618c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4628c10e0baSHervé Poussineau } 463620775d1SDaniel P. Berrange } 4648c10e0baSHervé Poussineau } else { 465ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset2_len) 466ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 4678c10e0baSHervé Poussineau if (keycode) { 4688c10e0baSHervé Poussineau if (keycode & 0xff00) { 4698c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4708c10e0baSHervé Poussineau } 4718c10e0baSHervé Poussineau if (!key->down) { 4728c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4738c10e0baSHervé Poussineau } 4748c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 47557d5c005SHervé Poussineau } else { 476ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 477ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 47857d5c005SHervé Poussineau } 47957d5c005SHervé Poussineau } 48057d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 481ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset3_len) 482ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 4838c10e0baSHervé Poussineau if (keycode) { 4848c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 4858c10e0baSHervé Poussineau if (!key->down) { 4868c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 48757d5c005SHervé Poussineau } 48857d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 4898c10e0baSHervé Poussineau } else { 490ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 491ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 4928c10e0baSHervé Poussineau } 49366e6536eSGerd Hoffmann } 49466e6536eSGerd Hoffmann } 49566e6536eSGerd Hoffmann 4968498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 4970e43e99cSbellard { 4980e43e99cSbellard PS2Queue *q; 4990e43e99cSbellard int val, index; 5000e43e99cSbellard 5018498bb8dSGerd Hoffmann trace_ps2_read_data(s); 5020e43e99cSbellard q = &s->queue; 5030e43e99cSbellard if (q->count == 0) { 5040e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 5050e43e99cSbellard (needed for EMM386) */ 5060e43e99cSbellard /* XXX: need a timer to do things correctly */ 5070e43e99cSbellard index = q->rptr - 1; 5080e43e99cSbellard if (index < 0) 5090e43e99cSbellard index = PS2_QUEUE_SIZE - 1; 5100e43e99cSbellard val = q->data[index]; 5110e43e99cSbellard } else { 5120e43e99cSbellard val = q->data[q->rptr]; 5130e43e99cSbellard if (++q->rptr == PS2_QUEUE_SIZE) 5140e43e99cSbellard q->rptr = 0; 5150e43e99cSbellard q->count--; 5160e43e99cSbellard /* reading deasserts IRQ */ 5170e43e99cSbellard s->update_irq(s->update_arg, 0); 5180e43e99cSbellard /* reassert IRQs if data left */ 5190e43e99cSbellard s->update_irq(s->update_arg, q->count != 0); 5200e43e99cSbellard } 5210e43e99cSbellard return val; 5220e43e99cSbellard } 5230e43e99cSbellard 5247f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 5257f540ab5SChristophe Fergeau { 5265edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 5277f540ab5SChristophe Fergeau s->ledstate = ledstate; 5287f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 5297f540ab5SChristophe Fergeau } 5307f540ab5SChristophe Fergeau 5310e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 5320e43e99cSbellard { 5335edab03dSDon Koch trace_ps2_reset_keyboard(s); 5340e43e99cSbellard s->scan_enabled = 1; 535e7d93956Saurel32 s->scancode_set = 2; 5366e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 5377f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 5380e43e99cSbellard } 5390e43e99cSbellard 5400e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 5410e43e99cSbellard { 5420e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 5430e43e99cSbellard 5445edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 5450e43e99cSbellard switch(s->common.write_cmd) { 5460e43e99cSbellard default: 5470e43e99cSbellard case -1: 5480e43e99cSbellard switch(val) { 5490e43e99cSbellard case 0x00: 5500e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5510e43e99cSbellard break; 5520e43e99cSbellard case 0x05: 5530e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_RESEND); 5540e43e99cSbellard break; 5550e43e99cSbellard case KBD_CMD_GET_ID: 556e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 55735c4d671Saurel32 if (s->translate) 5587abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 5597abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5607abe7eb2SGeoffrey McRae KBD_REPLY_ID, 5617abe7eb2SGeoffrey McRae 0x41); 56235c4d671Saurel32 else 5637abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 5647abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5657abe7eb2SGeoffrey McRae KBD_REPLY_ID, 5667abe7eb2SGeoffrey McRae 0x83); 5670e43e99cSbellard break; 5680e43e99cSbellard case KBD_CMD_ECHO: 5690e43e99cSbellard ps2_queue(&s->common, KBD_CMD_ECHO); 5700e43e99cSbellard break; 5710e43e99cSbellard case KBD_CMD_ENABLE: 5720e43e99cSbellard s->scan_enabled = 1; 5730e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5740e43e99cSbellard break; 575e7d93956Saurel32 case KBD_CMD_SCANCODE: 5760e43e99cSbellard case KBD_CMD_SET_LEDS: 5770e43e99cSbellard case KBD_CMD_SET_RATE: 578*c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 5790e43e99cSbellard s->common.write_cmd = val; 5800e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5810e43e99cSbellard break; 5820e43e99cSbellard case KBD_CMD_RESET_DISABLE: 5830e43e99cSbellard ps2_reset_keyboard(s); 5840e43e99cSbellard s->scan_enabled = 0; 5850e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5860e43e99cSbellard break; 5870e43e99cSbellard case KBD_CMD_RESET_ENABLE: 5880e43e99cSbellard ps2_reset_keyboard(s); 5890e43e99cSbellard s->scan_enabled = 1; 5900e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5910e43e99cSbellard break; 5920e43e99cSbellard case KBD_CMD_RESET: 5930e43e99cSbellard ps2_reset_keyboard(s); 5947abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 5957abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5967abe7eb2SGeoffrey McRae KBD_REPLY_POR); 5970e43e99cSbellard break; 598*c56b6209SSven Schnelle case KBD_CMD_SET_TYPEMATIC: 599*c56b6209SSven Schnelle ps2_queue(&s->common, KBD_REPLY_ACK); 600*c56b6209SSven Schnelle break; 6010e43e99cSbellard default: 60206b3611fSHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 6030e43e99cSbellard break; 6040e43e99cSbellard } 6050e43e99cSbellard break; 606*c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 607*c56b6209SSven Schnelle ps2_queue(&s->common, KBD_REPLY_ACK); 608*c56b6209SSven Schnelle s->common.write_cmd = -1; 609*c56b6209SSven Schnelle break; 610e7d93956Saurel32 case KBD_CMD_SCANCODE: 611e7d93956Saurel32 if (val == 0) { 6127abe7eb2SGeoffrey McRae if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) { 6134df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_ACK); 61457d5c005SHervé Poussineau ps2_put_keycode(s, s->scancode_set); 6157abe7eb2SGeoffrey McRae } 6164df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 617e7d93956Saurel32 s->scancode_set = val; 618e7d93956Saurel32 ps2_queue(&s->common, KBD_REPLY_ACK); 6194df23b64SHervé Poussineau } else { 6204df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 621e7d93956Saurel32 } 622e7d93956Saurel32 s->common.write_cmd = -1; 623e7d93956Saurel32 break; 6240e43e99cSbellard case KBD_CMD_SET_LEDS: 6257f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 6260e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6270e43e99cSbellard s->common.write_cmd = -1; 6280e43e99cSbellard break; 6290e43e99cSbellard case KBD_CMD_SET_RATE: 6300e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6310e43e99cSbellard s->common.write_cmd = -1; 6320e43e99cSbellard break; 6330e43e99cSbellard } 6340e43e99cSbellard } 6350e43e99cSbellard 636f94f5d71Spbrook /* Set the scancode translation mode. 637f94f5d71Spbrook 0 = raw scancodes. 638f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 639f94f5d71Spbrook 640f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 641f94f5d71Spbrook { 642f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 6435edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 644f94f5d71Spbrook s->translate = mode; 645f94f5d71Spbrook } 646f94f5d71Spbrook 6477abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 6480e43e99cSbellard { 6497abe7eb2SGeoffrey McRae const int needed = 3 + (s->mouse_type - 2); 6500e43e99cSbellard unsigned int b; 6510e43e99cSbellard int dx1, dy1, dz1; 6520e43e99cSbellard 6537abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { 6547abe7eb2SGeoffrey McRae return 0; 6557abe7eb2SGeoffrey McRae } 6567abe7eb2SGeoffrey McRae 6570e43e99cSbellard dx1 = s->mouse_dx; 6580e43e99cSbellard dy1 = s->mouse_dy; 6590e43e99cSbellard dz1 = s->mouse_dz; 6600e43e99cSbellard /* XXX: increase range to 8 bits ? */ 6610e43e99cSbellard if (dx1 > 127) 6620e43e99cSbellard dx1 = 127; 6630e43e99cSbellard else if (dx1 < -127) 6640e43e99cSbellard dx1 = -127; 6650e43e99cSbellard if (dy1 > 127) 6660e43e99cSbellard dy1 = 127; 6670e43e99cSbellard else if (dy1 < -127) 6680e43e99cSbellard dy1 = -127; 6690e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 6707abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 6717abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dx1 & 0xff); 6727abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dy1 & 0xff); 6730e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 6740e43e99cSbellard switch(s->mouse_type) { 6750e43e99cSbellard default: 6760e43e99cSbellard break; 6770e43e99cSbellard case 3: 6780e43e99cSbellard if (dz1 > 127) 6790e43e99cSbellard dz1 = 127; 6800e43e99cSbellard else if (dz1 < -127) 6810e43e99cSbellard dz1 = -127; 6827abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dz1 & 0xff); 6830e43e99cSbellard break; 6840e43e99cSbellard case 4: 6850e43e99cSbellard if (dz1 > 7) 6860e43e99cSbellard dz1 = 7; 6870e43e99cSbellard else if (dz1 < -7) 6880e43e99cSbellard dz1 = -7; 6890e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 6907abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 6910e43e99cSbellard break; 6920e43e99cSbellard } 6930e43e99cSbellard 6947abe7eb2SGeoffrey McRae ps2_raise_irq(&s->common); 6957abe7eb2SGeoffrey McRae 6965edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 6970e43e99cSbellard /* update deltas */ 6980e43e99cSbellard s->mouse_dx -= dx1; 6990e43e99cSbellard s->mouse_dy -= dy1; 7000e43e99cSbellard s->mouse_dz -= dz1; 7017abe7eb2SGeoffrey McRae 7027abe7eb2SGeoffrey McRae return 1; 7030e43e99cSbellard } 7040e43e99cSbellard 7052a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 7062a766d29SGerd Hoffmann InputEvent *evt) 7070e43e99cSbellard { 7087fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 7098b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 7108b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 7118b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 7128b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 7138b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 7142a766d29SGerd Hoffmann }; 7152a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 716b5a1b443SEric Blake InputMoveEvent *move; 717b5a1b443SEric Blake InputBtnEvent *btn; 7180e43e99cSbellard 7190e43e99cSbellard /* check if deltas are recorded when disabled */ 7200e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 7210e43e99cSbellard return; 7220e43e99cSbellard 723568c73a4SEric Blake switch (evt->type) { 7242a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 72532bafa8fSEric Blake move = evt->u.rel.data; 726b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 727b5a1b443SEric Blake s->mouse_dx += move->value; 728b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 729b5a1b443SEric Blake s->mouse_dy -= move->value; 7302a766d29SGerd Hoffmann } 7312a766d29SGerd Hoffmann break; 7320e43e99cSbellard 7332a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 73432bafa8fSEric Blake btn = evt->u.btn.data; 735b5a1b443SEric Blake if (btn->down) { 736b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 737b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 7382a766d29SGerd Hoffmann s->mouse_dz--; 739b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 7402a766d29SGerd Hoffmann s->mouse_dz++; 7412a766d29SGerd Hoffmann } 7422a766d29SGerd Hoffmann } else { 743b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 7442a766d29SGerd Hoffmann } 7452a766d29SGerd Hoffmann break; 7462a766d29SGerd Hoffmann 7472a766d29SGerd Hoffmann default: 7482a766d29SGerd Hoffmann /* keep gcc happy */ 7492a766d29SGerd Hoffmann break; 7502a766d29SGerd Hoffmann } 751fd214d18SGerd Hoffmann } 752fd214d18SGerd Hoffmann 7532a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 7542a766d29SGerd Hoffmann { 7552a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 7562a766d29SGerd Hoffmann 757143c04c7SGeoffrey McRae /* do not sync while disabled to prevent stream corruption */ 758143c04c7SGeoffrey McRae if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 759143c04c7SGeoffrey McRae return; 760143c04c7SGeoffrey McRae } 761143c04c7SGeoffrey McRae 7622a766d29SGerd Hoffmann if (s->mouse_buttons) { 763fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 7642a766d29SGerd Hoffmann } 7652858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 7660e43e99cSbellard /* if not remote, send event. Multiple events are sent if 7670e43e99cSbellard too big deltas */ 7687abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 7690e43e99cSbellard if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 7700e43e99cSbellard break; 7710e43e99cSbellard } 7720e43e99cSbellard } 7730e43e99cSbellard } 7740e43e99cSbellard 775548df2acSths void ps2_mouse_fake_event(void *opaque) 776548df2acSths { 7772a766d29SGerd Hoffmann PS2MouseState *s = opaque; 7785edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 7792a766d29SGerd Hoffmann s->mouse_dx++; 7802a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 781548df2acSths } 782548df2acSths 7830e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 7840e43e99cSbellard { 7850e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 7865edab03dSDon Koch 7875edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 7880e43e99cSbellard #ifdef DEBUG_MOUSE 7890e43e99cSbellard printf("kbd: write mouse 0x%02x\n", val); 7900e43e99cSbellard #endif 7910e43e99cSbellard switch(s->common.write_cmd) { 7920e43e99cSbellard default: 7930e43e99cSbellard case -1: 7940e43e99cSbellard /* mouse command */ 7950e43e99cSbellard if (s->mouse_wrap) { 7960e43e99cSbellard if (val == AUX_RESET_WRAP) { 7970e43e99cSbellard s->mouse_wrap = 0; 7980e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 7990e43e99cSbellard return; 8000e43e99cSbellard } else if (val != AUX_RESET) { 8010e43e99cSbellard ps2_queue(&s->common, val); 8020e43e99cSbellard return; 8030e43e99cSbellard } 8040e43e99cSbellard } 8050e43e99cSbellard switch(val) { 8060e43e99cSbellard case AUX_SET_SCALE11: 8070e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 8080e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8090e43e99cSbellard break; 8100e43e99cSbellard case AUX_SET_SCALE21: 8110e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 8120e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8130e43e99cSbellard break; 8140e43e99cSbellard case AUX_SET_STREAM: 8150e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 8160e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8170e43e99cSbellard break; 8180e43e99cSbellard case AUX_SET_WRAP: 8190e43e99cSbellard s->mouse_wrap = 1; 8200e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8210e43e99cSbellard break; 8220e43e99cSbellard case AUX_SET_REMOTE: 8230e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 8240e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8250e43e99cSbellard break; 8260e43e99cSbellard case AUX_GET_TYPE: 8277abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 8287abe7eb2SGeoffrey McRae AUX_ACK, 8297abe7eb2SGeoffrey McRae s->mouse_type); 8300e43e99cSbellard break; 8310e43e99cSbellard case AUX_SET_RES: 8320e43e99cSbellard case AUX_SET_SAMPLE: 8330e43e99cSbellard s->common.write_cmd = val; 8340e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8350e43e99cSbellard break; 8360e43e99cSbellard case AUX_GET_SCALE: 8377abe7eb2SGeoffrey McRae ps2_queue_4(&s->common, 8387abe7eb2SGeoffrey McRae AUX_ACK, 8397abe7eb2SGeoffrey McRae s->mouse_status, 8407abe7eb2SGeoffrey McRae s->mouse_resolution, 8417abe7eb2SGeoffrey McRae s->mouse_sample_rate); 8420e43e99cSbellard break; 8430e43e99cSbellard case AUX_POLL: 8440e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8450e43e99cSbellard ps2_mouse_send_packet(s); 8460e43e99cSbellard break; 8470e43e99cSbellard case AUX_ENABLE_DEV: 8480e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 8490e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8500e43e99cSbellard break; 8510e43e99cSbellard case AUX_DISABLE_DEV: 8520e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 8530e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8540e43e99cSbellard break; 8550e43e99cSbellard case AUX_SET_DEFAULT: 8560e43e99cSbellard s->mouse_sample_rate = 100; 8570e43e99cSbellard s->mouse_resolution = 2; 8580e43e99cSbellard s->mouse_status = 0; 8590e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8600e43e99cSbellard break; 8610e43e99cSbellard case AUX_RESET: 8620e43e99cSbellard s->mouse_sample_rate = 100; 8630e43e99cSbellard s->mouse_resolution = 2; 8640e43e99cSbellard s->mouse_status = 0; 8650e43e99cSbellard s->mouse_type = 0; 866143c04c7SGeoffrey McRae ps2_reset_queue(&s->common); 8677abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 8687abe7eb2SGeoffrey McRae AUX_ACK, 8697abe7eb2SGeoffrey McRae 0xaa, 8707abe7eb2SGeoffrey McRae s->mouse_type); 8710e43e99cSbellard break; 8720e43e99cSbellard default: 8730e43e99cSbellard break; 8740e43e99cSbellard } 8750e43e99cSbellard break; 8760e43e99cSbellard case AUX_SET_SAMPLE: 8770e43e99cSbellard s->mouse_sample_rate = val; 8780e43e99cSbellard /* detect IMPS/2 or IMEX */ 8790e43e99cSbellard switch(s->mouse_detect_state) { 8800e43e99cSbellard default: 8810e43e99cSbellard case 0: 8820e43e99cSbellard if (val == 200) 8830e43e99cSbellard s->mouse_detect_state = 1; 8840e43e99cSbellard break; 8850e43e99cSbellard case 1: 8860e43e99cSbellard if (val == 100) 8870e43e99cSbellard s->mouse_detect_state = 2; 8880e43e99cSbellard else if (val == 200) 8890e43e99cSbellard s->mouse_detect_state = 3; 8900e43e99cSbellard else 8910e43e99cSbellard s->mouse_detect_state = 0; 8920e43e99cSbellard break; 8930e43e99cSbellard case 2: 8940e43e99cSbellard if (val == 80) 8950e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 8960e43e99cSbellard s->mouse_detect_state = 0; 8970e43e99cSbellard break; 8980e43e99cSbellard case 3: 8990e43e99cSbellard if (val == 80) 9000e43e99cSbellard s->mouse_type = 4; /* IMEX */ 9010e43e99cSbellard s->mouse_detect_state = 0; 9020e43e99cSbellard break; 9030e43e99cSbellard } 9040e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9050e43e99cSbellard s->common.write_cmd = -1; 9060e43e99cSbellard break; 9070e43e99cSbellard case AUX_SET_RES: 9080e43e99cSbellard s->mouse_resolution = val; 9090e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9100e43e99cSbellard s->common.write_cmd = -1; 9110e43e99cSbellard break; 9120e43e99cSbellard } 9130e43e99cSbellard } 9140e43e99cSbellard 915ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 9160e43e99cSbellard { 9170e43e99cSbellard s->write_cmd = -1; 918954ee55bSGerd Hoffmann ps2_reset_queue(s); 919deeccef3Saliguori s->update_irq(s->update_arg, 0); 9200e43e99cSbellard } 9210e43e99cSbellard 9222858ab09SGonglei static void ps2_common_post_load(PS2State *s) 9232858ab09SGonglei { 9242858ab09SGonglei PS2Queue *q = &s->queue; 925802cbcb7SPrasad J Pandit uint8_t i, size; 926802cbcb7SPrasad J Pandit uint8_t tmp_data[PS2_QUEUE_SIZE]; 9272858ab09SGonglei 9282858ab09SGonglei /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ 929a1f2ed2aSPavel Dovgalyuk size = q->count; 930a1f2ed2aSPavel Dovgalyuk if (q->count < 0) { 931a1f2ed2aSPavel Dovgalyuk size = 0; 932a1f2ed2aSPavel Dovgalyuk } else if (q->count > PS2_QUEUE_SIZE) { 933a1f2ed2aSPavel Dovgalyuk size = PS2_QUEUE_SIZE; 934a1f2ed2aSPavel Dovgalyuk } 9352858ab09SGonglei 9362858ab09SGonglei /* move the queue elements to the start of data array */ 9372858ab09SGonglei for (i = 0; i < size; i++) { 938802cbcb7SPrasad J Pandit if (q->rptr < 0 || q->rptr >= sizeof(q->data)) { 9392858ab09SGonglei q->rptr = 0; 9402858ab09SGonglei } 941802cbcb7SPrasad J Pandit tmp_data[i] = q->data[q->rptr++]; 9422858ab09SGonglei } 9432858ab09SGonglei memcpy(q->data, tmp_data, size); 944802cbcb7SPrasad J Pandit 9452858ab09SGonglei /* reset rptr/wptr/count */ 9462858ab09SGonglei q->rptr = 0; 947b55a06dfSliujunjie q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size; 9482858ab09SGonglei q->count = size; 9492858ab09SGonglei } 9502858ab09SGonglei 951ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 952ef74679aSDinesh Subhraveti { 953ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 954ef74679aSDinesh Subhraveti 9555edab03dSDon Koch trace_ps2_kbd_reset(opaque); 956ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 957d2e550a8SHervé Poussineau s->scan_enabled = 1; 958ef74679aSDinesh Subhraveti s->translate = 0; 959089adafdSHervé Poussineau s->scancode_set = 2; 960620775d1SDaniel P. Berrange s->modifiers = 0; 961ef74679aSDinesh Subhraveti } 962ef74679aSDinesh Subhraveti 963ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 964ef74679aSDinesh Subhraveti { 965ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 966ef74679aSDinesh Subhraveti 9675edab03dSDon Koch trace_ps2_mouse_reset(opaque); 968ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 969ef74679aSDinesh Subhraveti s->mouse_status = 0; 970ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 971ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 972ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 973ef74679aSDinesh Subhraveti s->mouse_type = 0; 974ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 975ef74679aSDinesh Subhraveti s->mouse_dx = 0; 976ef74679aSDinesh Subhraveti s->mouse_dy = 0; 977ef74679aSDinesh Subhraveti s->mouse_dz = 0; 978ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 979ef74679aSDinesh Subhraveti } 980ef74679aSDinesh Subhraveti 981b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 982b31442c3SJuan Quintela .name = "PS2 Common State", 983b31442c3SJuan Quintela .version_id = 3, 984b31442c3SJuan Quintela .minimum_version_id = 2, 985b31442c3SJuan Quintela .fields = (VMStateField[]) { 986b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 987b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 988b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 989b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 990b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 991b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 9927783e9f0Spbrook } 993b31442c3SJuan Quintela }; 9947783e9f0Spbrook 9957f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 9967f540ab5SChristophe Fergeau { 9977f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 9987f540ab5SChristophe Fergeau 9997f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 10007f540ab5SChristophe Fergeau } 10017f540ab5SChristophe Fergeau 10027f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 10037f540ab5SChristophe Fergeau { 10047f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 10057f540ab5SChristophe Fergeau 10067f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 10077f540ab5SChristophe Fergeau return 0; 10087f540ab5SChristophe Fergeau } 10097f540ab5SChristophe Fergeau 10107f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 10117f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 10127f540ab5SChristophe Fergeau .version_id = 3, 10137f540ab5SChristophe Fergeau .minimum_version_id = 2, 10147f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 10155cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 10167f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 10177f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 10187f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 10197f540ab5SChristophe Fergeau } 10207f540ab5SChristophe Fergeau }; 10217f540ab5SChristophe Fergeau 102257d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 102357d5c005SHervé Poussineau { 102457d5c005SHervé Poussineau PS2KbdState *s = opaque; 102557d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 102657d5c005SHervé Poussineau } 102757d5c005SHervé Poussineau 102857d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 102957d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 103057d5c005SHervé Poussineau .version_id = 1, 103157d5c005SHervé Poussineau .minimum_version_id = 1, 103257d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 103357d5c005SHervé Poussineau .fields = (VMStateField[]) { 103457d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 103557d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 103657d5c005SHervé Poussineau } 103757d5c005SHervé Poussineau }; 103857d5c005SHervé Poussineau 1039db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 10400e43e99cSbellard { 10410e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 10422858ab09SGonglei PS2State *ps2 = &s->common; 10430e43e99cSbellard 1044db596c53SJuan Quintela if (version_id == 2) 1045e7d93956Saurel32 s->scancode_set=2; 10462858ab09SGonglei 10472858ab09SGonglei ps2_common_post_load(ps2); 10482858ab09SGonglei 10490e43e99cSbellard return 0; 10500e43e99cSbellard } 10510e43e99cSbellard 105244b1ff31SDr. David Alan Gilbert static int ps2_kbd_pre_save(void *opaque) 10532858ab09SGonglei { 10542858ab09SGonglei PS2KbdState *s = (PS2KbdState *)opaque; 10552858ab09SGonglei PS2State *ps2 = &s->common; 10562858ab09SGonglei 10572858ab09SGonglei ps2_common_post_load(ps2); 105844b1ff31SDr. David Alan Gilbert 105944b1ff31SDr. David Alan Gilbert return 0; 10602858ab09SGonglei } 10612858ab09SGonglei 1062b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 1063b31442c3SJuan Quintela .name = "ps2kbd", 1064b31442c3SJuan Quintela .version_id = 3, 1065db596c53SJuan Quintela .minimum_version_id = 2, 1066db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 10672858ab09SGonglei .pre_save = ps2_kbd_pre_save, 1068b31442c3SJuan Quintela .fields = (VMStateField[]) { 1069b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 1070b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 1071b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 1072b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 1073b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 10747f540ab5SChristophe Fergeau }, 10755cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 10765cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 107757d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 10785cd8cadaSJuan Quintela NULL 10790e43e99cSbellard } 1080b31442c3SJuan Quintela }; 1081b31442c3SJuan Quintela 10822858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 10832858ab09SGonglei { 10842858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 10852858ab09SGonglei PS2State *ps2 = &s->common; 10862858ab09SGonglei 10872858ab09SGonglei ps2_common_post_load(ps2); 10882858ab09SGonglei 10892858ab09SGonglei return 0; 10902858ab09SGonglei } 10912858ab09SGonglei 109244b1ff31SDr. David Alan Gilbert static int ps2_mouse_pre_save(void *opaque) 10932858ab09SGonglei { 10942858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 10952858ab09SGonglei PS2State *ps2 = &s->common; 10962858ab09SGonglei 10972858ab09SGonglei ps2_common_post_load(ps2); 109844b1ff31SDr. David Alan Gilbert 109944b1ff31SDr. David Alan Gilbert return 0; 11002858ab09SGonglei } 11012858ab09SGonglei 1102b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1103b31442c3SJuan Quintela .name = "ps2mouse", 1104b31442c3SJuan Quintela .version_id = 2, 1105b31442c3SJuan Quintela .minimum_version_id = 2, 11062858ab09SGonglei .post_load = ps2_mouse_post_load, 11072858ab09SGonglei .pre_save = ps2_mouse_pre_save, 1108b31442c3SJuan Quintela .fields = (VMStateField[]) { 1109b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 1110b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1111b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1112b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1113b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1114b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1115b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1116b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1117b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1118b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1119b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1120b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1121b31442c3SJuan Quintela } 1122b31442c3SJuan Quintela }; 11230e43e99cSbellard 112466e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 112566e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 112666e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 112766e6536eSGerd Hoffmann .event = ps2_keyboard_event, 112866e6536eSGerd Hoffmann }; 112966e6536eSGerd Hoffmann 11300e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 11310e43e99cSbellard { 11327267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 11330e43e99cSbellard 11345edab03dSDon Koch trace_ps2_kbd_init(s); 11350e43e99cSbellard s->common.update_irq = update_irq; 11360e43e99cSbellard s->common.update_arg = update_arg; 1137e7d93956Saurel32 s->scancode_set = 2; 11380be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 113966e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 114066e6536eSGerd Hoffmann &ps2_keyboard_handler); 1141ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 11420e43e99cSbellard return s; 11430e43e99cSbellard } 11440e43e99cSbellard 11452a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 11462a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 11472a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 11482a766d29SGerd Hoffmann .event = ps2_mouse_event, 11492a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 11502a766d29SGerd Hoffmann }; 11512a766d29SGerd Hoffmann 11520e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 11530e43e99cSbellard { 11547267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 11550e43e99cSbellard 11565edab03dSDon Koch trace_ps2_mouse_init(s); 11570e43e99cSbellard s->common.update_irq = update_irq; 11580e43e99cSbellard s->common.update_arg = update_arg; 11590be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 11602a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 11612a766d29SGerd Hoffmann &ps2_mouse_handler); 1162ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 11630e43e99cSbellard return s; 11640e43e99cSbellard } 1165