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 7747db2432SVolker Rümelin /* 7847db2432SVolker Rümelin * PS/2 buffer size. Keep 256 bytes for compatibility with 7947db2432SVolker Rümelin * older QEMU versions. 8047db2432SVolker Rümelin */ 8147db2432SVolker Rümelin #define PS2_BUFFER_SIZE 256 8247db2432SVolker 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 { 9347db2432SVolker Rümelin uint8_t data[PS2_BUFFER_SIZE]; 94*9e24b2ddSVolker Rümelin int rptr, wptr, cwptr, 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; 189*9e24b2ddSVolker Rümelin q->cwptr = -1; 190954ee55bSGerd Hoffmann q->count = 0; 191954ee55bSGerd Hoffmann } 192954ee55bSGerd Hoffmann 1932a6505b0SSven Schnelle int ps2_queue_empty(PS2State *s) 1942a6505b0SSven Schnelle { 1952a6505b0SSven Schnelle return s->queue.count == 0; 1962a6505b0SSven Schnelle } 1972a6505b0SSven Schnelle 1987abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 1990e43e99cSbellard { 2000e43e99cSbellard PS2Queue *q = &s->queue; 2010e43e99cSbellard 202*9e24b2ddSVolker Rümelin if (q->count >= PS2_QUEUE_SIZE) { 2030e43e99cSbellard return; 2047abe7eb2SGeoffrey McRae } 2057abe7eb2SGeoffrey McRae 2060e43e99cSbellard q->data[q->wptr] = b; 20747db2432SVolker Rümelin if (++q->wptr == PS2_BUFFER_SIZE) { 2080e43e99cSbellard q->wptr = 0; 20947db2432SVolker Rümelin } 2100e43e99cSbellard q->count++; 2117abe7eb2SGeoffrey McRae } 2127abe7eb2SGeoffrey McRae 2137abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s) 2147abe7eb2SGeoffrey McRae { 2157abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2167abe7eb2SGeoffrey McRae } 2177abe7eb2SGeoffrey McRae 2187abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 2197abe7eb2SGeoffrey McRae { 2207704bb02SVolker Rümelin if (PS2_QUEUE_SIZE - s->queue.count < 1) { 2217704bb02SVolker Rümelin return; 2227704bb02SVolker Rümelin } 2237704bb02SVolker Rümelin 2247abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 22596376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2267abe7eb2SGeoffrey McRae } 2277abe7eb2SGeoffrey McRae 2287abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 2297abe7eb2SGeoffrey McRae { 2307abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 2317abe7eb2SGeoffrey McRae return; 2327abe7eb2SGeoffrey McRae } 2337abe7eb2SGeoffrey McRae 2347abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2357abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 23696376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2377abe7eb2SGeoffrey McRae } 2387abe7eb2SGeoffrey McRae 2397abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 2407abe7eb2SGeoffrey McRae { 2417abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 2427abe7eb2SGeoffrey McRae return; 2437abe7eb2SGeoffrey McRae } 2447abe7eb2SGeoffrey McRae 2457abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2467abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2477abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 24896376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2497abe7eb2SGeoffrey McRae } 2507abe7eb2SGeoffrey McRae 2517abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 2527abe7eb2SGeoffrey McRae { 2537abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 2547abe7eb2SGeoffrey McRae return; 2557abe7eb2SGeoffrey McRae } 2567abe7eb2SGeoffrey McRae 2577abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2587abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2597abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2607abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 26196376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2620e43e99cSbellard } 2630e43e99cSbellard 264*9e24b2ddSVolker Rümelin static void ps2_cqueue_data(PS2Queue *q, int b) 265*9e24b2ddSVolker Rümelin { 266*9e24b2ddSVolker Rümelin q->data[q->cwptr] = b; 267*9e24b2ddSVolker Rümelin if (++q->cwptr >= PS2_BUFFER_SIZE) { 268*9e24b2ddSVolker Rümelin q->cwptr = 0; 269*9e24b2ddSVolker Rümelin } 270*9e24b2ddSVolker Rümelin q->count++; 271*9e24b2ddSVolker Rümelin } 272*9e24b2ddSVolker Rümelin 273*9e24b2ddSVolker Rümelin static void ps2_cqueue_1(PS2State *s, int b1) 274*9e24b2ddSVolker Rümelin { 275*9e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 276*9e24b2ddSVolker Rümelin 277*9e24b2ddSVolker Rümelin q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1); 278*9e24b2ddSVolker Rümelin q->cwptr = q->rptr; 279*9e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 280*9e24b2ddSVolker Rümelin ps2_raise_irq(s); 281*9e24b2ddSVolker Rümelin } 282*9e24b2ddSVolker Rümelin 283*9e24b2ddSVolker Rümelin static void ps2_cqueue_2(PS2State *s, int b1, int b2) 284*9e24b2ddSVolker Rümelin { 285*9e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 286*9e24b2ddSVolker Rümelin 287*9e24b2ddSVolker Rümelin q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1); 288*9e24b2ddSVolker Rümelin q->cwptr = q->rptr; 289*9e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 290*9e24b2ddSVolker Rümelin ps2_cqueue_data(q, b2); 291*9e24b2ddSVolker Rümelin ps2_raise_irq(s); 292*9e24b2ddSVolker Rümelin } 293*9e24b2ddSVolker Rümelin 294*9e24b2ddSVolker Rümelin static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3) 295*9e24b2ddSVolker Rümelin { 296*9e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 297*9e24b2ddSVolker Rümelin 298*9e24b2ddSVolker Rümelin q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1); 299*9e24b2ddSVolker Rümelin q->cwptr = q->rptr; 300*9e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 301*9e24b2ddSVolker Rümelin ps2_cqueue_data(q, b2); 302*9e24b2ddSVolker Rümelin ps2_cqueue_data(q, b3); 303*9e24b2ddSVolker Rümelin ps2_raise_irq(s); 304*9e24b2ddSVolker Rümelin } 305*9e24b2ddSVolker Rümelin 306*9e24b2ddSVolker Rümelin static void ps2_cqueue_reset(PS2State *s) 307*9e24b2ddSVolker Rümelin { 308*9e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 309*9e24b2ddSVolker Rümelin int ccount; 310*9e24b2ddSVolker Rümelin 311*9e24b2ddSVolker Rümelin if (q->cwptr == -1) { 312*9e24b2ddSVolker Rümelin return; 313*9e24b2ddSVolker Rümelin } 314*9e24b2ddSVolker Rümelin 315*9e24b2ddSVolker Rümelin ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1); 316*9e24b2ddSVolker Rümelin q->count -= ccount; 317*9e24b2ddSVolker Rümelin q->rptr = q->cwptr; 318*9e24b2ddSVolker Rümelin q->cwptr = -1; 319*9e24b2ddSVolker Rümelin } 320*9e24b2ddSVolker Rümelin 32157d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 3220e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 3230e43e99cSbellard { 324f94f5d71Spbrook PS2KbdState *s = opaque; 325e7d93956Saurel32 3265edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 327fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 32857d5c005SHervé Poussineau 32957d5c005SHervé Poussineau if (s->translate) { 33057d5c005SHervé Poussineau if (keycode == 0xf0) { 33157d5c005SHervé Poussineau s->need_high_bit = true; 33257d5c005SHervé Poussineau } else if (s->need_high_bit) { 33357d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode] | 0x80); 33457d5c005SHervé Poussineau s->need_high_bit = false; 33557d5c005SHervé Poussineau } else { 33657d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode]); 3377096a96dSRoy Tam } 33857d5c005SHervé Poussineau } else { 3390e43e99cSbellard ps2_queue(&s->common, keycode); 3400e43e99cSbellard } 34157d5c005SHervé Poussineau } 3420e43e99cSbellard 34366e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 34466e6536eSGerd Hoffmann InputEvent *evt) 34566e6536eSGerd Hoffmann { 34666e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 34732bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 3488c10e0baSHervé Poussineau int qcode; 349ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 350620775d1SDaniel P. Berrange int mod; 35166e6536eSGerd Hoffmann 352143c04c7SGeoffrey McRae /* do not process events while disabled to prevent stream corruption */ 353143c04c7SGeoffrey McRae if (!s->scan_enabled) { 354143c04c7SGeoffrey McRae return; 355143c04c7SGeoffrey McRae } 356143c04c7SGeoffrey McRae 357fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 3588c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 3598c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 36057d5c005SHervé Poussineau 361620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 362644f66bfSDaniel P. Berrangé trace_ps2_keyboard_event(s, qcode, key->down, mod, 363644f66bfSDaniel P. Berrangé s->modifiers, s->scancode_set, s->translate); 364620775d1SDaniel P. Berrange if (key->down) { 365620775d1SDaniel P. Berrange s->modifiers |= mod; 366620775d1SDaniel P. Berrange } else { 367620775d1SDaniel P. Berrange s->modifiers &= ~mod; 368620775d1SDaniel P. Berrange } 369620775d1SDaniel P. Berrange 3708c10e0baSHervé Poussineau if (s->scancode_set == 1) { 3718c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 37229fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 37329fd23a5SDaniel P. Berrange if (key->down) { 37429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 37529fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 37629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 37729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 37829fd23a5SDaniel P. Berrange } 37929fd23a5SDaniel P. Berrange } else { 3808c10e0baSHervé Poussineau if (key->down) { 3818c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3828c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 3838c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 384927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 3858c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 3868c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 3878c10e0baSHervé Poussineau } 38829fd23a5SDaniel P. Berrange } 3898c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 390620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 391620775d1SDaniel P. Berrange if (key->down) { 392620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 393620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 394620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 395620775d1SDaniel P. Berrange } else { 396620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 397620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 398620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 399620775d1SDaniel P. Berrange } 400620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 401620775d1SDaniel P. Berrange if (key->down) { 402620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 403620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 404620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 405620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 406620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 407620775d1SDaniel P. Berrange } else { 408620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 409620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 410620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 411620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 412620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 413620775d1SDaniel P. Berrange } 4148f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 4158f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 4168f63458fSDaniel P. Berrange if (key->down) { 4178f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4188f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 4198f63458fSDaniel P. Berrange } else { 4208f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4218f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 4228f63458fSDaniel P. Berrange } 423620775d1SDaniel P. Berrange } else { 4248c10e0baSHervé Poussineau if (key->down) { 4258c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4268c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 4278c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4288c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 4298c10e0baSHervé Poussineau } else { 4308c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4318c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 4328c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4338c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 4348c10e0baSHervé Poussineau } 435620775d1SDaniel P. Berrange } 4368c10e0baSHervé Poussineau } else { 437ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset1_len) 438ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 4398c10e0baSHervé Poussineau if (keycode) { 4408c10e0baSHervé Poussineau if (keycode & 0xff00) { 4418c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4428c10e0baSHervé Poussineau } 4438c10e0baSHervé Poussineau if (!key->down) { 4448c10e0baSHervé Poussineau keycode |= 0x80; 4458c10e0baSHervé Poussineau } 4468c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 4478c10e0baSHervé Poussineau } else { 448ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 449ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 4508c10e0baSHervé Poussineau } 4518c10e0baSHervé Poussineau } 4528c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 4538c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 45429fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 45529fd23a5SDaniel P. Berrange if (key->down) { 45629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 45729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 45829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 45929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 46029fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 46129fd23a5SDaniel P. Berrange } 46229fd23a5SDaniel P. Berrange } else { 4638c10e0baSHervé Poussineau if (key->down) { 4648c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4658c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4668c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4678c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4688c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4698c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4708c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4718c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4728c10e0baSHervé Poussineau } 47329fd23a5SDaniel P. Berrange } 4748c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 475620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 476620775d1SDaniel P. Berrange if (key->down) { 477620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 478620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 479620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 480620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 481620775d1SDaniel P. Berrange } else { 482620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 483620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 484620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 485620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 486620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 487620775d1SDaniel P. Berrange } 488620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 489620775d1SDaniel P. Berrange if (key->down) { 490620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 491620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 492620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 493620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 494620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 495620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 496620775d1SDaniel P. Berrange } else { 497620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 498620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 499620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 500620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 501620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 502620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 503620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 504620775d1SDaniel P. Berrange } 5058f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 5068f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 5078f63458fSDaniel P. Berrange if (key->down) { 5088f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 5098f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 5108f63458fSDaniel P. Berrange } else { 5118f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 5128f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 5138f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 5148f63458fSDaniel P. Berrange } 515620775d1SDaniel P. Berrange } else { 5168c10e0baSHervé Poussineau if (key->down) { 5178c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5188c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 5198c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5208c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 5218c10e0baSHervé Poussineau } else { 5228c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5238c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5248c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 5258c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5268c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5278c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 5288c10e0baSHervé Poussineau } 529620775d1SDaniel P. Berrange } 5308c10e0baSHervé Poussineau } else { 531ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset2_len) 532ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 5338c10e0baSHervé Poussineau if (keycode) { 5348c10e0baSHervé Poussineau if (keycode & 0xff00) { 5358c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 5368c10e0baSHervé Poussineau } 5378c10e0baSHervé Poussineau if (!key->down) { 5388c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5398c10e0baSHervé Poussineau } 5408c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 54157d5c005SHervé Poussineau } else { 542ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 543ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 54457d5c005SHervé Poussineau } 54557d5c005SHervé Poussineau } 54657d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 547ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset3_len) 548ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 5498c10e0baSHervé Poussineau if (keycode) { 5508c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 5518c10e0baSHervé Poussineau if (!key->down) { 5528c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 55357d5c005SHervé Poussineau } 55457d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 5558c10e0baSHervé Poussineau } else { 556ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 557ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 5588c10e0baSHervé Poussineau } 55966e6536eSGerd Hoffmann } 56066e6536eSGerd Hoffmann } 56166e6536eSGerd Hoffmann 5628498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 5630e43e99cSbellard { 5640e43e99cSbellard PS2Queue *q; 5650e43e99cSbellard int val, index; 5660e43e99cSbellard 5678498bb8dSGerd Hoffmann trace_ps2_read_data(s); 5680e43e99cSbellard q = &s->queue; 5690e43e99cSbellard if (q->count == 0) { 5700e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 5710e43e99cSbellard (needed for EMM386) */ 5720e43e99cSbellard /* XXX: need a timer to do things correctly */ 5730e43e99cSbellard index = q->rptr - 1; 57447db2432SVolker Rümelin if (index < 0) { 57547db2432SVolker Rümelin index = PS2_BUFFER_SIZE - 1; 57647db2432SVolker Rümelin } 5770e43e99cSbellard val = q->data[index]; 5780e43e99cSbellard } else { 5790e43e99cSbellard val = q->data[q->rptr]; 58047db2432SVolker Rümelin if (++q->rptr == PS2_BUFFER_SIZE) { 5810e43e99cSbellard q->rptr = 0; 58247db2432SVolker Rümelin } 5830e43e99cSbellard q->count--; 584*9e24b2ddSVolker Rümelin if (q->rptr == q->cwptr) { 585*9e24b2ddSVolker Rümelin /* command reply queue is empty */ 586*9e24b2ddSVolker Rümelin q->cwptr = -1; 587*9e24b2ddSVolker Rümelin } 5880e43e99cSbellard /* reading deasserts IRQ */ 5890e43e99cSbellard s->update_irq(s->update_arg, 0); 5900e43e99cSbellard /* reassert IRQs if data left */ 591cec32524SVolker Rümelin if (q->count) { 592cec32524SVolker Rümelin s->update_irq(s->update_arg, 1); 593cec32524SVolker Rümelin } 5940e43e99cSbellard } 5950e43e99cSbellard return val; 5960e43e99cSbellard } 5970e43e99cSbellard 5987f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 5997f540ab5SChristophe Fergeau { 6005edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 6017f540ab5SChristophe Fergeau s->ledstate = ledstate; 6027f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 6037f540ab5SChristophe Fergeau } 6047f540ab5SChristophe Fergeau 6050e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 6060e43e99cSbellard { 6075edab03dSDon Koch trace_ps2_reset_keyboard(s); 6080e43e99cSbellard s->scan_enabled = 1; 609e7d93956Saurel32 s->scancode_set = 2; 6106e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 6117f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 6120e43e99cSbellard } 6130e43e99cSbellard 6140e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 6150e43e99cSbellard { 6160e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 6170e43e99cSbellard 6185edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 619*9e24b2ddSVolker Rümelin ps2_cqueue_reset(&s->common); 6200e43e99cSbellard switch(s->common.write_cmd) { 6210e43e99cSbellard default: 6220e43e99cSbellard case -1: 6230e43e99cSbellard switch(val) { 6240e43e99cSbellard case 0x00: 625*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6260e43e99cSbellard break; 6270e43e99cSbellard case 0x05: 628*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); 6290e43e99cSbellard break; 6300e43e99cSbellard case KBD_CMD_GET_ID: 631e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 632*9e24b2ddSVolker Rümelin ps2_cqueue_3(&s->common, KBD_REPLY_ACK, KBD_REPLY_ID, 633*9e24b2ddSVolker Rümelin s->translate ? 0x41 : 0x83); 6340e43e99cSbellard break; 6350e43e99cSbellard case KBD_CMD_ECHO: 636*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_CMD_ECHO); 6370e43e99cSbellard break; 6380e43e99cSbellard case KBD_CMD_ENABLE: 6390e43e99cSbellard s->scan_enabled = 1; 640*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6410e43e99cSbellard break; 642e7d93956Saurel32 case KBD_CMD_SCANCODE: 6430e43e99cSbellard case KBD_CMD_SET_LEDS: 6440e43e99cSbellard case KBD_CMD_SET_RATE: 645c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 6460e43e99cSbellard s->common.write_cmd = val; 647*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6480e43e99cSbellard break; 6490e43e99cSbellard case KBD_CMD_RESET_DISABLE: 6500e43e99cSbellard ps2_reset_keyboard(s); 6510e43e99cSbellard s->scan_enabled = 0; 652*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6530e43e99cSbellard break; 6540e43e99cSbellard case KBD_CMD_RESET_ENABLE: 6550e43e99cSbellard ps2_reset_keyboard(s); 6560e43e99cSbellard s->scan_enabled = 1; 657*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6580e43e99cSbellard break; 6590e43e99cSbellard case KBD_CMD_RESET: 6600e43e99cSbellard ps2_reset_keyboard(s); 661*9e24b2ddSVolker Rümelin ps2_cqueue_2(&s->common, 6627abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 6637abe7eb2SGeoffrey McRae KBD_REPLY_POR); 6640e43e99cSbellard break; 665c56b6209SSven Schnelle case KBD_CMD_SET_TYPEMATIC: 666*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 667c56b6209SSven Schnelle break; 6680e43e99cSbellard default: 669*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); 6700e43e99cSbellard break; 6710e43e99cSbellard } 6720e43e99cSbellard break; 673c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 674*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 675c56b6209SSven Schnelle s->common.write_cmd = -1; 676c56b6209SSven Schnelle break; 677e7d93956Saurel32 case KBD_CMD_SCANCODE: 678e7d93956Saurel32 if (val == 0) { 679*9e24b2ddSVolker Rümelin ps2_cqueue_2(&s->common, KBD_REPLY_ACK, s->translate ? 680*9e24b2ddSVolker Rümelin translate_table[s->scancode_set] : s->scancode_set); 6814df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 682e7d93956Saurel32 s->scancode_set = val; 683*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6844df23b64SHervé Poussineau } else { 685*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); 686e7d93956Saurel32 } 687e7d93956Saurel32 s->common.write_cmd = -1; 688e7d93956Saurel32 break; 6890e43e99cSbellard case KBD_CMD_SET_LEDS: 6907f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 691*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6920e43e99cSbellard s->common.write_cmd = -1; 6930e43e99cSbellard break; 6940e43e99cSbellard case KBD_CMD_SET_RATE: 695*9e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6960e43e99cSbellard s->common.write_cmd = -1; 6970e43e99cSbellard break; 6980e43e99cSbellard } 6990e43e99cSbellard } 7000e43e99cSbellard 701f94f5d71Spbrook /* Set the scancode translation mode. 702f94f5d71Spbrook 0 = raw scancodes. 703f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 704f94f5d71Spbrook 705f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 706f94f5d71Spbrook { 707f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 7085edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 709f94f5d71Spbrook s->translate = mode; 710f94f5d71Spbrook } 711f94f5d71Spbrook 7127abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 7130e43e99cSbellard { 71476968101SVolker Rümelin /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ 71576968101SVolker Rümelin const int needed = s->mouse_type ? 4 : 3; 7160e43e99cSbellard unsigned int b; 7170e43e99cSbellard int dx1, dy1, dz1; 7180e43e99cSbellard 7197abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { 7207abe7eb2SGeoffrey McRae return 0; 7217abe7eb2SGeoffrey McRae } 7227abe7eb2SGeoffrey McRae 7230e43e99cSbellard dx1 = s->mouse_dx; 7240e43e99cSbellard dy1 = s->mouse_dy; 7250e43e99cSbellard dz1 = s->mouse_dz; 7260e43e99cSbellard /* XXX: increase range to 8 bits ? */ 7270e43e99cSbellard if (dx1 > 127) 7280e43e99cSbellard dx1 = 127; 7290e43e99cSbellard else if (dx1 < -127) 7300e43e99cSbellard dx1 = -127; 7310e43e99cSbellard if (dy1 > 127) 7320e43e99cSbellard dy1 = 127; 7330e43e99cSbellard else if (dy1 < -127) 7340e43e99cSbellard dy1 = -127; 7350e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 7367abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 7377abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dx1 & 0xff); 7387abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dy1 & 0xff); 7390e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 7400e43e99cSbellard switch(s->mouse_type) { 7410e43e99cSbellard default: 7420e43e99cSbellard break; 7430e43e99cSbellard case 3: 7440e43e99cSbellard if (dz1 > 127) 7450e43e99cSbellard dz1 = 127; 7460e43e99cSbellard else if (dz1 < -127) 7470e43e99cSbellard dz1 = -127; 7487abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dz1 & 0xff); 7490e43e99cSbellard break; 7500e43e99cSbellard case 4: 7510e43e99cSbellard if (dz1 > 7) 7520e43e99cSbellard dz1 = 7; 7530e43e99cSbellard else if (dz1 < -7) 7540e43e99cSbellard dz1 = -7; 7550e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 7567abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 7570e43e99cSbellard break; 7580e43e99cSbellard } 7590e43e99cSbellard 7607abe7eb2SGeoffrey McRae ps2_raise_irq(&s->common); 7617abe7eb2SGeoffrey McRae 7625edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 7630e43e99cSbellard /* update deltas */ 7640e43e99cSbellard s->mouse_dx -= dx1; 7650e43e99cSbellard s->mouse_dy -= dy1; 7660e43e99cSbellard s->mouse_dz -= dz1; 7677abe7eb2SGeoffrey McRae 7687abe7eb2SGeoffrey McRae return 1; 7690e43e99cSbellard } 7700e43e99cSbellard 7712a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 7722a766d29SGerd Hoffmann InputEvent *evt) 7730e43e99cSbellard { 7747fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 7758b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 7768b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 7778b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 7788b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 7798b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 7802a766d29SGerd Hoffmann }; 7812a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 782b5a1b443SEric Blake InputMoveEvent *move; 783b5a1b443SEric Blake InputBtnEvent *btn; 7840e43e99cSbellard 7850e43e99cSbellard /* check if deltas are recorded when disabled */ 7860e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 7870e43e99cSbellard return; 7880e43e99cSbellard 789568c73a4SEric Blake switch (evt->type) { 7902a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 79132bafa8fSEric Blake move = evt->u.rel.data; 792b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 793b5a1b443SEric Blake s->mouse_dx += move->value; 794b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 795b5a1b443SEric Blake s->mouse_dy -= move->value; 7962a766d29SGerd Hoffmann } 7972a766d29SGerd Hoffmann break; 7980e43e99cSbellard 7992a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 80032bafa8fSEric Blake btn = evt->u.btn.data; 801b5a1b443SEric Blake if (btn->down) { 802b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 803b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 8042a766d29SGerd Hoffmann s->mouse_dz--; 805b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 8062a766d29SGerd Hoffmann s->mouse_dz++; 8072a766d29SGerd Hoffmann } 8082a766d29SGerd Hoffmann } else { 809b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 8102a766d29SGerd Hoffmann } 8112a766d29SGerd Hoffmann break; 8122a766d29SGerd Hoffmann 8132a766d29SGerd Hoffmann default: 8142a766d29SGerd Hoffmann /* keep gcc happy */ 8152a766d29SGerd Hoffmann break; 8162a766d29SGerd Hoffmann } 817fd214d18SGerd Hoffmann } 818fd214d18SGerd Hoffmann 8192a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 8202a766d29SGerd Hoffmann { 8212a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 8222a766d29SGerd Hoffmann 823143c04c7SGeoffrey McRae /* do not sync while disabled to prevent stream corruption */ 824143c04c7SGeoffrey McRae if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 825143c04c7SGeoffrey McRae return; 826143c04c7SGeoffrey McRae } 827143c04c7SGeoffrey McRae 8282a766d29SGerd Hoffmann if (s->mouse_buttons) { 829fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 8302a766d29SGerd Hoffmann } 8312858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 8320e43e99cSbellard /* if not remote, send event. Multiple events are sent if 8330e43e99cSbellard too big deltas */ 8347abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 8350e43e99cSbellard if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) 8360e43e99cSbellard break; 8370e43e99cSbellard } 8380e43e99cSbellard } 8390e43e99cSbellard } 8400e43e99cSbellard 841548df2acSths void ps2_mouse_fake_event(void *opaque) 842548df2acSths { 8432a766d29SGerd Hoffmann PS2MouseState *s = opaque; 8445edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 8452a766d29SGerd Hoffmann s->mouse_dx++; 8462a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 847548df2acSths } 848548df2acSths 8490e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 8500e43e99cSbellard { 8510e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 8525edab03dSDon Koch 8535edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 8540e43e99cSbellard switch(s->common.write_cmd) { 8550e43e99cSbellard default: 8560e43e99cSbellard case -1: 8570e43e99cSbellard /* mouse command */ 8580e43e99cSbellard if (s->mouse_wrap) { 8590e43e99cSbellard if (val == AUX_RESET_WRAP) { 8600e43e99cSbellard s->mouse_wrap = 0; 8610e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8620e43e99cSbellard return; 8630e43e99cSbellard } else if (val != AUX_RESET) { 8640e43e99cSbellard ps2_queue(&s->common, val); 8650e43e99cSbellard return; 8660e43e99cSbellard } 8670e43e99cSbellard } 8680e43e99cSbellard switch(val) { 8690e43e99cSbellard case AUX_SET_SCALE11: 8700e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 8710e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8720e43e99cSbellard break; 8730e43e99cSbellard case AUX_SET_SCALE21: 8740e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 8750e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8760e43e99cSbellard break; 8770e43e99cSbellard case AUX_SET_STREAM: 8780e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 8790e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8800e43e99cSbellard break; 8810e43e99cSbellard case AUX_SET_WRAP: 8820e43e99cSbellard s->mouse_wrap = 1; 8830e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8840e43e99cSbellard break; 8850e43e99cSbellard case AUX_SET_REMOTE: 8860e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 8870e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8880e43e99cSbellard break; 8890e43e99cSbellard case AUX_GET_TYPE: 8907abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 8917abe7eb2SGeoffrey McRae AUX_ACK, 8927abe7eb2SGeoffrey McRae s->mouse_type); 8930e43e99cSbellard break; 8940e43e99cSbellard case AUX_SET_RES: 8950e43e99cSbellard case AUX_SET_SAMPLE: 8960e43e99cSbellard s->common.write_cmd = val; 8970e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 8980e43e99cSbellard break; 8990e43e99cSbellard case AUX_GET_SCALE: 9007abe7eb2SGeoffrey McRae ps2_queue_4(&s->common, 9017abe7eb2SGeoffrey McRae AUX_ACK, 9027abe7eb2SGeoffrey McRae s->mouse_status, 9037abe7eb2SGeoffrey McRae s->mouse_resolution, 9047abe7eb2SGeoffrey McRae s->mouse_sample_rate); 9050e43e99cSbellard break; 9060e43e99cSbellard case AUX_POLL: 9070e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9080e43e99cSbellard ps2_mouse_send_packet(s); 9090e43e99cSbellard break; 9100e43e99cSbellard case AUX_ENABLE_DEV: 9110e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 9120e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9130e43e99cSbellard break; 9140e43e99cSbellard case AUX_DISABLE_DEV: 9150e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 9160e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9170e43e99cSbellard break; 9180e43e99cSbellard case AUX_SET_DEFAULT: 9190e43e99cSbellard s->mouse_sample_rate = 100; 9200e43e99cSbellard s->mouse_resolution = 2; 9210e43e99cSbellard s->mouse_status = 0; 9220e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9230e43e99cSbellard break; 9240e43e99cSbellard case AUX_RESET: 9250e43e99cSbellard s->mouse_sample_rate = 100; 9260e43e99cSbellard s->mouse_resolution = 2; 9270e43e99cSbellard s->mouse_status = 0; 9280e43e99cSbellard s->mouse_type = 0; 929143c04c7SGeoffrey McRae ps2_reset_queue(&s->common); 9307abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 9317abe7eb2SGeoffrey McRae AUX_ACK, 9327abe7eb2SGeoffrey McRae 0xaa, 9337abe7eb2SGeoffrey McRae s->mouse_type); 9340e43e99cSbellard break; 9350e43e99cSbellard default: 9360e43e99cSbellard break; 9370e43e99cSbellard } 9380e43e99cSbellard break; 9390e43e99cSbellard case AUX_SET_SAMPLE: 9400e43e99cSbellard s->mouse_sample_rate = val; 9410e43e99cSbellard /* detect IMPS/2 or IMEX */ 9420e43e99cSbellard switch(s->mouse_detect_state) { 9430e43e99cSbellard default: 9440e43e99cSbellard case 0: 9450e43e99cSbellard if (val == 200) 9460e43e99cSbellard s->mouse_detect_state = 1; 9470e43e99cSbellard break; 9480e43e99cSbellard case 1: 9490e43e99cSbellard if (val == 100) 9500e43e99cSbellard s->mouse_detect_state = 2; 9510e43e99cSbellard else if (val == 200) 9520e43e99cSbellard s->mouse_detect_state = 3; 9530e43e99cSbellard else 9540e43e99cSbellard s->mouse_detect_state = 0; 9550e43e99cSbellard break; 9560e43e99cSbellard case 2: 9570e43e99cSbellard if (val == 80) 9580e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 9590e43e99cSbellard s->mouse_detect_state = 0; 9600e43e99cSbellard break; 9610e43e99cSbellard case 3: 9620e43e99cSbellard if (val == 80) 9630e43e99cSbellard s->mouse_type = 4; /* IMEX */ 9640e43e99cSbellard s->mouse_detect_state = 0; 9650e43e99cSbellard break; 9660e43e99cSbellard } 9670e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9680e43e99cSbellard s->common.write_cmd = -1; 9690e43e99cSbellard break; 9700e43e99cSbellard case AUX_SET_RES: 9710e43e99cSbellard s->mouse_resolution = val; 9720e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9730e43e99cSbellard s->common.write_cmd = -1; 9740e43e99cSbellard break; 9750e43e99cSbellard } 9760e43e99cSbellard } 9770e43e99cSbellard 978ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 9790e43e99cSbellard { 9800e43e99cSbellard s->write_cmd = -1; 981954ee55bSGerd Hoffmann ps2_reset_queue(s); 982deeccef3Saliguori s->update_irq(s->update_arg, 0); 9830e43e99cSbellard } 9840e43e99cSbellard 9852858ab09SGonglei static void ps2_common_post_load(PS2State *s) 9862858ab09SGonglei { 9872858ab09SGonglei PS2Queue *q = &s->queue; 9882858ab09SGonglei 98947db2432SVolker Rümelin /* set the useful data buffer queue size <= PS2_QUEUE_SIZE */ 990a1f2ed2aSPavel Dovgalyuk if (q->count < 0) { 99147db2432SVolker Rümelin q->count = 0; 992a1f2ed2aSPavel Dovgalyuk } else if (q->count > PS2_QUEUE_SIZE) { 99347db2432SVolker Rümelin q->count = PS2_QUEUE_SIZE; 994a1f2ed2aSPavel Dovgalyuk } 9952858ab09SGonglei 99647db2432SVolker Rümelin /* sanitize rptr and recalculate wptr */ 99747db2432SVolker Rümelin q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1); 99847db2432SVolker Rümelin q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1); 9992858ab09SGonglei } 10002858ab09SGonglei 1001ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 1002ef74679aSDinesh Subhraveti { 1003ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 1004ef74679aSDinesh Subhraveti 10055edab03dSDon Koch trace_ps2_kbd_reset(opaque); 1006ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 1007d2e550a8SHervé Poussineau s->scan_enabled = 1; 1008ef74679aSDinesh Subhraveti s->translate = 0; 1009089adafdSHervé Poussineau s->scancode_set = 2; 1010620775d1SDaniel P. Berrange s->modifiers = 0; 1011ef74679aSDinesh Subhraveti } 1012ef74679aSDinesh Subhraveti 1013ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 1014ef74679aSDinesh Subhraveti { 1015ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 1016ef74679aSDinesh Subhraveti 10175edab03dSDon Koch trace_ps2_mouse_reset(opaque); 1018ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 1019ef74679aSDinesh Subhraveti s->mouse_status = 0; 1020ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 1021ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 1022ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 1023ef74679aSDinesh Subhraveti s->mouse_type = 0; 1024ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 1025ef74679aSDinesh Subhraveti s->mouse_dx = 0; 1026ef74679aSDinesh Subhraveti s->mouse_dy = 0; 1027ef74679aSDinesh Subhraveti s->mouse_dz = 0; 1028ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 1029ef74679aSDinesh Subhraveti } 1030ef74679aSDinesh Subhraveti 1031b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 1032b31442c3SJuan Quintela .name = "PS2 Common State", 1033b31442c3SJuan Quintela .version_id = 3, 1034b31442c3SJuan Quintela .minimum_version_id = 2, 1035b31442c3SJuan Quintela .fields = (VMStateField[]) { 1036b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 1037b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 1038b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 1039b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 1040b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 1041b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 10427783e9f0Spbrook } 1043b31442c3SJuan Quintela }; 10447783e9f0Spbrook 10457f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 10467f540ab5SChristophe Fergeau { 10477f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 10487f540ab5SChristophe Fergeau 10497f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 10507f540ab5SChristophe Fergeau } 10517f540ab5SChristophe Fergeau 10527f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 10537f540ab5SChristophe Fergeau { 10547f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 10557f540ab5SChristophe Fergeau 10567f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 10577f540ab5SChristophe Fergeau return 0; 10587f540ab5SChristophe Fergeau } 10597f540ab5SChristophe Fergeau 10607f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 10617f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 10627f540ab5SChristophe Fergeau .version_id = 3, 10637f540ab5SChristophe Fergeau .minimum_version_id = 2, 10647f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 10655cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 10667f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 10677f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 10687f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 10697f540ab5SChristophe Fergeau } 10707f540ab5SChristophe Fergeau }; 10717f540ab5SChristophe Fergeau 107257d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 107357d5c005SHervé Poussineau { 107457d5c005SHervé Poussineau PS2KbdState *s = opaque; 107557d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 107657d5c005SHervé Poussineau } 107757d5c005SHervé Poussineau 107857d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 107957d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 108057d5c005SHervé Poussineau .version_id = 1, 108157d5c005SHervé Poussineau .minimum_version_id = 1, 108257d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 108357d5c005SHervé Poussineau .fields = (VMStateField[]) { 108457d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 108557d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 108657d5c005SHervé Poussineau } 108757d5c005SHervé Poussineau }; 108857d5c005SHervé Poussineau 1089db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 10900e43e99cSbellard { 10910e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 10922858ab09SGonglei PS2State *ps2 = &s->common; 10930e43e99cSbellard 1094db596c53SJuan Quintela if (version_id == 2) 1095e7d93956Saurel32 s->scancode_set=2; 10962858ab09SGonglei 10972858ab09SGonglei ps2_common_post_load(ps2); 10982858ab09SGonglei 10990e43e99cSbellard return 0; 11000e43e99cSbellard } 11010e43e99cSbellard 1102b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 1103b31442c3SJuan Quintela .name = "ps2kbd", 1104b31442c3SJuan Quintela .version_id = 3, 1105db596c53SJuan Quintela .minimum_version_id = 2, 1106db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 1107b31442c3SJuan Quintela .fields = (VMStateField[]) { 1108b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 1109b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 1110b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 1111b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 1112b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 11137f540ab5SChristophe Fergeau }, 11145cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 11155cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 111657d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 11175cd8cadaSJuan Quintela NULL 11180e43e99cSbellard } 1119b31442c3SJuan Quintela }; 1120b31442c3SJuan Quintela 11212858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 11222858ab09SGonglei { 11232858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 11242858ab09SGonglei PS2State *ps2 = &s->common; 11252858ab09SGonglei 11262858ab09SGonglei ps2_common_post_load(ps2); 11272858ab09SGonglei 11282858ab09SGonglei return 0; 11292858ab09SGonglei } 11302858ab09SGonglei 1131b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1132b31442c3SJuan Quintela .name = "ps2mouse", 1133b31442c3SJuan Quintela .version_id = 2, 1134b31442c3SJuan Quintela .minimum_version_id = 2, 11352858ab09SGonglei .post_load = ps2_mouse_post_load, 1136b31442c3SJuan Quintela .fields = (VMStateField[]) { 1137b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 1138b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1139b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1140b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1141b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1142b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1143b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1144b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1145b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1146b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1147b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1148b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1149b31442c3SJuan Quintela } 1150b31442c3SJuan Quintela }; 11510e43e99cSbellard 115266e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 115366e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 115466e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 115566e6536eSGerd Hoffmann .event = ps2_keyboard_event, 115666e6536eSGerd Hoffmann }; 115766e6536eSGerd Hoffmann 11580e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 11590e43e99cSbellard { 11607267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 11610e43e99cSbellard 11625edab03dSDon Koch trace_ps2_kbd_init(s); 11630e43e99cSbellard s->common.update_irq = update_irq; 11640e43e99cSbellard s->common.update_arg = update_arg; 1165e7d93956Saurel32 s->scancode_set = 2; 11660be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 116766e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 116866e6536eSGerd Hoffmann &ps2_keyboard_handler); 1169ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 11700e43e99cSbellard return s; 11710e43e99cSbellard } 11720e43e99cSbellard 11732a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 11742a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 11752a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 11762a766d29SGerd Hoffmann .event = ps2_mouse_event, 11772a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 11782a766d29SGerd Hoffmann }; 11792a766d29SGerd Hoffmann 11800e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 11810e43e99cSbellard { 11827267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 11830e43e99cSbellard 11845edab03dSDon Koch trace_ps2_mouse_init(s); 11850e43e99cSbellard s->common.update_irq = update_irq; 11860e43e99cSbellard s->common.update_arg = update_arg; 11870be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 11882a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 11892a766d29SGerd Hoffmann &ps2_mouse_handler); 1190ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 11910e43e99cSbellard return s; 11920e43e99cSbellard } 1193