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 */ 834e9bddcbSVolker Rümelin #define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */ 840e43e99cSbellard 85620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */ 86620775d1SDaniel P. Berrange #define MOD_CTRL_L (1 << 0) 87620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1) 88620775d1SDaniel P. Berrange #define MOD_ALT_L (1 << 2) 89620775d1SDaniel P. Berrange #define MOD_CTRL_R (1 << 3) 90620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4) 91620775d1SDaniel P. Berrange #define MOD_ALT_R (1 << 5) 92620775d1SDaniel P. Berrange 930e43e99cSbellard typedef struct { 9447db2432SVolker Rümelin uint8_t data[PS2_BUFFER_SIZE]; 959e24b2ddSVolker Rümelin int rptr, wptr, cwptr, count; 960e43e99cSbellard } PS2Queue; 970e43e99cSbellard 988498bb8dSGerd Hoffmann struct PS2State { 990e43e99cSbellard PS2Queue queue; 1000e43e99cSbellard int32_t write_cmd; 1010e43e99cSbellard void (*update_irq)(void *, int); 1020e43e99cSbellard void *update_arg; 1038498bb8dSGerd Hoffmann }; 1040e43e99cSbellard 1050e43e99cSbellard typedef struct { 1060e43e99cSbellard PS2State common; 1070e43e99cSbellard int scan_enabled; 108f94f5d71Spbrook int translate; 109e7d93956Saurel32 int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */ 1107f540ab5SChristophe Fergeau int ledstate; 11157d5c005SHervé Poussineau bool need_high_bit; 112620775d1SDaniel P. Berrange unsigned int modifiers; /* bitmask of MOD_* constants above */ 1130e43e99cSbellard } PS2KbdState; 1140e43e99cSbellard 1150e43e99cSbellard typedef struct { 1160e43e99cSbellard PS2State common; 1170e43e99cSbellard uint8_t mouse_status; 1180e43e99cSbellard uint8_t mouse_resolution; 1190e43e99cSbellard uint8_t mouse_sample_rate; 1200e43e99cSbellard uint8_t mouse_wrap; 1210e43e99cSbellard uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ 1220e43e99cSbellard uint8_t mouse_detect_state; 1230e43e99cSbellard int mouse_dx; /* current values, needed for 'poll' mode */ 1240e43e99cSbellard int mouse_dy; 1250e43e99cSbellard int mouse_dz; 126*64ebbb7dSDmitry Petrov int mouse_dw; 1270e43e99cSbellard uint8_t mouse_buttons; 1280e43e99cSbellard } PS2MouseState; 1290e43e99cSbellard 13057d5c005SHervé Poussineau static uint8_t translate_table[256] = { 13157d5c005SHervé Poussineau 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 13257d5c005SHervé Poussineau 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 13357d5c005SHervé Poussineau 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 13457d5c005SHervé Poussineau 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 13557d5c005SHervé Poussineau 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 13657d5c005SHervé Poussineau 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 13757d5c005SHervé Poussineau 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 13857d5c005SHervé Poussineau 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 13957d5c005SHervé Poussineau 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 14057d5c005SHervé Poussineau 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 14157d5c005SHervé Poussineau 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 14257d5c005SHervé Poussineau 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 14357d5c005SHervé Poussineau 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 14457d5c005SHervé Poussineau 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 14557d5c005SHervé Poussineau 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 14657d5c005SHervé Poussineau 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 14757d5c005SHervé Poussineau 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 14857d5c005SHervé Poussineau 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 14957d5c005SHervé Poussineau 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 15057d5c005SHervé Poussineau 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 15157d5c005SHervé Poussineau 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 15257d5c005SHervé Poussineau 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 15357d5c005SHervé Poussineau 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 15457d5c005SHervé Poussineau 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 15557d5c005SHervé Poussineau 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 15657d5c005SHervé Poussineau 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 15757d5c005SHervé Poussineau 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 15857d5c005SHervé Poussineau 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 15957d5c005SHervé Poussineau 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 16057d5c005SHervé Poussineau 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 16157d5c005SHervé Poussineau 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 16257d5c005SHervé Poussineau 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 16357d5c005SHervé Poussineau }; 16457d5c005SHervé Poussineau 165620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key) 166620775d1SDaniel P. Berrange { 167620775d1SDaniel P. Berrange switch (key) { 168620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL: 169620775d1SDaniel P. Berrange return MOD_CTRL_L; 170620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL_R: 171620775d1SDaniel P. Berrange return MOD_CTRL_R; 172620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT: 173620775d1SDaniel P. Berrange return MOD_SHIFT_L; 174620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT_R: 175620775d1SDaniel P. Berrange return MOD_SHIFT_R; 176620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT: 177620775d1SDaniel P. Berrange return MOD_ALT_L; 178620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT_R: 179620775d1SDaniel P. Berrange return MOD_ALT_R; 180620775d1SDaniel P. Berrange default: 181620775d1SDaniel P. Berrange return 0; 182620775d1SDaniel P. Berrange } 183620775d1SDaniel P. Berrange } 184620775d1SDaniel P. Berrange 185954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s) 186954ee55bSGerd Hoffmann { 187954ee55bSGerd Hoffmann PS2Queue *q = &s->queue; 188954ee55bSGerd Hoffmann 189954ee55bSGerd Hoffmann q->rptr = 0; 190954ee55bSGerd Hoffmann q->wptr = 0; 1919e24b2ddSVolker Rümelin q->cwptr = -1; 192954ee55bSGerd Hoffmann q->count = 0; 193954ee55bSGerd Hoffmann } 194954ee55bSGerd Hoffmann 1952a6505b0SSven Schnelle int ps2_queue_empty(PS2State *s) 1962a6505b0SSven Schnelle { 1972a6505b0SSven Schnelle return s->queue.count == 0; 1982a6505b0SSven Schnelle } 1992a6505b0SSven Schnelle 2007abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 2010e43e99cSbellard { 2020e43e99cSbellard PS2Queue *q = &s->queue; 2030e43e99cSbellard 2049e24b2ddSVolker Rümelin if (q->count >= PS2_QUEUE_SIZE) { 2050e43e99cSbellard return; 2067abe7eb2SGeoffrey McRae } 2077abe7eb2SGeoffrey McRae 2080e43e99cSbellard q->data[q->wptr] = b; 20947db2432SVolker Rümelin if (++q->wptr == PS2_BUFFER_SIZE) { 2100e43e99cSbellard q->wptr = 0; 21147db2432SVolker Rümelin } 2120e43e99cSbellard q->count++; 2137abe7eb2SGeoffrey McRae } 2147abe7eb2SGeoffrey McRae 2157abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s) 2167abe7eb2SGeoffrey McRae { 2177abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 2187abe7eb2SGeoffrey McRae } 2197abe7eb2SGeoffrey McRae 2207abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 2217abe7eb2SGeoffrey McRae { 2227704bb02SVolker Rümelin if (PS2_QUEUE_SIZE - s->queue.count < 1) { 2237704bb02SVolker Rümelin return; 2247704bb02SVolker Rümelin } 2257704bb02SVolker Rümelin 2267abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 22796376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2287abe7eb2SGeoffrey McRae } 2297abe7eb2SGeoffrey McRae 2307abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 2317abe7eb2SGeoffrey McRae { 2327abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 2337abe7eb2SGeoffrey McRae return; 2347abe7eb2SGeoffrey McRae } 2357abe7eb2SGeoffrey McRae 2367abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2377abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 23896376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2397abe7eb2SGeoffrey McRae } 2407abe7eb2SGeoffrey McRae 2417abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 2427abe7eb2SGeoffrey McRae { 2437abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 2447abe7eb2SGeoffrey McRae return; 2457abe7eb2SGeoffrey McRae } 2467abe7eb2SGeoffrey McRae 2477abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2487abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2497abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 25096376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2517abe7eb2SGeoffrey McRae } 2527abe7eb2SGeoffrey McRae 2537abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 2547abe7eb2SGeoffrey McRae { 2557abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 2567abe7eb2SGeoffrey McRae return; 2577abe7eb2SGeoffrey McRae } 2587abe7eb2SGeoffrey McRae 2597abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2607abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2617abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2627abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 26396376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2640e43e99cSbellard } 2650e43e99cSbellard 2669e24b2ddSVolker Rümelin static void ps2_cqueue_data(PS2Queue *q, int b) 2679e24b2ddSVolker Rümelin { 2689e24b2ddSVolker Rümelin q->data[q->cwptr] = b; 2699e24b2ddSVolker Rümelin if (++q->cwptr >= PS2_BUFFER_SIZE) { 2709e24b2ddSVolker Rümelin q->cwptr = 0; 2719e24b2ddSVolker Rümelin } 2729e24b2ddSVolker Rümelin q->count++; 2739e24b2ddSVolker Rümelin } 2749e24b2ddSVolker Rümelin 2759e24b2ddSVolker Rümelin static void ps2_cqueue_1(PS2State *s, int b1) 2769e24b2ddSVolker Rümelin { 2779e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2789e24b2ddSVolker Rümelin 2799e24b2ddSVolker Rümelin q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1); 2809e24b2ddSVolker Rümelin q->cwptr = q->rptr; 2819e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 2829e24b2ddSVolker Rümelin ps2_raise_irq(s); 2839e24b2ddSVolker Rümelin } 2849e24b2ddSVolker Rümelin 2859e24b2ddSVolker Rümelin static void ps2_cqueue_2(PS2State *s, int b1, int b2) 2869e24b2ddSVolker Rümelin { 2879e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2889e24b2ddSVolker Rümelin 2899e24b2ddSVolker Rümelin q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1); 2909e24b2ddSVolker Rümelin q->cwptr = q->rptr; 2919e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 2929e24b2ddSVolker Rümelin ps2_cqueue_data(q, b2); 2939e24b2ddSVolker Rümelin ps2_raise_irq(s); 2949e24b2ddSVolker Rümelin } 2959e24b2ddSVolker Rümelin 2969e24b2ddSVolker Rümelin static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3) 2979e24b2ddSVolker Rümelin { 2989e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2999e24b2ddSVolker Rümelin 3009e24b2ddSVolker Rümelin q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1); 3019e24b2ddSVolker Rümelin q->cwptr = q->rptr; 3029e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 3039e24b2ddSVolker Rümelin ps2_cqueue_data(q, b2); 3049e24b2ddSVolker Rümelin ps2_cqueue_data(q, b3); 3059e24b2ddSVolker Rümelin ps2_raise_irq(s); 3069e24b2ddSVolker Rümelin } 3079e24b2ddSVolker Rümelin 3089e24b2ddSVolker Rümelin static void ps2_cqueue_reset(PS2State *s) 3099e24b2ddSVolker Rümelin { 3109e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 3119e24b2ddSVolker Rümelin int ccount; 3129e24b2ddSVolker Rümelin 3139e24b2ddSVolker Rümelin if (q->cwptr == -1) { 3149e24b2ddSVolker Rümelin return; 3159e24b2ddSVolker Rümelin } 3169e24b2ddSVolker Rümelin 3179e24b2ddSVolker Rümelin ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1); 3189e24b2ddSVolker Rümelin q->count -= ccount; 3199e24b2ddSVolker Rümelin q->rptr = q->cwptr; 3209e24b2ddSVolker Rümelin q->cwptr = -1; 3219e24b2ddSVolker Rümelin } 3229e24b2ddSVolker Rümelin 32357d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 3240e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 3250e43e99cSbellard { 326f94f5d71Spbrook PS2KbdState *s = opaque; 327e7d93956Saurel32 3285edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 329fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 33057d5c005SHervé Poussineau 33157d5c005SHervé Poussineau if (s->translate) { 33257d5c005SHervé Poussineau if (keycode == 0xf0) { 33357d5c005SHervé Poussineau s->need_high_bit = true; 33457d5c005SHervé Poussineau } else if (s->need_high_bit) { 33557d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode] | 0x80); 33657d5c005SHervé Poussineau s->need_high_bit = false; 33757d5c005SHervé Poussineau } else { 33857d5c005SHervé Poussineau ps2_queue(&s->common, translate_table[keycode]); 3397096a96dSRoy Tam } 34057d5c005SHervé Poussineau } else { 3410e43e99cSbellard ps2_queue(&s->common, keycode); 3420e43e99cSbellard } 34357d5c005SHervé Poussineau } 3440e43e99cSbellard 34566e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 34666e6536eSGerd Hoffmann InputEvent *evt) 34766e6536eSGerd Hoffmann { 34866e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 34932bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 3508c10e0baSHervé Poussineau int qcode; 351ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 352620775d1SDaniel P. Berrange int mod; 35366e6536eSGerd Hoffmann 354143c04c7SGeoffrey McRae /* do not process events while disabled to prevent stream corruption */ 355143c04c7SGeoffrey McRae if (!s->scan_enabled) { 356143c04c7SGeoffrey McRae return; 357143c04c7SGeoffrey McRae } 358143c04c7SGeoffrey McRae 359fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 3608c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 3618c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 36257d5c005SHervé Poussineau 363620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 364644f66bfSDaniel P. Berrangé trace_ps2_keyboard_event(s, qcode, key->down, mod, 365644f66bfSDaniel P. Berrangé s->modifiers, s->scancode_set, s->translate); 366620775d1SDaniel P. Berrange if (key->down) { 367620775d1SDaniel P. Berrange s->modifiers |= mod; 368620775d1SDaniel P. Berrange } else { 369620775d1SDaniel P. Berrange s->modifiers &= ~mod; 370620775d1SDaniel P. Berrange } 371620775d1SDaniel P. Berrange 3728c10e0baSHervé Poussineau if (s->scancode_set == 1) { 3738c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 37429fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 37529fd23a5SDaniel P. Berrange if (key->down) { 37629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 37729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 37829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 37929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 38029fd23a5SDaniel P. Berrange } 38129fd23a5SDaniel P. Berrange } else { 3828c10e0baSHervé Poussineau if (key->down) { 3838c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3848c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 3858c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 386927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 3878c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 3888c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 3898c10e0baSHervé Poussineau } 39029fd23a5SDaniel P. Berrange } 3918c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 392620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 393620775d1SDaniel P. Berrange if (key->down) { 394620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 395620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 396620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 397620775d1SDaniel P. Berrange } else { 398620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 399620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 400620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 401620775d1SDaniel P. Berrange } 402620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 403620775d1SDaniel P. Berrange if (key->down) { 404620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 405620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 406620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 407620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 408620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 409620775d1SDaniel P. Berrange } else { 410620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 411620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 412620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 413620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 414620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 415620775d1SDaniel P. Berrange } 4168f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 4178f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 4188f63458fSDaniel P. Berrange if (key->down) { 4198f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4208f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 4218f63458fSDaniel P. Berrange } else { 4228f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4238f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 4248f63458fSDaniel P. Berrange } 425620775d1SDaniel P. Berrange } else { 4268c10e0baSHervé Poussineau if (key->down) { 4278c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4288c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 4298c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4308c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 4318c10e0baSHervé Poussineau } else { 4328c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4338c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 4348c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4358c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 4368c10e0baSHervé Poussineau } 437620775d1SDaniel P. Berrange } 4388c10e0baSHervé Poussineau } else { 439ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset1_len) 440ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 4418c10e0baSHervé Poussineau if (keycode) { 4428c10e0baSHervé Poussineau if (keycode & 0xff00) { 4438c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4448c10e0baSHervé Poussineau } 4458c10e0baSHervé Poussineau if (!key->down) { 4468c10e0baSHervé Poussineau keycode |= 0x80; 4478c10e0baSHervé Poussineau } 4488c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 4498c10e0baSHervé Poussineau } else { 450ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 451ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 4528c10e0baSHervé Poussineau } 4538c10e0baSHervé Poussineau } 4548c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 4558c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 45629fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 45729fd23a5SDaniel P. Berrange if (key->down) { 45829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 45929fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 46029fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 46129fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 46229fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 46329fd23a5SDaniel P. Berrange } 46429fd23a5SDaniel P. Berrange } else { 4658c10e0baSHervé Poussineau if (key->down) { 4668c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4678c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4688c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4698c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4708c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4718c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4728c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4738c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4748c10e0baSHervé Poussineau } 47529fd23a5SDaniel P. Berrange } 4768c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 477620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 478620775d1SDaniel P. Berrange if (key->down) { 479620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 480620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 481620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 482620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 483620775d1SDaniel P. Berrange } else { 484620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 485620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 486620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 487620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 488620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 489620775d1SDaniel P. Berrange } 490620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 491620775d1SDaniel P. Berrange if (key->down) { 492620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 493620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 494620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 495620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 496620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 497620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 498620775d1SDaniel P. Berrange } else { 499620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 500620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 501620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 502620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 503620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 504620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 505620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 506620775d1SDaniel P. Berrange } 5078f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 5088f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 5098f63458fSDaniel P. Berrange if (key->down) { 5108f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 5118f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 5128f63458fSDaniel P. Berrange } else { 5138f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 5148f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 5158f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 5168f63458fSDaniel P. Berrange } 517620775d1SDaniel P. Berrange } else { 5188c10e0baSHervé Poussineau if (key->down) { 5198c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5208c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 5218c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5228c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 5238c10e0baSHervé Poussineau } else { 5248c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5258c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5268c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 5278c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5288c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5298c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 5308c10e0baSHervé Poussineau } 531620775d1SDaniel P. Berrange } 5328c10e0baSHervé Poussineau } else { 533ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset2_len) 534ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 5358c10e0baSHervé Poussineau if (keycode) { 5368c10e0baSHervé Poussineau if (keycode & 0xff00) { 5378c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 5388c10e0baSHervé Poussineau } 5398c10e0baSHervé Poussineau if (!key->down) { 5408c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5418c10e0baSHervé Poussineau } 5428c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 54357d5c005SHervé Poussineau } else { 544ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 545ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 54657d5c005SHervé Poussineau } 54757d5c005SHervé Poussineau } 54857d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 549ab8f9d49SDaniel P. Berrange if (qcode < qemu_input_map_qcode_to_atset3_len) 550ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 5518c10e0baSHervé Poussineau if (keycode) { 5528c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 5538c10e0baSHervé Poussineau if (!key->down) { 5548c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 55557d5c005SHervé Poussineau } 55657d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 5578c10e0baSHervé Poussineau } else { 558ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 559ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 5608c10e0baSHervé Poussineau } 56166e6536eSGerd Hoffmann } 56266e6536eSGerd Hoffmann } 56366e6536eSGerd Hoffmann 5648498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 5650e43e99cSbellard { 5660e43e99cSbellard PS2Queue *q; 5670e43e99cSbellard int val, index; 5680e43e99cSbellard 5698498bb8dSGerd Hoffmann trace_ps2_read_data(s); 5700e43e99cSbellard q = &s->queue; 5710e43e99cSbellard if (q->count == 0) { 5720e43e99cSbellard /* NOTE: if no data left, we return the last keyboard one 5730e43e99cSbellard (needed for EMM386) */ 5740e43e99cSbellard /* XXX: need a timer to do things correctly */ 5750e43e99cSbellard index = q->rptr - 1; 57647db2432SVolker Rümelin if (index < 0) { 57747db2432SVolker Rümelin index = PS2_BUFFER_SIZE - 1; 57847db2432SVolker Rümelin } 5790e43e99cSbellard val = q->data[index]; 5800e43e99cSbellard } else { 5810e43e99cSbellard val = q->data[q->rptr]; 58247db2432SVolker Rümelin if (++q->rptr == PS2_BUFFER_SIZE) { 5830e43e99cSbellard q->rptr = 0; 58447db2432SVolker Rümelin } 5850e43e99cSbellard q->count--; 5869e24b2ddSVolker Rümelin if (q->rptr == q->cwptr) { 5879e24b2ddSVolker Rümelin /* command reply queue is empty */ 5889e24b2ddSVolker Rümelin q->cwptr = -1; 5899e24b2ddSVolker Rümelin } 5900e43e99cSbellard /* reading deasserts IRQ */ 5910e43e99cSbellard s->update_irq(s->update_arg, 0); 5920e43e99cSbellard /* reassert IRQs if data left */ 593cec32524SVolker Rümelin if (q->count) { 594cec32524SVolker Rümelin s->update_irq(s->update_arg, 1); 595cec32524SVolker Rümelin } 5960e43e99cSbellard } 5970e43e99cSbellard return val; 5980e43e99cSbellard } 5990e43e99cSbellard 6007f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 6017f540ab5SChristophe Fergeau { 6025edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 6037f540ab5SChristophe Fergeau s->ledstate = ledstate; 6047f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 6057f540ab5SChristophe Fergeau } 6067f540ab5SChristophe Fergeau 6070e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 6080e43e99cSbellard { 6095edab03dSDon Koch trace_ps2_reset_keyboard(s); 6100e43e99cSbellard s->scan_enabled = 1; 611e7d93956Saurel32 s->scancode_set = 2; 6126e24ee0cSGerd Hoffmann ps2_reset_queue(&s->common); 6137f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 6140e43e99cSbellard } 6150e43e99cSbellard 6160e43e99cSbellard void ps2_write_keyboard(void *opaque, int val) 6170e43e99cSbellard { 6180e43e99cSbellard PS2KbdState *s = (PS2KbdState *)opaque; 6190e43e99cSbellard 6205edab03dSDon Koch trace_ps2_write_keyboard(opaque, val); 6219e24b2ddSVolker Rümelin ps2_cqueue_reset(&s->common); 6220e43e99cSbellard switch(s->common.write_cmd) { 6230e43e99cSbellard default: 6240e43e99cSbellard case -1: 6250e43e99cSbellard switch(val) { 6260e43e99cSbellard case 0x00: 6279e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6280e43e99cSbellard break; 6290e43e99cSbellard case 0x05: 6309e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); 6310e43e99cSbellard break; 6320e43e99cSbellard case KBD_CMD_GET_ID: 633e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 6349e24b2ddSVolker Rümelin ps2_cqueue_3(&s->common, KBD_REPLY_ACK, KBD_REPLY_ID, 6359e24b2ddSVolker Rümelin s->translate ? 0x41 : 0x83); 6360e43e99cSbellard break; 6370e43e99cSbellard case KBD_CMD_ECHO: 6389e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_CMD_ECHO); 6390e43e99cSbellard break; 6400e43e99cSbellard case KBD_CMD_ENABLE: 6410e43e99cSbellard s->scan_enabled = 1; 6429e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6430e43e99cSbellard break; 644e7d93956Saurel32 case KBD_CMD_SCANCODE: 6450e43e99cSbellard case KBD_CMD_SET_LEDS: 6460e43e99cSbellard case KBD_CMD_SET_RATE: 647c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 6480e43e99cSbellard s->common.write_cmd = val; 6499e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6500e43e99cSbellard break; 6510e43e99cSbellard case KBD_CMD_RESET_DISABLE: 6520e43e99cSbellard ps2_reset_keyboard(s); 6530e43e99cSbellard s->scan_enabled = 0; 6549e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6550e43e99cSbellard break; 6560e43e99cSbellard case KBD_CMD_RESET_ENABLE: 6570e43e99cSbellard ps2_reset_keyboard(s); 6580e43e99cSbellard s->scan_enabled = 1; 6599e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6600e43e99cSbellard break; 6610e43e99cSbellard case KBD_CMD_RESET: 6620e43e99cSbellard ps2_reset_keyboard(s); 6639e24b2ddSVolker Rümelin ps2_cqueue_2(&s->common, 6647abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 6657abe7eb2SGeoffrey McRae KBD_REPLY_POR); 6660e43e99cSbellard break; 667c56b6209SSven Schnelle case KBD_CMD_SET_TYPEMATIC: 6689e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 669c56b6209SSven Schnelle break; 6700e43e99cSbellard default: 6719e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); 6720e43e99cSbellard break; 6730e43e99cSbellard } 6740e43e99cSbellard break; 675c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 6769e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 677c56b6209SSven Schnelle s->common.write_cmd = -1; 678c56b6209SSven Schnelle break; 679e7d93956Saurel32 case KBD_CMD_SCANCODE: 680e7d93956Saurel32 if (val == 0) { 6819e24b2ddSVolker Rümelin ps2_cqueue_2(&s->common, KBD_REPLY_ACK, s->translate ? 6829e24b2ddSVolker Rümelin translate_table[s->scancode_set] : s->scancode_set); 6834df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 684e7d93956Saurel32 s->scancode_set = val; 6859e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6864df23b64SHervé Poussineau } else { 6879e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_RESEND); 688e7d93956Saurel32 } 689e7d93956Saurel32 s->common.write_cmd = -1; 690e7d93956Saurel32 break; 6910e43e99cSbellard case KBD_CMD_SET_LEDS: 6927f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 6939e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6940e43e99cSbellard s->common.write_cmd = -1; 6950e43e99cSbellard break; 6960e43e99cSbellard case KBD_CMD_SET_RATE: 6979e24b2ddSVolker Rümelin ps2_cqueue_1(&s->common, KBD_REPLY_ACK); 6980e43e99cSbellard s->common.write_cmd = -1; 6990e43e99cSbellard break; 7000e43e99cSbellard } 7010e43e99cSbellard } 7020e43e99cSbellard 703f94f5d71Spbrook /* Set the scancode translation mode. 704f94f5d71Spbrook 0 = raw scancodes. 705f94f5d71Spbrook 1 = translated scancodes (used by qemu internally). */ 706f94f5d71Spbrook 707f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode) 708f94f5d71Spbrook { 709f94f5d71Spbrook PS2KbdState *s = (PS2KbdState *)opaque; 7105edab03dSDon Koch trace_ps2_keyboard_set_translation(opaque, mode); 711f94f5d71Spbrook s->translate = mode; 712f94f5d71Spbrook } 713f94f5d71Spbrook 7147abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 7150e43e99cSbellard { 71676968101SVolker Rümelin /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ 71776968101SVolker Rümelin const int needed = s->mouse_type ? 4 : 3; 7180e43e99cSbellard unsigned int b; 719*64ebbb7dSDmitry Petrov int dx1, dy1, dz1, dw1; 7200e43e99cSbellard 7217abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->common.queue.count < needed) { 7227abe7eb2SGeoffrey McRae return 0; 7237abe7eb2SGeoffrey McRae } 7247abe7eb2SGeoffrey McRae 7250e43e99cSbellard dx1 = s->mouse_dx; 7260e43e99cSbellard dy1 = s->mouse_dy; 7270e43e99cSbellard dz1 = s->mouse_dz; 728*64ebbb7dSDmitry Petrov dw1 = s->mouse_dw; 7290e43e99cSbellard /* XXX: increase range to 8 bits ? */ 7300e43e99cSbellard if (dx1 > 127) 7310e43e99cSbellard dx1 = 127; 7320e43e99cSbellard else if (dx1 < -127) 7330e43e99cSbellard dx1 = -127; 7340e43e99cSbellard if (dy1 > 127) 7350e43e99cSbellard dy1 = 127; 7360e43e99cSbellard else if (dy1 < -127) 7370e43e99cSbellard dy1 = -127; 7380e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 7397abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 7407abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dx1 & 0xff); 7417abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dy1 & 0xff); 7420e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 7430e43e99cSbellard switch(s->mouse_type) { 7440e43e99cSbellard default: 745*64ebbb7dSDmitry Petrov /* Just ignore the wheels if not supported */ 746*64ebbb7dSDmitry Petrov s->mouse_dz = 0; 747*64ebbb7dSDmitry Petrov s->mouse_dw = 0; 7480e43e99cSbellard break; 7490e43e99cSbellard case 3: 7500e43e99cSbellard if (dz1 > 127) 7510e43e99cSbellard dz1 = 127; 7520e43e99cSbellard else if (dz1 < -127) 7530e43e99cSbellard dz1 = -127; 7547abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, dz1 & 0xff); 755*64ebbb7dSDmitry Petrov s->mouse_dz -= dz1; 756*64ebbb7dSDmitry Petrov s->mouse_dw = 0; 7570e43e99cSbellard break; 7580e43e99cSbellard case 4: 759*64ebbb7dSDmitry Petrov /* 760*64ebbb7dSDmitry Petrov * This matches what the Linux kernel expects for exps/2 in 761*64ebbb7dSDmitry Petrov * drivers/input/mouse/psmouse-base.c. Note, if you happen to 762*64ebbb7dSDmitry Petrov * press/release the 4th or 5th buttons at the same moment as a 763*64ebbb7dSDmitry Petrov * horizontal wheel scroll, those button presses will get lost. I'm not 764*64ebbb7dSDmitry Petrov * sure what to do about that, since by this point we don't know 765*64ebbb7dSDmitry Petrov * whether those buttons actually changed state. 766*64ebbb7dSDmitry Petrov */ 767*64ebbb7dSDmitry Petrov if (dw1 != 0) { 768*64ebbb7dSDmitry Petrov if (dw1 > 31) { 769*64ebbb7dSDmitry Petrov dw1 = 31; 770*64ebbb7dSDmitry Petrov } else if (dw1 < -31) { 771*64ebbb7dSDmitry Petrov dw1 = -31; 772*64ebbb7dSDmitry Petrov } 773*64ebbb7dSDmitry Petrov 774*64ebbb7dSDmitry Petrov /* 775*64ebbb7dSDmitry Petrov * linux kernel expects first 6 bits to represent the value 776*64ebbb7dSDmitry Petrov * for horizontal scroll 777*64ebbb7dSDmitry Petrov */ 778*64ebbb7dSDmitry Petrov b = (dw1 & 0x3f) | 0x40; 779*64ebbb7dSDmitry Petrov s->mouse_dw -= dw1; 780*64ebbb7dSDmitry Petrov } else { 781*64ebbb7dSDmitry Petrov if (dz1 > 7) { 7820e43e99cSbellard dz1 = 7; 783*64ebbb7dSDmitry Petrov } else if (dz1 < -7) { 7840e43e99cSbellard dz1 = -7; 785*64ebbb7dSDmitry Petrov } 786*64ebbb7dSDmitry Petrov 7870e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 788*64ebbb7dSDmitry Petrov s->mouse_dz -= dz1; 789*64ebbb7dSDmitry Petrov } 7907abe7eb2SGeoffrey McRae ps2_queue_noirq(&s->common, b); 7910e43e99cSbellard break; 7920e43e99cSbellard } 7930e43e99cSbellard 7947abe7eb2SGeoffrey McRae ps2_raise_irq(&s->common); 7957abe7eb2SGeoffrey McRae 7965edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 7970e43e99cSbellard /* update deltas */ 7980e43e99cSbellard s->mouse_dx -= dx1; 7990e43e99cSbellard s->mouse_dy -= dy1; 8007abe7eb2SGeoffrey McRae 8017abe7eb2SGeoffrey McRae return 1; 8020e43e99cSbellard } 8030e43e99cSbellard 8042a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 8052a766d29SGerd Hoffmann InputEvent *evt) 8060e43e99cSbellard { 8077fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 8088b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 8098b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 8108b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 8118b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 8128b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 8132a766d29SGerd Hoffmann }; 8142a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 815b5a1b443SEric Blake InputMoveEvent *move; 816b5a1b443SEric Blake InputBtnEvent *btn; 8170e43e99cSbellard 8180e43e99cSbellard /* check if deltas are recorded when disabled */ 8190e43e99cSbellard if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) 8200e43e99cSbellard return; 8210e43e99cSbellard 822568c73a4SEric Blake switch (evt->type) { 8232a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 82432bafa8fSEric Blake move = evt->u.rel.data; 825b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 826b5a1b443SEric Blake s->mouse_dx += move->value; 827b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 828b5a1b443SEric Blake s->mouse_dy -= move->value; 8292a766d29SGerd Hoffmann } 8302a766d29SGerd Hoffmann break; 8310e43e99cSbellard 8322a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 83332bafa8fSEric Blake btn = evt->u.btn.data; 834b5a1b443SEric Blake if (btn->down) { 835b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 836b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 8372a766d29SGerd Hoffmann s->mouse_dz--; 838b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 8392a766d29SGerd Hoffmann s->mouse_dz++; 8402a766d29SGerd Hoffmann } 841*64ebbb7dSDmitry Petrov 842*64ebbb7dSDmitry Petrov if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) { 843*64ebbb7dSDmitry Petrov s->mouse_dw--; 844*64ebbb7dSDmitry Petrov } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) { 845*64ebbb7dSDmitry Petrov s->mouse_dw++; 846*64ebbb7dSDmitry Petrov } 8472a766d29SGerd Hoffmann } else { 848b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 8492a766d29SGerd Hoffmann } 8502a766d29SGerd Hoffmann break; 8512a766d29SGerd Hoffmann 8522a766d29SGerd Hoffmann default: 8532a766d29SGerd Hoffmann /* keep gcc happy */ 8542a766d29SGerd Hoffmann break; 8552a766d29SGerd Hoffmann } 856fd214d18SGerd Hoffmann } 857fd214d18SGerd Hoffmann 8582a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 8592a766d29SGerd Hoffmann { 8602a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 8612a766d29SGerd Hoffmann 862143c04c7SGeoffrey McRae /* do not sync while disabled to prevent stream corruption */ 863143c04c7SGeoffrey McRae if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 864143c04c7SGeoffrey McRae return; 865143c04c7SGeoffrey McRae } 866143c04c7SGeoffrey McRae 8672a766d29SGerd Hoffmann if (s->mouse_buttons) { 868fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 8692a766d29SGerd Hoffmann } 8702858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 8710e43e99cSbellard /* if not remote, send event. Multiple events are sent if 8720e43e99cSbellard too big deltas */ 8737abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 874*64ebbb7dSDmitry Petrov if (s->mouse_dx == 0 && s->mouse_dy == 0 875*64ebbb7dSDmitry Petrov && s->mouse_dz == 0 && s->mouse_dw == 0) { 8760e43e99cSbellard break; 8770e43e99cSbellard } 8780e43e99cSbellard } 8790e43e99cSbellard } 880*64ebbb7dSDmitry Petrov } 8810e43e99cSbellard 882548df2acSths void ps2_mouse_fake_event(void *opaque) 883548df2acSths { 8842a766d29SGerd Hoffmann PS2MouseState *s = opaque; 8855edab03dSDon Koch trace_ps2_mouse_fake_event(opaque); 8862a766d29SGerd Hoffmann s->mouse_dx++; 8872a766d29SGerd Hoffmann ps2_mouse_sync(opaque); 888548df2acSths } 889548df2acSths 8900e43e99cSbellard void ps2_write_mouse(void *opaque, int val) 8910e43e99cSbellard { 8920e43e99cSbellard PS2MouseState *s = (PS2MouseState *)opaque; 8935edab03dSDon Koch 8945edab03dSDon Koch trace_ps2_write_mouse(opaque, val); 8950e43e99cSbellard switch(s->common.write_cmd) { 8960e43e99cSbellard default: 8970e43e99cSbellard case -1: 8980e43e99cSbellard /* mouse command */ 8990e43e99cSbellard if (s->mouse_wrap) { 9000e43e99cSbellard if (val == AUX_RESET_WRAP) { 9010e43e99cSbellard s->mouse_wrap = 0; 9020e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9030e43e99cSbellard return; 9040e43e99cSbellard } else if (val != AUX_RESET) { 9050e43e99cSbellard ps2_queue(&s->common, val); 9060e43e99cSbellard return; 9070e43e99cSbellard } 9080e43e99cSbellard } 9090e43e99cSbellard switch(val) { 9100e43e99cSbellard case AUX_SET_SCALE11: 9110e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 9120e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9130e43e99cSbellard break; 9140e43e99cSbellard case AUX_SET_SCALE21: 9150e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 9160e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9170e43e99cSbellard break; 9180e43e99cSbellard case AUX_SET_STREAM: 9190e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 9200e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9210e43e99cSbellard break; 9220e43e99cSbellard case AUX_SET_WRAP: 9230e43e99cSbellard s->mouse_wrap = 1; 9240e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9250e43e99cSbellard break; 9260e43e99cSbellard case AUX_SET_REMOTE: 9270e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 9280e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9290e43e99cSbellard break; 9300e43e99cSbellard case AUX_GET_TYPE: 9317abe7eb2SGeoffrey McRae ps2_queue_2(&s->common, 9327abe7eb2SGeoffrey McRae AUX_ACK, 9337abe7eb2SGeoffrey McRae s->mouse_type); 9340e43e99cSbellard break; 9350e43e99cSbellard case AUX_SET_RES: 9360e43e99cSbellard case AUX_SET_SAMPLE: 9370e43e99cSbellard s->common.write_cmd = val; 9380e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9390e43e99cSbellard break; 9400e43e99cSbellard case AUX_GET_SCALE: 9417abe7eb2SGeoffrey McRae ps2_queue_4(&s->common, 9427abe7eb2SGeoffrey McRae AUX_ACK, 9437abe7eb2SGeoffrey McRae s->mouse_status, 9447abe7eb2SGeoffrey McRae s->mouse_resolution, 9457abe7eb2SGeoffrey McRae s->mouse_sample_rate); 9460e43e99cSbellard break; 9470e43e99cSbellard case AUX_POLL: 9480e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9490e43e99cSbellard ps2_mouse_send_packet(s); 9500e43e99cSbellard break; 9510e43e99cSbellard case AUX_ENABLE_DEV: 9520e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 9530e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9540e43e99cSbellard break; 9550e43e99cSbellard case AUX_DISABLE_DEV: 9560e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 9570e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9580e43e99cSbellard break; 9590e43e99cSbellard case AUX_SET_DEFAULT: 9600e43e99cSbellard s->mouse_sample_rate = 100; 9610e43e99cSbellard s->mouse_resolution = 2; 9620e43e99cSbellard s->mouse_status = 0; 9630e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 9640e43e99cSbellard break; 9650e43e99cSbellard case AUX_RESET: 9660e43e99cSbellard s->mouse_sample_rate = 100; 9670e43e99cSbellard s->mouse_resolution = 2; 9680e43e99cSbellard s->mouse_status = 0; 9690e43e99cSbellard s->mouse_type = 0; 970143c04c7SGeoffrey McRae ps2_reset_queue(&s->common); 9717abe7eb2SGeoffrey McRae ps2_queue_3(&s->common, 9727abe7eb2SGeoffrey McRae AUX_ACK, 9737abe7eb2SGeoffrey McRae 0xaa, 9747abe7eb2SGeoffrey McRae s->mouse_type); 9750e43e99cSbellard break; 9760e43e99cSbellard default: 9770e43e99cSbellard break; 9780e43e99cSbellard } 9790e43e99cSbellard break; 9800e43e99cSbellard case AUX_SET_SAMPLE: 9810e43e99cSbellard s->mouse_sample_rate = val; 9820e43e99cSbellard /* detect IMPS/2 or IMEX */ 9830e43e99cSbellard switch(s->mouse_detect_state) { 9840e43e99cSbellard default: 9850e43e99cSbellard case 0: 9860e43e99cSbellard if (val == 200) 9870e43e99cSbellard s->mouse_detect_state = 1; 9880e43e99cSbellard break; 9890e43e99cSbellard case 1: 9900e43e99cSbellard if (val == 100) 9910e43e99cSbellard s->mouse_detect_state = 2; 9920e43e99cSbellard else if (val == 200) 9930e43e99cSbellard s->mouse_detect_state = 3; 9940e43e99cSbellard else 9950e43e99cSbellard s->mouse_detect_state = 0; 9960e43e99cSbellard break; 9970e43e99cSbellard case 2: 9980e43e99cSbellard if (val == 80) 9990e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 10000e43e99cSbellard s->mouse_detect_state = 0; 10010e43e99cSbellard break; 10020e43e99cSbellard case 3: 10030e43e99cSbellard if (val == 80) 10040e43e99cSbellard s->mouse_type = 4; /* IMEX */ 10050e43e99cSbellard s->mouse_detect_state = 0; 10060e43e99cSbellard break; 10070e43e99cSbellard } 10080e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 10090e43e99cSbellard s->common.write_cmd = -1; 10100e43e99cSbellard break; 10110e43e99cSbellard case AUX_SET_RES: 10120e43e99cSbellard s->mouse_resolution = val; 10130e43e99cSbellard ps2_queue(&s->common, AUX_ACK); 10140e43e99cSbellard s->common.write_cmd = -1; 10150e43e99cSbellard break; 10160e43e99cSbellard } 10170e43e99cSbellard } 10180e43e99cSbellard 1019ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s) 10200e43e99cSbellard { 10210e43e99cSbellard s->write_cmd = -1; 1022954ee55bSGerd Hoffmann ps2_reset_queue(s); 1023deeccef3Saliguori s->update_irq(s->update_arg, 0); 10240e43e99cSbellard } 10250e43e99cSbellard 10262858ab09SGonglei static void ps2_common_post_load(PS2State *s) 10272858ab09SGonglei { 10282858ab09SGonglei PS2Queue *q = &s->queue; 10294e9bddcbSVolker Rümelin int ccount = 0; 10302858ab09SGonglei 10314e9bddcbSVolker Rümelin /* limit the number of queued command replies to PS2_QUEUE_HEADROOM */ 10324e9bddcbSVolker Rümelin if (q->cwptr != -1) { 10334e9bddcbSVolker Rümelin ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1); 10344e9bddcbSVolker Rümelin if (ccount > PS2_QUEUE_HEADROOM) { 10354e9bddcbSVolker Rümelin ccount = PS2_QUEUE_HEADROOM; 10364e9bddcbSVolker Rümelin } 1037a1f2ed2aSPavel Dovgalyuk } 10382858ab09SGonglei 10394e9bddcbSVolker Rümelin /* limit the scancode queue size to PS2_QUEUE_SIZE */ 10404e9bddcbSVolker Rümelin if (q->count < ccount) { 10414e9bddcbSVolker Rümelin q->count = ccount; 10424e9bddcbSVolker Rümelin } else if (q->count > ccount + PS2_QUEUE_SIZE) { 10434e9bddcbSVolker Rümelin q->count = ccount + PS2_QUEUE_SIZE; 10444e9bddcbSVolker Rümelin } 10454e9bddcbSVolker Rümelin 10464e9bddcbSVolker Rümelin /* sanitize rptr and recalculate wptr and cwptr */ 104747db2432SVolker Rümelin q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1); 104847db2432SVolker Rümelin q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1); 10494e9bddcbSVolker Rümelin q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1; 10502858ab09SGonglei } 10512858ab09SGonglei 1052ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque) 1053ef74679aSDinesh Subhraveti { 1054ef74679aSDinesh Subhraveti PS2KbdState *s = (PS2KbdState *) opaque; 1055ef74679aSDinesh Subhraveti 10565edab03dSDon Koch trace_ps2_kbd_reset(opaque); 1057ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 1058d2e550a8SHervé Poussineau s->scan_enabled = 1; 1059ef74679aSDinesh Subhraveti s->translate = 0; 1060089adafdSHervé Poussineau s->scancode_set = 2; 1061620775d1SDaniel P. Berrange s->modifiers = 0; 1062ef74679aSDinesh Subhraveti } 1063ef74679aSDinesh Subhraveti 1064ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque) 1065ef74679aSDinesh Subhraveti { 1066ef74679aSDinesh Subhraveti PS2MouseState *s = (PS2MouseState *) opaque; 1067ef74679aSDinesh Subhraveti 10685edab03dSDon Koch trace_ps2_mouse_reset(opaque); 1069ef74679aSDinesh Subhraveti ps2_common_reset(&s->common); 1070ef74679aSDinesh Subhraveti s->mouse_status = 0; 1071ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 1072ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 1073ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 1074ef74679aSDinesh Subhraveti s->mouse_type = 0; 1075ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 1076ef74679aSDinesh Subhraveti s->mouse_dx = 0; 1077ef74679aSDinesh Subhraveti s->mouse_dy = 0; 1078ef74679aSDinesh Subhraveti s->mouse_dz = 0; 1079*64ebbb7dSDmitry Petrov s->mouse_dw = 0; 1080ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 1081ef74679aSDinesh Subhraveti } 1082ef74679aSDinesh Subhraveti 1083b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 1084b31442c3SJuan Quintela .name = "PS2 Common State", 1085b31442c3SJuan Quintela .version_id = 3, 1086b31442c3SJuan Quintela .minimum_version_id = 2, 1087b31442c3SJuan Quintela .fields = (VMStateField[]) { 1088b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 1089b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 1090b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 1091b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 1092b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 1093b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 10947783e9f0Spbrook } 1095b31442c3SJuan Quintela }; 10967783e9f0Spbrook 10977f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 10987f540ab5SChristophe Fergeau { 10997f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 11007f540ab5SChristophe Fergeau 11017f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 11027f540ab5SChristophe Fergeau } 11037f540ab5SChristophe Fergeau 11047f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 11057f540ab5SChristophe Fergeau { 11067f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 11077f540ab5SChristophe Fergeau 11087f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 11097f540ab5SChristophe Fergeau return 0; 11107f540ab5SChristophe Fergeau } 11117f540ab5SChristophe Fergeau 11127f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 11137f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 11147f540ab5SChristophe Fergeau .version_id = 3, 11157f540ab5SChristophe Fergeau .minimum_version_id = 2, 11167f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 11175cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 11187f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 11197f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 11207f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 11217f540ab5SChristophe Fergeau } 11227f540ab5SChristophe Fergeau }; 11237f540ab5SChristophe Fergeau 112457d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 112557d5c005SHervé Poussineau { 112657d5c005SHervé Poussineau PS2KbdState *s = opaque; 112757d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 112857d5c005SHervé Poussineau } 112957d5c005SHervé Poussineau 113057d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 113157d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 113257d5c005SHervé Poussineau .version_id = 1, 113357d5c005SHervé Poussineau .minimum_version_id = 1, 113457d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 113557d5c005SHervé Poussineau .fields = (VMStateField[]) { 113657d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 113757d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 113857d5c005SHervé Poussineau } 113957d5c005SHervé Poussineau }; 114057d5c005SHervé Poussineau 11414e9bddcbSVolker Rümelin static bool ps2_keyboard_cqueue_needed(void *opaque) 11424e9bddcbSVolker Rümelin { 11434e9bddcbSVolker Rümelin PS2KbdState *s = opaque; 11444e9bddcbSVolker Rümelin 11454e9bddcbSVolker Rümelin return s->common.queue.cwptr != -1; /* the queue is mostly empty */ 11464e9bddcbSVolker Rümelin } 11474e9bddcbSVolker Rümelin 11484e9bddcbSVolker Rümelin static const VMStateDescription vmstate_ps2_keyboard_cqueue = { 11494e9bddcbSVolker Rümelin .name = "ps2kbd/command_reply_queue", 11504e9bddcbSVolker Rümelin .needed = ps2_keyboard_cqueue_needed, 11514e9bddcbSVolker Rümelin .fields = (VMStateField[]) { 11524e9bddcbSVolker Rümelin VMSTATE_INT32(common.queue.cwptr, PS2KbdState), 11534e9bddcbSVolker Rümelin VMSTATE_END_OF_LIST() 11544e9bddcbSVolker Rümelin } 11554e9bddcbSVolker Rümelin }; 11564e9bddcbSVolker Rümelin 1157db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id) 11580e43e99cSbellard { 11590e43e99cSbellard PS2KbdState *s = (PS2KbdState*)opaque; 11602858ab09SGonglei PS2State *ps2 = &s->common; 11610e43e99cSbellard 1162db596c53SJuan Quintela if (version_id == 2) 1163e7d93956Saurel32 s->scancode_set=2; 11642858ab09SGonglei 11652858ab09SGonglei ps2_common_post_load(ps2); 11662858ab09SGonglei 11670e43e99cSbellard return 0; 11680e43e99cSbellard } 11690e43e99cSbellard 1170b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 1171b31442c3SJuan Quintela .name = "ps2kbd", 1172b31442c3SJuan Quintela .version_id = 3, 1173db596c53SJuan Quintela .minimum_version_id = 2, 1174db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 1175b31442c3SJuan Quintela .fields = (VMStateField[]) { 1176b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), 1177b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 1178b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 1179b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState,3), 1180b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 11817f540ab5SChristophe Fergeau }, 11825cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 11835cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 118457d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 11854e9bddcbSVolker Rümelin &vmstate_ps2_keyboard_cqueue, 11865cd8cadaSJuan Quintela NULL 11870e43e99cSbellard } 1188b31442c3SJuan Quintela }; 1189b31442c3SJuan Quintela 11902858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 11912858ab09SGonglei { 11922858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 11932858ab09SGonglei PS2State *ps2 = &s->common; 11942858ab09SGonglei 11952858ab09SGonglei ps2_common_post_load(ps2); 11962858ab09SGonglei 11972858ab09SGonglei return 0; 11982858ab09SGonglei } 11992858ab09SGonglei 1200b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1201b31442c3SJuan Quintela .name = "ps2mouse", 1202b31442c3SJuan Quintela .version_id = 2, 1203b31442c3SJuan Quintela .minimum_version_id = 2, 12042858ab09SGonglei .post_load = ps2_mouse_post_load, 1205b31442c3SJuan Quintela .fields = (VMStateField[]) { 1206b31442c3SJuan Quintela VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), 1207b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1208b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1209b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1210b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1211b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1212b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1213b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1214b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1215b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1216b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1217b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1218b31442c3SJuan Quintela } 1219b31442c3SJuan Quintela }; 12200e43e99cSbellard 122166e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 122266e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 122366e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 122466e6536eSGerd Hoffmann .event = ps2_keyboard_event, 122566e6536eSGerd Hoffmann }; 122666e6536eSGerd Hoffmann 12270e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 12280e43e99cSbellard { 12297267c094SAnthony Liguori PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); 12300e43e99cSbellard 12315edab03dSDon Koch trace_ps2_kbd_init(s); 12320e43e99cSbellard s->common.update_irq = update_irq; 12330e43e99cSbellard s->common.update_arg = update_arg; 1234e7d93956Saurel32 s->scancode_set = 2; 12350be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); 123666e6536eSGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 123766e6536eSGerd Hoffmann &ps2_keyboard_handler); 1238ef74679aSDinesh Subhraveti qemu_register_reset(ps2_kbd_reset, s); 12390e43e99cSbellard return s; 12400e43e99cSbellard } 12410e43e99cSbellard 12422a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 12432a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 12442a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 12452a766d29SGerd Hoffmann .event = ps2_mouse_event, 12462a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 12472a766d29SGerd Hoffmann }; 12482a766d29SGerd Hoffmann 12490e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 12500e43e99cSbellard { 12517267c094SAnthony Liguori PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); 12520e43e99cSbellard 12535edab03dSDon Koch trace_ps2_mouse_init(s); 12540e43e99cSbellard s->common.update_irq = update_irq; 12550e43e99cSbellard s->common.update_arg = update_arg; 12560be71e32SAlex Williamson vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); 12572a766d29SGerd Hoffmann qemu_input_handler_register((DeviceState *)s, 12582a766d29SGerd Hoffmann &ps2_mouse_handler); 1259ef74679aSDinesh Subhraveti qemu_register_reset(ps2_mouse_reset, s); 12600e43e99cSbellard return s; 12610e43e99cSbellard } 1262