xref: /qemu/hw/input/ps2.c (revision 8f63458ff72e6c160db560dca494df5ffbebb15e)
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  */
240430891cSPeter Maydell #include "qemu/osdep.h"
25ec044a80SHervé Poussineau #include "qemu/log.h"
2683c9f4caSPaolo Bonzini #include "hw/hw.h"
270d09e41aSPaolo Bonzini #include "hw/input/ps2.h"
2828ecbaeeSPaolo Bonzini #include "ui/console.h"
2966e6536eSGerd Hoffmann #include "ui/input.h"
309c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
310e43e99cSbellard 
325edab03dSDon Koch #include "trace.h"
335edab03dSDon Koch 
340e43e99cSbellard /* debug PC keyboard */
350e43e99cSbellard //#define DEBUG_KBD
360e43e99cSbellard 
370e43e99cSbellard /* debug PC keyboard : only mouse */
380e43e99cSbellard //#define DEBUG_MOUSE
390e43e99cSbellard 
400e43e99cSbellard /* Keyboard Commands */
410e43e99cSbellard #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
420e43e99cSbellard #define KBD_CMD_ECHO     	0xEE
43e7d93956Saurel32 #define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
440e43e99cSbellard #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
450e43e99cSbellard #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
460e43e99cSbellard #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
470e43e99cSbellard #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
480e43e99cSbellard #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
490e43e99cSbellard #define KBD_CMD_RESET		0xFF	/* Reset */
500e43e99cSbellard 
510e43e99cSbellard /* Keyboard Replies */
520e43e99cSbellard #define KBD_REPLY_POR		0xAA	/* Power on reset */
5335c4d671Saurel32 #define KBD_REPLY_ID		0xAB	/* Keyboard ID */
540e43e99cSbellard #define KBD_REPLY_ACK		0xFA	/* Command ACK */
550e43e99cSbellard #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
560e43e99cSbellard 
570e43e99cSbellard /* Mouse Commands */
580e43e99cSbellard #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
590e43e99cSbellard #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
600e43e99cSbellard #define AUX_SET_RES		0xE8	/* Set resolution */
610e43e99cSbellard #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
620e43e99cSbellard #define AUX_SET_STREAM		0xEA	/* Set stream mode */
630e43e99cSbellard #define AUX_POLL		0xEB	/* Poll */
640e43e99cSbellard #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
650e43e99cSbellard #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
660e43e99cSbellard #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
670e43e99cSbellard #define AUX_GET_TYPE		0xF2	/* Get type */
680e43e99cSbellard #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
690e43e99cSbellard #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
700e43e99cSbellard #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
710e43e99cSbellard #define AUX_SET_DEFAULT		0xF6
720e43e99cSbellard #define AUX_RESET		0xFF	/* Reset aux device */
730e43e99cSbellard #define AUX_ACK			0xFA	/* Command byte ACK. */
740e43e99cSbellard 
750e43e99cSbellard #define MOUSE_STATUS_REMOTE     0x40
760e43e99cSbellard #define MOUSE_STATUS_ENABLED    0x20
770e43e99cSbellard #define MOUSE_STATUS_SCALE21    0x10
780e43e99cSbellard 
792858ab09SGonglei #define PS2_QUEUE_SIZE 16  /* Buffer size required by PS/2 protocol */
800e43e99cSbellard 
81620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */
82620775d1SDaniel P. Berrange #define MOD_CTRL_L  (1 << 0)
83620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1)
84620775d1SDaniel P. Berrange #define MOD_ALT_L   (1 << 2)
85620775d1SDaniel P. Berrange #define MOD_CTRL_R  (1 << 3)
86620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4)
87620775d1SDaniel P. Berrange #define MOD_ALT_R   (1 << 5)
88620775d1SDaniel P. Berrange 
890e43e99cSbellard typedef struct {
902858ab09SGonglei     /* Keep the data array 256 bytes long, which compatibility
912858ab09SGonglei      with older qemu versions. */
922858ab09SGonglei     uint8_t data[256];
930e43e99cSbellard     int rptr, wptr, count;
940e43e99cSbellard } PS2Queue;
950e43e99cSbellard 
968498bb8dSGerd Hoffmann struct PS2State {
970e43e99cSbellard     PS2Queue queue;
980e43e99cSbellard     int32_t write_cmd;
990e43e99cSbellard     void (*update_irq)(void *, int);
1000e43e99cSbellard     void *update_arg;
1018498bb8dSGerd Hoffmann };
1020e43e99cSbellard 
1030e43e99cSbellard typedef struct {
1040e43e99cSbellard     PS2State common;
1050e43e99cSbellard     int scan_enabled;
106f94f5d71Spbrook     int translate;
107e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
1087f540ab5SChristophe Fergeau     int ledstate;
10957d5c005SHervé Poussineau     bool need_high_bit;
110620775d1SDaniel P. Berrange     unsigned int modifiers; /* bitmask of MOD_* constants above */
1110e43e99cSbellard } PS2KbdState;
1120e43e99cSbellard 
1130e43e99cSbellard typedef struct {
1140e43e99cSbellard     PS2State common;
1150e43e99cSbellard     uint8_t mouse_status;
1160e43e99cSbellard     uint8_t mouse_resolution;
1170e43e99cSbellard     uint8_t mouse_sample_rate;
1180e43e99cSbellard     uint8_t mouse_wrap;
1190e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1200e43e99cSbellard     uint8_t mouse_detect_state;
1210e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1220e43e99cSbellard     int mouse_dy;
1230e43e99cSbellard     int mouse_dz;
1240e43e99cSbellard     uint8_t mouse_buttons;
1250e43e99cSbellard } PS2MouseState;
1260e43e99cSbellard 
1278c10e0baSHervé Poussineau /* Table to convert from QEMU codes to scancodes.  */
1288c10e0baSHervé Poussineau static const uint16_t qcode_to_keycode_set1[Q_KEY_CODE__MAX] = {
1298c10e0baSHervé Poussineau     [0 ... Q_KEY_CODE__MAX - 1] = 0,
1308c10e0baSHervé Poussineau 
1318c10e0baSHervé Poussineau     [Q_KEY_CODE_A] = 0x1e,
1328c10e0baSHervé Poussineau     [Q_KEY_CODE_B] = 0x30,
1338c10e0baSHervé Poussineau     [Q_KEY_CODE_C] = 0x2e,
1348c10e0baSHervé Poussineau     [Q_KEY_CODE_D] = 0x20,
1358c10e0baSHervé Poussineau     [Q_KEY_CODE_E] = 0x12,
1368c10e0baSHervé Poussineau     [Q_KEY_CODE_F] = 0x21,
1378c10e0baSHervé Poussineau     [Q_KEY_CODE_G] = 0x22,
1388c10e0baSHervé Poussineau     [Q_KEY_CODE_H] = 0x23,
1398c10e0baSHervé Poussineau     [Q_KEY_CODE_I] = 0x17,
1408c10e0baSHervé Poussineau     [Q_KEY_CODE_J] = 0x24,
1418c10e0baSHervé Poussineau     [Q_KEY_CODE_K] = 0x25,
1428c10e0baSHervé Poussineau     [Q_KEY_CODE_L] = 0x26,
1438c10e0baSHervé Poussineau     [Q_KEY_CODE_M] = 0x32,
1448c10e0baSHervé Poussineau     [Q_KEY_CODE_N] = 0x31,
1458c10e0baSHervé Poussineau     [Q_KEY_CODE_O] = 0x18,
1468c10e0baSHervé Poussineau     [Q_KEY_CODE_P] = 0x19,
1478c10e0baSHervé Poussineau     [Q_KEY_CODE_Q] = 0x10,
1488c10e0baSHervé Poussineau     [Q_KEY_CODE_R] = 0x13,
1498c10e0baSHervé Poussineau     [Q_KEY_CODE_S] = 0x1f,
1508c10e0baSHervé Poussineau     [Q_KEY_CODE_T] = 0x14,
1518c10e0baSHervé Poussineau     [Q_KEY_CODE_U] = 0x16,
1528c10e0baSHervé Poussineau     [Q_KEY_CODE_V] = 0x2f,
1538c10e0baSHervé Poussineau     [Q_KEY_CODE_W] = 0x11,
1548c10e0baSHervé Poussineau     [Q_KEY_CODE_X] = 0x2d,
1558c10e0baSHervé Poussineau     [Q_KEY_CODE_Y] = 0x15,
1568c10e0baSHervé Poussineau     [Q_KEY_CODE_Z] = 0x2c,
1578c10e0baSHervé Poussineau     [Q_KEY_CODE_0] = 0x0b,
1588c10e0baSHervé Poussineau     [Q_KEY_CODE_1] = 0x02,
1598c10e0baSHervé Poussineau     [Q_KEY_CODE_2] = 0x03,
1608c10e0baSHervé Poussineau     [Q_KEY_CODE_3] = 0x04,
1618c10e0baSHervé Poussineau     [Q_KEY_CODE_4] = 0x05,
1628c10e0baSHervé Poussineau     [Q_KEY_CODE_5] = 0x06,
1638c10e0baSHervé Poussineau     [Q_KEY_CODE_6] = 0x07,
1648c10e0baSHervé Poussineau     [Q_KEY_CODE_7] = 0x08,
1658c10e0baSHervé Poussineau     [Q_KEY_CODE_8] = 0x09,
1668c10e0baSHervé Poussineau     [Q_KEY_CODE_9] = 0x0a,
1678c10e0baSHervé Poussineau     [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
1688c10e0baSHervé Poussineau     [Q_KEY_CODE_MINUS] = 0x0c,
1698c10e0baSHervé Poussineau     [Q_KEY_CODE_EQUAL] = 0x0d,
1708c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSLASH] = 0x2b,
1718c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSPACE] = 0x0e,
1728c10e0baSHervé Poussineau     [Q_KEY_CODE_SPC] = 0x39,
1738c10e0baSHervé Poussineau     [Q_KEY_CODE_TAB] = 0x0f,
1748c10e0baSHervé Poussineau     [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
1758c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT] = 0x2a,
1768c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL] = 0x1d,
1778c10e0baSHervé Poussineau     [Q_KEY_CODE_META_L] = 0xe05b,
1788c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT] = 0x38,
1798c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT_R] = 0x36,
1808c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL_R] = 0xe01d,
1818c10e0baSHervé Poussineau     [Q_KEY_CODE_META_R] = 0xe05c,
1828c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT_R] = 0xe038,
1838c10e0baSHervé Poussineau     [Q_KEY_CODE_MENU] = 0xe05d,
1848c10e0baSHervé Poussineau     [Q_KEY_CODE_RET] = 0x1c,
1858c10e0baSHervé Poussineau     [Q_KEY_CODE_ESC] = 0x01,
1868c10e0baSHervé Poussineau     [Q_KEY_CODE_F1] = 0x3b,
1878c10e0baSHervé Poussineau     [Q_KEY_CODE_F2] = 0x3c,
1888c10e0baSHervé Poussineau     [Q_KEY_CODE_F3] = 0x3d,
1898c10e0baSHervé Poussineau     [Q_KEY_CODE_F4] = 0x3e,
1908c10e0baSHervé Poussineau     [Q_KEY_CODE_F5] = 0x3f,
1918c10e0baSHervé Poussineau     [Q_KEY_CODE_F6] = 0x40,
1928c10e0baSHervé Poussineau     [Q_KEY_CODE_F7] = 0x41,
1938c10e0baSHervé Poussineau     [Q_KEY_CODE_F8] = 0x42,
1948c10e0baSHervé Poussineau     [Q_KEY_CODE_F9] = 0x43,
1958c10e0baSHervé Poussineau     [Q_KEY_CODE_F10] = 0x44,
1968c10e0baSHervé Poussineau     [Q_KEY_CODE_F11] = 0x57,
1978c10e0baSHervé Poussineau     [Q_KEY_CODE_F12] = 0x58,
1988c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PRINT */
1998c10e0baSHervé Poussineau     [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
2008c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PAUSE */
2018c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
2028c10e0baSHervé Poussineau     [Q_KEY_CODE_INSERT] = 0xe052,
2038c10e0baSHervé Poussineau     [Q_KEY_CODE_HOME] = 0xe047,
2048c10e0baSHervé Poussineau     [Q_KEY_CODE_PGUP] = 0xe049,
2058c10e0baSHervé Poussineau     [Q_KEY_CODE_DELETE] = 0xe053,
2068c10e0baSHervé Poussineau     [Q_KEY_CODE_END] = 0xe04f,
2078c10e0baSHervé Poussineau     [Q_KEY_CODE_PGDN] = 0xe051,
2088c10e0baSHervé Poussineau     [Q_KEY_CODE_UP] = 0xe048,
2098c10e0baSHervé Poussineau     [Q_KEY_CODE_LEFT] = 0xe04b,
2108c10e0baSHervé Poussineau     [Q_KEY_CODE_DOWN] = 0xe050,
2118c10e0baSHervé Poussineau     [Q_KEY_CODE_RIGHT] = 0xe04d,
2128c10e0baSHervé Poussineau     [Q_KEY_CODE_NUM_LOCK] = 0x45,
2138c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DIVIDE] = 0xe035,
2148c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
2158c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
2168c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ADD] = 0x4e,
2178c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ENTER] = 0xe01c,
2188c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DECIMAL] = 0x53,
2198c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_0] = 0x52,
2208c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_1] = 0x4f,
2218c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_2] = 0x50,
2228c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_3] = 0x51,
2238c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_4] = 0x4b,
2248c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_5] = 0x4c,
2258c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_6] = 0x4d,
2268c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_7] = 0x47,
2278c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_8] = 0x48,
2288c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_9] = 0x49,
2298c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
2308c10e0baSHervé Poussineau     [Q_KEY_CODE_SEMICOLON] = 0x27,
2318c10e0baSHervé Poussineau     [Q_KEY_CODE_APOSTROPHE] = 0x28,
2328c10e0baSHervé Poussineau     [Q_KEY_CODE_COMMA] = 0x33,
2338c10e0baSHervé Poussineau     [Q_KEY_CODE_DOT] = 0x34,
2348c10e0baSHervé Poussineau     [Q_KEY_CODE_SLASH] = 0x35,
2358c10e0baSHervé Poussineau 
2368c10e0baSHervé Poussineau     [Q_KEY_CODE_POWER] = 0x0e5e,
2378c10e0baSHervé Poussineau     [Q_KEY_CODE_SLEEP] = 0x0e5f,
2388c10e0baSHervé Poussineau     [Q_KEY_CODE_WAKE] = 0x0e63,
2398c10e0baSHervé Poussineau 
2408c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIONEXT] = 0xe019,
2418c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPREV] = 0xe010,
2428c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOSTOP] = 0xe024,
2438c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPLAY] = 0xe022,
2448c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOMUTE] = 0xe020,
2458c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEUP] = 0xe030,
2468c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEDOWN] = 0xe02e,
2478c10e0baSHervé Poussineau     [Q_KEY_CODE_MEDIASELECT] = 0xe06d,
2488c10e0baSHervé Poussineau     [Q_KEY_CODE_MAIL] = 0xe06c,
2498c10e0baSHervé Poussineau     [Q_KEY_CODE_CALCULATOR] = 0xe021,
2508c10e0baSHervé Poussineau     [Q_KEY_CODE_COMPUTER] = 0xe06b,
251103dce8fSGerd Hoffmann     [Q_KEY_CODE_FIND] = 0xe065,
2528c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_HOME] = 0xe032,
2538c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BACK] = 0xe06a,
2548c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_FORWARD] = 0xe069,
255103dce8fSGerd Hoffmann     [Q_KEY_CODE_STOP] = 0xe068,
2568c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_REFRESH] = 0xe067,
2578c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BOOKMARKS] = 0xe066,
2588c10e0baSHervé Poussineau 
2598c10e0baSHervé Poussineau     [Q_KEY_CODE_ASTERISK] = 0x37,
2608c10e0baSHervé Poussineau     [Q_KEY_CODE_LESS] = 0x56,
2618c10e0baSHervé Poussineau     [Q_KEY_CODE_RO] = 0x73,
262e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HIRAGANA] = 0x70,
263e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HENKAN] = 0x79,
264e9346441SOGAWA Hirofumi     [Q_KEY_CODE_YEN] = 0x7d,
2658c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_COMMA] = 0x7e,
266f94f5d71Spbrook };
2678c10e0baSHervé Poussineau 
2688c10e0baSHervé Poussineau static const uint16_t qcode_to_keycode_set2[Q_KEY_CODE__MAX] = {
2698c10e0baSHervé Poussineau     [0 ... Q_KEY_CODE__MAX - 1] = 0,
2708c10e0baSHervé Poussineau 
2718c10e0baSHervé Poussineau     [Q_KEY_CODE_A] = 0x1c,
2728c10e0baSHervé Poussineau     [Q_KEY_CODE_B] = 0x32,
2738c10e0baSHervé Poussineau     [Q_KEY_CODE_C] = 0x21,
2748c10e0baSHervé Poussineau     [Q_KEY_CODE_D] = 0x23,
2758c10e0baSHervé Poussineau     [Q_KEY_CODE_E] = 0x24,
2768c10e0baSHervé Poussineau     [Q_KEY_CODE_F] = 0x2b,
2778c10e0baSHervé Poussineau     [Q_KEY_CODE_G] = 0x34,
2788c10e0baSHervé Poussineau     [Q_KEY_CODE_H] = 0x33,
2798c10e0baSHervé Poussineau     [Q_KEY_CODE_I] = 0x43,
2808c10e0baSHervé Poussineau     [Q_KEY_CODE_J] = 0x3b,
2818c10e0baSHervé Poussineau     [Q_KEY_CODE_K] = 0x42,
2828c10e0baSHervé Poussineau     [Q_KEY_CODE_L] = 0x4b,
2838c10e0baSHervé Poussineau     [Q_KEY_CODE_M] = 0x3a,
2848c10e0baSHervé Poussineau     [Q_KEY_CODE_N] = 0x31,
2858c10e0baSHervé Poussineau     [Q_KEY_CODE_O] = 0x44,
2868c10e0baSHervé Poussineau     [Q_KEY_CODE_P] = 0x4d,
2878c10e0baSHervé Poussineau     [Q_KEY_CODE_Q] = 0x15,
2888c10e0baSHervé Poussineau     [Q_KEY_CODE_R] = 0x2d,
2898c10e0baSHervé Poussineau     [Q_KEY_CODE_S] = 0x1b,
2908c10e0baSHervé Poussineau     [Q_KEY_CODE_T] = 0x2c,
2918c10e0baSHervé Poussineau     [Q_KEY_CODE_U] = 0x3c,
2928c10e0baSHervé Poussineau     [Q_KEY_CODE_V] = 0x2a,
2938c10e0baSHervé Poussineau     [Q_KEY_CODE_W] = 0x1d,
2948c10e0baSHervé Poussineau     [Q_KEY_CODE_X] = 0x22,
2958c10e0baSHervé Poussineau     [Q_KEY_CODE_Y] = 0x35,
2968c10e0baSHervé Poussineau     [Q_KEY_CODE_Z] = 0x1a,
2978c10e0baSHervé Poussineau     [Q_KEY_CODE_0] = 0x45,
2988c10e0baSHervé Poussineau     [Q_KEY_CODE_1] = 0x16,
2998c10e0baSHervé Poussineau     [Q_KEY_CODE_2] = 0x1e,
3008c10e0baSHervé Poussineau     [Q_KEY_CODE_3] = 0x26,
3018c10e0baSHervé Poussineau     [Q_KEY_CODE_4] = 0x25,
3028c10e0baSHervé Poussineau     [Q_KEY_CODE_5] = 0x2e,
3038c10e0baSHervé Poussineau     [Q_KEY_CODE_6] = 0x36,
3048c10e0baSHervé Poussineau     [Q_KEY_CODE_7] = 0x3d,
3058c10e0baSHervé Poussineau     [Q_KEY_CODE_8] = 0x3e,
3068c10e0baSHervé Poussineau     [Q_KEY_CODE_9] = 0x46,
3078c10e0baSHervé Poussineau     [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e,
3088c10e0baSHervé Poussineau     [Q_KEY_CODE_MINUS] = 0x4e,
3098c10e0baSHervé Poussineau     [Q_KEY_CODE_EQUAL] = 0x55,
3108c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSLASH] = 0x5d,
3118c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSPACE] = 0x66,
3128c10e0baSHervé Poussineau     [Q_KEY_CODE_SPC] = 0x29,
3138c10e0baSHervé Poussineau     [Q_KEY_CODE_TAB] = 0x0d,
3148c10e0baSHervé Poussineau     [Q_KEY_CODE_CAPS_LOCK] = 0x58,
3158c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT] = 0x12,
3168c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL] = 0x14,
3178c10e0baSHervé Poussineau     [Q_KEY_CODE_META_L] = 0xe01f,
3188c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT] = 0x11,
3198c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT_R] = 0x59,
3208c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL_R] = 0xe014,
3218c10e0baSHervé Poussineau     [Q_KEY_CODE_META_R] = 0xe027,
3228c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT_R] = 0xe011,
3238c10e0baSHervé Poussineau     [Q_KEY_CODE_MENU] = 0xe02f,
3248c10e0baSHervé Poussineau     [Q_KEY_CODE_RET] = 0x5a,
3258c10e0baSHervé Poussineau     [Q_KEY_CODE_ESC] = 0x76,
3268c10e0baSHervé Poussineau     [Q_KEY_CODE_F1] = 0x05,
3278c10e0baSHervé Poussineau     [Q_KEY_CODE_F2] = 0x06,
3288c10e0baSHervé Poussineau     [Q_KEY_CODE_F3] = 0x04,
3298c10e0baSHervé Poussineau     [Q_KEY_CODE_F4] = 0x0c,
3308c10e0baSHervé Poussineau     [Q_KEY_CODE_F5] = 0x03,
3318c10e0baSHervé Poussineau     [Q_KEY_CODE_F6] = 0x0b,
3328c10e0baSHervé Poussineau     [Q_KEY_CODE_F7] = 0x83,
3338c10e0baSHervé Poussineau     [Q_KEY_CODE_F8] = 0x0a,
3348c10e0baSHervé Poussineau     [Q_KEY_CODE_F9] = 0x01,
3358c10e0baSHervé Poussineau     [Q_KEY_CODE_F10] = 0x09,
3368c10e0baSHervé Poussineau     [Q_KEY_CODE_F11] = 0x78,
3378c10e0baSHervé Poussineau     [Q_KEY_CODE_F12] = 0x07,
3388c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PRINT */
3398c10e0baSHervé Poussineau     [Q_KEY_CODE_SCROLL_LOCK] = 0x7e,
3408c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PAUSE */
3418c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_LEFT] = 0x54,
3428c10e0baSHervé Poussineau     [Q_KEY_CODE_INSERT] = 0xe070,
3438c10e0baSHervé Poussineau     [Q_KEY_CODE_HOME] = 0xe06c,
3448c10e0baSHervé Poussineau     [Q_KEY_CODE_PGUP] = 0xe07d,
3458c10e0baSHervé Poussineau     [Q_KEY_CODE_DELETE] = 0xe071,
3468c10e0baSHervé Poussineau     [Q_KEY_CODE_END] = 0xe069,
3478c10e0baSHervé Poussineau     [Q_KEY_CODE_PGDN] = 0xe07a,
3488c10e0baSHervé Poussineau     [Q_KEY_CODE_UP] = 0xe075,
3498c10e0baSHervé Poussineau     [Q_KEY_CODE_LEFT] = 0xe06b,
3508c10e0baSHervé Poussineau     [Q_KEY_CODE_DOWN] = 0xe072,
3518c10e0baSHervé Poussineau     [Q_KEY_CODE_RIGHT] = 0xe074,
3528c10e0baSHervé Poussineau     [Q_KEY_CODE_NUM_LOCK] = 0x77,
3538c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DIVIDE] = 0xe04a,
3548c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_MULTIPLY] = 0x7c,
3558c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_SUBTRACT] = 0x7b,
3568c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ADD] = 0x79,
3578c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ENTER] = 0xe05a,
3588c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DECIMAL] = 0x71,
3598c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_0] = 0x70,
3608c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_1] = 0x69,
3618c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_2] = 0x72,
3628c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_3] = 0x7a,
3638c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_4] = 0x6b,
3648c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_5] = 0x73,
3658c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_6] = 0x74,
3668c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_7] = 0x6c,
3678c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_8] = 0x75,
3688c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_9] = 0x7d,
3698c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b,
3708c10e0baSHervé Poussineau     [Q_KEY_CODE_SEMICOLON] = 0x4c,
3718c10e0baSHervé Poussineau     [Q_KEY_CODE_APOSTROPHE] = 0x52,
3728c10e0baSHervé Poussineau     [Q_KEY_CODE_COMMA] = 0x41,
3738c10e0baSHervé Poussineau     [Q_KEY_CODE_DOT] = 0x49,
3748c10e0baSHervé Poussineau     [Q_KEY_CODE_SLASH] = 0x4a,
3758c10e0baSHervé Poussineau 
3768c10e0baSHervé Poussineau     [Q_KEY_CODE_POWER] = 0x0e37,
3778c10e0baSHervé Poussineau     [Q_KEY_CODE_SLEEP] = 0x0e3f,
3788c10e0baSHervé Poussineau     [Q_KEY_CODE_WAKE] = 0x0e5e,
3798c10e0baSHervé Poussineau 
3808c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIONEXT] = 0xe04d,
3818c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPREV] = 0xe015,
3828c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOSTOP] = 0xe03b,
3838c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPLAY] = 0xe034,
3848c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOMUTE] = 0xe023,
3858c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEUP] = 0xe032,
3868c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEDOWN] = 0xe021,
3878c10e0baSHervé Poussineau     [Q_KEY_CODE_MEDIASELECT] = 0xe050,
3888c10e0baSHervé Poussineau     [Q_KEY_CODE_MAIL] = 0xe048,
3898c10e0baSHervé Poussineau     [Q_KEY_CODE_CALCULATOR] = 0xe02b,
3908c10e0baSHervé Poussineau     [Q_KEY_CODE_COMPUTER] = 0xe040,
391103dce8fSGerd Hoffmann     [Q_KEY_CODE_FIND] = 0xe010,
3928c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_HOME] = 0xe03a,
3938c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BACK] = 0xe038,
3948c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_FORWARD] = 0xe030,
395103dce8fSGerd Hoffmann     [Q_KEY_CODE_STOP] = 0xe028,
3968c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_REFRESH] = 0xe020,
3978c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BOOKMARKS] = 0xe018,
3988c10e0baSHervé Poussineau 
3998c10e0baSHervé Poussineau     [Q_KEY_CODE_ASTERISK] = 0x7c,
4008c10e0baSHervé Poussineau     [Q_KEY_CODE_LESS] = 0x61,
4018c10e0baSHervé Poussineau     [Q_KEY_CODE_SYSRQ] = 0x7f,
4028c10e0baSHervé Poussineau     [Q_KEY_CODE_RO] = 0x51,
403e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HIRAGANA] = 0x13,
404e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HENKAN] = 0x64,
405e9346441SOGAWA Hirofumi     [Q_KEY_CODE_YEN] = 0x6a,
4068c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_COMMA] = 0x6d,
4078c10e0baSHervé Poussineau };
4088c10e0baSHervé Poussineau 
4098c10e0baSHervé Poussineau static const uint16_t qcode_to_keycode_set3[Q_KEY_CODE__MAX] = {
4108c10e0baSHervé Poussineau     [0 ... Q_KEY_CODE__MAX - 1] = 0,
4118c10e0baSHervé Poussineau 
4128c10e0baSHervé Poussineau     [Q_KEY_CODE_A] = 0x1c,
4138c10e0baSHervé Poussineau     [Q_KEY_CODE_B] = 0x32,
4148c10e0baSHervé Poussineau     [Q_KEY_CODE_C] = 0x21,
4158c10e0baSHervé Poussineau     [Q_KEY_CODE_D] = 0x23,
4168c10e0baSHervé Poussineau     [Q_KEY_CODE_E] = 0x24,
4178c10e0baSHervé Poussineau     [Q_KEY_CODE_F] = 0x2b,
4188c10e0baSHervé Poussineau     [Q_KEY_CODE_G] = 0x34,
4198c10e0baSHervé Poussineau     [Q_KEY_CODE_H] = 0x33,
4208c10e0baSHervé Poussineau     [Q_KEY_CODE_I] = 0x43,
4218c10e0baSHervé Poussineau     [Q_KEY_CODE_J] = 0x3b,
4228c10e0baSHervé Poussineau     [Q_KEY_CODE_K] = 0x42,
4238c10e0baSHervé Poussineau     [Q_KEY_CODE_L] = 0x4b,
4248c10e0baSHervé Poussineau     [Q_KEY_CODE_M] = 0x3a,
4258c10e0baSHervé Poussineau     [Q_KEY_CODE_N] = 0x31,
4268c10e0baSHervé Poussineau     [Q_KEY_CODE_O] = 0x44,
4278c10e0baSHervé Poussineau     [Q_KEY_CODE_P] = 0x4d,
4288c10e0baSHervé Poussineau     [Q_KEY_CODE_Q] = 0x15,
4298c10e0baSHervé Poussineau     [Q_KEY_CODE_R] = 0x2d,
4308c10e0baSHervé Poussineau     [Q_KEY_CODE_S] = 0x1b,
4318c10e0baSHervé Poussineau     [Q_KEY_CODE_T] = 0x2c,
4328c10e0baSHervé Poussineau     [Q_KEY_CODE_U] = 0x3c,
4338c10e0baSHervé Poussineau     [Q_KEY_CODE_V] = 0x2a,
4348c10e0baSHervé Poussineau     [Q_KEY_CODE_W] = 0x1d,
4358c10e0baSHervé Poussineau     [Q_KEY_CODE_X] = 0x22,
4368c10e0baSHervé Poussineau     [Q_KEY_CODE_Y] = 0x35,
4378c10e0baSHervé Poussineau     [Q_KEY_CODE_Z] = 0x1a,
4388c10e0baSHervé Poussineau     [Q_KEY_CODE_0] = 0x45,
4398c10e0baSHervé Poussineau     [Q_KEY_CODE_1] = 0x16,
4408c10e0baSHervé Poussineau     [Q_KEY_CODE_2] = 0x1e,
4418c10e0baSHervé Poussineau     [Q_KEY_CODE_3] = 0x26,
4428c10e0baSHervé Poussineau     [Q_KEY_CODE_4] = 0x25,
4438c10e0baSHervé Poussineau     [Q_KEY_CODE_5] = 0x2e,
4448c10e0baSHervé Poussineau     [Q_KEY_CODE_6] = 0x36,
4458c10e0baSHervé Poussineau     [Q_KEY_CODE_7] = 0x3d,
4468c10e0baSHervé Poussineau     [Q_KEY_CODE_8] = 0x3e,
4478c10e0baSHervé Poussineau     [Q_KEY_CODE_9] = 0x46,
4488c10e0baSHervé Poussineau     [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e,
4498c10e0baSHervé Poussineau     [Q_KEY_CODE_MINUS] = 0x4e,
4508c10e0baSHervé Poussineau     [Q_KEY_CODE_EQUAL] = 0x55,
4518c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSLASH] = 0x5c,
4528c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSPACE] = 0x66,
4538c10e0baSHervé Poussineau     [Q_KEY_CODE_SPC] = 0x29,
4548c10e0baSHervé Poussineau     [Q_KEY_CODE_TAB] = 0x0d,
4558c10e0baSHervé Poussineau     [Q_KEY_CODE_CAPS_LOCK] = 0x14,
4568c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT] = 0x12,
4578c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL] = 0x11,
4588c10e0baSHervé Poussineau     [Q_KEY_CODE_META_L] = 0x8b,
4598c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT] = 0x19,
4608c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT_R] = 0x59,
4618c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL_R] = 0x58,
4628c10e0baSHervé Poussineau     [Q_KEY_CODE_META_R] = 0x8c,
4638c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT_R] = 0x39,
4648c10e0baSHervé Poussineau     [Q_KEY_CODE_MENU] = 0x8d,
4658c10e0baSHervé Poussineau     [Q_KEY_CODE_RET] = 0x5a,
4668c10e0baSHervé Poussineau     [Q_KEY_CODE_ESC] = 0x08,
4678c10e0baSHervé Poussineau     [Q_KEY_CODE_F1] = 0x07,
4688c10e0baSHervé Poussineau     [Q_KEY_CODE_F2] = 0x0f,
4698c10e0baSHervé Poussineau     [Q_KEY_CODE_F3] = 0x17,
4708c10e0baSHervé Poussineau     [Q_KEY_CODE_F4] = 0x1f,
4718c10e0baSHervé Poussineau     [Q_KEY_CODE_F5] = 0x27,
4728c10e0baSHervé Poussineau     [Q_KEY_CODE_F6] = 0x2f,
4738c10e0baSHervé Poussineau     [Q_KEY_CODE_F7] = 0x37,
4748c10e0baSHervé Poussineau     [Q_KEY_CODE_F8] = 0x3f,
4758c10e0baSHervé Poussineau     [Q_KEY_CODE_F9] = 0x47,
4768c10e0baSHervé Poussineau     [Q_KEY_CODE_F10] = 0x4f,
4778c10e0baSHervé Poussineau     [Q_KEY_CODE_F11] = 0x56,
4788c10e0baSHervé Poussineau     [Q_KEY_CODE_F12] = 0x5e,
4798c10e0baSHervé Poussineau     [Q_KEY_CODE_PRINT] = 0x57,
4808c10e0baSHervé Poussineau     [Q_KEY_CODE_SCROLL_LOCK] = 0x5f,
4818c10e0baSHervé Poussineau     [Q_KEY_CODE_PAUSE] = 0x62,
4828c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_LEFT] = 0x54,
4838c10e0baSHervé Poussineau     [Q_KEY_CODE_INSERT] = 0x67,
4848c10e0baSHervé Poussineau     [Q_KEY_CODE_HOME] = 0x6e,
4858c10e0baSHervé Poussineau     [Q_KEY_CODE_PGUP] = 0x6f,
4868c10e0baSHervé Poussineau     [Q_KEY_CODE_DELETE] = 0x64,
4878c10e0baSHervé Poussineau     [Q_KEY_CODE_END] = 0x65,
4888c10e0baSHervé Poussineau     [Q_KEY_CODE_PGDN] = 0x6d,
4898c10e0baSHervé Poussineau     [Q_KEY_CODE_UP] = 0x63,
4908c10e0baSHervé Poussineau     [Q_KEY_CODE_LEFT] = 0x61,
4918c10e0baSHervé Poussineau     [Q_KEY_CODE_DOWN] = 0x60,
4928c10e0baSHervé Poussineau     [Q_KEY_CODE_RIGHT] = 0x6a,
4938c10e0baSHervé Poussineau     [Q_KEY_CODE_NUM_LOCK] = 0x76,
4948c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DIVIDE] = 0x4a,
4958c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_MULTIPLY] = 0x7e,
4968c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_SUBTRACT] = 0x4e,
4978c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ADD] = 0x7c,
4988c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ENTER] = 0x79,
4998c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DECIMAL] = 0x71,
5008c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_0] = 0x70,
5018c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_1] = 0x69,
5028c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_2] = 0x72,
5038c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_3] = 0x7a,
5048c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_4] = 0x6b,
5058c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_5] = 0x73,
5068c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_6] = 0x74,
5078c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_7] = 0x6c,
5088c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_8] = 0x75,
5098c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_9] = 0x7d,
5108c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b,
5118c10e0baSHervé Poussineau     [Q_KEY_CODE_SEMICOLON] = 0x4c,
5128c10e0baSHervé Poussineau     [Q_KEY_CODE_APOSTROPHE] = 0x52,
5138c10e0baSHervé Poussineau     [Q_KEY_CODE_COMMA] = 0x41,
5148c10e0baSHervé Poussineau     [Q_KEY_CODE_DOT] = 0x49,
5158c10e0baSHervé Poussineau     [Q_KEY_CODE_SLASH] = 0x4a,
516e9346441SOGAWA Hirofumi 
517e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HIRAGANA] = 0x87,
518e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HENKAN] = 0x86,
519e9346441SOGAWA Hirofumi     [Q_KEY_CODE_YEN] = 0x5d,
5207096a96dSRoy Tam };
521f94f5d71Spbrook 
52257d5c005SHervé Poussineau static uint8_t translate_table[256] = {
52357d5c005SHervé Poussineau     0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
52457d5c005SHervé Poussineau     0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
52557d5c005SHervé Poussineau     0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
52657d5c005SHervé Poussineau     0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
52757d5c005SHervé Poussineau     0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
52857d5c005SHervé Poussineau     0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
52957d5c005SHervé Poussineau     0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
53057d5c005SHervé Poussineau     0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
53157d5c005SHervé Poussineau     0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
53257d5c005SHervé Poussineau     0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
53357d5c005SHervé Poussineau     0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
53457d5c005SHervé Poussineau     0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
53557d5c005SHervé Poussineau     0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
53657d5c005SHervé Poussineau     0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
53757d5c005SHervé Poussineau     0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
53857d5c005SHervé Poussineau     0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
53957d5c005SHervé Poussineau     0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
54057d5c005SHervé Poussineau     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
54157d5c005SHervé Poussineau     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
54257d5c005SHervé Poussineau     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
54357d5c005SHervé Poussineau     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
54457d5c005SHervé Poussineau     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
54557d5c005SHervé Poussineau     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
54657d5c005SHervé Poussineau     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
54757d5c005SHervé Poussineau     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
54857d5c005SHervé Poussineau     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
54957d5c005SHervé Poussineau     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
55057d5c005SHervé Poussineau     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
55157d5c005SHervé Poussineau     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
55257d5c005SHervé Poussineau     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
55357d5c005SHervé Poussineau     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
55457d5c005SHervé Poussineau     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
55557d5c005SHervé Poussineau };
55657d5c005SHervé Poussineau 
557620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key)
558620775d1SDaniel P. Berrange {
559620775d1SDaniel P. Berrange     switch (key) {
560620775d1SDaniel P. Berrange     case Q_KEY_CODE_CTRL:
561620775d1SDaniel P. Berrange         return MOD_CTRL_L;
562620775d1SDaniel P. Berrange     case Q_KEY_CODE_CTRL_R:
563620775d1SDaniel P. Berrange         return MOD_CTRL_R;
564620775d1SDaniel P. Berrange     case Q_KEY_CODE_SHIFT:
565620775d1SDaniel P. Berrange         return MOD_SHIFT_L;
566620775d1SDaniel P. Berrange     case Q_KEY_CODE_SHIFT_R:
567620775d1SDaniel P. Berrange         return MOD_SHIFT_R;
568620775d1SDaniel P. Berrange     case Q_KEY_CODE_ALT:
569620775d1SDaniel P. Berrange         return MOD_ALT_L;
570620775d1SDaniel P. Berrange     case Q_KEY_CODE_ALT_R:
571620775d1SDaniel P. Berrange         return MOD_ALT_R;
572620775d1SDaniel P. Berrange     default:
573620775d1SDaniel P. Berrange         return 0;
574620775d1SDaniel P. Berrange     }
575620775d1SDaniel P. Berrange }
576620775d1SDaniel P. Berrange 
577954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s)
578954ee55bSGerd Hoffmann {
579954ee55bSGerd Hoffmann     PS2Queue *q = &s->queue;
580954ee55bSGerd Hoffmann 
581954ee55bSGerd Hoffmann     q->rptr = 0;
582954ee55bSGerd Hoffmann     q->wptr = 0;
583954ee55bSGerd Hoffmann     q->count = 0;
584954ee55bSGerd Hoffmann }
585954ee55bSGerd Hoffmann 
5868498bb8dSGerd Hoffmann void ps2_queue(PS2State *s, int b)
5870e43e99cSbellard {
5880e43e99cSbellard     PS2Queue *q = &s->queue;
5890e43e99cSbellard 
5902858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
5910e43e99cSbellard         return;
5920e43e99cSbellard     q->data[q->wptr] = b;
5930e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
5940e43e99cSbellard         q->wptr = 0;
5950e43e99cSbellard     q->count++;
5960e43e99cSbellard     s->update_irq(s->update_arg, 1);
5970e43e99cSbellard }
5980e43e99cSbellard 
59957d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */
6000e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
6010e43e99cSbellard {
602f94f5d71Spbrook     PS2KbdState *s = opaque;
603e7d93956Saurel32 
6045edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
605fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
60657d5c005SHervé Poussineau 
60757d5c005SHervé Poussineau     if (s->translate) {
60857d5c005SHervé Poussineau         if (keycode == 0xf0) {
60957d5c005SHervé Poussineau             s->need_high_bit = true;
61057d5c005SHervé Poussineau         } else if (s->need_high_bit) {
61157d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode] | 0x80);
61257d5c005SHervé Poussineau             s->need_high_bit = false;
61357d5c005SHervé Poussineau         } else {
61457d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode]);
6157096a96dSRoy Tam         }
61657d5c005SHervé Poussineau     } else {
6170e43e99cSbellard         ps2_queue(&s->common, keycode);
6180e43e99cSbellard     }
61957d5c005SHervé Poussineau }
6200e43e99cSbellard 
62166e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
62266e6536eSGerd Hoffmann                                InputEvent *evt)
62366e6536eSGerd Hoffmann {
62466e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
62532bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
6268c10e0baSHervé Poussineau     int qcode;
6278c10e0baSHervé Poussineau     uint16_t keycode;
628620775d1SDaniel P. Berrange     int mod;
62966e6536eSGerd Hoffmann 
63066e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
6318c10e0baSHervé Poussineau     assert(evt->type == INPUT_EVENT_KIND_KEY);
6328c10e0baSHervé Poussineau     qcode = qemu_input_key_value_to_qcode(key->key);
63357d5c005SHervé Poussineau 
634620775d1SDaniel P. Berrange     mod = ps2_modifier_bit(qcode);
635620775d1SDaniel P. Berrange     trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers);
636620775d1SDaniel P. Berrange     if (key->down) {
637620775d1SDaniel P. Berrange         s->modifiers |= mod;
638620775d1SDaniel P. Berrange     } else {
639620775d1SDaniel P. Berrange         s->modifiers &= ~mod;
640620775d1SDaniel P. Berrange     }
641620775d1SDaniel P. Berrange 
6428c10e0baSHervé Poussineau     if (s->scancode_set == 1) {
6438c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
6448c10e0baSHervé Poussineau             if (key->down) {
6458c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe1);
6468c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x1d);
6478c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x45);
6488c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x91);
6498c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x9d);
6508c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xc5);
6518c10e0baSHervé Poussineau             }
6528c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
653620775d1SDaniel P. Berrange             if (s->modifiers & MOD_ALT_L) {
654620775d1SDaniel P. Berrange                 if (key->down) {
655620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
656620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
657620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x54);
658620775d1SDaniel P. Berrange                 } else {
659620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xd4);
660620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
661620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
662620775d1SDaniel P. Berrange                 }
663620775d1SDaniel P. Berrange             } else if (s->modifiers & MOD_ALT_R) {
664620775d1SDaniel P. Berrange                 if (key->down) {
665620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
666620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
667620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
668620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
669620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x54);
670620775d1SDaniel P. Berrange                 } else {
671620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xd4);
672620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
673620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
674620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
675620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
676620775d1SDaniel P. Berrange                 }
677*8f63458fSDaniel P. Berrange             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
678*8f63458fSDaniel P. Berrange                                        MOD_SHIFT_R | MOD_CTRL_R)) {
679*8f63458fSDaniel P. Berrange                 if (key->down) {
680*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
681*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x37);
682*8f63458fSDaniel P. Berrange                 } else {
683*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
684*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xb7);
685*8f63458fSDaniel P. Berrange                 }
686620775d1SDaniel P. Berrange             } else {
6878c10e0baSHervé Poussineau                 if (key->down) {
6888c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
6898c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x2a);
6908c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
6918c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x37);
6928c10e0baSHervé Poussineau                 } else {
6938c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
6948c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xb7);
6958c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
6968c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xaa);
6978c10e0baSHervé Poussineau                 }
698620775d1SDaniel P. Berrange             }
6998c10e0baSHervé Poussineau         } else {
7008c10e0baSHervé Poussineau             keycode = qcode_to_keycode_set1[qcode];
7018c10e0baSHervé Poussineau             if (keycode) {
7028c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
7038c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
7048c10e0baSHervé Poussineau                 }
7058c10e0baSHervé Poussineau                 if (!key->down) {
7068c10e0baSHervé Poussineau                     keycode |= 0x80;
7078c10e0baSHervé Poussineau                 }
7088c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
7098c10e0baSHervé Poussineau             } else {
710ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
711ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
7128c10e0baSHervé Poussineau             }
7138c10e0baSHervé Poussineau         }
7148c10e0baSHervé Poussineau     } else if (s->scancode_set == 2) {
7158c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
7168c10e0baSHervé Poussineau             if (key->down) {
7178c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe1);
7188c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x14);
7198c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x77);
7208c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe1);
7218c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
7228c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x14);
7238c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
7248c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x77);
7258c10e0baSHervé Poussineau             }
7268c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
727620775d1SDaniel P. Berrange             if (s->modifiers & MOD_ALT_L) {
728620775d1SDaniel P. Berrange                 if (key->down) {
729620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
730620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
731620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
732620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
733620775d1SDaniel P. Berrange                 } else {
734620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
735620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
736620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
737620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
738620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
739620775d1SDaniel P. Berrange                 }
740620775d1SDaniel P. Berrange             } else if (s->modifiers & MOD_ALT_R) {
741620775d1SDaniel P. Berrange                 if (key->down) {
742620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
743620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
744620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
745620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
746620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
747620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
748620775d1SDaniel P. Berrange                 } else {
749620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
750620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
751620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
752620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
753620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
754620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
755620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
756620775d1SDaniel P. Berrange                 }
757*8f63458fSDaniel P. Berrange             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
758*8f63458fSDaniel P. Berrange                                        MOD_SHIFT_R | MOD_CTRL_R)) {
759*8f63458fSDaniel P. Berrange                 if (key->down) {
760*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
761*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x7c);
762*8f63458fSDaniel P. Berrange                 } else {
763*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
764*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
765*8f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x7c);
766*8f63458fSDaniel P. Berrange                 }
767620775d1SDaniel P. Berrange             } else {
7688c10e0baSHervé Poussineau                 if (key->down) {
7698c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
7708c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x12);
7718c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
7728c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x7c);
7738c10e0baSHervé Poussineau                 } else {
7748c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
7758c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
7768c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x7c);
7778c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
7788c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
7798c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x12);
7808c10e0baSHervé Poussineau                 }
781620775d1SDaniel P. Berrange             }
7828c10e0baSHervé Poussineau         } else {
7838c10e0baSHervé Poussineau             keycode = qcode_to_keycode_set2[qcode];
7848c10e0baSHervé Poussineau             if (keycode) {
7858c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
7868c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
7878c10e0baSHervé Poussineau                 }
7888c10e0baSHervé Poussineau                 if (!key->down) {
7898c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
7908c10e0baSHervé Poussineau                 }
7918c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
79257d5c005SHervé Poussineau             } else {
793ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
794ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
79557d5c005SHervé Poussineau             }
79657d5c005SHervé Poussineau         }
79757d5c005SHervé Poussineau     } else if (s->scancode_set == 3) {
7988c10e0baSHervé Poussineau         keycode = qcode_to_keycode_set3[qcode];
7998c10e0baSHervé Poussineau         if (keycode) {
8008c10e0baSHervé Poussineau             /* FIXME: break code should be configured on a key by key basis */
8018c10e0baSHervé Poussineau             if (!key->down) {
8028c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
80357d5c005SHervé Poussineau             }
80457d5c005SHervé Poussineau             ps2_put_keycode(s, keycode);
8058c10e0baSHervé Poussineau         } else {
806ec044a80SHervé Poussineau             qemu_log_mask(LOG_UNIMP,
807ec044a80SHervé Poussineau                           "ps2: ignoring key with qcode %d\n", qcode);
8088c10e0baSHervé Poussineau         }
80966e6536eSGerd Hoffmann     }
81066e6536eSGerd Hoffmann }
81166e6536eSGerd Hoffmann 
8128498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s)
8130e43e99cSbellard {
8140e43e99cSbellard     PS2Queue *q;
8150e43e99cSbellard     int val, index;
8160e43e99cSbellard 
8178498bb8dSGerd Hoffmann     trace_ps2_read_data(s);
8180e43e99cSbellard     q = &s->queue;
8190e43e99cSbellard     if (q->count == 0) {
8200e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
8210e43e99cSbellard            (needed for EMM386) */
8220e43e99cSbellard         /* XXX: need a timer to do things correctly */
8230e43e99cSbellard         index = q->rptr - 1;
8240e43e99cSbellard         if (index < 0)
8250e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
8260e43e99cSbellard         val = q->data[index];
8270e43e99cSbellard     } else {
8280e43e99cSbellard         val = q->data[q->rptr];
8290e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
8300e43e99cSbellard             q->rptr = 0;
8310e43e99cSbellard         q->count--;
8320e43e99cSbellard         /* reading deasserts IRQ */
8330e43e99cSbellard         s->update_irq(s->update_arg, 0);
8340e43e99cSbellard         /* reassert IRQs if data left */
8350e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
8360e43e99cSbellard     }
8370e43e99cSbellard     return val;
8380e43e99cSbellard }
8390e43e99cSbellard 
8407f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
8417f540ab5SChristophe Fergeau {
8425edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
8437f540ab5SChristophe Fergeau     s->ledstate = ledstate;
8447f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
8457f540ab5SChristophe Fergeau }
8467f540ab5SChristophe Fergeau 
8470e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
8480e43e99cSbellard {
8495edab03dSDon Koch     trace_ps2_reset_keyboard(s);
8500e43e99cSbellard     s->scan_enabled = 1;
851e7d93956Saurel32     s->scancode_set = 2;
8526e24ee0cSGerd Hoffmann     ps2_reset_queue(&s->common);
8537f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
8540e43e99cSbellard }
8550e43e99cSbellard 
8560e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
8570e43e99cSbellard {
8580e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
8590e43e99cSbellard 
8605edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
8610e43e99cSbellard     switch(s->common.write_cmd) {
8620e43e99cSbellard     default:
8630e43e99cSbellard     case -1:
8640e43e99cSbellard         switch(val) {
8650e43e99cSbellard         case 0x00:
8660e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
8670e43e99cSbellard             break;
8680e43e99cSbellard         case 0x05:
8690e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
8700e43e99cSbellard             break;
8710e43e99cSbellard         case KBD_CMD_GET_ID:
8720e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
873e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
87435c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
87535c4d671Saurel32             if (s->translate)
87635c4d671Saurel32                 ps2_queue(&s->common, 0x41);
87735c4d671Saurel32             else
87835c4d671Saurel32                 ps2_queue(&s->common, 0x83);
8790e43e99cSbellard             break;
8800e43e99cSbellard         case KBD_CMD_ECHO:
8810e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
8820e43e99cSbellard             break;
8830e43e99cSbellard         case KBD_CMD_ENABLE:
8840e43e99cSbellard             s->scan_enabled = 1;
8850e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
8860e43e99cSbellard             break;
887e7d93956Saurel32         case KBD_CMD_SCANCODE:
8880e43e99cSbellard         case KBD_CMD_SET_LEDS:
8890e43e99cSbellard         case KBD_CMD_SET_RATE:
8900e43e99cSbellard             s->common.write_cmd = val;
8910e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
8920e43e99cSbellard             break;
8930e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
8940e43e99cSbellard             ps2_reset_keyboard(s);
8950e43e99cSbellard             s->scan_enabled = 0;
8960e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
8970e43e99cSbellard             break;
8980e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
8990e43e99cSbellard             ps2_reset_keyboard(s);
9000e43e99cSbellard             s->scan_enabled = 1;
9010e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
9020e43e99cSbellard             break;
9030e43e99cSbellard         case KBD_CMD_RESET:
9040e43e99cSbellard             ps2_reset_keyboard(s);
9050e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
9060e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
9070e43e99cSbellard             break;
9080e43e99cSbellard         default:
90906b3611fSHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
9100e43e99cSbellard             break;
9110e43e99cSbellard         }
9120e43e99cSbellard         break;
913e7d93956Saurel32     case KBD_CMD_SCANCODE:
914e7d93956Saurel32         if (val == 0) {
9154df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_ACK);
91657d5c005SHervé Poussineau             ps2_put_keycode(s, s->scancode_set);
9174df23b64SHervé Poussineau         } else if (val >= 1 && val <= 3) {
918e7d93956Saurel32             s->scancode_set = val;
919e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
9204df23b64SHervé Poussineau         } else {
9214df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
922e7d93956Saurel32         }
923e7d93956Saurel32         s->common.write_cmd = -1;
924e7d93956Saurel32         break;
9250e43e99cSbellard     case KBD_CMD_SET_LEDS:
9267f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
9270e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
9280e43e99cSbellard         s->common.write_cmd = -1;
9290e43e99cSbellard         break;
9300e43e99cSbellard     case KBD_CMD_SET_RATE:
9310e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
9320e43e99cSbellard         s->common.write_cmd = -1;
9330e43e99cSbellard         break;
9340e43e99cSbellard     }
9350e43e99cSbellard }
9360e43e99cSbellard 
937f94f5d71Spbrook /* Set the scancode translation mode.
938f94f5d71Spbrook    0 = raw scancodes.
939f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
940f94f5d71Spbrook 
941f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
942f94f5d71Spbrook {
943f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
9445edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
945f94f5d71Spbrook     s->translate = mode;
946f94f5d71Spbrook }
947f94f5d71Spbrook 
9480e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
9490e43e99cSbellard {
9500e43e99cSbellard     unsigned int b;
9510e43e99cSbellard     int dx1, dy1, dz1;
9520e43e99cSbellard 
9530e43e99cSbellard     dx1 = s->mouse_dx;
9540e43e99cSbellard     dy1 = s->mouse_dy;
9550e43e99cSbellard     dz1 = s->mouse_dz;
9560e43e99cSbellard     /* XXX: increase range to 8 bits ? */
9570e43e99cSbellard     if (dx1 > 127)
9580e43e99cSbellard         dx1 = 127;
9590e43e99cSbellard     else if (dx1 < -127)
9600e43e99cSbellard         dx1 = -127;
9610e43e99cSbellard     if (dy1 > 127)
9620e43e99cSbellard         dy1 = 127;
9630e43e99cSbellard     else if (dy1 < -127)
9640e43e99cSbellard         dy1 = -127;
9650e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
9660e43e99cSbellard     ps2_queue(&s->common, b);
9670e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
9680e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
9690e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
9700e43e99cSbellard     switch(s->mouse_type) {
9710e43e99cSbellard     default:
9720e43e99cSbellard         break;
9730e43e99cSbellard     case 3:
9740e43e99cSbellard         if (dz1 > 127)
9750e43e99cSbellard             dz1 = 127;
9760e43e99cSbellard         else if (dz1 < -127)
9770e43e99cSbellard                 dz1 = -127;
9780e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
9790e43e99cSbellard         break;
9800e43e99cSbellard     case 4:
9810e43e99cSbellard         if (dz1 > 7)
9820e43e99cSbellard             dz1 = 7;
9830e43e99cSbellard         else if (dz1 < -7)
9840e43e99cSbellard             dz1 = -7;
9850e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
9860e43e99cSbellard         ps2_queue(&s->common, b);
9870e43e99cSbellard         break;
9880e43e99cSbellard     }
9890e43e99cSbellard 
9905edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
9910e43e99cSbellard     /* update deltas */
9920e43e99cSbellard     s->mouse_dx -= dx1;
9930e43e99cSbellard     s->mouse_dy -= dy1;
9940e43e99cSbellard     s->mouse_dz -= dz1;
9950e43e99cSbellard }
9960e43e99cSbellard 
9972a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
9982a766d29SGerd Hoffmann                             InputEvent *evt)
9990e43e99cSbellard {
10007fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
10018b0caab0SFabian Lesniak         [INPUT_BUTTON_LEFT]   = PS2_MOUSE_BUTTON_LEFT,
10028b0caab0SFabian Lesniak         [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
10038b0caab0SFabian Lesniak         [INPUT_BUTTON_RIGHT]  = PS2_MOUSE_BUTTON_RIGHT,
10048b0caab0SFabian Lesniak         [INPUT_BUTTON_SIDE]   = PS2_MOUSE_BUTTON_SIDE,
10058b0caab0SFabian Lesniak         [INPUT_BUTTON_EXTRA]  = PS2_MOUSE_BUTTON_EXTRA,
10062a766d29SGerd Hoffmann     };
10072a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
1008b5a1b443SEric Blake     InputMoveEvent *move;
1009b5a1b443SEric Blake     InputBtnEvent *btn;
10100e43e99cSbellard 
10110e43e99cSbellard     /* check if deltas are recorded when disabled */
10120e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
10130e43e99cSbellard         return;
10140e43e99cSbellard 
1015568c73a4SEric Blake     switch (evt->type) {
10162a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
101732bafa8fSEric Blake         move = evt->u.rel.data;
1018b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
1019b5a1b443SEric Blake             s->mouse_dx += move->value;
1020b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
1021b5a1b443SEric Blake             s->mouse_dy -= move->value;
10222a766d29SGerd Hoffmann         }
10232a766d29SGerd Hoffmann         break;
10240e43e99cSbellard 
10252a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
102632bafa8fSEric Blake         btn = evt->u.btn.data;
1027b5a1b443SEric Blake         if (btn->down) {
1028b5a1b443SEric Blake             s->mouse_buttons |= bmap[btn->button];
1029b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
10302a766d29SGerd Hoffmann                 s->mouse_dz--;
1031b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
10322a766d29SGerd Hoffmann                 s->mouse_dz++;
10332a766d29SGerd Hoffmann             }
10342a766d29SGerd Hoffmann         } else {
1035b5a1b443SEric Blake             s->mouse_buttons &= ~bmap[btn->button];
10362a766d29SGerd Hoffmann         }
10372a766d29SGerd Hoffmann         break;
10382a766d29SGerd Hoffmann 
10392a766d29SGerd Hoffmann     default:
10402a766d29SGerd Hoffmann         /* keep gcc happy */
10412a766d29SGerd Hoffmann         break;
10422a766d29SGerd Hoffmann     }
1043fd214d18SGerd Hoffmann }
1044fd214d18SGerd Hoffmann 
10452a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
10462a766d29SGerd Hoffmann {
10472a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
10482a766d29SGerd Hoffmann 
10492a766d29SGerd Hoffmann     if (s->mouse_buttons) {
10502a766d29SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
10512a766d29SGerd Hoffmann     }
10522858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
10532858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
10540e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
10550e43e99cSbellard                too big deltas */
10560e43e99cSbellard             ps2_mouse_send_packet(s);
10570e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
10580e43e99cSbellard                 break;
10590e43e99cSbellard         }
10600e43e99cSbellard     }
10610e43e99cSbellard }
10620e43e99cSbellard 
1063548df2acSths void ps2_mouse_fake_event(void *opaque)
1064548df2acSths {
10652a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
10665edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
10672a766d29SGerd Hoffmann     s->mouse_dx++;
10682a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
1069548df2acSths }
1070548df2acSths 
10710e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
10720e43e99cSbellard {
10730e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
10745edab03dSDon Koch 
10755edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
10760e43e99cSbellard #ifdef DEBUG_MOUSE
10770e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
10780e43e99cSbellard #endif
10790e43e99cSbellard     switch(s->common.write_cmd) {
10800e43e99cSbellard     default:
10810e43e99cSbellard     case -1:
10820e43e99cSbellard         /* mouse command */
10830e43e99cSbellard         if (s->mouse_wrap) {
10840e43e99cSbellard             if (val == AUX_RESET_WRAP) {
10850e43e99cSbellard                 s->mouse_wrap = 0;
10860e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
10870e43e99cSbellard                 return;
10880e43e99cSbellard             } else if (val != AUX_RESET) {
10890e43e99cSbellard                 ps2_queue(&s->common, val);
10900e43e99cSbellard                 return;
10910e43e99cSbellard             }
10920e43e99cSbellard         }
10930e43e99cSbellard         switch(val) {
10940e43e99cSbellard         case AUX_SET_SCALE11:
10950e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
10960e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10970e43e99cSbellard             break;
10980e43e99cSbellard         case AUX_SET_SCALE21:
10990e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
11000e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11010e43e99cSbellard             break;
11020e43e99cSbellard         case AUX_SET_STREAM:
11030e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
11040e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11050e43e99cSbellard             break;
11060e43e99cSbellard         case AUX_SET_WRAP:
11070e43e99cSbellard             s->mouse_wrap = 1;
11080e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11090e43e99cSbellard             break;
11100e43e99cSbellard         case AUX_SET_REMOTE:
11110e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
11120e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11130e43e99cSbellard             break;
11140e43e99cSbellard         case AUX_GET_TYPE:
11150e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11160e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
11170e43e99cSbellard             break;
11180e43e99cSbellard         case AUX_SET_RES:
11190e43e99cSbellard         case AUX_SET_SAMPLE:
11200e43e99cSbellard             s->common.write_cmd = val;
11210e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11220e43e99cSbellard             break;
11230e43e99cSbellard         case AUX_GET_SCALE:
11240e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11250e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
11260e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
11270e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
11280e43e99cSbellard             break;
11290e43e99cSbellard         case AUX_POLL:
11300e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11310e43e99cSbellard             ps2_mouse_send_packet(s);
11320e43e99cSbellard             break;
11330e43e99cSbellard         case AUX_ENABLE_DEV:
11340e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
11350e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11360e43e99cSbellard             break;
11370e43e99cSbellard         case AUX_DISABLE_DEV:
11380e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
11390e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11400e43e99cSbellard             break;
11410e43e99cSbellard         case AUX_SET_DEFAULT:
11420e43e99cSbellard             s->mouse_sample_rate = 100;
11430e43e99cSbellard             s->mouse_resolution = 2;
11440e43e99cSbellard             s->mouse_status = 0;
11450e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11460e43e99cSbellard             break;
11470e43e99cSbellard         case AUX_RESET:
11480e43e99cSbellard             s->mouse_sample_rate = 100;
11490e43e99cSbellard             s->mouse_resolution = 2;
11500e43e99cSbellard             s->mouse_status = 0;
11510e43e99cSbellard             s->mouse_type = 0;
11520e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
11530e43e99cSbellard             ps2_queue(&s->common, 0xaa);
11540e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
11550e43e99cSbellard             break;
11560e43e99cSbellard         default:
11570e43e99cSbellard             break;
11580e43e99cSbellard         }
11590e43e99cSbellard         break;
11600e43e99cSbellard     case AUX_SET_SAMPLE:
11610e43e99cSbellard         s->mouse_sample_rate = val;
11620e43e99cSbellard         /* detect IMPS/2 or IMEX */
11630e43e99cSbellard         switch(s->mouse_detect_state) {
11640e43e99cSbellard         default:
11650e43e99cSbellard         case 0:
11660e43e99cSbellard             if (val == 200)
11670e43e99cSbellard                 s->mouse_detect_state = 1;
11680e43e99cSbellard             break;
11690e43e99cSbellard         case 1:
11700e43e99cSbellard             if (val == 100)
11710e43e99cSbellard                 s->mouse_detect_state = 2;
11720e43e99cSbellard             else if (val == 200)
11730e43e99cSbellard                 s->mouse_detect_state = 3;
11740e43e99cSbellard             else
11750e43e99cSbellard                 s->mouse_detect_state = 0;
11760e43e99cSbellard             break;
11770e43e99cSbellard         case 2:
11780e43e99cSbellard             if (val == 80)
11790e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
11800e43e99cSbellard             s->mouse_detect_state = 0;
11810e43e99cSbellard             break;
11820e43e99cSbellard         case 3:
11830e43e99cSbellard             if (val == 80)
11840e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
11850e43e99cSbellard             s->mouse_detect_state = 0;
11860e43e99cSbellard             break;
11870e43e99cSbellard         }
11880e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
11890e43e99cSbellard         s->common.write_cmd = -1;
11900e43e99cSbellard         break;
11910e43e99cSbellard     case AUX_SET_RES:
11920e43e99cSbellard         s->mouse_resolution = val;
11930e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
11940e43e99cSbellard         s->common.write_cmd = -1;
11950e43e99cSbellard         break;
11960e43e99cSbellard     }
11970e43e99cSbellard }
11980e43e99cSbellard 
1199ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
12000e43e99cSbellard {
12010e43e99cSbellard     s->write_cmd = -1;
1202954ee55bSGerd Hoffmann     ps2_reset_queue(s);
1203deeccef3Saliguori     s->update_irq(s->update_arg, 0);
12040e43e99cSbellard }
12050e43e99cSbellard 
12062858ab09SGonglei static void ps2_common_post_load(PS2State *s)
12072858ab09SGonglei {
12082858ab09SGonglei     PS2Queue *q = &s->queue;
12092858ab09SGonglei     int size;
12102858ab09SGonglei     int i;
12112858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
12122858ab09SGonglei 
12132858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
12142858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
12152858ab09SGonglei 
12162858ab09SGonglei     /* move the queue elements to the start of data array */
12172858ab09SGonglei     if (size > 0) {
12182858ab09SGonglei         for (i = 0; i < size; i++) {
12192858ab09SGonglei             /* move the queue elements to the temporary buffer */
12202858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
12212858ab09SGonglei             if (++q->rptr == 256) {
12222858ab09SGonglei                 q->rptr = 0;
12232858ab09SGonglei             }
12242858ab09SGonglei         }
12252858ab09SGonglei         memcpy(q->data, tmp_data, size);
12262858ab09SGonglei     }
12272858ab09SGonglei     /* reset rptr/wptr/count */
12282858ab09SGonglei     q->rptr = 0;
12292858ab09SGonglei     q->wptr = size;
12302858ab09SGonglei     q->count = size;
12312858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
12322858ab09SGonglei }
12332858ab09SGonglei 
1234ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
1235ef74679aSDinesh Subhraveti {
1236ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
1237ef74679aSDinesh Subhraveti 
12385edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
1239ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
1240ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
1241ef74679aSDinesh Subhraveti     s->translate = 0;
1242089adafdSHervé Poussineau     s->scancode_set = 2;
1243620775d1SDaniel P. Berrange     s->modifiers = 0;
1244ef74679aSDinesh Subhraveti }
1245ef74679aSDinesh Subhraveti 
1246ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
1247ef74679aSDinesh Subhraveti {
1248ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
1249ef74679aSDinesh Subhraveti 
12505edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
1251ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
1252ef74679aSDinesh Subhraveti     s->mouse_status = 0;
1253ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
1254ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
1255ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
1256ef74679aSDinesh Subhraveti     s->mouse_type = 0;
1257ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
1258ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
1259ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
1260ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
1261ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
1262ef74679aSDinesh Subhraveti }
1263ef74679aSDinesh Subhraveti 
1264b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
1265b31442c3SJuan Quintela     .name = "PS2 Common State",
1266b31442c3SJuan Quintela     .version_id = 3,
1267b31442c3SJuan Quintela     .minimum_version_id = 2,
1268b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1269b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
1270b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
1271b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
1272b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
1273b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
1274b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
12757783e9f0Spbrook     }
1276b31442c3SJuan Quintela };
12777783e9f0Spbrook 
12787f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
12797f540ab5SChristophe Fergeau {
12807f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
12817f540ab5SChristophe Fergeau 
12827f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
12837f540ab5SChristophe Fergeau }
12847f540ab5SChristophe Fergeau 
12857f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
12867f540ab5SChristophe Fergeau {
12877f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
12887f540ab5SChristophe Fergeau 
12897f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
12907f540ab5SChristophe Fergeau     return 0;
12917f540ab5SChristophe Fergeau }
12927f540ab5SChristophe Fergeau 
12937f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
12947f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
12957f540ab5SChristophe Fergeau     .version_id = 3,
12967f540ab5SChristophe Fergeau     .minimum_version_id = 2,
12977f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
12985cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
12997f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
13007f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
13017f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
13027f540ab5SChristophe Fergeau     }
13037f540ab5SChristophe Fergeau };
13047f540ab5SChristophe Fergeau 
130557d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque)
130657d5c005SHervé Poussineau {
130757d5c005SHervé Poussineau     PS2KbdState *s = opaque;
130857d5c005SHervé Poussineau     return s->need_high_bit != 0; /* 0 is the usual state */
130957d5c005SHervé Poussineau }
131057d5c005SHervé Poussineau 
131157d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
131257d5c005SHervé Poussineau     .name = "ps2kbd/need_high_bit",
131357d5c005SHervé Poussineau     .version_id = 1,
131457d5c005SHervé Poussineau     .minimum_version_id = 1,
131557d5c005SHervé Poussineau     .needed = ps2_keyboard_need_high_bit_needed,
131657d5c005SHervé Poussineau     .fields = (VMStateField[]) {
131757d5c005SHervé Poussineau         VMSTATE_BOOL(need_high_bit, PS2KbdState),
131857d5c005SHervé Poussineau         VMSTATE_END_OF_LIST()
131957d5c005SHervé Poussineau     }
132057d5c005SHervé Poussineau };
132157d5c005SHervé Poussineau 
1322db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
13230e43e99cSbellard {
13240e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
13252858ab09SGonglei     PS2State *ps2 = &s->common;
13260e43e99cSbellard 
1327db596c53SJuan Quintela     if (version_id == 2)
1328e7d93956Saurel32         s->scancode_set=2;
13292858ab09SGonglei 
13302858ab09SGonglei     ps2_common_post_load(ps2);
13312858ab09SGonglei 
13320e43e99cSbellard     return 0;
13330e43e99cSbellard }
13340e43e99cSbellard 
133544b1ff31SDr. David Alan Gilbert static int ps2_kbd_pre_save(void *opaque)
13362858ab09SGonglei {
13372858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
13382858ab09SGonglei     PS2State *ps2 = &s->common;
13392858ab09SGonglei 
13402858ab09SGonglei     ps2_common_post_load(ps2);
134144b1ff31SDr. David Alan Gilbert 
134244b1ff31SDr. David Alan Gilbert     return 0;
13432858ab09SGonglei }
13442858ab09SGonglei 
1345b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
1346b31442c3SJuan Quintela     .name = "ps2kbd",
1347b31442c3SJuan Quintela     .version_id = 3,
1348db596c53SJuan Quintela     .minimum_version_id = 2,
1349db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
13502858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
1351b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1352b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
1353b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
1354b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
1355b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
1356b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
13577f540ab5SChristophe Fergeau     },
13585cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
13595cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
136057d5c005SHervé Poussineau         &vmstate_ps2_keyboard_need_high_bit,
13615cd8cadaSJuan Quintela         NULL
13620e43e99cSbellard     }
1363b31442c3SJuan Quintela };
1364b31442c3SJuan Quintela 
13652858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
13662858ab09SGonglei {
13672858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
13682858ab09SGonglei     PS2State *ps2 = &s->common;
13692858ab09SGonglei 
13702858ab09SGonglei     ps2_common_post_load(ps2);
13712858ab09SGonglei 
13722858ab09SGonglei     return 0;
13732858ab09SGonglei }
13742858ab09SGonglei 
137544b1ff31SDr. David Alan Gilbert static int ps2_mouse_pre_save(void *opaque)
13762858ab09SGonglei {
13772858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
13782858ab09SGonglei     PS2State *ps2 = &s->common;
13792858ab09SGonglei 
13802858ab09SGonglei     ps2_common_post_load(ps2);
138144b1ff31SDr. David Alan Gilbert 
138244b1ff31SDr. David Alan Gilbert     return 0;
13832858ab09SGonglei }
13842858ab09SGonglei 
1385b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
1386b31442c3SJuan Quintela     .name = "ps2mouse",
1387b31442c3SJuan Quintela     .version_id = 2,
1388b31442c3SJuan Quintela     .minimum_version_id = 2,
13892858ab09SGonglei     .post_load = ps2_mouse_post_load,
13902858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
1391b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1392b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
1393b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
1394b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1395b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1396b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1397b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
1398b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1399b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
1400b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
1401b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
1402b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1403b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
1404b31442c3SJuan Quintela     }
1405b31442c3SJuan Quintela };
14060e43e99cSbellard 
140766e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
140866e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
140966e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
141066e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
141166e6536eSGerd Hoffmann };
141266e6536eSGerd Hoffmann 
14130e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
14140e43e99cSbellard {
14157267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
14160e43e99cSbellard 
14175edab03dSDon Koch     trace_ps2_kbd_init(s);
14180e43e99cSbellard     s->common.update_irq = update_irq;
14190e43e99cSbellard     s->common.update_arg = update_arg;
1420e7d93956Saurel32     s->scancode_set = 2;
14210be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
142266e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
142366e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
1424ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
14250e43e99cSbellard     return s;
14260e43e99cSbellard }
14270e43e99cSbellard 
14282a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
14292a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
14302a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
14312a766d29SGerd Hoffmann     .event = ps2_mouse_event,
14322a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
14332a766d29SGerd Hoffmann };
14342a766d29SGerd Hoffmann 
14350e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
14360e43e99cSbellard {
14377267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
14380e43e99cSbellard 
14395edab03dSDon Koch     trace_ps2_mouse_init(s);
14400e43e99cSbellard     s->common.update_irq = update_irq;
14410e43e99cSbellard     s->common.update_arg = update_arg;
14420be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
14432a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
14442a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
1445ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
14460e43e99cSbellard     return s;
14470e43e99cSbellard }
1448