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" 27*6beb79e1SMark Cave-Ayland #include "hw/irq.h" 2864bbdd13SMark Cave-Ayland #include "hw/sysbus.h" 290d09e41aSPaolo Bonzini #include "hw/input/ps2.h" 30d6454270SMarkus Armbruster #include "migration/vmstate.h" 3128ecbaeeSPaolo Bonzini #include "ui/console.h" 3266e6536eSGerd Hoffmann #include "ui/input.h" 3371e8a915SMarkus Armbruster #include "sysemu/reset.h" 3454d31236SMarkus Armbruster #include "sysemu/runstate.h" 358f84e53cSMark Cave-Ayland #include "qapi/error.h" 360e43e99cSbellard 375edab03dSDon Koch #include "trace.h" 385edab03dSDon Koch 390e43e99cSbellard /* Keyboard Commands */ 400e43e99cSbellard #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ 410e43e99cSbellard #define KBD_CMD_ECHO 0xEE 42e7d93956Saurel32 #define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */ 430e43e99cSbellard #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ 440e43e99cSbellard #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ 450e43e99cSbellard #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ 460e43e99cSbellard #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ 470e43e99cSbellard #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ 480e43e99cSbellard #define KBD_CMD_RESET 0xFF /* Reset */ 49c56b6209SSven Schnelle #define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */ 50c56b6209SSven Schnelle #define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */ 510e43e99cSbellard 520e43e99cSbellard /* Keyboard Replies */ 530e43e99cSbellard #define KBD_REPLY_POR 0xAA /* Power on reset */ 5435c4d671Saurel32 #define KBD_REPLY_ID 0xAB /* Keyboard ID */ 550e43e99cSbellard #define KBD_REPLY_ACK 0xFA /* Command ACK */ 560e43e99cSbellard #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ 570e43e99cSbellard 580e43e99cSbellard /* Mouse Commands */ 590e43e99cSbellard #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ 600e43e99cSbellard #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ 610e43e99cSbellard #define AUX_SET_RES 0xE8 /* Set resolution */ 620e43e99cSbellard #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ 630e43e99cSbellard #define AUX_SET_STREAM 0xEA /* Set stream mode */ 640e43e99cSbellard #define AUX_POLL 0xEB /* Poll */ 650e43e99cSbellard #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ 660e43e99cSbellard #define AUX_SET_WRAP 0xEE /* Set wrap mode */ 670e43e99cSbellard #define AUX_SET_REMOTE 0xF0 /* Set remote mode */ 680e43e99cSbellard #define AUX_GET_TYPE 0xF2 /* Get type */ 690e43e99cSbellard #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ 700e43e99cSbellard #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ 710e43e99cSbellard #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ 720e43e99cSbellard #define AUX_SET_DEFAULT 0xF6 730e43e99cSbellard #define AUX_RESET 0xFF /* Reset aux device */ 740e43e99cSbellard #define AUX_ACK 0xFA /* Command byte ACK. */ 750e43e99cSbellard 760e43e99cSbellard #define MOUSE_STATUS_REMOTE 0x40 770e43e99cSbellard #define MOUSE_STATUS_ENABLED 0x20 780e43e99cSbellard #define MOUSE_STATUS_SCALE21 0x10 790e43e99cSbellard 8047db2432SVolker Rümelin #define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */ 814e9bddcbSVolker Rümelin #define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */ 820e43e99cSbellard 83620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */ 84620775d1SDaniel P. Berrange #define MOD_CTRL_L (1 << 0) 85620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1) 86620775d1SDaniel P. Berrange #define MOD_ALT_L (1 << 2) 87620775d1SDaniel P. Berrange #define MOD_CTRL_R (1 << 3) 88620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4) 89620775d1SDaniel P. Berrange #define MOD_ALT_R (1 << 5) 90620775d1SDaniel P. Berrange 9157d5c005SHervé Poussineau static uint8_t translate_table[256] = { 9257d5c005SHervé Poussineau 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 9357d5c005SHervé Poussineau 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 9457d5c005SHervé Poussineau 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 9557d5c005SHervé Poussineau 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 9657d5c005SHervé Poussineau 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 9757d5c005SHervé Poussineau 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 9857d5c005SHervé Poussineau 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 9957d5c005SHervé Poussineau 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 10057d5c005SHervé Poussineau 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 10157d5c005SHervé Poussineau 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 10257d5c005SHervé Poussineau 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 10357d5c005SHervé Poussineau 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 10457d5c005SHervé Poussineau 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 10557d5c005SHervé Poussineau 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 10657d5c005SHervé Poussineau 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 10757d5c005SHervé Poussineau 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 10857d5c005SHervé Poussineau 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 10957d5c005SHervé Poussineau 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 11057d5c005SHervé Poussineau 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 11157d5c005SHervé Poussineau 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 11257d5c005SHervé Poussineau 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 11357d5c005SHervé Poussineau 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 11457d5c005SHervé Poussineau 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 11557d5c005SHervé Poussineau 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 11657d5c005SHervé Poussineau 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 11757d5c005SHervé Poussineau 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 11857d5c005SHervé Poussineau 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 11957d5c005SHervé Poussineau 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 12057d5c005SHervé Poussineau 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 12157d5c005SHervé Poussineau 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 12257d5c005SHervé Poussineau 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 12357d5c005SHervé Poussineau 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 12457d5c005SHervé Poussineau }; 12557d5c005SHervé Poussineau 126620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key) 127620775d1SDaniel P. Berrange { 128620775d1SDaniel P. Berrange switch (key) { 129620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL: 130620775d1SDaniel P. Berrange return MOD_CTRL_L; 131620775d1SDaniel P. Berrange case Q_KEY_CODE_CTRL_R: 132620775d1SDaniel P. Berrange return MOD_CTRL_R; 133620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT: 134620775d1SDaniel P. Berrange return MOD_SHIFT_L; 135620775d1SDaniel P. Berrange case Q_KEY_CODE_SHIFT_R: 136620775d1SDaniel P. Berrange return MOD_SHIFT_R; 137620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT: 138620775d1SDaniel P. Berrange return MOD_ALT_L; 139620775d1SDaniel P. Berrange case Q_KEY_CODE_ALT_R: 140620775d1SDaniel P. Berrange return MOD_ALT_R; 141620775d1SDaniel P. Berrange default: 142620775d1SDaniel P. Berrange return 0; 143620775d1SDaniel P. Berrange } 144620775d1SDaniel P. Berrange } 145620775d1SDaniel P. Berrange 146954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s) 147954ee55bSGerd Hoffmann { 148954ee55bSGerd Hoffmann PS2Queue *q = &s->queue; 149954ee55bSGerd Hoffmann 150954ee55bSGerd Hoffmann q->rptr = 0; 151954ee55bSGerd Hoffmann q->wptr = 0; 1529e24b2ddSVolker Rümelin q->cwptr = -1; 153954ee55bSGerd Hoffmann q->count = 0; 154954ee55bSGerd Hoffmann } 155954ee55bSGerd Hoffmann 1562a6505b0SSven Schnelle int ps2_queue_empty(PS2State *s) 1572a6505b0SSven Schnelle { 1582a6505b0SSven Schnelle return s->queue.count == 0; 1592a6505b0SSven Schnelle } 1602a6505b0SSven Schnelle 1617abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b) 1620e43e99cSbellard { 1630e43e99cSbellard PS2Queue *q = &s->queue; 1640e43e99cSbellard 1659e24b2ddSVolker Rümelin if (q->count >= PS2_QUEUE_SIZE) { 1660e43e99cSbellard return; 1677abe7eb2SGeoffrey McRae } 1687abe7eb2SGeoffrey McRae 1690e43e99cSbellard q->data[q->wptr] = b; 17047db2432SVolker Rümelin if (++q->wptr == PS2_BUFFER_SIZE) { 1710e43e99cSbellard q->wptr = 0; 17247db2432SVolker Rümelin } 1730e43e99cSbellard q->count++; 1747abe7eb2SGeoffrey McRae } 1757abe7eb2SGeoffrey McRae 17652b28f76SMark Cave-Ayland static void ps2_raise_irq(PS2State *s) 1777abe7eb2SGeoffrey McRae { 178*6beb79e1SMark Cave-Ayland if (qemu_irq_is_connected(s->irq)) { 179*6beb79e1SMark Cave-Ayland qemu_set_irq(s->irq, 1); 180*6beb79e1SMark Cave-Ayland } else { 1817abe7eb2SGeoffrey McRae s->update_irq(s->update_arg, 1); 1827abe7eb2SGeoffrey McRae } 183*6beb79e1SMark Cave-Ayland } 1847abe7eb2SGeoffrey McRae 1855cb6e556SMark Cave-Ayland static void ps2_lower_irq(PS2State *s) 1865cb6e556SMark Cave-Ayland { 187*6beb79e1SMark Cave-Ayland if (qemu_irq_is_connected(s->irq)) { 188*6beb79e1SMark Cave-Ayland qemu_set_irq(s->irq, 0); 189*6beb79e1SMark Cave-Ayland } else { 1905cb6e556SMark Cave-Ayland s->update_irq(s->update_arg, 0); 1915cb6e556SMark Cave-Ayland } 192*6beb79e1SMark Cave-Ayland } 1935cb6e556SMark Cave-Ayland 1947abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b) 1957abe7eb2SGeoffrey McRae { 1967704bb02SVolker Rümelin if (PS2_QUEUE_SIZE - s->queue.count < 1) { 1977704bb02SVolker Rümelin return; 1987704bb02SVolker Rümelin } 1997704bb02SVolker Rümelin 2007abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b); 20196376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2027abe7eb2SGeoffrey McRae } 2037abe7eb2SGeoffrey McRae 2047abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2) 2057abe7eb2SGeoffrey McRae { 2067abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 2) { 2077abe7eb2SGeoffrey McRae return; 2087abe7eb2SGeoffrey McRae } 2097abe7eb2SGeoffrey McRae 2107abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2117abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 21296376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2137abe7eb2SGeoffrey McRae } 2147abe7eb2SGeoffrey McRae 2157abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3) 2167abe7eb2SGeoffrey McRae { 2177abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 3) { 2187abe7eb2SGeoffrey McRae return; 2197abe7eb2SGeoffrey McRae } 2207abe7eb2SGeoffrey McRae 2217abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2227abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2237abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 22496376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2257abe7eb2SGeoffrey McRae } 2267abe7eb2SGeoffrey McRae 2277abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4) 2287abe7eb2SGeoffrey McRae { 2297abe7eb2SGeoffrey McRae if (PS2_QUEUE_SIZE - s->queue.count < 4) { 2307abe7eb2SGeoffrey McRae return; 2317abe7eb2SGeoffrey McRae } 2327abe7eb2SGeoffrey McRae 2337abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b1); 2347abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b2); 2357abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b3); 2367abe7eb2SGeoffrey McRae ps2_queue_noirq(s, b4); 23796376ab1SPhilippe Mathieu-Daudé ps2_raise_irq(s); 2380e43e99cSbellard } 2390e43e99cSbellard 2409e24b2ddSVolker Rümelin static void ps2_cqueue_data(PS2Queue *q, int b) 2419e24b2ddSVolker Rümelin { 2429e24b2ddSVolker Rümelin q->data[q->cwptr] = b; 2439e24b2ddSVolker Rümelin if (++q->cwptr >= PS2_BUFFER_SIZE) { 2449e24b2ddSVolker Rümelin q->cwptr = 0; 2459e24b2ddSVolker Rümelin } 2469e24b2ddSVolker Rümelin q->count++; 2479e24b2ddSVolker Rümelin } 2489e24b2ddSVolker Rümelin 2499e24b2ddSVolker Rümelin static void ps2_cqueue_1(PS2State *s, int b1) 2509e24b2ddSVolker Rümelin { 2519e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2529e24b2ddSVolker Rümelin 2539e24b2ddSVolker Rümelin q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1); 2549e24b2ddSVolker Rümelin q->cwptr = q->rptr; 2559e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 2569e24b2ddSVolker Rümelin ps2_raise_irq(s); 2579e24b2ddSVolker Rümelin } 2589e24b2ddSVolker Rümelin 2599e24b2ddSVolker Rümelin static void ps2_cqueue_2(PS2State *s, int b1, int b2) 2609e24b2ddSVolker Rümelin { 2619e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2629e24b2ddSVolker Rümelin 2639e24b2ddSVolker Rümelin q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1); 2649e24b2ddSVolker Rümelin q->cwptr = q->rptr; 2659e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 2669e24b2ddSVolker Rümelin ps2_cqueue_data(q, b2); 2679e24b2ddSVolker Rümelin ps2_raise_irq(s); 2689e24b2ddSVolker Rümelin } 2699e24b2ddSVolker Rümelin 2709e24b2ddSVolker Rümelin static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3) 2719e24b2ddSVolker Rümelin { 2729e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2739e24b2ddSVolker Rümelin 2749e24b2ddSVolker Rümelin q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1); 2759e24b2ddSVolker Rümelin q->cwptr = q->rptr; 2769e24b2ddSVolker Rümelin ps2_cqueue_data(q, b1); 2779e24b2ddSVolker Rümelin ps2_cqueue_data(q, b2); 2789e24b2ddSVolker Rümelin ps2_cqueue_data(q, b3); 2799e24b2ddSVolker Rümelin ps2_raise_irq(s); 2809e24b2ddSVolker Rümelin } 2819e24b2ddSVolker Rümelin 2829e24b2ddSVolker Rümelin static void ps2_cqueue_reset(PS2State *s) 2839e24b2ddSVolker Rümelin { 2849e24b2ddSVolker Rümelin PS2Queue *q = &s->queue; 2859e24b2ddSVolker Rümelin int ccount; 2869e24b2ddSVolker Rümelin 2879e24b2ddSVolker Rümelin if (q->cwptr == -1) { 2889e24b2ddSVolker Rümelin return; 2899e24b2ddSVolker Rümelin } 2909e24b2ddSVolker Rümelin 2919e24b2ddSVolker Rümelin ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1); 2929e24b2ddSVolker Rümelin q->count -= ccount; 2939e24b2ddSVolker Rümelin q->rptr = q->cwptr; 2949e24b2ddSVolker Rümelin q->cwptr = -1; 2959e24b2ddSVolker Rümelin } 2969e24b2ddSVolker Rümelin 29757d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */ 2980e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode) 2990e43e99cSbellard { 300f94f5d71Spbrook PS2KbdState *s = opaque; 3018f84e53cSMark Cave-Ayland PS2State *ps = PS2_DEVICE(s); 302e7d93956Saurel32 3035edab03dSDon Koch trace_ps2_put_keycode(opaque, keycode); 304fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 30557d5c005SHervé Poussineau 30657d5c005SHervé Poussineau if (s->translate) { 30757d5c005SHervé Poussineau if (keycode == 0xf0) { 30857d5c005SHervé Poussineau s->need_high_bit = true; 30957d5c005SHervé Poussineau } else if (s->need_high_bit) { 3108f84e53cSMark Cave-Ayland ps2_queue(ps, translate_table[keycode] | 0x80); 31157d5c005SHervé Poussineau s->need_high_bit = false; 31257d5c005SHervé Poussineau } else { 3138f84e53cSMark Cave-Ayland ps2_queue(ps, translate_table[keycode]); 3147096a96dSRoy Tam } 31557d5c005SHervé Poussineau } else { 3168f84e53cSMark Cave-Ayland ps2_queue(ps, keycode); 3170e43e99cSbellard } 31857d5c005SHervé Poussineau } 3190e43e99cSbellard 32066e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, 32166e6536eSGerd Hoffmann InputEvent *evt) 32266e6536eSGerd Hoffmann { 32366e6536eSGerd Hoffmann PS2KbdState *s = (PS2KbdState *)dev; 32432bafa8fSEric Blake InputKeyEvent *key = evt->u.key.data; 3258c10e0baSHervé Poussineau int qcode; 326ab8f9d49SDaniel P. Berrange uint16_t keycode = 0; 327620775d1SDaniel P. Berrange int mod; 32866e6536eSGerd Hoffmann 329143c04c7SGeoffrey McRae /* do not process events while disabled to prevent stream corruption */ 330143c04c7SGeoffrey McRae if (!s->scan_enabled) { 331143c04c7SGeoffrey McRae return; 332143c04c7SGeoffrey McRae } 333143c04c7SGeoffrey McRae 334fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 3358c10e0baSHervé Poussineau assert(evt->type == INPUT_EVENT_KIND_KEY); 3368c10e0baSHervé Poussineau qcode = qemu_input_key_value_to_qcode(key->key); 33757d5c005SHervé Poussineau 338620775d1SDaniel P. Berrange mod = ps2_modifier_bit(qcode); 339644f66bfSDaniel P. Berrangé trace_ps2_keyboard_event(s, qcode, key->down, mod, 340644f66bfSDaniel P. Berrangé s->modifiers, s->scancode_set, s->translate); 341620775d1SDaniel P. Berrange if (key->down) { 342620775d1SDaniel P. Berrange s->modifiers |= mod; 343620775d1SDaniel P. Berrange } else { 344620775d1SDaniel P. Berrange s->modifiers &= ~mod; 345620775d1SDaniel P. Berrange } 346620775d1SDaniel P. Berrange 3478c10e0baSHervé Poussineau if (s->scancode_set == 1) { 3488c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 34929fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 35029fd23a5SDaniel P. Berrange if (key->down) { 35129fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 35229fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x46); 35329fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 35429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xc6); 35529fd23a5SDaniel P. Berrange } 35629fd23a5SDaniel P. Berrange } else { 3578c10e0baSHervé Poussineau if (key->down) { 3588c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 3598c10e0baSHervé Poussineau ps2_put_keycode(s, 0x1d); 3608c10e0baSHervé Poussineau ps2_put_keycode(s, 0x45); 361927f0425SDaniel P. Berrange ps2_put_keycode(s, 0xe1); 3628c10e0baSHervé Poussineau ps2_put_keycode(s, 0x9d); 3638c10e0baSHervé Poussineau ps2_put_keycode(s, 0xc5); 3648c10e0baSHervé Poussineau } 36529fd23a5SDaniel P. Berrange } 3668c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 367620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 368620775d1SDaniel P. Berrange if (key->down) { 369620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 370620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 371620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 372620775d1SDaniel P. Berrange } else { 373620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 374620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 375620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 376620775d1SDaniel P. Berrange } 377620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 378620775d1SDaniel P. Berrange if (key->down) { 379620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 380620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 381620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 382620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 383620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x54); 384620775d1SDaniel P. Berrange } else { 385620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xd4); 386620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 387620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xb8); 388620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 389620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x38); 390620775d1SDaniel P. Berrange } 3918f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 3928f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 3938f63458fSDaniel P. Berrange if (key->down) { 3948f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3958f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x37); 3968f63458fSDaniel P. Berrange } else { 3978f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 3988f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xb7); 3998f63458fSDaniel P. Berrange } 400620775d1SDaniel P. Berrange } else { 4018c10e0baSHervé Poussineau if (key->down) { 4028c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4038c10e0baSHervé Poussineau ps2_put_keycode(s, 0x2a); 4048c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4058c10e0baSHervé Poussineau ps2_put_keycode(s, 0x37); 4068c10e0baSHervé Poussineau } else { 4078c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4088c10e0baSHervé Poussineau ps2_put_keycode(s, 0xb7); 4098c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4108c10e0baSHervé Poussineau ps2_put_keycode(s, 0xaa); 4118c10e0baSHervé Poussineau } 412620775d1SDaniel P. Berrange } 4138c10e0baSHervé Poussineau } else { 414545e5cf8SMark Cave-Ayland if (qcode < qemu_input_map_qcode_to_atset1_len) { 415ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset1[qcode]; 416545e5cf8SMark Cave-Ayland } 4178c10e0baSHervé Poussineau if (keycode) { 4188c10e0baSHervé Poussineau if (keycode & 0xff00) { 4198c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 4208c10e0baSHervé Poussineau } 4218c10e0baSHervé Poussineau if (!key->down) { 4228c10e0baSHervé Poussineau keycode |= 0x80; 4238c10e0baSHervé Poussineau } 4248c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 4258c10e0baSHervé Poussineau } else { 426ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 427ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 4288c10e0baSHervé Poussineau } 4298c10e0baSHervé Poussineau } 4308c10e0baSHervé Poussineau } else if (s->scancode_set == 2) { 4318c10e0baSHervé Poussineau if (qcode == Q_KEY_CODE_PAUSE) { 43229fd23a5SDaniel P. Berrange if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) { 43329fd23a5SDaniel P. Berrange if (key->down) { 43429fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 43529fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 43629fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 43729fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 43829fd23a5SDaniel P. Berrange ps2_put_keycode(s, 0x7e); 43929fd23a5SDaniel P. Berrange } 44029fd23a5SDaniel P. Berrange } else { 4418c10e0baSHervé Poussineau if (key->down) { 4428c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4438c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4448c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4458c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe1); 4468c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4478c10e0baSHervé Poussineau ps2_put_keycode(s, 0x14); 4488c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 4498c10e0baSHervé Poussineau ps2_put_keycode(s, 0x77); 4508c10e0baSHervé Poussineau } 45129fd23a5SDaniel P. Berrange } 4528c10e0baSHervé Poussineau } else if (qcode == Q_KEY_CODE_PRINT) { 453620775d1SDaniel P. Berrange if (s->modifiers & MOD_ALT_L) { 454620775d1SDaniel P. Berrange if (key->down) { 455620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 456620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 457620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 458620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 459620775d1SDaniel P. Berrange } else { 460620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 461620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 462620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 463620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 464620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 465620775d1SDaniel P. Berrange } 466620775d1SDaniel P. Berrange } else if (s->modifiers & MOD_ALT_R) { 467620775d1SDaniel P. Berrange if (key->down) { 468620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 469620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 470620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 471620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 472620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 473620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 474620775d1SDaniel P. Berrange } else { 475620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 476620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x84); 477620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 478620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xf0); 479620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 480620775d1SDaniel P. Berrange ps2_put_keycode(s, 0xe0); 481620775d1SDaniel P. Berrange ps2_put_keycode(s, 0x11); 482620775d1SDaniel P. Berrange } 4838f63458fSDaniel P. Berrange } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L | 4848f63458fSDaniel P. Berrange MOD_SHIFT_R | MOD_CTRL_R)) { 4858f63458fSDaniel P. Berrange if (key->down) { 4868f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4878f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4888f63458fSDaniel P. Berrange } else { 4898f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xe0); 4908f63458fSDaniel P. Berrange ps2_put_keycode(s, 0xf0); 4918f63458fSDaniel P. Berrange ps2_put_keycode(s, 0x7c); 4928f63458fSDaniel P. Berrange } 493620775d1SDaniel P. Berrange } else { 4948c10e0baSHervé Poussineau if (key->down) { 4958c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4968c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 4978c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 4988c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 4998c10e0baSHervé Poussineau } else { 5008c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5018c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5028c10e0baSHervé Poussineau ps2_put_keycode(s, 0x7c); 5038c10e0baSHervé Poussineau ps2_put_keycode(s, 0xe0); 5048c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5058c10e0baSHervé Poussineau ps2_put_keycode(s, 0x12); 5068c10e0baSHervé Poussineau } 507620775d1SDaniel P. Berrange } 5088c10e0baSHervé Poussineau } else { 509545e5cf8SMark Cave-Ayland if (qcode < qemu_input_map_qcode_to_atset2_len) { 510ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset2[qcode]; 511545e5cf8SMark Cave-Ayland } 5128c10e0baSHervé Poussineau if (keycode) { 5138c10e0baSHervé Poussineau if (keycode & 0xff00) { 5148c10e0baSHervé Poussineau ps2_put_keycode(s, keycode >> 8); 5158c10e0baSHervé Poussineau } 5168c10e0baSHervé Poussineau if (!key->down) { 5178c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 5188c10e0baSHervé Poussineau } 5198c10e0baSHervé Poussineau ps2_put_keycode(s, keycode & 0xff); 52057d5c005SHervé Poussineau } else { 521ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 522ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 52357d5c005SHervé Poussineau } 52457d5c005SHervé Poussineau } 52557d5c005SHervé Poussineau } else if (s->scancode_set == 3) { 526545e5cf8SMark Cave-Ayland if (qcode < qemu_input_map_qcode_to_atset3_len) { 527ab8f9d49SDaniel P. Berrange keycode = qemu_input_map_qcode_to_atset3[qcode]; 528545e5cf8SMark Cave-Ayland } 5298c10e0baSHervé Poussineau if (keycode) { 5308c10e0baSHervé Poussineau /* FIXME: break code should be configured on a key by key basis */ 5318c10e0baSHervé Poussineau if (!key->down) { 5328c10e0baSHervé Poussineau ps2_put_keycode(s, 0xf0); 53357d5c005SHervé Poussineau } 53457d5c005SHervé Poussineau ps2_put_keycode(s, keycode); 5358c10e0baSHervé Poussineau } else { 536ec044a80SHervé Poussineau qemu_log_mask(LOG_UNIMP, 537ec044a80SHervé Poussineau "ps2: ignoring key with qcode %d\n", qcode); 5388c10e0baSHervé Poussineau } 53966e6536eSGerd Hoffmann } 54066e6536eSGerd Hoffmann } 54166e6536eSGerd Hoffmann 5428498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s) 5430e43e99cSbellard { 5440e43e99cSbellard PS2Queue *q; 5450e43e99cSbellard int val, index; 5460e43e99cSbellard 5478498bb8dSGerd Hoffmann trace_ps2_read_data(s); 5480e43e99cSbellard q = &s->queue; 5490e43e99cSbellard if (q->count == 0) { 550545e5cf8SMark Cave-Ayland /* 551545e5cf8SMark Cave-Ayland * NOTE: if no data left, we return the last keyboard one 552545e5cf8SMark Cave-Ayland * (needed for EMM386) 553545e5cf8SMark Cave-Ayland */ 5540e43e99cSbellard /* XXX: need a timer to do things correctly */ 5550e43e99cSbellard index = q->rptr - 1; 55647db2432SVolker Rümelin if (index < 0) { 55747db2432SVolker Rümelin index = PS2_BUFFER_SIZE - 1; 55847db2432SVolker Rümelin } 5590e43e99cSbellard val = q->data[index]; 5600e43e99cSbellard } else { 5610e43e99cSbellard val = q->data[q->rptr]; 56247db2432SVolker Rümelin if (++q->rptr == PS2_BUFFER_SIZE) { 5630e43e99cSbellard q->rptr = 0; 56447db2432SVolker Rümelin } 5650e43e99cSbellard q->count--; 5669e24b2ddSVolker Rümelin if (q->rptr == q->cwptr) { 5679e24b2ddSVolker Rümelin /* command reply queue is empty */ 5689e24b2ddSVolker Rümelin q->cwptr = -1; 5699e24b2ddSVolker Rümelin } 5700e43e99cSbellard /* reading deasserts IRQ */ 5715cb6e556SMark Cave-Ayland ps2_lower_irq(s); 5720e43e99cSbellard /* reassert IRQs if data left */ 573cec32524SVolker Rümelin if (q->count) { 574892e9bbeSMark Cave-Ayland ps2_raise_irq(s); 575cec32524SVolker Rümelin } 5760e43e99cSbellard } 5770e43e99cSbellard return val; 5780e43e99cSbellard } 5790e43e99cSbellard 5807f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate) 5817f540ab5SChristophe Fergeau { 5825edab03dSDon Koch trace_ps2_set_ledstate(s, ledstate); 5837f540ab5SChristophe Fergeau s->ledstate = ledstate; 5847f540ab5SChristophe Fergeau kbd_put_ledstate(ledstate); 5857f540ab5SChristophe Fergeau } 5867f540ab5SChristophe Fergeau 5870e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s) 5880e43e99cSbellard { 5898f84e53cSMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 5908f84e53cSMark Cave-Ayland 5915edab03dSDon Koch trace_ps2_reset_keyboard(s); 5920e43e99cSbellard s->scan_enabled = 1; 593e7d93956Saurel32 s->scancode_set = 2; 5948f84e53cSMark Cave-Ayland ps2_reset_queue(ps2); 5957f540ab5SChristophe Fergeau ps2_set_ledstate(s, 0); 5960e43e99cSbellard } 5970e43e99cSbellard 59854334e73SMark Cave-Ayland void ps2_write_keyboard(PS2KbdState *s, int val) 5990e43e99cSbellard { 6008f84e53cSMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 6010e43e99cSbellard 60254334e73SMark Cave-Ayland trace_ps2_write_keyboard(s, val); 6038f84e53cSMark Cave-Ayland ps2_cqueue_reset(ps2); 6048f84e53cSMark Cave-Ayland switch (ps2->write_cmd) { 6050e43e99cSbellard default: 6060e43e99cSbellard case -1: 6070e43e99cSbellard switch (val) { 6080e43e99cSbellard case 0x00: 6098f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6100e43e99cSbellard break; 6110e43e99cSbellard case 0x05: 6128f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_RESEND); 6130e43e99cSbellard break; 6140e43e99cSbellard case KBD_CMD_GET_ID: 615e7d93956Saurel32 /* We emulate a MF2 AT keyboard here */ 6168f84e53cSMark Cave-Ayland ps2_cqueue_3(ps2, KBD_REPLY_ACK, KBD_REPLY_ID, 6179e24b2ddSVolker Rümelin s->translate ? 0x41 : 0x83); 6180e43e99cSbellard break; 6190e43e99cSbellard case KBD_CMD_ECHO: 6208f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_CMD_ECHO); 6210e43e99cSbellard break; 6220e43e99cSbellard case KBD_CMD_ENABLE: 6230e43e99cSbellard s->scan_enabled = 1; 6248f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6250e43e99cSbellard break; 626e7d93956Saurel32 case KBD_CMD_SCANCODE: 6270e43e99cSbellard case KBD_CMD_SET_LEDS: 6280e43e99cSbellard case KBD_CMD_SET_RATE: 629c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 6308f84e53cSMark Cave-Ayland ps2->write_cmd = val; 6318f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6320e43e99cSbellard break; 6330e43e99cSbellard case KBD_CMD_RESET_DISABLE: 6340e43e99cSbellard ps2_reset_keyboard(s); 6350e43e99cSbellard s->scan_enabled = 0; 6368f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6370e43e99cSbellard break; 6380e43e99cSbellard case KBD_CMD_RESET_ENABLE: 6390e43e99cSbellard ps2_reset_keyboard(s); 6400e43e99cSbellard s->scan_enabled = 1; 6418f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6420e43e99cSbellard break; 6430e43e99cSbellard case KBD_CMD_RESET: 6440e43e99cSbellard ps2_reset_keyboard(s); 6458f84e53cSMark Cave-Ayland ps2_cqueue_2(ps2, 6467abe7eb2SGeoffrey McRae KBD_REPLY_ACK, 6477abe7eb2SGeoffrey McRae KBD_REPLY_POR); 6480e43e99cSbellard break; 649c56b6209SSven Schnelle case KBD_CMD_SET_TYPEMATIC: 6508f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 651c56b6209SSven Schnelle break; 6520e43e99cSbellard default: 6538f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_RESEND); 6540e43e99cSbellard break; 6550e43e99cSbellard } 6560e43e99cSbellard break; 657c56b6209SSven Schnelle case KBD_CMD_SET_MAKE_BREAK: 6588f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6598f84e53cSMark Cave-Ayland ps2->write_cmd = -1; 660c56b6209SSven Schnelle break; 661e7d93956Saurel32 case KBD_CMD_SCANCODE: 662e7d93956Saurel32 if (val == 0) { 6638f84e53cSMark Cave-Ayland ps2_cqueue_2(ps2, KBD_REPLY_ACK, s->translate ? 6649e24b2ddSVolker Rümelin translate_table[s->scancode_set] : s->scancode_set); 6654df23b64SHervé Poussineau } else if (val >= 1 && val <= 3) { 666e7d93956Saurel32 s->scancode_set = val; 6678f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6684df23b64SHervé Poussineau } else { 6698f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_RESEND); 670e7d93956Saurel32 } 6718f84e53cSMark Cave-Ayland ps2->write_cmd = -1; 672e7d93956Saurel32 break; 6730e43e99cSbellard case KBD_CMD_SET_LEDS: 6747f540ab5SChristophe Fergeau ps2_set_ledstate(s, val); 6758f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6768f84e53cSMark Cave-Ayland ps2->write_cmd = -1; 6770e43e99cSbellard break; 6780e43e99cSbellard case KBD_CMD_SET_RATE: 6798f84e53cSMark Cave-Ayland ps2_cqueue_1(ps2, KBD_REPLY_ACK); 6808f84e53cSMark Cave-Ayland ps2->write_cmd = -1; 6810e43e99cSbellard break; 6820e43e99cSbellard } 6830e43e99cSbellard } 6840e43e99cSbellard 685545e5cf8SMark Cave-Ayland /* 686545e5cf8SMark Cave-Ayland * Set the scancode translation mode. 687545e5cf8SMark Cave-Ayland * 0 = raw scancodes. 688545e5cf8SMark Cave-Ayland * 1 = translated scancodes (used by qemu internally). 689545e5cf8SMark Cave-Ayland */ 690f94f5d71Spbrook 69154334e73SMark Cave-Ayland void ps2_keyboard_set_translation(PS2KbdState *s, int mode) 692f94f5d71Spbrook { 69354334e73SMark Cave-Ayland trace_ps2_keyboard_set_translation(s, mode); 694f94f5d71Spbrook s->translate = mode; 695f94f5d71Spbrook } 696f94f5d71Spbrook 6977abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s) 6980e43e99cSbellard { 6992d135409SMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 70076968101SVolker Rümelin /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */ 70176968101SVolker Rümelin const int needed = s->mouse_type ? 4 : 3; 7020e43e99cSbellard unsigned int b; 70364ebbb7dSDmitry Petrov int dx1, dy1, dz1, dw1; 7040e43e99cSbellard 7052d135409SMark Cave-Ayland if (PS2_QUEUE_SIZE - ps2->queue.count < needed) { 7067abe7eb2SGeoffrey McRae return 0; 7077abe7eb2SGeoffrey McRae } 7087abe7eb2SGeoffrey McRae 7090e43e99cSbellard dx1 = s->mouse_dx; 7100e43e99cSbellard dy1 = s->mouse_dy; 7110e43e99cSbellard dz1 = s->mouse_dz; 71264ebbb7dSDmitry Petrov dw1 = s->mouse_dw; 7130e43e99cSbellard /* XXX: increase range to 8 bits ? */ 714545e5cf8SMark Cave-Ayland if (dx1 > 127) { 7150e43e99cSbellard dx1 = 127; 716545e5cf8SMark Cave-Ayland } else if (dx1 < -127) { 7170e43e99cSbellard dx1 = -127; 718545e5cf8SMark Cave-Ayland } 719545e5cf8SMark Cave-Ayland if (dy1 > 127) { 7200e43e99cSbellard dy1 = 127; 721545e5cf8SMark Cave-Ayland } else if (dy1 < -127) { 7220e43e99cSbellard dy1 = -127; 723545e5cf8SMark Cave-Ayland } 7240e43e99cSbellard b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); 7252d135409SMark Cave-Ayland ps2_queue_noirq(ps2, b); 7262d135409SMark Cave-Ayland ps2_queue_noirq(ps2, dx1 & 0xff); 7272d135409SMark Cave-Ayland ps2_queue_noirq(ps2, dy1 & 0xff); 7280e43e99cSbellard /* extra byte for IMPS/2 or IMEX */ 7290e43e99cSbellard switch (s->mouse_type) { 7300e43e99cSbellard default: 73164ebbb7dSDmitry Petrov /* Just ignore the wheels if not supported */ 73264ebbb7dSDmitry Petrov s->mouse_dz = 0; 73364ebbb7dSDmitry Petrov s->mouse_dw = 0; 7340e43e99cSbellard break; 7350e43e99cSbellard case 3: 736545e5cf8SMark Cave-Ayland if (dz1 > 127) { 7370e43e99cSbellard dz1 = 127; 738545e5cf8SMark Cave-Ayland } else if (dz1 < -127) { 7390e43e99cSbellard dz1 = -127; 740545e5cf8SMark Cave-Ayland } 7412d135409SMark Cave-Ayland ps2_queue_noirq(ps2, dz1 & 0xff); 74264ebbb7dSDmitry Petrov s->mouse_dz -= dz1; 74364ebbb7dSDmitry Petrov s->mouse_dw = 0; 7440e43e99cSbellard break; 7450e43e99cSbellard case 4: 74664ebbb7dSDmitry Petrov /* 74764ebbb7dSDmitry Petrov * This matches what the Linux kernel expects for exps/2 in 74864ebbb7dSDmitry Petrov * drivers/input/mouse/psmouse-base.c. Note, if you happen to 74964ebbb7dSDmitry Petrov * press/release the 4th or 5th buttons at the same moment as a 75064ebbb7dSDmitry Petrov * horizontal wheel scroll, those button presses will get lost. I'm not 75164ebbb7dSDmitry Petrov * sure what to do about that, since by this point we don't know 75264ebbb7dSDmitry Petrov * whether those buttons actually changed state. 75364ebbb7dSDmitry Petrov */ 75464ebbb7dSDmitry Petrov if (dw1 != 0) { 75564ebbb7dSDmitry Petrov if (dw1 > 31) { 75664ebbb7dSDmitry Petrov dw1 = 31; 75764ebbb7dSDmitry Petrov } else if (dw1 < -31) { 75864ebbb7dSDmitry Petrov dw1 = -31; 75964ebbb7dSDmitry Petrov } 76064ebbb7dSDmitry Petrov 76164ebbb7dSDmitry Petrov /* 76264ebbb7dSDmitry Petrov * linux kernel expects first 6 bits to represent the value 76364ebbb7dSDmitry Petrov * for horizontal scroll 76464ebbb7dSDmitry Petrov */ 76564ebbb7dSDmitry Petrov b = (dw1 & 0x3f) | 0x40; 76664ebbb7dSDmitry Petrov s->mouse_dw -= dw1; 76764ebbb7dSDmitry Petrov } else { 76864ebbb7dSDmitry Petrov if (dz1 > 7) { 7690e43e99cSbellard dz1 = 7; 77064ebbb7dSDmitry Petrov } else if (dz1 < -7) { 7710e43e99cSbellard dz1 = -7; 77264ebbb7dSDmitry Petrov } 77364ebbb7dSDmitry Petrov 7740e43e99cSbellard b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); 77564ebbb7dSDmitry Petrov s->mouse_dz -= dz1; 77664ebbb7dSDmitry Petrov } 7772d135409SMark Cave-Ayland ps2_queue_noirq(ps2, b); 7780e43e99cSbellard break; 7790e43e99cSbellard } 7800e43e99cSbellard 7812d135409SMark Cave-Ayland ps2_raise_irq(ps2); 7827abe7eb2SGeoffrey McRae 7835edab03dSDon Koch trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b); 7840e43e99cSbellard /* update deltas */ 7850e43e99cSbellard s->mouse_dx -= dx1; 7860e43e99cSbellard s->mouse_dy -= dy1; 7877abe7eb2SGeoffrey McRae 7887abe7eb2SGeoffrey McRae return 1; 7890e43e99cSbellard } 7900e43e99cSbellard 7912a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, 7922a766d29SGerd Hoffmann InputEvent *evt) 7930e43e99cSbellard { 7947fb1cf16SEric Blake static const int bmap[INPUT_BUTTON__MAX] = { 7958b0caab0SFabian Lesniak [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT, 7968b0caab0SFabian Lesniak [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE, 7978b0caab0SFabian Lesniak [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT, 7988b0caab0SFabian Lesniak [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE, 7998b0caab0SFabian Lesniak [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA, 8002a766d29SGerd Hoffmann }; 8012a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 802b5a1b443SEric Blake InputMoveEvent *move; 803b5a1b443SEric Blake InputBtnEvent *btn; 8040e43e99cSbellard 8050e43e99cSbellard /* check if deltas are recorded when disabled */ 806545e5cf8SMark Cave-Ayland if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 8070e43e99cSbellard return; 808545e5cf8SMark Cave-Ayland } 8090e43e99cSbellard 810568c73a4SEric Blake switch (evt->type) { 8112a766d29SGerd Hoffmann case INPUT_EVENT_KIND_REL: 81232bafa8fSEric Blake move = evt->u.rel.data; 813b5a1b443SEric Blake if (move->axis == INPUT_AXIS_X) { 814b5a1b443SEric Blake s->mouse_dx += move->value; 815b5a1b443SEric Blake } else if (move->axis == INPUT_AXIS_Y) { 816b5a1b443SEric Blake s->mouse_dy -= move->value; 8172a766d29SGerd Hoffmann } 8182a766d29SGerd Hoffmann break; 8190e43e99cSbellard 8202a766d29SGerd Hoffmann case INPUT_EVENT_KIND_BTN: 82132bafa8fSEric Blake btn = evt->u.btn.data; 822b5a1b443SEric Blake if (btn->down) { 823b5a1b443SEric Blake s->mouse_buttons |= bmap[btn->button]; 824b5a1b443SEric Blake if (btn->button == INPUT_BUTTON_WHEEL_UP) { 8252a766d29SGerd Hoffmann s->mouse_dz--; 826b5a1b443SEric Blake } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) { 8272a766d29SGerd Hoffmann s->mouse_dz++; 8282a766d29SGerd Hoffmann } 82964ebbb7dSDmitry Petrov 83064ebbb7dSDmitry Petrov if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) { 83164ebbb7dSDmitry Petrov s->mouse_dw--; 83264ebbb7dSDmitry Petrov } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) { 83364ebbb7dSDmitry Petrov s->mouse_dw++; 83464ebbb7dSDmitry Petrov } 8352a766d29SGerd Hoffmann } else { 836b5a1b443SEric Blake s->mouse_buttons &= ~bmap[btn->button]; 8372a766d29SGerd Hoffmann } 8382a766d29SGerd Hoffmann break; 8392a766d29SGerd Hoffmann 8402a766d29SGerd Hoffmann default: 8412a766d29SGerd Hoffmann /* keep gcc happy */ 8422a766d29SGerd Hoffmann break; 8432a766d29SGerd Hoffmann } 844fd214d18SGerd Hoffmann } 845fd214d18SGerd Hoffmann 8462a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev) 8472a766d29SGerd Hoffmann { 8482a766d29SGerd Hoffmann PS2MouseState *s = (PS2MouseState *)dev; 8492a766d29SGerd Hoffmann 850143c04c7SGeoffrey McRae /* do not sync while disabled to prevent stream corruption */ 851143c04c7SGeoffrey McRae if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) { 852143c04c7SGeoffrey McRae return; 853143c04c7SGeoffrey McRae } 854143c04c7SGeoffrey McRae 8552a766d29SGerd Hoffmann if (s->mouse_buttons) { 856fb064112SDaniel Henrique Barboza qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL); 8572a766d29SGerd Hoffmann } 8582858ab09SGonglei if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { 859545e5cf8SMark Cave-Ayland /* 860545e5cf8SMark Cave-Ayland * if not remote, send event. Multiple events are sent if 861545e5cf8SMark Cave-Ayland * too big deltas 862545e5cf8SMark Cave-Ayland */ 8637abe7eb2SGeoffrey McRae while (ps2_mouse_send_packet(s)) { 86464ebbb7dSDmitry Petrov if (s->mouse_dx == 0 && s->mouse_dy == 0 86564ebbb7dSDmitry Petrov && s->mouse_dz == 0 && s->mouse_dw == 0) { 8660e43e99cSbellard break; 8670e43e99cSbellard } 8680e43e99cSbellard } 8690e43e99cSbellard } 87064ebbb7dSDmitry Petrov } 8710e43e99cSbellard 87254334e73SMark Cave-Ayland void ps2_mouse_fake_event(PS2MouseState *s) 873548df2acSths { 87454334e73SMark Cave-Ayland trace_ps2_mouse_fake_event(s); 8752a766d29SGerd Hoffmann s->mouse_dx++; 87654334e73SMark Cave-Ayland ps2_mouse_sync(DEVICE(s)); 877548df2acSths } 878548df2acSths 87954334e73SMark Cave-Ayland void ps2_write_mouse(PS2MouseState *s, int val) 8800e43e99cSbellard { 8812d135409SMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 8825edab03dSDon Koch 88354334e73SMark Cave-Ayland trace_ps2_write_mouse(s, val); 8842d135409SMark Cave-Ayland switch (ps2->write_cmd) { 8850e43e99cSbellard default: 8860e43e99cSbellard case -1: 8870e43e99cSbellard /* mouse command */ 8880e43e99cSbellard if (s->mouse_wrap) { 8890e43e99cSbellard if (val == AUX_RESET_WRAP) { 8900e43e99cSbellard s->mouse_wrap = 0; 8912d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 8920e43e99cSbellard return; 8930e43e99cSbellard } else if (val != AUX_RESET) { 8942d135409SMark Cave-Ayland ps2_queue(ps2, val); 8950e43e99cSbellard return; 8960e43e99cSbellard } 8970e43e99cSbellard } 8980e43e99cSbellard switch (val) { 8990e43e99cSbellard case AUX_SET_SCALE11: 9000e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_SCALE21; 9012d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9020e43e99cSbellard break; 9030e43e99cSbellard case AUX_SET_SCALE21: 9040e43e99cSbellard s->mouse_status |= MOUSE_STATUS_SCALE21; 9052d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9060e43e99cSbellard break; 9070e43e99cSbellard case AUX_SET_STREAM: 9080e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_REMOTE; 9092d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9100e43e99cSbellard break; 9110e43e99cSbellard case AUX_SET_WRAP: 9120e43e99cSbellard s->mouse_wrap = 1; 9132d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9140e43e99cSbellard break; 9150e43e99cSbellard case AUX_SET_REMOTE: 9160e43e99cSbellard s->mouse_status |= MOUSE_STATUS_REMOTE; 9172d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9180e43e99cSbellard break; 9190e43e99cSbellard case AUX_GET_TYPE: 9202d135409SMark Cave-Ayland ps2_queue_2(ps2, 9217abe7eb2SGeoffrey McRae AUX_ACK, 9227abe7eb2SGeoffrey McRae s->mouse_type); 9230e43e99cSbellard break; 9240e43e99cSbellard case AUX_SET_RES: 9250e43e99cSbellard case AUX_SET_SAMPLE: 9262d135409SMark Cave-Ayland ps2->write_cmd = val; 9272d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9280e43e99cSbellard break; 9290e43e99cSbellard case AUX_GET_SCALE: 9302d135409SMark Cave-Ayland ps2_queue_4(ps2, 9317abe7eb2SGeoffrey McRae AUX_ACK, 9327abe7eb2SGeoffrey McRae s->mouse_status, 9337abe7eb2SGeoffrey McRae s->mouse_resolution, 9347abe7eb2SGeoffrey McRae s->mouse_sample_rate); 9350e43e99cSbellard break; 9360e43e99cSbellard case AUX_POLL: 9372d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9380e43e99cSbellard ps2_mouse_send_packet(s); 9390e43e99cSbellard break; 9400e43e99cSbellard case AUX_ENABLE_DEV: 9410e43e99cSbellard s->mouse_status |= MOUSE_STATUS_ENABLED; 9422d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9430e43e99cSbellard break; 9440e43e99cSbellard case AUX_DISABLE_DEV: 9450e43e99cSbellard s->mouse_status &= ~MOUSE_STATUS_ENABLED; 9462d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9470e43e99cSbellard break; 9480e43e99cSbellard case AUX_SET_DEFAULT: 9490e43e99cSbellard s->mouse_sample_rate = 100; 9500e43e99cSbellard s->mouse_resolution = 2; 9510e43e99cSbellard s->mouse_status = 0; 9522d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 9530e43e99cSbellard break; 9540e43e99cSbellard case AUX_RESET: 9550e43e99cSbellard s->mouse_sample_rate = 100; 9560e43e99cSbellard s->mouse_resolution = 2; 9570e43e99cSbellard s->mouse_status = 0; 9580e43e99cSbellard s->mouse_type = 0; 9592d135409SMark Cave-Ayland ps2_reset_queue(ps2); 9602d135409SMark Cave-Ayland ps2_queue_3(ps2, 9617abe7eb2SGeoffrey McRae AUX_ACK, 9627abe7eb2SGeoffrey McRae 0xaa, 9637abe7eb2SGeoffrey McRae s->mouse_type); 9640e43e99cSbellard break; 9650e43e99cSbellard default: 9660e43e99cSbellard break; 9670e43e99cSbellard } 9680e43e99cSbellard break; 9690e43e99cSbellard case AUX_SET_SAMPLE: 9700e43e99cSbellard s->mouse_sample_rate = val; 9710e43e99cSbellard /* detect IMPS/2 or IMEX */ 9720e43e99cSbellard switch (s->mouse_detect_state) { 9730e43e99cSbellard default: 9740e43e99cSbellard case 0: 975545e5cf8SMark Cave-Ayland if (val == 200) { 9760e43e99cSbellard s->mouse_detect_state = 1; 977545e5cf8SMark Cave-Ayland } 9780e43e99cSbellard break; 9790e43e99cSbellard case 1: 980545e5cf8SMark Cave-Ayland if (val == 100) { 9810e43e99cSbellard s->mouse_detect_state = 2; 982545e5cf8SMark Cave-Ayland } else if (val == 200) { 9830e43e99cSbellard s->mouse_detect_state = 3; 984545e5cf8SMark Cave-Ayland } else { 9850e43e99cSbellard s->mouse_detect_state = 0; 986545e5cf8SMark Cave-Ayland } 9870e43e99cSbellard break; 9880e43e99cSbellard case 2: 989545e5cf8SMark Cave-Ayland if (val == 80) { 9900e43e99cSbellard s->mouse_type = 3; /* IMPS/2 */ 991545e5cf8SMark Cave-Ayland } 9920e43e99cSbellard s->mouse_detect_state = 0; 9930e43e99cSbellard break; 9940e43e99cSbellard case 3: 995545e5cf8SMark Cave-Ayland if (val == 80) { 9960e43e99cSbellard s->mouse_type = 4; /* IMEX */ 997545e5cf8SMark Cave-Ayland } 9980e43e99cSbellard s->mouse_detect_state = 0; 9990e43e99cSbellard break; 10000e43e99cSbellard } 10012d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 10022d135409SMark Cave-Ayland ps2->write_cmd = -1; 10030e43e99cSbellard break; 10040e43e99cSbellard case AUX_SET_RES: 10050e43e99cSbellard s->mouse_resolution = val; 10062d135409SMark Cave-Ayland ps2_queue(ps2, AUX_ACK); 10072d135409SMark Cave-Ayland ps2->write_cmd = -1; 10080e43e99cSbellard break; 10090e43e99cSbellard } 10100e43e99cSbellard } 10110e43e99cSbellard 1012108cb22eSMark Cave-Ayland static void ps2_reset(DeviceState *dev) 10130e43e99cSbellard { 1014108cb22eSMark Cave-Ayland PS2State *s = PS2_DEVICE(dev); 1015108cb22eSMark Cave-Ayland 10160e43e99cSbellard s->write_cmd = -1; 1017954ee55bSGerd Hoffmann ps2_reset_queue(s); 10185cb6e556SMark Cave-Ayland ps2_lower_irq(s); 10190e43e99cSbellard } 10200e43e99cSbellard 10212858ab09SGonglei static void ps2_common_post_load(PS2State *s) 10222858ab09SGonglei { 10232858ab09SGonglei PS2Queue *q = &s->queue; 10244e9bddcbSVolker Rümelin int ccount = 0; 10252858ab09SGonglei 10264e9bddcbSVolker Rümelin /* limit the number of queued command replies to PS2_QUEUE_HEADROOM */ 10274e9bddcbSVolker Rümelin if (q->cwptr != -1) { 10284e9bddcbSVolker Rümelin ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1); 10294e9bddcbSVolker Rümelin if (ccount > PS2_QUEUE_HEADROOM) { 10304e9bddcbSVolker Rümelin ccount = PS2_QUEUE_HEADROOM; 10314e9bddcbSVolker Rümelin } 1032a1f2ed2aSPavel Dovgalyuk } 10332858ab09SGonglei 10344e9bddcbSVolker Rümelin /* limit the scancode queue size to PS2_QUEUE_SIZE */ 10354e9bddcbSVolker Rümelin if (q->count < ccount) { 10364e9bddcbSVolker Rümelin q->count = ccount; 10374e9bddcbSVolker Rümelin } else if (q->count > ccount + PS2_QUEUE_SIZE) { 10384e9bddcbSVolker Rümelin q->count = ccount + PS2_QUEUE_SIZE; 10394e9bddcbSVolker Rümelin } 10404e9bddcbSVolker Rümelin 10414e9bddcbSVolker Rümelin /* sanitize rptr and recalculate wptr and cwptr */ 104247db2432SVolker Rümelin q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1); 104347db2432SVolker Rümelin q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1); 10444e9bddcbSVolker Rümelin q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1; 10452858ab09SGonglei } 10462858ab09SGonglei 1047108cb22eSMark Cave-Ayland static void ps2_kbd_reset(DeviceState *dev) 1048ef74679aSDinesh Subhraveti { 1049108cb22eSMark Cave-Ayland PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(dev); 1050108cb22eSMark Cave-Ayland PS2KbdState *s = PS2_KBD_DEVICE(dev); 1051ef74679aSDinesh Subhraveti 1052108cb22eSMark Cave-Ayland trace_ps2_kbd_reset(s); 1053108cb22eSMark Cave-Ayland ps2dc->parent_reset(dev); 1054108cb22eSMark Cave-Ayland 1055d2e550a8SHervé Poussineau s->scan_enabled = 1; 1056ef74679aSDinesh Subhraveti s->translate = 0; 1057089adafdSHervé Poussineau s->scancode_set = 2; 1058620775d1SDaniel P. Berrange s->modifiers = 0; 1059ef74679aSDinesh Subhraveti } 1060ef74679aSDinesh Subhraveti 1061108cb22eSMark Cave-Ayland static void ps2_mouse_reset(DeviceState *dev) 1062ef74679aSDinesh Subhraveti { 1063108cb22eSMark Cave-Ayland PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(dev); 1064108cb22eSMark Cave-Ayland PS2MouseState *s = PS2_MOUSE_DEVICE(dev); 1065ef74679aSDinesh Subhraveti 1066108cb22eSMark Cave-Ayland trace_ps2_mouse_reset(s); 1067108cb22eSMark Cave-Ayland ps2dc->parent_reset(dev); 1068108cb22eSMark Cave-Ayland 1069ef74679aSDinesh Subhraveti s->mouse_status = 0; 1070ef74679aSDinesh Subhraveti s->mouse_resolution = 0; 1071ef74679aSDinesh Subhraveti s->mouse_sample_rate = 0; 1072ef74679aSDinesh Subhraveti s->mouse_wrap = 0; 1073ef74679aSDinesh Subhraveti s->mouse_type = 0; 1074ef74679aSDinesh Subhraveti s->mouse_detect_state = 0; 1075ef74679aSDinesh Subhraveti s->mouse_dx = 0; 1076ef74679aSDinesh Subhraveti s->mouse_dy = 0; 1077ef74679aSDinesh Subhraveti s->mouse_dz = 0; 107864ebbb7dSDmitry Petrov s->mouse_dw = 0; 1079ef74679aSDinesh Subhraveti s->mouse_buttons = 0; 1080ef74679aSDinesh Subhraveti } 1081ef74679aSDinesh Subhraveti 1082b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = { 1083b31442c3SJuan Quintela .name = "PS2 Common State", 1084b31442c3SJuan Quintela .version_id = 3, 1085b31442c3SJuan Quintela .minimum_version_id = 2, 1086b31442c3SJuan Quintela .fields = (VMStateField[]) { 1087b31442c3SJuan Quintela VMSTATE_INT32(write_cmd, PS2State), 1088b31442c3SJuan Quintela VMSTATE_INT32(queue.rptr, PS2State), 1089b31442c3SJuan Quintela VMSTATE_INT32(queue.wptr, PS2State), 1090b31442c3SJuan Quintela VMSTATE_INT32(queue.count, PS2State), 1091b31442c3SJuan Quintela VMSTATE_BUFFER(queue.data, PS2State), 1092b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 10937783e9f0Spbrook } 1094b31442c3SJuan Quintela }; 10957783e9f0Spbrook 10967f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque) 10977f540ab5SChristophe Fergeau { 10987f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 10997f540ab5SChristophe Fergeau 11007f540ab5SChristophe Fergeau return s->ledstate != 0; /* 0 is default state */ 11017f540ab5SChristophe Fergeau } 11027f540ab5SChristophe Fergeau 11037f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id) 11047f540ab5SChristophe Fergeau { 11057f540ab5SChristophe Fergeau PS2KbdState *s = opaque; 11067f540ab5SChristophe Fergeau 11077f540ab5SChristophe Fergeau kbd_put_ledstate(s->ledstate); 11087f540ab5SChristophe Fergeau return 0; 11097f540ab5SChristophe Fergeau } 11107f540ab5SChristophe Fergeau 11117f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = { 11127f540ab5SChristophe Fergeau .name = "ps2kbd/ledstate", 11137f540ab5SChristophe Fergeau .version_id = 3, 11147f540ab5SChristophe Fergeau .minimum_version_id = 2, 11157f540ab5SChristophe Fergeau .post_load = ps2_kbd_ledstate_post_load, 11165cd8cadaSJuan Quintela .needed = ps2_keyboard_ledstate_needed, 11177f540ab5SChristophe Fergeau .fields = (VMStateField[]) { 11187f540ab5SChristophe Fergeau VMSTATE_INT32(ledstate, PS2KbdState), 11197f540ab5SChristophe Fergeau VMSTATE_END_OF_LIST() 11207f540ab5SChristophe Fergeau } 11217f540ab5SChristophe Fergeau }; 11227f540ab5SChristophe Fergeau 112357d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque) 112457d5c005SHervé Poussineau { 112557d5c005SHervé Poussineau PS2KbdState *s = opaque; 112657d5c005SHervé Poussineau return s->need_high_bit != 0; /* 0 is the usual state */ 112757d5c005SHervé Poussineau } 112857d5c005SHervé Poussineau 112957d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = { 113057d5c005SHervé Poussineau .name = "ps2kbd/need_high_bit", 113157d5c005SHervé Poussineau .version_id = 1, 113257d5c005SHervé Poussineau .minimum_version_id = 1, 113357d5c005SHervé Poussineau .needed = ps2_keyboard_need_high_bit_needed, 113457d5c005SHervé Poussineau .fields = (VMStateField[]) { 113557d5c005SHervé Poussineau VMSTATE_BOOL(need_high_bit, PS2KbdState), 113657d5c005SHervé Poussineau VMSTATE_END_OF_LIST() 113757d5c005SHervé Poussineau } 113857d5c005SHervé Poussineau }; 113957d5c005SHervé Poussineau 11404e9bddcbSVolker Rümelin static bool ps2_keyboard_cqueue_needed(void *opaque) 11414e9bddcbSVolker Rümelin { 11424e9bddcbSVolker Rümelin PS2KbdState *s = opaque; 11438f84e53cSMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 11444e9bddcbSVolker Rümelin 11458f84e53cSMark Cave-Ayland return ps2->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[]) { 11528f84e53cSMark Cave-Ayland VMSTATE_INT32(parent_obj.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; 11608f84e53cSMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 11610e43e99cSbellard 1162545e5cf8SMark Cave-Ayland if (version_id == 2) { 1163e7d93956Saurel32 s->scancode_set = 2; 1164545e5cf8SMark Cave-Ayland } 11652858ab09SGonglei 11662858ab09SGonglei ps2_common_post_load(ps2); 11672858ab09SGonglei 11680e43e99cSbellard return 0; 11690e43e99cSbellard } 11700e43e99cSbellard 1171b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = { 1172b31442c3SJuan Quintela .name = "ps2kbd", 1173b31442c3SJuan Quintela .version_id = 3, 1174db596c53SJuan Quintela .minimum_version_id = 2, 1175db596c53SJuan Quintela .post_load = ps2_kbd_post_load, 1176b31442c3SJuan Quintela .fields = (VMStateField[]) { 11778f84e53cSMark Cave-Ayland VMSTATE_STRUCT(parent_obj, PS2KbdState, 0, vmstate_ps2_common, 11788f84e53cSMark Cave-Ayland PS2State), 1179b31442c3SJuan Quintela VMSTATE_INT32(scan_enabled, PS2KbdState), 1180b31442c3SJuan Quintela VMSTATE_INT32(translate, PS2KbdState), 1181b31442c3SJuan Quintela VMSTATE_INT32_V(scancode_set, PS2KbdState, 3), 1182b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 11837f540ab5SChristophe Fergeau }, 11845cd8cadaSJuan Quintela .subsections = (const VMStateDescription * []) { 11855cd8cadaSJuan Quintela &vmstate_ps2_keyboard_ledstate, 118657d5c005SHervé Poussineau &vmstate_ps2_keyboard_need_high_bit, 11874e9bddcbSVolker Rümelin &vmstate_ps2_keyboard_cqueue, 11885cd8cadaSJuan Quintela NULL 11890e43e99cSbellard } 1190b31442c3SJuan Quintela }; 1191b31442c3SJuan Quintela 11922858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id) 11932858ab09SGonglei { 11942858ab09SGonglei PS2MouseState *s = (PS2MouseState *)opaque; 11952d135409SMark Cave-Ayland PS2State *ps2 = PS2_DEVICE(s); 11962858ab09SGonglei 11972858ab09SGonglei ps2_common_post_load(ps2); 11982858ab09SGonglei 11992858ab09SGonglei return 0; 12002858ab09SGonglei } 12012858ab09SGonglei 1202b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = { 1203b31442c3SJuan Quintela .name = "ps2mouse", 1204b31442c3SJuan Quintela .version_id = 2, 1205b31442c3SJuan Quintela .minimum_version_id = 2, 12062858ab09SGonglei .post_load = ps2_mouse_post_load, 1207b31442c3SJuan Quintela .fields = (VMStateField[]) { 12082d135409SMark Cave-Ayland VMSTATE_STRUCT(parent_obj, PS2MouseState, 0, vmstate_ps2_common, 12092d135409SMark Cave-Ayland PS2State), 1210b31442c3SJuan Quintela VMSTATE_UINT8(mouse_status, PS2MouseState), 1211b31442c3SJuan Quintela VMSTATE_UINT8(mouse_resolution, PS2MouseState), 1212b31442c3SJuan Quintela VMSTATE_UINT8(mouse_sample_rate, PS2MouseState), 1213b31442c3SJuan Quintela VMSTATE_UINT8(mouse_wrap, PS2MouseState), 1214b31442c3SJuan Quintela VMSTATE_UINT8(mouse_type, PS2MouseState), 1215b31442c3SJuan Quintela VMSTATE_UINT8(mouse_detect_state, PS2MouseState), 1216b31442c3SJuan Quintela VMSTATE_INT32(mouse_dx, PS2MouseState), 1217b31442c3SJuan Quintela VMSTATE_INT32(mouse_dy, PS2MouseState), 1218b31442c3SJuan Quintela VMSTATE_INT32(mouse_dz, PS2MouseState), 1219b31442c3SJuan Quintela VMSTATE_UINT8(mouse_buttons, PS2MouseState), 1220b31442c3SJuan Quintela VMSTATE_END_OF_LIST() 1221b31442c3SJuan Quintela } 1222b31442c3SJuan Quintela }; 12230e43e99cSbellard 122466e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = { 122566e6536eSGerd Hoffmann .name = "QEMU PS/2 Keyboard", 122666e6536eSGerd Hoffmann .mask = INPUT_EVENT_MASK_KEY, 122766e6536eSGerd Hoffmann .event = ps2_keyboard_event, 122866e6536eSGerd Hoffmann }; 122966e6536eSGerd Hoffmann 1230ea247a0fSMark Cave-Ayland static void ps2_kbd_realize(DeviceState *dev, Error **errp) 1231ea247a0fSMark Cave-Ayland { 1232ea247a0fSMark Cave-Ayland qemu_input_handler_register(dev, &ps2_keyboard_handler); 1233ea247a0fSMark Cave-Ayland } 1234ea247a0fSMark Cave-Ayland 12350e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) 12360e43e99cSbellard { 12378f84e53cSMark Cave-Ayland DeviceState *dev; 12388f84e53cSMark Cave-Ayland PS2KbdState *s; 12398f84e53cSMark Cave-Ayland PS2State *ps2; 12408f84e53cSMark Cave-Ayland 12418f84e53cSMark Cave-Ayland dev = qdev_new(TYPE_PS2_KBD_DEVICE); 12428f84e53cSMark Cave-Ayland sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 12438f84e53cSMark Cave-Ayland s = PS2_KBD_DEVICE(dev); 12448f84e53cSMark Cave-Ayland ps2 = PS2_DEVICE(s); 12450e43e99cSbellard 12465edab03dSDon Koch trace_ps2_kbd_init(s); 12478f84e53cSMark Cave-Ayland ps2->update_irq = update_irq; 12488f84e53cSMark Cave-Ayland ps2->update_arg = update_arg; 1249ea247a0fSMark Cave-Ayland 12500e43e99cSbellard return s; 12510e43e99cSbellard } 12520e43e99cSbellard 12532a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = { 12542a766d29SGerd Hoffmann .name = "QEMU PS/2 Mouse", 12552a766d29SGerd Hoffmann .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, 12562a766d29SGerd Hoffmann .event = ps2_mouse_event, 12572a766d29SGerd Hoffmann .sync = ps2_mouse_sync, 12582a766d29SGerd Hoffmann }; 12592a766d29SGerd Hoffmann 12604a68b482SMark Cave-Ayland static void ps2_mouse_realize(DeviceState *dev, Error **errp) 12614a68b482SMark Cave-Ayland { 12624a68b482SMark Cave-Ayland qemu_input_handler_register(dev, &ps2_mouse_handler); 12634a68b482SMark Cave-Ayland } 12644a68b482SMark Cave-Ayland 12650e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) 12660e43e99cSbellard { 12672d135409SMark Cave-Ayland DeviceState *dev; 12682d135409SMark Cave-Ayland PS2MouseState *s; 12692d135409SMark Cave-Ayland PS2State *ps2; 12702d135409SMark Cave-Ayland 12712d135409SMark Cave-Ayland dev = qdev_new(TYPE_PS2_MOUSE_DEVICE); 12722d135409SMark Cave-Ayland sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 12732d135409SMark Cave-Ayland s = PS2_MOUSE_DEVICE(dev); 12742d135409SMark Cave-Ayland ps2 = PS2_DEVICE(s); 12750e43e99cSbellard 12765edab03dSDon Koch trace_ps2_mouse_init(s); 12772d135409SMark Cave-Ayland ps2->update_irq = update_irq; 12782d135409SMark Cave-Ayland ps2->update_arg = update_arg; 12790e43e99cSbellard return s; 12800e43e99cSbellard } 128164bbdd13SMark Cave-Ayland 1282108cb22eSMark Cave-Ayland static void ps2_kbd_class_init(ObjectClass *klass, void *data) 1283108cb22eSMark Cave-Ayland { 1284108cb22eSMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1285108cb22eSMark Cave-Ayland PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass); 1286108cb22eSMark Cave-Ayland 1287ea247a0fSMark Cave-Ayland dc->realize = ps2_kbd_realize; 1288108cb22eSMark Cave-Ayland device_class_set_parent_reset(dc, ps2_kbd_reset, &ps2dc->parent_reset); 1289f055f507SMark Cave-Ayland dc->vmsd = &vmstate_ps2_keyboard; 1290108cb22eSMark Cave-Ayland } 1291108cb22eSMark Cave-Ayland 12928f84e53cSMark Cave-Ayland static const TypeInfo ps2_kbd_info = { 12938f84e53cSMark Cave-Ayland .name = TYPE_PS2_KBD_DEVICE, 12948f84e53cSMark Cave-Ayland .parent = TYPE_PS2_DEVICE, 12958f84e53cSMark Cave-Ayland .instance_size = sizeof(PS2KbdState), 1296108cb22eSMark Cave-Ayland .class_init = ps2_kbd_class_init 12978f84e53cSMark Cave-Ayland }; 12988f84e53cSMark Cave-Ayland 1299108cb22eSMark Cave-Ayland static void ps2_mouse_class_init(ObjectClass *klass, void *data) 1300108cb22eSMark Cave-Ayland { 1301108cb22eSMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1302108cb22eSMark Cave-Ayland PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass); 1303108cb22eSMark Cave-Ayland 13044a68b482SMark Cave-Ayland dc->realize = ps2_mouse_realize; 1305108cb22eSMark Cave-Ayland device_class_set_parent_reset(dc, ps2_mouse_reset, 1306108cb22eSMark Cave-Ayland &ps2dc->parent_reset); 130797259e70SMark Cave-Ayland dc->vmsd = &vmstate_ps2_mouse; 1308108cb22eSMark Cave-Ayland } 1309108cb22eSMark Cave-Ayland 13102d135409SMark Cave-Ayland static const TypeInfo ps2_mouse_info = { 13112d135409SMark Cave-Ayland .name = TYPE_PS2_MOUSE_DEVICE, 13122d135409SMark Cave-Ayland .parent = TYPE_PS2_DEVICE, 13132d135409SMark Cave-Ayland .instance_size = sizeof(PS2MouseState), 1314108cb22eSMark Cave-Ayland .class_init = ps2_mouse_class_init 13152d135409SMark Cave-Ayland }; 13162d135409SMark Cave-Ayland 1317*6beb79e1SMark Cave-Ayland static void ps2_init(Object *obj) 1318*6beb79e1SMark Cave-Ayland { 1319*6beb79e1SMark Cave-Ayland PS2State *s = PS2_DEVICE(obj); 1320*6beb79e1SMark Cave-Ayland 1321*6beb79e1SMark Cave-Ayland qdev_init_gpio_out(DEVICE(obj), &s->irq, 1); 1322*6beb79e1SMark Cave-Ayland } 1323*6beb79e1SMark Cave-Ayland 132464bbdd13SMark Cave-Ayland static void ps2_class_init(ObjectClass *klass, void *data) 132564bbdd13SMark Cave-Ayland { 132664bbdd13SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 132764bbdd13SMark Cave-Ayland 1328108cb22eSMark Cave-Ayland dc->reset = ps2_reset; 132964bbdd13SMark Cave-Ayland set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 133064bbdd13SMark Cave-Ayland } 133164bbdd13SMark Cave-Ayland 133264bbdd13SMark Cave-Ayland static const TypeInfo ps2_info = { 133364bbdd13SMark Cave-Ayland .name = TYPE_PS2_DEVICE, 133464bbdd13SMark Cave-Ayland .parent = TYPE_SYS_BUS_DEVICE, 1335*6beb79e1SMark Cave-Ayland .instance_init = ps2_init, 133664bbdd13SMark Cave-Ayland .instance_size = sizeof(PS2State), 133764bbdd13SMark Cave-Ayland .class_init = ps2_class_init, 1338494145b2SMark Cave-Ayland .class_size = sizeof(PS2DeviceClass), 133964bbdd13SMark Cave-Ayland .abstract = true 134064bbdd13SMark Cave-Ayland }; 134164bbdd13SMark Cave-Ayland 134264bbdd13SMark Cave-Ayland static void ps2_register_types(void) 134364bbdd13SMark Cave-Ayland { 134464bbdd13SMark Cave-Ayland type_register_static(&ps2_info); 13458f84e53cSMark Cave-Ayland type_register_static(&ps2_kbd_info); 13462d135409SMark Cave-Ayland type_register_static(&ps2_mouse_info); 134764bbdd13SMark Cave-Ayland } 134864bbdd13SMark Cave-Ayland 134964bbdd13SMark Cave-Ayland type_init(ps2_register_types) 1350