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 /* Keyboard Commands */ 370e43e99cSbellard #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ 380e43e99cSbellard #define KBD_CMD_ECHO 0xEE 39e7d93956Saurel32 #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ 400e43e99cSbellard #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ 410e43e99cSbellard #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ 420e43e99cSbellard #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ 430e43e99cSbellard #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ 440e43e99cSbellard #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ 450e43e99cSbellard #define KBD_CMD_RESET 0xFF /* Reset */ 46c56b6209SSven Schnelle #define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */ 47c56b6209SSven Schnelle #define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */ 480e43e99cSbellard 490e43e99cSbellard /* Keyboard Replies */ 500e43e99cSbellard #define KBD_REPLY_POR 0xAA /* Power on reset */ 5135c4d671Saurel32 #define KBD_REPLY_ID 0xAB /* Keyboard ID */ 520e43e99cSbellard #define KBD_REPLY_ACK 0xFA /* Command ACK */ 530e43e99cSbellard #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ 540e43e99cSbellard 550e43e99cSbellard /* Mouse Commands */ 560e43e99cSbellard #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ 570e43e99cSbellard #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ 580e43e99cSbellard #define AUX_SET_RES 0xE8 /* Set resolution */ 590e43e99cSbellard #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ 600e43e99cSbellard #define AUX_SET_STREAM 0xEA /* Set stream mode */ 610e43e99cSbellard #define AUX_POLL 0xEB /* Poll */ 620e43e99cSbellard #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ 630e43e99cSbellard #define AUX_SET_WRAP 0xEE /* Set wrap mode */ 640e43e99cSbellard #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ 650e43e99cSbellard #define AUX_GET_TYPE 0xF2 /* Get type */ 660e43e99cSbellard #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ 670e43e99cSbellard #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ 680e43e99cSbellard #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ 690e43e99cSbellard #define AUX_SET_DEFAULT 0xF6 700e43e99cSbellard #define AUX_RESET 0xFF /* Reset aux device */ 710e43e99cSbellard #define AUX_ACK 0xFA /* Command byte ACK. */ 720e43e99cSbellard 730e43e99cSbellard #define MOUSE_STATUS_REMOTE 0x40 740e43e99cSbellard #define MOUSE_STATUS_ENABLED 0x20 750e43e99cSbellard #define MOUSE_STATUS_SCALE21 0x10 760e43e99cSbellard 77*47db2432SVolker Rümelin /* 78*47db2432SVolker Rümelin * PS/2 buffer size. Keep 256 bytes for compatibility with 79*47db2432SVolker Rümelin * older QEMU versions. 80*47db2432SVolker Rümelin */ 81*47db2432SVolker Rümelin #define PS2_BUFFER_SIZE 256 82*47db2432SVolker Rümelin #define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */ 830e43e99cSbellard 84620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */ 85620775d1SDaniel P. Berrange #define MOD_CTRL_L (1 << 0) 86620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1) 87620775d1SDaniel P. Berrange #define MOD_ALT_L (1 << 2) 88620775d1SDaniel P. Berrange #define MOD_CTRL_R (1 << 3) 89620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4) 90620775d1SDaniel P. Berrange #define MOD_ALT_R (1 << 5) 91620775d1SDaniel P. Berrange 920e43e99cSbellard typedef struct { 93*47db2432SVolker Rümelin uint8_t data[PS2_BUFFER_SIZE]; 940e43e99cSbellard int rptr, wptr, count; 950e43e99cSbellard } PS2Queue; 960e43e99cSbellard 978498bb8dSGerd Hoffmann struct PS2State { 980e43e99cSbellard PS2Queue queue; 990e43e99cSbellard int32_t write_cmd; 1000e43e99cSbellard void (*update_irq)(void *, int); 1010e43e99cSbellard void *update_arg; 1028498bb8dSGerd Hoffmann }; 1030e43e99cSbellard 1040e43e99cSbellard typedef struct { 1050e43e99cSbellard PS2State common; 1060e43e99cSbellard int scan_enabled; 107f94f5d71Spbrook int translate; 108e7d93956Saurel32 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ 1097f540ab5SChristophe Fergeau int ledstate; 11057d5c005SHervé Poussineau bool need_high_bit; 111620775d1SDaniel P. Berrange unsigned int modifiers; /* bitmask of MOD_* constants above */ 1120e43e99cSbellard } PS2KbdState; 1130e43e99cSbellard 1140e43e99cSbellard typedef struct { 1150e43e99cSbellard PS2State common; 1160e43e99cSbellard uint8_t mouse_status; 1170e43e99cSbellard uint8_t mouse_resolution; 1180e43e99cSbellard uint8_t mouse_sample_rate; 1190e43e99cSbellard uint8_t mouse_wrap; 1200e43e99cSbellard uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ 1210e43e99cSbellard uint8_t mouse_detect_state; 1220e43e99cSbellard int mouse_dx; /* current values, needed for 'poll' mode */ 1230e43e99cSbellard int mouse_dy; 1240e43e99cSbellard int mouse_dz; 1250e43e99cSbellard uint8_t mouse_buttons; 1260e43e99cSbellard } PS2MouseState; 1270e43e99cSbellard 12857d5c005SHervé Poussineau static uint8_t translate_table[256] = { 12957d5c005SHervé Poussineau 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 13057d5c005SHervé Poussineau 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 13157d5c005SHervé Poussineau 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 13257d5c005SHervé Poussineau 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 13357d5c005SHervé Poussineau 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 13457d5c005SHervé Poussineau 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 13557d5c005SHervé Poussineau 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 13657d5c005SHervé Poussineau 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 13757d5c005SHervé Poussineau 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 13857d5c005SHervé Poussineau 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 13957d5c005SHervé Poussineau 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 14057d5c005SHervé Poussineau 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 14157d5c005SHervé Poussineau 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 14257d5c005SHervé Poussineau 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 14357d5c005SHervé Poussineau 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 14457d5c005SHervé Poussineau 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 14557d5c005SHervé Poussineau 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 14657d5c005SHervé Poussineau 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 14757d5c005SHervé Poussineau 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 14857d5c005SHervé Poussineau 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 14957d5c005SHervé Poussineau 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 15057d5c005SHervé Poussineau 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 15157d5c005SHervé Poussineau 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 15257d5c005SHervé Poussineau 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 15357d5c005SHervé Poussineau 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 15457d5c005SHervé Poussineau 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 15557d5c005SHervé Poussineau 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 15657d5c005SHervé Poussineau 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 15757d5c005SHervé Poussineau 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 15857d5c005SHervé Poussineau 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 15957d5c005SHervé Poussineau 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 16057d5c005SHervé Poussineau 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 16157d5c005SHervé Poussineau }; 16257d5c005SHervé Poussineau 163620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key) 164620775d1SDaniel P. Berrange { 165620775d1SDaniel P. Berrange switch (key) { 166620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL: 167620775d1SDaniel P. Berrange return MOD_CTRL_L; 168620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL_R: 169620775d1SDaniel P. Berrange return MOD_CTRL_R; 170620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT: 171620775d1SDaniel P. Berrange return MOD_SHIFT_L; 172620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT_R: 173620775d1SDaniel P. Berrange return MOD_SHIFT_R; 174620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT: 175620775d1SDaniel P. Berrange return MOD_ALT_L; 176620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT_R: 177620775d1SDaniel P. Berrange return MOD_ALT_R; 178620775d1SDaniel P. Berrange default: 179620775d1SDaniel P. Berrange return 0; 180620775d1SDaniel P. Berrange } 181620775d1SDaniel P. Berrange } 182620775d1SDaniel P. Berrange 183954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s) 184954ee55bSGerd Hoffmann { 185954ee55bSGerd Hoffmann PS2Queue *q = &s->queue; 186954ee55bSGerd Hoffmann 187954ee55bSGerd Hoffmann q->rptr = 0; 188954ee55bSGerd Hoffmann q->wptr = 0; 189954ee55bSGerd Hoffmann q->count = 0; 190954ee55bSGerd Hoffmann } 191954ee55bSGerd Hoffmann 1922a6505b0SSven Schnelle int ps2_queue_empty(PS2State *s) 1932a6505b0SSven Schnelle { 1942a6505b0SSven Schnelle return s->queue.count == 0; 1952a6505b0SSven Schnelle } 1962a6505b0SSven Schnelle 1977abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 1980e43e99cSbellard { 1990e43e99cSbellard PS2Queue *q = &s->queue; 2000e43e99cSbellard 2017abe7eb2SGeoffrey McRae if (q->count == PS2_QUEUE_SIZE) { 2020e43e99cSbellard return; 2037abe7eb2SGeoffrey McRae } 2047abe7eb2SGeoffrey McRae 2050e43e99cSbellard q->data[q->wptr] = b; 206*47db2432SVolker Rümelin if (++q->wptr == PS2_BUFFER_SIZE) { 2070e43e99cSbellard q->wptr = 0; 208*47db2432SVolker Rümelin } 2090e43e99cSbellard q->count++; 2107abe7eb2SGeoffrey McRae } 2117abe7eb2SGeoffrey McRae 2127abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s) 2137abe7eb2SGeoffrey McRae { 2147abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2157abe7eb2SGeoffrey McRae } 2167abe7eb2SGeoffrey McRae 2177abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 2187abe7eb2SGeoffrey McRae { 2197704bb02SVolker Rümelin if (PS2_QUEUE_SIZE - s->queue.count < 1) { 2207704bb02SVolker Rümelin return; 2217704bb02SVolker Rümelin } 2227704bb02SVolker Rümelin 2237abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 22496376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2257abe7eb2SGeoffrey McRae } 2267abe7eb2SGeoffrey McRae 2277abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 2287abe7eb2SGeoffrey McRae { 2297abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 2307abe7eb2SGeoffrey McRae return; 2317abe7eb2SGeoffrey McRae } 2327abe7eb2SGeoffrey McRae 2337abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2347abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 23596376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2367abe7eb2SGeoffrey McRae } 2377abe7eb2SGeoffrey McRae 2387abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 2397abe7eb2SGeoffrey McRae { 2407abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 2417abe7eb2SGeoffrey McRae return; 2427abe7eb2SGeoffrey McRae } 2437abe7eb2SGeoffrey McRae 2447abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2457abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2467abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 24796376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2487abe7eb2SGeoffrey McRae } 2497abe7eb2SGeoffrey McRae 2507abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 2517abe7eb2SGeoffrey McRae { 2527abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 2537abe7eb2SGeoffrey McRae return; 2547abe7eb2SGeoffrey McRae } 2557abe7eb2SGeoffrey McRae 2567abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2577abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2587abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2597abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 26096376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2610e43e99cSbellard } 2620e43e99cSbellard 26357d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 2640e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 2650e43e99cSbellard { 266f94f5d71Spbrook PS2KbdState *s = opaque; 267e7d93956Saurel32 2685edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 269fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 27057d5c005SHervé Poussineau 27157d5c005SHervé Poussineau if (s->translate) { 27257d5c005SHervé Poussineau if (keycode == 0xf0) { 27357d5c005SHervé Poussineau s->need_high_bit = true; 27457d5c005SHervé Poussineau } else if (s->need_high_bit) { 27557d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode] | 0x80); 27657d5c005SHervé Poussineau s->need_high_bit = false; 27757d5c005SHervé Poussineau } else { 27857d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode]); 2797096a96dSRoy Tam } 28057d5c005SHervé Poussineau } else { 2810e43e99cSbellard ps2_queue(&s->common, keycode); 2820e43e99cSbellard } 28357d5c005SHervé Poussineau } 2840e43e99cSbellard 28566e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 28666e6536eSGerd Hoffmann InputEvent *evt) 28766e6536eSGerd Hoffmann { 28866e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 28932bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 2908c10e0baSHervé Poussineau int qcode; 291ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 292620775d1SDaniel P. Berrange int mod; 29366e6536eSGerd Hoffmann 294143c04c7SGeoffrey McRae /* do not process events while disabled to prevent stream corruption */ 295143c04c7SGeoffrey McRae if (!s->scan_enabled) { 296143c04c7SGeoffrey McRae return; 297143c04c7SGeoffrey McRae } 298143c04c7SGeoffrey McRae 299fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 3008c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 3018c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 30257d5c005SHervé Poussineau 303620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 304644f66bfSDaniel P. Berrangé trace_ps2_keyboard_event(s, qcode, key->down, mod, 305644f66bfSDaniel P. Berrangé s->modifiers, s->scancode_set, s->translate); 306620775d1SDaniel P. Berrange if (key->down) { 307620775d1SDaniel P. Berrange s->modifiers |= mod; 308620775d1SDaniel P. Berrange } else { 309620775d1SDaniel P. Berrange s->modifiers &= ~mod; 310620775d1SDaniel P. Berrange } 311620775d1SDaniel P. Berrange 3128c10e0baSHervé Poussineau if (s->scancode_set == 1) { 3138c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 31429fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 31529fd23a5SDaniel P. Berrange if (key->down) { 31629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 31729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 31829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 31929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 32029fd23a5SDaniel P. Berrange } 32129fd23a5SDaniel P. Berrange } else { 3228c10e0baSHervé Poussineau if (key->down) { 3238c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3248c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 3258c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 326927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 3278c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 3288c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 3298c10e0baSHervé Poussineau } 33029fd23a5SDaniel P. Berrange } 3318c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 332620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 333620775d1SDaniel P. Berrange if (key->down) { 334620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 335620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 336620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 337620775d1SDaniel P. Berrange } else { 338620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 339620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 340620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 341620775d1SDaniel P. Berrange } 342620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 343620775d1SDaniel P. Berrange if (key->down) { 344620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 345620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 346620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 347620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 348620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 349620775d1SDaniel P. Berrange } else { 350620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 351620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 352620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 353620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 354620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 355620775d1SDaniel P. Berrange } 3568f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 3578f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 3588f63458fSDaniel P. Berrange if (key->down) { 3598f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3608f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 3618f63458fSDaniel P. Berrange } else { 3628f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3638f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 3648f63458fSDaniel P. Berrange } 365620775d1SDaniel P. Berrange } else { 3668c10e0baSHervé Poussineau if (key->down) { 3678c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3688c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 3698c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3708c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 3718c10e0baSHervé Poussineau } else { 3728c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3738c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 3748c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 3758c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 3768c10e0baSHervé Poussineau } 377620775d1SDaniel P. Berrange } 3788c10e0baSHervé Poussineau } else { 379ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset1_len) 380ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 3818c10e0baSHervé Poussineau if (keycode) { 3828c10e0baSHervé Poussineau if (keycode & 0xff00) { 3838c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 3848c10e0baSHervé Poussineau } 3858c10e0baSHervé Poussineau if (!key->down) { 3868c10e0baSHervé Poussineau keycode |= 0x80; 3878c10e0baSHervé Poussineau } 3888c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 3898c10e0baSHervé Poussineau } else { 390ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 391ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 3928c10e0baSHervé Poussineau } 3938c10e0baSHervé Poussineau } 3948c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 3958c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 39629fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 39729fd23a5SDaniel P. Berrange if (key->down) { 39829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 39929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 40029fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 40129fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 40229fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 40329fd23a5SDaniel P. Berrange } 40429fd23a5SDaniel P. Berrange } else { 4058c10e0baSHervé Poussineau if (key->down) { 4068c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4078c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4088c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4098c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4108c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4118c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4128c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4138c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4148c10e0baSHervé Poussineau } 41529fd23a5SDaniel P. Berrange } 4168c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 417620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 418620775d1SDaniel P. Berrange if (key->down) { 419620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 420620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 421620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 422620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 423620775d1SDaniel P. Berrange } else { 424620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 425620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 426620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 427620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 428620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 429620775d1SDaniel P. Berrange } 430620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 431620775d1SDaniel P. Berrange if (key->down) { 432620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 433620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 434620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 435620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 436620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 437620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 438620775d1SDaniel P. Berrange } else { 439620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 440620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 441620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 442620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 443620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 444620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 445620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 446620775d1SDaniel P. Berrange } 4478f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 4488f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 4498f63458fSDaniel P. Berrange if (key->down) { 4508f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4518f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4528f63458fSDaniel P. Berrange } else { 4538f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4548f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 4558f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4568f63458fSDaniel P. Berrange } 457620775d1SDaniel P. Berrange } else { 4588c10e0baSHervé Poussineau if (key->down) { 4598c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4608c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4618c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4628c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4638c10e0baSHervé Poussineau } else { 4648c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4658c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4668c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4678c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4688c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4698c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4708c10e0baSHervé Poussineau } 471620775d1SDaniel P. Berrange } 4728c10e0baSHervé Poussineau } else { 473ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset2_len) 474ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 4758c10e0baSHervé Poussineau if (keycode) { 4768c10e0baSHervé Poussineau if (keycode & 0xff00) { 4778c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4788c10e0baSHervé Poussineau } 4798c10e0baSHervé Poussineau if (!key->down) { 4808c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4818c10e0baSHervé Poussineau } 4828c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 48357d5c005SHervé Poussineau } else { 484ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 485ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 48657d5c005SHervé Poussineau } 48757d5c005SHervé Poussineau } 48857d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 489ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset3_len) 490ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 4918c10e0baSHervé Poussineau if (keycode) { 4928c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 4938c10e0baSHervé Poussineau if (!key->down) { 4948c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 49557d5c005SHervé Poussineau } 49657d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 4978c10e0baSHervé Poussineau } else { 498ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 499ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 5008c10e0baSHervé Poussineau } 50166e6536eSGerd Hoffmann } 50266e6536eSGerd Hoffmann } 50366e6536eSGerd Hoffmann 5048498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 5050e43e99cSbellard { 5060e43e99cSbellard PS2Queue *q; 5070e43e99cSbellard int val, index; 5080e43e99cSbellard 5098498bb8dSGerd Hoffmann trace_ps2_read_data(s); 5100e43e99cSbellard q = &s->queue; 5110e43e99cSbellard if (q->count == 0) { 5120e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 5130e43e99cSbellard (needed for EMM386) */ 5140e43e99cSbellard /* XXX: need a timer to do things correctly */ 5150e43e99cSbellard index = q->rptr - 1; 516*47db2432SVolker Rümelin if (index < 0) { 517*47db2432SVolker Rümelin index = PS2_BUFFER_SIZE - 1; 518*47db2432SVolker Rümelin } 5190e43e99cSbellard val = q->data[index]; 5200e43e99cSbellard } else { 5210e43e99cSbellard val = q->data[q->rptr]; 522*47db2432SVolker Rümelin if (++q->rptr == PS2_BUFFER_SIZE) { 5230e43e99cSbellard q->rptr = 0; 524*47db2432SVolker Rümelin } 5250e43e99cSbellard q->count--; 5260e43e99cSbellard /* reading deasserts IRQ */ 5270e43e99cSbellard s->update_irq(s->update_arg, 0); 5280e43e99cSbellard /* reassert IRQs if data left */ 529cec32524SVolker Rümelin if (q->count) { 530cec32524SVolker Rümelin s->update_irq(s->update_arg, 1); 531cec32524SVolker Rümelin } 5320e43e99cSbellard } 5330e43e99cSbellard return val; 5340e43e99cSbellard } 5350e43e99cSbellard 5367f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 5377f540ab5SChristophe Fergeau { 5385edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 5397f540ab5SChristophe Fergeau s->ledstate = ledstate; 5407f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 5417f540ab5SChristophe Fergeau } 5427f540ab5SChristophe Fergeau 5430e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 5440e43e99cSbellard { 5455edab03dSDon Koch trace_ps2_reset_keyboard(s); 5460e43e99cSbellard s->scan_enabled = 1; 547e7d93956Saurel32 s->scancode_set = 2; 5486e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 5497f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 5500e43e99cSbellard } 5510e43e99cSbellard 5520e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 5530e43e99cSbellard { 5540e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 5550e43e99cSbellard 5565edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 5570e43e99cSbellard switch(s->common.write_cmd) { 5580e43e99cSbellard default: 5590e43e99cSbellard case -1: 5600e43e99cSbellard switch(val) { 5610e43e99cSbellard case 0x00: 5620e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5630e43e99cSbellard break; 5640e43e99cSbellard case 0x05: 5650e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_RESEND); 5660e43e99cSbellard break; 5670e43e99cSbellard case KBD_CMD_GET_ID: 568e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 56935c4d671Saurel32 if (s->translate) 5707abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 5717abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5727abe7eb2SGeoffrey McRae KBD_REPLY_ID, 5737abe7eb2SGeoffrey McRae 0x41); 57435c4d671Saurel32 else 5757abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 5767abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 5777abe7eb2SGeoffrey McRae KBD_REPLY_ID, 5787abe7eb2SGeoffrey McRae 0x83); 5790e43e99cSbellard break; 5800e43e99cSbellard case KBD_CMD_ECHO: 5810e43e99cSbellard ps2_queue(&s->common, KBD_CMD_ECHO); 5820e43e99cSbellard break; 5830e43e99cSbellard case KBD_CMD_ENABLE: 5840e43e99cSbellard s->scan_enabled = 1; 5850e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5860e43e99cSbellard break; 587e7d93956Saurel32 case KBD_CMD_SCANCODE: 5880e43e99cSbellard case KBD_CMD_SET_LEDS: 5890e43e99cSbellard case KBD_CMD_SET_RATE: 590c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 5910e43e99cSbellard s->common.write_cmd = val; 5920e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5930e43e99cSbellard break; 5940e43e99cSbellard case KBD_CMD_RESET_DISABLE: 5950e43e99cSbellard ps2_reset_keyboard(s); 5960e43e99cSbellard s->scan_enabled = 0; 5970e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 5980e43e99cSbellard break; 5990e43e99cSbellard case KBD_CMD_RESET_ENABLE: 6000e43e99cSbellard ps2_reset_keyboard(s); 6010e43e99cSbellard s->scan_enabled = 1; 6020e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6030e43e99cSbellard break; 6040e43e99cSbellard case KBD_CMD_RESET: 6050e43e99cSbellard ps2_reset_keyboard(s); 6067abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 6077abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 6087abe7eb2SGeoffrey McRae KBD_REPLY_POR); 6090e43e99cSbellard break; 610c56b6209SSven Schnelle case KBD_CMD_SET_TYPEMATIC: 611c56b6209SSven Schnelle ps2_queue(&s->common, KBD_REPLY_ACK); 612c56b6209SSven Schnelle break; 6130e43e99cSbellard default: 61406b3611fSHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 6150e43e99cSbellard break; 6160e43e99cSbellard } 6170e43e99cSbellard break; 618c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 619c56b6209SSven Schnelle ps2_queue(&s->common, KBD_REPLY_ACK); 620c56b6209SSven Schnelle s->common.write_cmd = -1; 621c56b6209SSven Schnelle break; 622e7d93956Saurel32 case KBD_CMD_SCANCODE: 623e7d93956Saurel32 if (val == 0) { 6247abe7eb2SGeoffrey McRae if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) { 6254df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_ACK); 62657d5c005SHervé Poussineau ps2_put_keycode(s, s->scancode_set); 6277abe7eb2SGeoffrey McRae } 6284df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 629e7d93956Saurel32 s->scancode_set = val; 630e7d93956Saurel32 ps2_queue(&s->common, KBD_REPLY_ACK); 6314df23b64SHervé Poussineau } else { 6324df23b64SHervé Poussineau ps2_queue(&s->common, KBD_REPLY_RESEND); 633e7d93956Saurel32 } 634e7d93956Saurel32 s->common.write_cmd = -1; 635e7d93956Saurel32 break; 6360e43e99cSbellard case KBD_CMD_SET_LEDS: 6377f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 6380e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6390e43e99cSbellard s->common.write_cmd = -1; 6400e43e99cSbellard break; 6410e43e99cSbellard case KBD_CMD_SET_RATE: 6420e43e99cSbellard ps2_queue(&s->common, KBD_REPLY_ACK); 6430e43e99cSbellard s->common.write_cmd = -1; 6440e43e99cSbellard break; 6450e43e99cSbellard } 6460e43e99cSbellard } 6470e43e99cSbellard 648f94f5d71Spbrook /* Set the scancode translation mode. 649f94f5d71Spbrook 0 = raw scancodes. 650f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 651f94f5d71Spbrook 652f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 653f94f5d71Spbrook { 654f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 6555edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 656f94f5d71Spbrook s->translate = mode; 657f94f5d71Spbrook } 658f94f5d71Spbrook 6597abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 6600e43e99cSbellard { 66176968101SVolker Rümelin /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ 66276968101SVolker Rümelin const int needed = s->mouse_type ? 4 : 3; 6630e43e99cSbellard unsigned int b; 6640e43e99cSbellard int dx1, dy1, dz1; 6650e43e99cSbellard 6667abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { 6677abe7eb2SGeoffrey McRae return 0; 6687abe7eb2SGeoffrey McRae } 6697abe7eb2SGeoffrey McRae 6700e43e99cSbellard dx1 = s->mouse_dx; 6710e43e99cSbellard dy1 = s->mouse_dy; 6720e43e99cSbellard dz1 = s->mouse_dz; 6730e43e99cSbellard /* XXX: increase range to 8 bits ? */ 6740e43e99cSbellard if (dx1 > 127) 6750e43e99cSbellard dx1 = 127; 6760e43e99cSbellard else if (dx1 < -127) 6770e43e99cSbellard dx1 = -127; 6780e43e99cSbellard if (dy1 > 127) 6790e43e99cSbellard dy1 = 127; 6800e43e99cSbellard else if (dy1 < -127) 6810e43e99cSbellard dy1 = -127; 6820e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 6837abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 6847abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dx1 & 0xff); 6857abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dy1 & 0xff); 6860e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 6870e43e99cSbellard switch(s->mouse_type) { 6880e43e99cSbellard default: 6890e43e99cSbellard break; 6900e43e99cSbellard case 3: 6910e43e99cSbellard if (dz1 > 127) 6920e43e99cSbellard dz1 = 127; 6930e43e99cSbellard else if (dz1 < -127) 6940e43e99cSbellard dz1 = -127; 6957abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dz1 & 0xff); 6960e43e99cSbellard break; 6970e43e99cSbellard case 4: 6980e43e99cSbellard if (dz1 > 7) 6990e43e99cSbellard dz1 = 7; 7000e43e99cSbellard else if (dz1 < -7) 7010e43e99cSbellard dz1 = -7; 7020e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 7037abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 7040e43e99cSbellard break; 7050e43e99cSbellard } 7060e43e99cSbellard 7077abe7eb2SGeoffrey McRae ps2_raise_irq(&s->common); 7087abe7eb2SGeoffrey McRae 7095edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 7100e43e99cSbellard /* update deltas */ 7110e43e99cSbellard s->mouse_dx -= dx1; 7120e43e99cSbellard s->mouse_dy -= dy1; 7130e43e99cSbellard s->mouse_dz -= dz1; 7147abe7eb2SGeoffrey McRae 7157abe7eb2SGeoffrey McRae return 1; 7160e43e99cSbellard } 7170e43e99cSbellard 7182a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 7192a766d29SGerd Hoffmann InputEvent *evt) 7200e43e99cSbellard { 7217fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 7228b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 7238b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 7248b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 7258b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 7268b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 7272a766d29SGerd Hoffmann }; 7282a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 729b5a1b443SEric Blake InputMoveEvent *move; 730b5a1b443SEric Blake InputBtnEvent *btn; 7310e43e99cSbellard 7320e43e99cSbellard /* check if deltas are recorded when disabled */ 7330e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 7340e43e99cSbellard return; 7350e43e99cSbellard 736568c73a4SEric Blake switch (evt->type) { 7372a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 73832bafa8fSEric Blake move = evt->u.rel.data; 739b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 740b5a1b443SEric Blake s->mouse_dx += move->value; 741b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 742b5a1b443SEric Blake s->mouse_dy -= move->value; 7432a766d29SGerd Hoffmann } 7442a766d29SGerd Hoffmann break; 7450e43e99cSbellard 7462a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 74732bafa8fSEric Blake btn = evt->u.btn.data; 748b5a1b443SEric Blake if (btn->down) { 749b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 750b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 7512a766d29SGerd Hoffmann s->mouse_dz--; 752b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 7532a766d29SGerd Hoffmann s->mouse_dz++; 7542a766d29SGerd Hoffmann } 7552a766d29SGerd Hoffmann } else { 756b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 7572a766d29SGerd Hoffmann } 7582a766d29SGerd Hoffmann break; 7592a766d29SGerd Hoffmann 7602a766d29SGerd Hoffmann default: 7612a766d29SGerd Hoffmann /* keep gcc happy */ 7622a766d29SGerd Hoffmann break; 7632a766d29SGerd Hoffmann } 764fd214d18SGerd Hoffmann } 765fd214d18SGerd Hoffmann 7662a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 7672a766d29SGerd Hoffmann { 7682a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 7692a766d29SGerd Hoffmann 770143c04c7SGeoffrey McRae /* do not sync while disabled to prevent stream corruption */ 771143c04c7SGeoffrey McRae if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 772143c04c7SGeoffrey McRae return; 773143c04c7SGeoffrey McRae } 774143c04c7SGeoffrey McRae 7752a766d29SGerd Hoffmann if (s->mouse_buttons) { 776fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 7772a766d29SGerd Hoffmann } 7782858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 7790e43e99cSbellard /* if not remote, send event. Multiple events are sent if 7800e43e99cSbellard too big deltas */ 7817abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 7820e43e99cSbellard if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 7830e43e99cSbellard break; 7840e43e99cSbellard } 7850e43e99cSbellard } 7860e43e99cSbellard } 7870e43e99cSbellard 788548df2acSths void ps2_mouse_fake_event(void *opaque) 789548df2acSths { 7902a766d29SGerd Hoffmann PS2MouseState *s = opaque; 7915edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 7922a766d29SGerd Hoffmann s->mouse_dx++; 7932a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 794548df2acSths } 795548df2acSths 7960e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 7970e43e99cSbellard { 7980e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 7995edab03dSDon Koch 8005edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 8010e43e99cSbellard switch(s->common.write_cmd) { 8020e43e99cSbellard default: 8030e43e99cSbellard case -1: 8040e43e99cSbellard /* mouse command */ 8050e43e99cSbellard if (s->mouse_wrap) { 8060e43e99cSbellard if (val == AUX_RESET_WRAP) { 8070e43e99cSbellard s->mouse_wrap = 0; 8080e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8090e43e99cSbellard return; 8100e43e99cSbellard } else if (val != AUX_RESET) { 8110e43e99cSbellard ps2_queue(&s->common, val); 8120e43e99cSbellard return; 8130e43e99cSbellard } 8140e43e99cSbellard } 8150e43e99cSbellard switch(val) { 8160e43e99cSbellard case AUX_SET_SCALE11: 8170e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 8180e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8190e43e99cSbellard break; 8200e43e99cSbellard case AUX_SET_SCALE21: 8210e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 8220e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8230e43e99cSbellard break; 8240e43e99cSbellard case AUX_SET_STREAM: 8250e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 8260e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8270e43e99cSbellard break; 8280e43e99cSbellard case AUX_SET_WRAP: 8290e43e99cSbellard s->mouse_wrap = 1; 8300e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8310e43e99cSbellard break; 8320e43e99cSbellard case AUX_SET_REMOTE: 8330e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 8340e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8350e43e99cSbellard break; 8360e43e99cSbellard case AUX_GET_TYPE: 8377abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 8387abe7eb2SGeoffrey McRae AUX_ACK, 8397abe7eb2SGeoffrey McRae s->mouse_type); 8400e43e99cSbellard break; 8410e43e99cSbellard case AUX_SET_RES: 8420e43e99cSbellard case AUX_SET_SAMPLE: 8430e43e99cSbellard s->common.write_cmd = val; 8440e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8450e43e99cSbellard break; 8460e43e99cSbellard case AUX_GET_SCALE: 8477abe7eb2SGeoffrey McRae ps2_queue_4(&s->common, 8487abe7eb2SGeoffrey McRae AUX_ACK, 8497abe7eb2SGeoffrey McRae s->mouse_status, 8507abe7eb2SGeoffrey McRae s->mouse_resolution, 8517abe7eb2SGeoffrey McRae s->mouse_sample_rate); 8520e43e99cSbellard break; 8530e43e99cSbellard case AUX_POLL: 8540e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8550e43e99cSbellard ps2_mouse_send_packet(s); 8560e43e99cSbellard break; 8570e43e99cSbellard case AUX_ENABLE_DEV: 8580e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 8590e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8600e43e99cSbellard break; 8610e43e99cSbellard case AUX_DISABLE_DEV: 8620e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 8630e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8640e43e99cSbellard break; 8650e43e99cSbellard case AUX_SET_DEFAULT: 8660e43e99cSbellard s->mouse_sample_rate = 100; 8670e43e99cSbellard s->mouse_resolution = 2; 8680e43e99cSbellard s->mouse_status = 0; 8690e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8700e43e99cSbellard break; 8710e43e99cSbellard case AUX_RESET: 8720e43e99cSbellard s->mouse_sample_rate = 100; 8730e43e99cSbellard s->mouse_resolution = 2; 8740e43e99cSbellard s->mouse_status = 0; 8750e43e99cSbellard s->mouse_type = 0; 876143c04c7SGeoffrey McRae ps2_reset_queue(&s->common); 8777abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 8787abe7eb2SGeoffrey McRae AUX_ACK, 8797abe7eb2SGeoffrey McRae 0xaa, 8807abe7eb2SGeoffrey McRae s->mouse_type); 8810e43e99cSbellard break; 8820e43e99cSbellard default: 8830e43e99cSbellard break; 8840e43e99cSbellard } 8850e43e99cSbellard break; 8860e43e99cSbellard case AUX_SET_SAMPLE: 8870e43e99cSbellard s->mouse_sample_rate = val; 8880e43e99cSbellard /* detect IMPS/2 or IMEX */ 8890e43e99cSbellard switch(s->mouse_detect_state) { 8900e43e99cSbellard default: 8910e43e99cSbellard case 0: 8920e43e99cSbellard if (val == 200) 8930e43e99cSbellard s->mouse_detect_state = 1; 8940e43e99cSbellard break; 8950e43e99cSbellard case 1: 8960e43e99cSbellard if (val == 100) 8970e43e99cSbellard s->mouse_detect_state = 2; 8980e43e99cSbellard else if (val == 200) 8990e43e99cSbellard s->mouse_detect_state = 3; 9000e43e99cSbellard else 9010e43e99cSbellard s->mouse_detect_state = 0; 9020e43e99cSbellard break; 9030e43e99cSbellard case 2: 9040e43e99cSbellard if (val == 80) 9050e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 9060e43e99cSbellard s->mouse_detect_state = 0; 9070e43e99cSbellard break; 9080e43e99cSbellard case 3: 9090e43e99cSbellard if (val == 80) 9100e43e99cSbellard s->mouse_type = 4; /* IMEX */ 9110e43e99cSbellard s->mouse_detect_state = 0; 9120e43e99cSbellard break; 9130e43e99cSbellard } 9140e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9150e43e99cSbellard s->common.write_cmd = -1; 9160e43e99cSbellard break; 9170e43e99cSbellard case AUX_SET_RES: 9180e43e99cSbellard s->mouse_resolution = val; 9190e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9200e43e99cSbellard s->common.write_cmd = -1; 9210e43e99cSbellard break; 9220e43e99cSbellard } 9230e43e99cSbellard } 9240e43e99cSbellard 925ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 9260e43e99cSbellard { 9270e43e99cSbellard s->write_cmd = -1; 928954ee55bSGerd Hoffmann ps2_reset_queue(s); 929deeccef3Saliguori s->update_irq(s->update_arg, 0); 9300e43e99cSbellard } 9310e43e99cSbellard 9322858ab09SGonglei static void ps2_common_post_load(PS2State *s) 9332858ab09SGonglei { 9342858ab09SGonglei PS2Queue *q = &s->queue; 9352858ab09SGonglei 936*47db2432SVolker Rümelin /* set the useful data buffer queue size <= PS2_QUEUE_SIZE */ 937a1f2ed2aSPavel Dovgalyuk if (q->count < 0) { 938*47db2432SVolker Rümelin q->count = 0; 939a1f2ed2aSPavel Dovgalyuk } else if (q->count > PS2_QUEUE_SIZE) { 940*47db2432SVolker Rümelin q->count = PS2_QUEUE_SIZE; 941a1f2ed2aSPavel Dovgalyuk } 9422858ab09SGonglei 943*47db2432SVolker Rümelin /* sanitize rptr and recalculate wptr */ 944*47db2432SVolker Rümelin q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1); 945*47db2432SVolker Rümelin q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1); 9462858ab09SGonglei } 9472858ab09SGonglei 948ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 949ef74679aSDinesh Subhraveti { 950ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 951ef74679aSDinesh Subhraveti 9525edab03dSDon Koch trace_ps2_kbd_reset(opaque); 953ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 954d2e550a8SHervé Poussineau s->scan_enabled = 1; 955ef74679aSDinesh Subhraveti s->translate = 0; 956089adafdSHervé Poussineau s->scancode_set = 2; 957620775d1SDaniel P. Berrange s->modifiers = 0; 958ef74679aSDinesh Subhraveti } 959ef74679aSDinesh Subhraveti 960ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 961ef74679aSDinesh Subhraveti { 962ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 963ef74679aSDinesh Subhraveti 9645edab03dSDon Koch trace_ps2_mouse_reset(opaque); 965ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 966ef74679aSDinesh Subhraveti s->mouse_status = 0; 967ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 968ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 969ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 970ef74679aSDinesh Subhraveti s->mouse_type = 0; 971ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 972ef74679aSDinesh Subhraveti s->mouse_dx = 0; 973ef74679aSDinesh Subhraveti s->mouse_dy = 0; 974ef74679aSDinesh Subhraveti s->mouse_dz = 0; 975ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 976ef74679aSDinesh Subhraveti } 977ef74679aSDinesh Subhraveti 978b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 979b31442c3SJuan Quintela .name = "PS2 Common State", 980b31442c3SJuan Quintela .version_id = 3, 981b31442c3SJuan Quintela .minimum_version_id = 2, 982b31442c3SJuan Quintela .fields = (VMStateField[]) { 983b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 984b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 985b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 986b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 987b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 988b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 9897783e9f0Spbrook } 990b31442c3SJuan Quintela }; 9917783e9f0Spbrook 9927f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 9937f540ab5SChristophe Fergeau { 9947f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 9957f540ab5SChristophe Fergeau 9967f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 9977f540ab5SChristophe Fergeau } 9987f540ab5SChristophe Fergeau 9997f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 10007f540ab5SChristophe Fergeau { 10017f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 10027f540ab5SChristophe Fergeau 10037f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 10047f540ab5SChristophe Fergeau return 0; 10057f540ab5SChristophe Fergeau } 10067f540ab5SChristophe Fergeau 10077f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 10087f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 10097f540ab5SChristophe Fergeau .version_id = 3, 10107f540ab5SChristophe Fergeau .minimum_version_id = 2, 10117f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 10125cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 10137f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 10147f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 10157f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 10167f540ab5SChristophe Fergeau } 10177f540ab5SChristophe Fergeau }; 10187f540ab5SChristophe Fergeau 101957d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 102057d5c005SHervé Poussineau { 102157d5c005SHervé Poussineau PS2KbdState *s = opaque; 102257d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 102357d5c005SHervé Poussineau } 102457d5c005SHervé Poussineau 102557d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 102657d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 102757d5c005SHervé Poussineau .version_id = 1, 102857d5c005SHervé Poussineau .minimum_version_id = 1, 102957d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 103057d5c005SHervé Poussineau .fields = (VMStateField[]) { 103157d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 103257d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 103357d5c005SHervé Poussineau } 103457d5c005SHervé Poussineau }; 103557d5c005SHervé Poussineau 1036db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 10370e43e99cSbellard { 10380e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 10392858ab09SGonglei PS2State *ps2 = &s->common; 10400e43e99cSbellard 1041db596c53SJuan Quintela if (version_id == 2) 1042e7d93956Saurel32 s->scancode_set=2; 10432858ab09SGonglei 10442858ab09SGonglei ps2_common_post_load(ps2); 10452858ab09SGonglei 10460e43e99cSbellard return 0; 10470e43e99cSbellard } 10480e43e99cSbellard 1049b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 1050b31442c3SJuan Quintela .name = "ps2kbd", 1051b31442c3SJuan Quintela .version_id = 3, 1052db596c53SJuan Quintela .minimum_version_id = 2, 1053db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 1054b31442c3SJuan Quintela .fields = (VMStateField[]) { 1055b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 1056b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 1057b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 1058b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 1059b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 10607f540ab5SChristophe Fergeau }, 10615cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 10625cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 106357d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 10645cd8cadaSJuan Quintela NULL 10650e43e99cSbellard } 1066b31442c3SJuan Quintela }; 1067b31442c3SJuan Quintela 10682858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 10692858ab09SGonglei { 10702858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 10712858ab09SGonglei PS2State *ps2 = &s->common; 10722858ab09SGonglei 10732858ab09SGonglei ps2_common_post_load(ps2); 10742858ab09SGonglei 10752858ab09SGonglei return 0; 10762858ab09SGonglei } 10772858ab09SGonglei 1078b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1079b31442c3SJuan Quintela .name = "ps2mouse", 1080b31442c3SJuan Quintela .version_id = 2, 1081b31442c3SJuan Quintela .minimum_version_id = 2, 10822858ab09SGonglei .post_load = ps2_mouse_post_load, 1083b31442c3SJuan Quintela .fields = (VMStateField[]) { 1084b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 1085b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1086b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1087b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1088b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1089b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1090b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1091b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1092b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1093b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1094b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1095b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1096b31442c3SJuan Quintela } 1097b31442c3SJuan Quintela }; 10980e43e99cSbellard 109966e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 110066e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 110166e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 110266e6536eSGerd Hoffmann .event = ps2_keyboard_event, 110366e6536eSGerd Hoffmann }; 110466e6536eSGerd Hoffmann 11050e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 11060e43e99cSbellard { 11077267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 11080e43e99cSbellard 11095edab03dSDon Koch trace_ps2_kbd_init(s); 11100e43e99cSbellard s->common.update_irq = update_irq; 11110e43e99cSbellard s->common.update_arg = update_arg; 1112e7d93956Saurel32 s->scancode_set = 2; 11130be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 111466e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 111566e6536eSGerd Hoffmann &ps2_keyboard_handler); 1116ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 11170e43e99cSbellard return s; 11180e43e99cSbellard } 11190e43e99cSbellard 11202a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 11212a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 11222a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 11232a766d29SGerd Hoffmann .event = ps2_mouse_event, 11242a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 11252a766d29SGerd Hoffmann }; 11262a766d29SGerd Hoffmann 11270e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 11280e43e99cSbellard { 11297267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 11300e43e99cSbellard 11315edab03dSDon Koch trace_ps2_mouse_init(s); 11320e43e99cSbellard s->common.update_irq = update_irq; 11330e43e99cSbellard s->common.update_arg = update_arg; 11340be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 11352a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 11362a766d29SGerd Hoffmann &ps2_mouse_handler); 1137ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 11380e43e99cSbellard return s; 11390e43e99cSbellard } 1140