xref: /qemu/hw/input/ps2.c (revision 954ee55bd528a97347f19f815e00f1e375f82f0a)
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 
810e43e99cSbellard typedef struct {
822858ab09SGonglei     /* Keep the data array 256 bytes long, which compatibility
832858ab09SGonglei      with older qemu versions. */
842858ab09SGonglei     uint8_t data[256];
850e43e99cSbellard     int rptr, wptr, count;
860e43e99cSbellard } PS2Queue;
870e43e99cSbellard 
888498bb8dSGerd Hoffmann struct PS2State {
890e43e99cSbellard     PS2Queue queue;
900e43e99cSbellard     int32_t write_cmd;
910e43e99cSbellard     void (*update_irq)(void *, int);
920e43e99cSbellard     void *update_arg;
938498bb8dSGerd Hoffmann };
940e43e99cSbellard 
950e43e99cSbellard typedef struct {
960e43e99cSbellard     PS2State common;
970e43e99cSbellard     int scan_enabled;
98f94f5d71Spbrook     int translate;
99e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
1007f540ab5SChristophe Fergeau     int ledstate;
10157d5c005SHervé Poussineau     bool need_high_bit;
1020e43e99cSbellard } PS2KbdState;
1030e43e99cSbellard 
1040e43e99cSbellard typedef struct {
1050e43e99cSbellard     PS2State common;
1060e43e99cSbellard     uint8_t mouse_status;
1070e43e99cSbellard     uint8_t mouse_resolution;
1080e43e99cSbellard     uint8_t mouse_sample_rate;
1090e43e99cSbellard     uint8_t mouse_wrap;
1100e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1110e43e99cSbellard     uint8_t mouse_detect_state;
1120e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1130e43e99cSbellard     int mouse_dy;
1140e43e99cSbellard     int mouse_dz;
1150e43e99cSbellard     uint8_t mouse_buttons;
1160e43e99cSbellard } PS2MouseState;
1170e43e99cSbellard 
1188c10e0baSHervé Poussineau /* Table to convert from QEMU codes to scancodes.  */
1198c10e0baSHervé Poussineau static const uint16_t qcode_to_keycode_set1[Q_KEY_CODE__MAX] = {
1208c10e0baSHervé Poussineau     [0 ... Q_KEY_CODE__MAX - 1] = 0,
1218c10e0baSHervé Poussineau 
1228c10e0baSHervé Poussineau     [Q_KEY_CODE_A] = 0x1e,
1238c10e0baSHervé Poussineau     [Q_KEY_CODE_B] = 0x30,
1248c10e0baSHervé Poussineau     [Q_KEY_CODE_C] = 0x2e,
1258c10e0baSHervé Poussineau     [Q_KEY_CODE_D] = 0x20,
1268c10e0baSHervé Poussineau     [Q_KEY_CODE_E] = 0x12,
1278c10e0baSHervé Poussineau     [Q_KEY_CODE_F] = 0x21,
1288c10e0baSHervé Poussineau     [Q_KEY_CODE_G] = 0x22,
1298c10e0baSHervé Poussineau     [Q_KEY_CODE_H] = 0x23,
1308c10e0baSHervé Poussineau     [Q_KEY_CODE_I] = 0x17,
1318c10e0baSHervé Poussineau     [Q_KEY_CODE_J] = 0x24,
1328c10e0baSHervé Poussineau     [Q_KEY_CODE_K] = 0x25,
1338c10e0baSHervé Poussineau     [Q_KEY_CODE_L] = 0x26,
1348c10e0baSHervé Poussineau     [Q_KEY_CODE_M] = 0x32,
1358c10e0baSHervé Poussineau     [Q_KEY_CODE_N] = 0x31,
1368c10e0baSHervé Poussineau     [Q_KEY_CODE_O] = 0x18,
1378c10e0baSHervé Poussineau     [Q_KEY_CODE_P] = 0x19,
1388c10e0baSHervé Poussineau     [Q_KEY_CODE_Q] = 0x10,
1398c10e0baSHervé Poussineau     [Q_KEY_CODE_R] = 0x13,
1408c10e0baSHervé Poussineau     [Q_KEY_CODE_S] = 0x1f,
1418c10e0baSHervé Poussineau     [Q_KEY_CODE_T] = 0x14,
1428c10e0baSHervé Poussineau     [Q_KEY_CODE_U] = 0x16,
1438c10e0baSHervé Poussineau     [Q_KEY_CODE_V] = 0x2f,
1448c10e0baSHervé Poussineau     [Q_KEY_CODE_W] = 0x11,
1458c10e0baSHervé Poussineau     [Q_KEY_CODE_X] = 0x2d,
1468c10e0baSHervé Poussineau     [Q_KEY_CODE_Y] = 0x15,
1478c10e0baSHervé Poussineau     [Q_KEY_CODE_Z] = 0x2c,
1488c10e0baSHervé Poussineau     [Q_KEY_CODE_0] = 0x0b,
1498c10e0baSHervé Poussineau     [Q_KEY_CODE_1] = 0x02,
1508c10e0baSHervé Poussineau     [Q_KEY_CODE_2] = 0x03,
1518c10e0baSHervé Poussineau     [Q_KEY_CODE_3] = 0x04,
1528c10e0baSHervé Poussineau     [Q_KEY_CODE_4] = 0x05,
1538c10e0baSHervé Poussineau     [Q_KEY_CODE_5] = 0x06,
1548c10e0baSHervé Poussineau     [Q_KEY_CODE_6] = 0x07,
1558c10e0baSHervé Poussineau     [Q_KEY_CODE_7] = 0x08,
1568c10e0baSHervé Poussineau     [Q_KEY_CODE_8] = 0x09,
1578c10e0baSHervé Poussineau     [Q_KEY_CODE_9] = 0x0a,
1588c10e0baSHervé Poussineau     [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
1598c10e0baSHervé Poussineau     [Q_KEY_CODE_MINUS] = 0x0c,
1608c10e0baSHervé Poussineau     [Q_KEY_CODE_EQUAL] = 0x0d,
1618c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSLASH] = 0x2b,
1628c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSPACE] = 0x0e,
1638c10e0baSHervé Poussineau     [Q_KEY_CODE_SPC] = 0x39,
1648c10e0baSHervé Poussineau     [Q_KEY_CODE_TAB] = 0x0f,
1658c10e0baSHervé Poussineau     [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
1668c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT] = 0x2a,
1678c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL] = 0x1d,
1688c10e0baSHervé Poussineau     [Q_KEY_CODE_META_L] = 0xe05b,
1698c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT] = 0x38,
1708c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT_R] = 0x36,
1718c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL_R] = 0xe01d,
1728c10e0baSHervé Poussineau     [Q_KEY_CODE_META_R] = 0xe05c,
1738c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT_R] = 0xe038,
1748c10e0baSHervé Poussineau     [Q_KEY_CODE_MENU] = 0xe05d,
1758c10e0baSHervé Poussineau     [Q_KEY_CODE_RET] = 0x1c,
1768c10e0baSHervé Poussineau     [Q_KEY_CODE_ESC] = 0x01,
1778c10e0baSHervé Poussineau     [Q_KEY_CODE_F1] = 0x3b,
1788c10e0baSHervé Poussineau     [Q_KEY_CODE_F2] = 0x3c,
1798c10e0baSHervé Poussineau     [Q_KEY_CODE_F3] = 0x3d,
1808c10e0baSHervé Poussineau     [Q_KEY_CODE_F4] = 0x3e,
1818c10e0baSHervé Poussineau     [Q_KEY_CODE_F5] = 0x3f,
1828c10e0baSHervé Poussineau     [Q_KEY_CODE_F6] = 0x40,
1838c10e0baSHervé Poussineau     [Q_KEY_CODE_F7] = 0x41,
1848c10e0baSHervé Poussineau     [Q_KEY_CODE_F8] = 0x42,
1858c10e0baSHervé Poussineau     [Q_KEY_CODE_F9] = 0x43,
1868c10e0baSHervé Poussineau     [Q_KEY_CODE_F10] = 0x44,
1878c10e0baSHervé Poussineau     [Q_KEY_CODE_F11] = 0x57,
1888c10e0baSHervé Poussineau     [Q_KEY_CODE_F12] = 0x58,
1898c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PRINT */
1908c10e0baSHervé Poussineau     [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
1918c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PAUSE */
1928c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
1938c10e0baSHervé Poussineau     [Q_KEY_CODE_INSERT] = 0xe052,
1948c10e0baSHervé Poussineau     [Q_KEY_CODE_HOME] = 0xe047,
1958c10e0baSHervé Poussineau     [Q_KEY_CODE_PGUP] = 0xe049,
1968c10e0baSHervé Poussineau     [Q_KEY_CODE_DELETE] = 0xe053,
1978c10e0baSHervé Poussineau     [Q_KEY_CODE_END] = 0xe04f,
1988c10e0baSHervé Poussineau     [Q_KEY_CODE_PGDN] = 0xe051,
1998c10e0baSHervé Poussineau     [Q_KEY_CODE_UP] = 0xe048,
2008c10e0baSHervé Poussineau     [Q_KEY_CODE_LEFT] = 0xe04b,
2018c10e0baSHervé Poussineau     [Q_KEY_CODE_DOWN] = 0xe050,
2028c10e0baSHervé Poussineau     [Q_KEY_CODE_RIGHT] = 0xe04d,
2038c10e0baSHervé Poussineau     [Q_KEY_CODE_NUM_LOCK] = 0x45,
2048c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DIVIDE] = 0xe035,
2058c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
2068c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
2078c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ADD] = 0x4e,
2088c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ENTER] = 0xe01c,
2098c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DECIMAL] = 0x53,
2108c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_0] = 0x52,
2118c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_1] = 0x4f,
2128c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_2] = 0x50,
2138c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_3] = 0x51,
2148c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_4] = 0x4b,
2158c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_5] = 0x4c,
2168c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_6] = 0x4d,
2178c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_7] = 0x47,
2188c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_8] = 0x48,
2198c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_9] = 0x49,
2208c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
2218c10e0baSHervé Poussineau     [Q_KEY_CODE_SEMICOLON] = 0x27,
2228c10e0baSHervé Poussineau     [Q_KEY_CODE_APOSTROPHE] = 0x28,
2238c10e0baSHervé Poussineau     [Q_KEY_CODE_COMMA] = 0x33,
2248c10e0baSHervé Poussineau     [Q_KEY_CODE_DOT] = 0x34,
2258c10e0baSHervé Poussineau     [Q_KEY_CODE_SLASH] = 0x35,
2268c10e0baSHervé Poussineau 
2278c10e0baSHervé Poussineau #if 0
2288c10e0baSHervé Poussineau     [Q_KEY_CODE_POWER] = 0x0e5e,
2298c10e0baSHervé Poussineau     [Q_KEY_CODE_SLEEP] = 0x0e5f,
2308c10e0baSHervé Poussineau     [Q_KEY_CODE_WAKE] = 0x0e63,
2318c10e0baSHervé Poussineau 
2328c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIONEXT] = 0xe019,
2338c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPREV] = 0xe010,
2348c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOSTOP] = 0xe024,
2358c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPLAY] = 0xe022,
2368c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOMUTE] = 0xe020,
2378c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEUP] = 0xe030,
2388c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEDOWN] = 0xe02e,
2398c10e0baSHervé Poussineau     [Q_KEY_CODE_MEDIASELECT] = 0xe06d,
2408c10e0baSHervé Poussineau     [Q_KEY_CODE_MAIL] = 0xe06c,
2418c10e0baSHervé Poussineau     [Q_KEY_CODE_CALCULATOR] = 0xe021,
2428c10e0baSHervé Poussineau     [Q_KEY_CODE_COMPUTER] = 0xe06b,
2438c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_SEARCH] = 0xe065,
2448c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_HOME] = 0xe032,
2458c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BACK] = 0xe06a,
2468c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_FORWARD] = 0xe069,
2478c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_STOP] = 0xe068,
2488c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_REFRESH] = 0xe067,
2498c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BOOKMARKS] = 0xe066,
2508c10e0baSHervé Poussineau #endif
2518c10e0baSHervé Poussineau 
2528c10e0baSHervé Poussineau     [Q_KEY_CODE_ASTERISK] = 0x37,
2538c10e0baSHervé Poussineau     [Q_KEY_CODE_LESS] = 0x56,
2548c10e0baSHervé Poussineau     [Q_KEY_CODE_RO] = 0x73,
255e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HIRAGANA] = 0x70,
256e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HENKAN] = 0x79,
257e9346441SOGAWA Hirofumi     [Q_KEY_CODE_YEN] = 0x7d,
2588c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_COMMA] = 0x7e,
259f94f5d71Spbrook };
2608c10e0baSHervé Poussineau 
2618c10e0baSHervé Poussineau static const uint16_t qcode_to_keycode_set2[Q_KEY_CODE__MAX] = {
2628c10e0baSHervé Poussineau     [0 ... Q_KEY_CODE__MAX - 1] = 0,
2638c10e0baSHervé Poussineau 
2648c10e0baSHervé Poussineau     [Q_KEY_CODE_A] = 0x1c,
2658c10e0baSHervé Poussineau     [Q_KEY_CODE_B] = 0x32,
2668c10e0baSHervé Poussineau     [Q_KEY_CODE_C] = 0x21,
2678c10e0baSHervé Poussineau     [Q_KEY_CODE_D] = 0x23,
2688c10e0baSHervé Poussineau     [Q_KEY_CODE_E] = 0x24,
2698c10e0baSHervé Poussineau     [Q_KEY_CODE_F] = 0x2b,
2708c10e0baSHervé Poussineau     [Q_KEY_CODE_G] = 0x34,
2718c10e0baSHervé Poussineau     [Q_KEY_CODE_H] = 0x33,
2728c10e0baSHervé Poussineau     [Q_KEY_CODE_I] = 0x43,
2738c10e0baSHervé Poussineau     [Q_KEY_CODE_J] = 0x3b,
2748c10e0baSHervé Poussineau     [Q_KEY_CODE_K] = 0x42,
2758c10e0baSHervé Poussineau     [Q_KEY_CODE_L] = 0x4b,
2768c10e0baSHervé Poussineau     [Q_KEY_CODE_M] = 0x3a,
2778c10e0baSHervé Poussineau     [Q_KEY_CODE_N] = 0x31,
2788c10e0baSHervé Poussineau     [Q_KEY_CODE_O] = 0x44,
2798c10e0baSHervé Poussineau     [Q_KEY_CODE_P] = 0x4d,
2808c10e0baSHervé Poussineau     [Q_KEY_CODE_Q] = 0x15,
2818c10e0baSHervé Poussineau     [Q_KEY_CODE_R] = 0x2d,
2828c10e0baSHervé Poussineau     [Q_KEY_CODE_S] = 0x1b,
2838c10e0baSHervé Poussineau     [Q_KEY_CODE_T] = 0x2c,
2848c10e0baSHervé Poussineau     [Q_KEY_CODE_U] = 0x3c,
2858c10e0baSHervé Poussineau     [Q_KEY_CODE_V] = 0x2a,
2868c10e0baSHervé Poussineau     [Q_KEY_CODE_W] = 0x1d,
2878c10e0baSHervé Poussineau     [Q_KEY_CODE_X] = 0x22,
2888c10e0baSHervé Poussineau     [Q_KEY_CODE_Y] = 0x35,
2898c10e0baSHervé Poussineau     [Q_KEY_CODE_Z] = 0x1a,
2908c10e0baSHervé Poussineau     [Q_KEY_CODE_0] = 0x45,
2918c10e0baSHervé Poussineau     [Q_KEY_CODE_1] = 0x16,
2928c10e0baSHervé Poussineau     [Q_KEY_CODE_2] = 0x1e,
2938c10e0baSHervé Poussineau     [Q_KEY_CODE_3] = 0x26,
2948c10e0baSHervé Poussineau     [Q_KEY_CODE_4] = 0x25,
2958c10e0baSHervé Poussineau     [Q_KEY_CODE_5] = 0x2e,
2968c10e0baSHervé Poussineau     [Q_KEY_CODE_6] = 0x36,
2978c10e0baSHervé Poussineau     [Q_KEY_CODE_7] = 0x3d,
2988c10e0baSHervé Poussineau     [Q_KEY_CODE_8] = 0x3e,
2998c10e0baSHervé Poussineau     [Q_KEY_CODE_9] = 0x46,
3008c10e0baSHervé Poussineau     [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e,
3018c10e0baSHervé Poussineau     [Q_KEY_CODE_MINUS] = 0x4e,
3028c10e0baSHervé Poussineau     [Q_KEY_CODE_EQUAL] = 0x55,
3038c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSLASH] = 0x5d,
3048c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSPACE] = 0x66,
3058c10e0baSHervé Poussineau     [Q_KEY_CODE_SPC] = 0x29,
3068c10e0baSHervé Poussineau     [Q_KEY_CODE_TAB] = 0x0d,
3078c10e0baSHervé Poussineau     [Q_KEY_CODE_CAPS_LOCK] = 0x58,
3088c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT] = 0x12,
3098c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL] = 0x14,
3108c10e0baSHervé Poussineau     [Q_KEY_CODE_META_L] = 0xe01f,
3118c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT] = 0x11,
3128c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT_R] = 0x59,
3138c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL_R] = 0xe014,
3148c10e0baSHervé Poussineau     [Q_KEY_CODE_META_R] = 0xe027,
3158c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT_R] = 0xe011,
3168c10e0baSHervé Poussineau     [Q_KEY_CODE_MENU] = 0xe02f,
3178c10e0baSHervé Poussineau     [Q_KEY_CODE_RET] = 0x5a,
3188c10e0baSHervé Poussineau     [Q_KEY_CODE_ESC] = 0x76,
3198c10e0baSHervé Poussineau     [Q_KEY_CODE_F1] = 0x05,
3208c10e0baSHervé Poussineau     [Q_KEY_CODE_F2] = 0x06,
3218c10e0baSHervé Poussineau     [Q_KEY_CODE_F3] = 0x04,
3228c10e0baSHervé Poussineau     [Q_KEY_CODE_F4] = 0x0c,
3238c10e0baSHervé Poussineau     [Q_KEY_CODE_F5] = 0x03,
3248c10e0baSHervé Poussineau     [Q_KEY_CODE_F6] = 0x0b,
3258c10e0baSHervé Poussineau     [Q_KEY_CODE_F7] = 0x83,
3268c10e0baSHervé Poussineau     [Q_KEY_CODE_F8] = 0x0a,
3278c10e0baSHervé Poussineau     [Q_KEY_CODE_F9] = 0x01,
3288c10e0baSHervé Poussineau     [Q_KEY_CODE_F10] = 0x09,
3298c10e0baSHervé Poussineau     [Q_KEY_CODE_F11] = 0x78,
3308c10e0baSHervé Poussineau     [Q_KEY_CODE_F12] = 0x07,
3318c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PRINT */
3328c10e0baSHervé Poussineau     [Q_KEY_CODE_SCROLL_LOCK] = 0x7e,
3338c10e0baSHervé Poussineau     /* special handling for Q_KEY_CODE_PAUSE */
3348c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_LEFT] = 0x54,
3358c10e0baSHervé Poussineau     [Q_KEY_CODE_INSERT] = 0xe070,
3368c10e0baSHervé Poussineau     [Q_KEY_CODE_HOME] = 0xe06c,
3378c10e0baSHervé Poussineau     [Q_KEY_CODE_PGUP] = 0xe07d,
3388c10e0baSHervé Poussineau     [Q_KEY_CODE_DELETE] = 0xe071,
3398c10e0baSHervé Poussineau     [Q_KEY_CODE_END] = 0xe069,
3408c10e0baSHervé Poussineau     [Q_KEY_CODE_PGDN] = 0xe07a,
3418c10e0baSHervé Poussineau     [Q_KEY_CODE_UP] = 0xe075,
3428c10e0baSHervé Poussineau     [Q_KEY_CODE_LEFT] = 0xe06b,
3438c10e0baSHervé Poussineau     [Q_KEY_CODE_DOWN] = 0xe072,
3448c10e0baSHervé Poussineau     [Q_KEY_CODE_RIGHT] = 0xe074,
3458c10e0baSHervé Poussineau     [Q_KEY_CODE_NUM_LOCK] = 0x77,
3468c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DIVIDE] = 0xe04a,
3478c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_MULTIPLY] = 0x7c,
3488c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_SUBTRACT] = 0x7b,
3498c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ADD] = 0x79,
3508c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ENTER] = 0xe05a,
3518c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DECIMAL] = 0x71,
3528c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_0] = 0x70,
3538c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_1] = 0x69,
3548c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_2] = 0x72,
3558c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_3] = 0x7a,
3568c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_4] = 0x6b,
3578c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_5] = 0x73,
3588c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_6] = 0x74,
3598c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_7] = 0x6c,
3608c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_8] = 0x75,
3618c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_9] = 0x7d,
3628c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b,
3638c10e0baSHervé Poussineau     [Q_KEY_CODE_SEMICOLON] = 0x4c,
3648c10e0baSHervé Poussineau     [Q_KEY_CODE_APOSTROPHE] = 0x52,
3658c10e0baSHervé Poussineau     [Q_KEY_CODE_COMMA] = 0x41,
3668c10e0baSHervé Poussineau     [Q_KEY_CODE_DOT] = 0x49,
3678c10e0baSHervé Poussineau     [Q_KEY_CODE_SLASH] = 0x4a,
3688c10e0baSHervé Poussineau 
3698c10e0baSHervé Poussineau #if 0
3708c10e0baSHervé Poussineau     [Q_KEY_CODE_POWER] = 0x0e37,
3718c10e0baSHervé Poussineau     [Q_KEY_CODE_SLEEP] = 0x0e3f,
3728c10e0baSHervé Poussineau     [Q_KEY_CODE_WAKE] = 0x0e5e,
3738c10e0baSHervé Poussineau 
3748c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIONEXT] = 0xe04d,
3758c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPREV] = 0xe015,
3768c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOSTOP] = 0xe03b,
3778c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOPLAY] = 0xe034,
3788c10e0baSHervé Poussineau     [Q_KEY_CODE_AUDIOMUTE] = 0xe023,
3798c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEUP] = 0xe032,
3808c10e0baSHervé Poussineau     [Q_KEY_CODE_VOLUMEDOWN] = 0xe021,
3818c10e0baSHervé Poussineau     [Q_KEY_CODE_MEDIASELECT] = 0xe050,
3828c10e0baSHervé Poussineau     [Q_KEY_CODE_MAIL] = 0xe048,
3838c10e0baSHervé Poussineau     [Q_KEY_CODE_CALCULATOR] = 0xe02b,
3848c10e0baSHervé Poussineau     [Q_KEY_CODE_COMPUTER] = 0xe040,
3858c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_SEARCH] = 0xe010,
3868c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_HOME] = 0xe03a,
3878c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BACK] = 0xe038,
3888c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_FORWARD] = 0xe030,
3898c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_STOP] = 0xe028,
3908c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_REFRESH] = 0xe020,
3918c10e0baSHervé Poussineau     [Q_KEY_CODE_AC_BOOKMARKS] = 0xe018,
3928c10e0baSHervé Poussineau #endif
3938c10e0baSHervé Poussineau 
3948c10e0baSHervé Poussineau     [Q_KEY_CODE_ALTGR] = 0x08,
3958c10e0baSHervé Poussineau     [Q_KEY_CODE_ALTGR_R] = 0xe008,
3968c10e0baSHervé Poussineau     [Q_KEY_CODE_ASTERISK] = 0x7c,
3978c10e0baSHervé Poussineau     [Q_KEY_CODE_LESS] = 0x61,
3988c10e0baSHervé Poussineau     [Q_KEY_CODE_SYSRQ] = 0x7f,
3998c10e0baSHervé Poussineau     [Q_KEY_CODE_RO] = 0x51,
400e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HIRAGANA] = 0x13,
401e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HENKAN] = 0x64,
402e9346441SOGAWA Hirofumi     [Q_KEY_CODE_YEN] = 0x6a,
4038c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_COMMA] = 0x6d,
4048c10e0baSHervé Poussineau };
4058c10e0baSHervé Poussineau 
4068c10e0baSHervé Poussineau static const uint16_t qcode_to_keycode_set3[Q_KEY_CODE__MAX] = {
4078c10e0baSHervé Poussineau     [0 ... Q_KEY_CODE__MAX - 1] = 0,
4088c10e0baSHervé Poussineau 
4098c10e0baSHervé Poussineau     [Q_KEY_CODE_A] = 0x1c,
4108c10e0baSHervé Poussineau     [Q_KEY_CODE_B] = 0x32,
4118c10e0baSHervé Poussineau     [Q_KEY_CODE_C] = 0x21,
4128c10e0baSHervé Poussineau     [Q_KEY_CODE_D] = 0x23,
4138c10e0baSHervé Poussineau     [Q_KEY_CODE_E] = 0x24,
4148c10e0baSHervé Poussineau     [Q_KEY_CODE_F] = 0x2b,
4158c10e0baSHervé Poussineau     [Q_KEY_CODE_G] = 0x34,
4168c10e0baSHervé Poussineau     [Q_KEY_CODE_H] = 0x33,
4178c10e0baSHervé Poussineau     [Q_KEY_CODE_I] = 0x43,
4188c10e0baSHervé Poussineau     [Q_KEY_CODE_J] = 0x3b,
4198c10e0baSHervé Poussineau     [Q_KEY_CODE_K] = 0x42,
4208c10e0baSHervé Poussineau     [Q_KEY_CODE_L] = 0x4b,
4218c10e0baSHervé Poussineau     [Q_KEY_CODE_M] = 0x3a,
4228c10e0baSHervé Poussineau     [Q_KEY_CODE_N] = 0x31,
4238c10e0baSHervé Poussineau     [Q_KEY_CODE_O] = 0x44,
4248c10e0baSHervé Poussineau     [Q_KEY_CODE_P] = 0x4d,
4258c10e0baSHervé Poussineau     [Q_KEY_CODE_Q] = 0x15,
4268c10e0baSHervé Poussineau     [Q_KEY_CODE_R] = 0x2d,
4278c10e0baSHervé Poussineau     [Q_KEY_CODE_S] = 0x1b,
4288c10e0baSHervé Poussineau     [Q_KEY_CODE_T] = 0x2c,
4298c10e0baSHervé Poussineau     [Q_KEY_CODE_U] = 0x3c,
4308c10e0baSHervé Poussineau     [Q_KEY_CODE_V] = 0x2a,
4318c10e0baSHervé Poussineau     [Q_KEY_CODE_W] = 0x1d,
4328c10e0baSHervé Poussineau     [Q_KEY_CODE_X] = 0x22,
4338c10e0baSHervé Poussineau     [Q_KEY_CODE_Y] = 0x35,
4348c10e0baSHervé Poussineau     [Q_KEY_CODE_Z] = 0x1a,
4358c10e0baSHervé Poussineau     [Q_KEY_CODE_0] = 0x45,
4368c10e0baSHervé Poussineau     [Q_KEY_CODE_1] = 0x16,
4378c10e0baSHervé Poussineau     [Q_KEY_CODE_2] = 0x1e,
4388c10e0baSHervé Poussineau     [Q_KEY_CODE_3] = 0x26,
4398c10e0baSHervé Poussineau     [Q_KEY_CODE_4] = 0x25,
4408c10e0baSHervé Poussineau     [Q_KEY_CODE_5] = 0x2e,
4418c10e0baSHervé Poussineau     [Q_KEY_CODE_6] = 0x36,
4428c10e0baSHervé Poussineau     [Q_KEY_CODE_7] = 0x3d,
4438c10e0baSHervé Poussineau     [Q_KEY_CODE_8] = 0x3e,
4448c10e0baSHervé Poussineau     [Q_KEY_CODE_9] = 0x46,
4458c10e0baSHervé Poussineau     [Q_KEY_CODE_GRAVE_ACCENT] = 0x0e,
4468c10e0baSHervé Poussineau     [Q_KEY_CODE_MINUS] = 0x4e,
4478c10e0baSHervé Poussineau     [Q_KEY_CODE_EQUAL] = 0x55,
4488c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSLASH] = 0x5c,
4498c10e0baSHervé Poussineau     [Q_KEY_CODE_BACKSPACE] = 0x66,
4508c10e0baSHervé Poussineau     [Q_KEY_CODE_SPC] = 0x29,
4518c10e0baSHervé Poussineau     [Q_KEY_CODE_TAB] = 0x0d,
4528c10e0baSHervé Poussineau     [Q_KEY_CODE_CAPS_LOCK] = 0x14,
4538c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT] = 0x12,
4548c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL] = 0x11,
4558c10e0baSHervé Poussineau     [Q_KEY_CODE_META_L] = 0x8b,
4568c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT] = 0x19,
4578c10e0baSHervé Poussineau     [Q_KEY_CODE_SHIFT_R] = 0x59,
4588c10e0baSHervé Poussineau     [Q_KEY_CODE_CTRL_R] = 0x58,
4598c10e0baSHervé Poussineau     [Q_KEY_CODE_META_R] = 0x8c,
4608c10e0baSHervé Poussineau     [Q_KEY_CODE_ALT_R] = 0x39,
4618c10e0baSHervé Poussineau     [Q_KEY_CODE_MENU] = 0x8d,
4628c10e0baSHervé Poussineau     [Q_KEY_CODE_RET] = 0x5a,
4638c10e0baSHervé Poussineau     [Q_KEY_CODE_ESC] = 0x08,
4648c10e0baSHervé Poussineau     [Q_KEY_CODE_F1] = 0x07,
4658c10e0baSHervé Poussineau     [Q_KEY_CODE_F2] = 0x0f,
4668c10e0baSHervé Poussineau     [Q_KEY_CODE_F3] = 0x17,
4678c10e0baSHervé Poussineau     [Q_KEY_CODE_F4] = 0x1f,
4688c10e0baSHervé Poussineau     [Q_KEY_CODE_F5] = 0x27,
4698c10e0baSHervé Poussineau     [Q_KEY_CODE_F6] = 0x2f,
4708c10e0baSHervé Poussineau     [Q_KEY_CODE_F7] = 0x37,
4718c10e0baSHervé Poussineau     [Q_KEY_CODE_F8] = 0x3f,
4728c10e0baSHervé Poussineau     [Q_KEY_CODE_F9] = 0x47,
4738c10e0baSHervé Poussineau     [Q_KEY_CODE_F10] = 0x4f,
4748c10e0baSHervé Poussineau     [Q_KEY_CODE_F11] = 0x56,
4758c10e0baSHervé Poussineau     [Q_KEY_CODE_F12] = 0x5e,
4768c10e0baSHervé Poussineau     [Q_KEY_CODE_PRINT] = 0x57,
4778c10e0baSHervé Poussineau     [Q_KEY_CODE_SCROLL_LOCK] = 0x5f,
4788c10e0baSHervé Poussineau     [Q_KEY_CODE_PAUSE] = 0x62,
4798c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_LEFT] = 0x54,
4808c10e0baSHervé Poussineau     [Q_KEY_CODE_INSERT] = 0x67,
4818c10e0baSHervé Poussineau     [Q_KEY_CODE_HOME] = 0x6e,
4828c10e0baSHervé Poussineau     [Q_KEY_CODE_PGUP] = 0x6f,
4838c10e0baSHervé Poussineau     [Q_KEY_CODE_DELETE] = 0x64,
4848c10e0baSHervé Poussineau     [Q_KEY_CODE_END] = 0x65,
4858c10e0baSHervé Poussineau     [Q_KEY_CODE_PGDN] = 0x6d,
4868c10e0baSHervé Poussineau     [Q_KEY_CODE_UP] = 0x63,
4878c10e0baSHervé Poussineau     [Q_KEY_CODE_LEFT] = 0x61,
4888c10e0baSHervé Poussineau     [Q_KEY_CODE_DOWN] = 0x60,
4898c10e0baSHervé Poussineau     [Q_KEY_CODE_RIGHT] = 0x6a,
4908c10e0baSHervé Poussineau     [Q_KEY_CODE_NUM_LOCK] = 0x76,
4918c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DIVIDE] = 0x4a,
4928c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_MULTIPLY] = 0x7e,
4938c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_SUBTRACT] = 0x4e,
4948c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ADD] = 0x7c,
4958c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_ENTER] = 0x79,
4968c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_DECIMAL] = 0x71,
4978c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_0] = 0x70,
4988c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_1] = 0x69,
4998c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_2] = 0x72,
5008c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_3] = 0x7a,
5018c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_4] = 0x6b,
5028c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_5] = 0x73,
5038c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_6] = 0x74,
5048c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_7] = 0x6c,
5058c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_8] = 0x75,
5068c10e0baSHervé Poussineau     [Q_KEY_CODE_KP_9] = 0x7d,
5078c10e0baSHervé Poussineau     [Q_KEY_CODE_BRACKET_RIGHT] = 0x5b,
5088c10e0baSHervé Poussineau     [Q_KEY_CODE_SEMICOLON] = 0x4c,
5098c10e0baSHervé Poussineau     [Q_KEY_CODE_APOSTROPHE] = 0x52,
5108c10e0baSHervé Poussineau     [Q_KEY_CODE_COMMA] = 0x41,
5118c10e0baSHervé Poussineau     [Q_KEY_CODE_DOT] = 0x49,
5128c10e0baSHervé Poussineau     [Q_KEY_CODE_SLASH] = 0x4a,
513e9346441SOGAWA Hirofumi 
514e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HIRAGANA] = 0x87,
515e9346441SOGAWA Hirofumi     [Q_KEY_CODE_HENKAN] = 0x86,
516e9346441SOGAWA Hirofumi     [Q_KEY_CODE_YEN] = 0x5d,
5177096a96dSRoy Tam };
518f94f5d71Spbrook 
51957d5c005SHervé Poussineau static uint8_t translate_table[256] = {
52057d5c005SHervé Poussineau     0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
52157d5c005SHervé Poussineau     0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
52257d5c005SHervé Poussineau     0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
52357d5c005SHervé Poussineau     0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
52457d5c005SHervé Poussineau     0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
52557d5c005SHervé Poussineau     0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
52657d5c005SHervé Poussineau     0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
52757d5c005SHervé Poussineau     0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
52857d5c005SHervé Poussineau     0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
52957d5c005SHervé Poussineau     0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
53057d5c005SHervé Poussineau     0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
53157d5c005SHervé Poussineau     0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
53257d5c005SHervé Poussineau     0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
53357d5c005SHervé Poussineau     0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
53457d5c005SHervé Poussineau     0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
53557d5c005SHervé Poussineau     0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
53657d5c005SHervé Poussineau     0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
53757d5c005SHervé Poussineau     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
53857d5c005SHervé Poussineau     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
53957d5c005SHervé Poussineau     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
54057d5c005SHervé Poussineau     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
54157d5c005SHervé Poussineau     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
54257d5c005SHervé Poussineau     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
54357d5c005SHervé Poussineau     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
54457d5c005SHervé Poussineau     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
54557d5c005SHervé Poussineau     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
54657d5c005SHervé Poussineau     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
54757d5c005SHervé Poussineau     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
54857d5c005SHervé Poussineau     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
54957d5c005SHervé Poussineau     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
55057d5c005SHervé Poussineau     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
55157d5c005SHervé Poussineau     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
55257d5c005SHervé Poussineau };
55357d5c005SHervé Poussineau 
554*954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s)
555*954ee55bSGerd Hoffmann {
556*954ee55bSGerd Hoffmann     PS2Queue *q = &s->queue;
557*954ee55bSGerd Hoffmann 
558*954ee55bSGerd Hoffmann     q->rptr = 0;
559*954ee55bSGerd Hoffmann     q->wptr = 0;
560*954ee55bSGerd Hoffmann     q->count = 0;
561*954ee55bSGerd Hoffmann }
562*954ee55bSGerd Hoffmann 
5638498bb8dSGerd Hoffmann void ps2_queue(PS2State *s, int b)
5640e43e99cSbellard {
5650e43e99cSbellard     PS2Queue *q = &s->queue;
5660e43e99cSbellard 
5672858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
5680e43e99cSbellard         return;
5690e43e99cSbellard     q->data[q->wptr] = b;
5700e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
5710e43e99cSbellard         q->wptr = 0;
5720e43e99cSbellard     q->count++;
5730e43e99cSbellard     s->update_irq(s->update_arg, 1);
5740e43e99cSbellard }
5750e43e99cSbellard 
57657d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */
5770e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
5780e43e99cSbellard {
579f94f5d71Spbrook     PS2KbdState *s = opaque;
580e7d93956Saurel32 
5815edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
582fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
58357d5c005SHervé Poussineau 
58457d5c005SHervé Poussineau     if (s->translate) {
58557d5c005SHervé Poussineau         if (keycode == 0xf0) {
58657d5c005SHervé Poussineau             s->need_high_bit = true;
58757d5c005SHervé Poussineau         } else if (s->need_high_bit) {
58857d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode] | 0x80);
58957d5c005SHervé Poussineau             s->need_high_bit = false;
59057d5c005SHervé Poussineau         } else {
59157d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode]);
5927096a96dSRoy Tam         }
59357d5c005SHervé Poussineau     } else {
5940e43e99cSbellard         ps2_queue(&s->common, keycode);
5950e43e99cSbellard     }
59657d5c005SHervé Poussineau }
5970e43e99cSbellard 
59866e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
59966e6536eSGerd Hoffmann                                InputEvent *evt)
60066e6536eSGerd Hoffmann {
60166e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
60232bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
6038c10e0baSHervé Poussineau     int qcode;
6048c10e0baSHervé Poussineau     uint16_t keycode;
60566e6536eSGerd Hoffmann 
60666e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
6078c10e0baSHervé Poussineau     assert(evt->type == INPUT_EVENT_KIND_KEY);
6088c10e0baSHervé Poussineau     qcode = qemu_input_key_value_to_qcode(key->key);
60957d5c005SHervé Poussineau 
6108c10e0baSHervé Poussineau     if (s->scancode_set == 1) {
6118c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
6128c10e0baSHervé Poussineau             if (key->down) {
6138c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe1);
6148c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x1d);
6158c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x45);
6168c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x91);
6178c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x9d);
6188c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xc5);
6198c10e0baSHervé Poussineau             }
6208c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
6218c10e0baSHervé Poussineau             if (key->down) {
6228c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6238c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x2a);
6248c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6258c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x37);
6268c10e0baSHervé Poussineau             } else {
6278c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6288c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xb7);
6298c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6308c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xaa);
6318c10e0baSHervé Poussineau             }
6328c10e0baSHervé Poussineau         } else {
6338c10e0baSHervé Poussineau             keycode = qcode_to_keycode_set1[qcode];
6348c10e0baSHervé Poussineau             if (keycode) {
6358c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
6368c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
6378c10e0baSHervé Poussineau                 }
6388c10e0baSHervé Poussineau                 if (!key->down) {
6398c10e0baSHervé Poussineau                     keycode |= 0x80;
6408c10e0baSHervé Poussineau                 }
6418c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
6428c10e0baSHervé Poussineau             } else {
643ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
644ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
6458c10e0baSHervé Poussineau             }
6468c10e0baSHervé Poussineau         }
6478c10e0baSHervé Poussineau     } else if (s->scancode_set == 2) {
6488c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
6498c10e0baSHervé Poussineau             if (key->down) {
6508c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe1);
6518c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x14);
6528c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x77);
6538c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe1);
6548c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
6558c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x14);
6568c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
6578c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x77);
6588c10e0baSHervé Poussineau             }
6598c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
6608c10e0baSHervé Poussineau             if (key->down) {
6618c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6628c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x12);
6638c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6648c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x7c);
6658c10e0baSHervé Poussineau             } else {
6668c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6678c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
6688c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x7c);
6698c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xe0);
6708c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
6718c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0x12);
6728c10e0baSHervé Poussineau             }
6738c10e0baSHervé Poussineau         } else {
6748c10e0baSHervé Poussineau             keycode = qcode_to_keycode_set2[qcode];
6758c10e0baSHervé Poussineau             if (keycode) {
6768c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
6778c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
6788c10e0baSHervé Poussineau                 }
6798c10e0baSHervé Poussineau                 if (!key->down) {
6808c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
6818c10e0baSHervé Poussineau                 }
6828c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
68357d5c005SHervé Poussineau             } else {
684ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
685ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
68657d5c005SHervé Poussineau             }
68757d5c005SHervé Poussineau         }
68857d5c005SHervé Poussineau     } else if (s->scancode_set == 3) {
6898c10e0baSHervé Poussineau         keycode = qcode_to_keycode_set3[qcode];
6908c10e0baSHervé Poussineau         if (keycode) {
6918c10e0baSHervé Poussineau             /* FIXME: break code should be configured on a key by key basis */
6928c10e0baSHervé Poussineau             if (!key->down) {
6938c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
69457d5c005SHervé Poussineau             }
69557d5c005SHervé Poussineau             ps2_put_keycode(s, keycode);
6968c10e0baSHervé Poussineau         } else {
697ec044a80SHervé Poussineau             qemu_log_mask(LOG_UNIMP,
698ec044a80SHervé Poussineau                           "ps2: ignoring key with qcode %d\n", qcode);
6998c10e0baSHervé Poussineau         }
70066e6536eSGerd Hoffmann     }
70166e6536eSGerd Hoffmann }
70266e6536eSGerd Hoffmann 
7038498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s)
7040e43e99cSbellard {
7050e43e99cSbellard     PS2Queue *q;
7060e43e99cSbellard     int val, index;
7070e43e99cSbellard 
7088498bb8dSGerd Hoffmann     trace_ps2_read_data(s);
7090e43e99cSbellard     q = &s->queue;
7100e43e99cSbellard     if (q->count == 0) {
7110e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
7120e43e99cSbellard            (needed for EMM386) */
7130e43e99cSbellard         /* XXX: need a timer to do things correctly */
7140e43e99cSbellard         index = q->rptr - 1;
7150e43e99cSbellard         if (index < 0)
7160e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
7170e43e99cSbellard         val = q->data[index];
7180e43e99cSbellard     } else {
7190e43e99cSbellard         val = q->data[q->rptr];
7200e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
7210e43e99cSbellard             q->rptr = 0;
7220e43e99cSbellard         q->count--;
7230e43e99cSbellard         /* reading deasserts IRQ */
7240e43e99cSbellard         s->update_irq(s->update_arg, 0);
7250e43e99cSbellard         /* reassert IRQs if data left */
7260e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
7270e43e99cSbellard     }
7280e43e99cSbellard     return val;
7290e43e99cSbellard }
7300e43e99cSbellard 
7317f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
7327f540ab5SChristophe Fergeau {
7335edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
7347f540ab5SChristophe Fergeau     s->ledstate = ledstate;
7357f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
7367f540ab5SChristophe Fergeau }
7377f540ab5SChristophe Fergeau 
7380e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
7390e43e99cSbellard {
7405edab03dSDon Koch     trace_ps2_reset_keyboard(s);
7410e43e99cSbellard     s->scan_enabled = 1;
742e7d93956Saurel32     s->scancode_set = 2;
7437f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
7440e43e99cSbellard }
7450e43e99cSbellard 
7460e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
7470e43e99cSbellard {
7480e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
7490e43e99cSbellard 
7505edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
7510e43e99cSbellard     switch(s->common.write_cmd) {
7520e43e99cSbellard     default:
7530e43e99cSbellard     case -1:
7540e43e99cSbellard         switch(val) {
7550e43e99cSbellard         case 0x00:
7560e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
7570e43e99cSbellard             break;
7580e43e99cSbellard         case 0x05:
7590e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
7600e43e99cSbellard             break;
7610e43e99cSbellard         case KBD_CMD_GET_ID:
7620e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
763e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
76435c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
76535c4d671Saurel32             if (s->translate)
76635c4d671Saurel32                 ps2_queue(&s->common, 0x41);
76735c4d671Saurel32             else
76835c4d671Saurel32                 ps2_queue(&s->common, 0x83);
7690e43e99cSbellard             break;
7700e43e99cSbellard         case KBD_CMD_ECHO:
7710e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
7720e43e99cSbellard             break;
7730e43e99cSbellard         case KBD_CMD_ENABLE:
7740e43e99cSbellard             s->scan_enabled = 1;
7750e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
7760e43e99cSbellard             break;
777e7d93956Saurel32         case KBD_CMD_SCANCODE:
7780e43e99cSbellard         case KBD_CMD_SET_LEDS:
7790e43e99cSbellard         case KBD_CMD_SET_RATE:
7800e43e99cSbellard             s->common.write_cmd = val;
7810e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
7820e43e99cSbellard             break;
7830e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
7840e43e99cSbellard             ps2_reset_keyboard(s);
7850e43e99cSbellard             s->scan_enabled = 0;
7860e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
7870e43e99cSbellard             break;
7880e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
7890e43e99cSbellard             ps2_reset_keyboard(s);
7900e43e99cSbellard             s->scan_enabled = 1;
7910e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
7920e43e99cSbellard             break;
7930e43e99cSbellard         case KBD_CMD_RESET:
7940e43e99cSbellard             ps2_reset_keyboard(s);
7950e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
7960e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
7970e43e99cSbellard             break;
7980e43e99cSbellard         default:
79906b3611fSHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
8000e43e99cSbellard             break;
8010e43e99cSbellard         }
8020e43e99cSbellard         break;
803e7d93956Saurel32     case KBD_CMD_SCANCODE:
804e7d93956Saurel32         if (val == 0) {
8054df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_ACK);
80657d5c005SHervé Poussineau             ps2_put_keycode(s, s->scancode_set);
8074df23b64SHervé Poussineau         } else if (val >= 1 && val <= 3) {
808e7d93956Saurel32             s->scancode_set = val;
809e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
8104df23b64SHervé Poussineau         } else {
8114df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
812e7d93956Saurel32         }
813e7d93956Saurel32         s->common.write_cmd = -1;
814e7d93956Saurel32         break;
8150e43e99cSbellard     case KBD_CMD_SET_LEDS:
8167f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
8170e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
8180e43e99cSbellard         s->common.write_cmd = -1;
8190e43e99cSbellard         break;
8200e43e99cSbellard     case KBD_CMD_SET_RATE:
8210e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
8220e43e99cSbellard         s->common.write_cmd = -1;
8230e43e99cSbellard         break;
8240e43e99cSbellard     }
8250e43e99cSbellard }
8260e43e99cSbellard 
827f94f5d71Spbrook /* Set the scancode translation mode.
828f94f5d71Spbrook    0 = raw scancodes.
829f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
830f94f5d71Spbrook 
831f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
832f94f5d71Spbrook {
833f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
8345edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
835f94f5d71Spbrook     s->translate = mode;
836f94f5d71Spbrook }
837f94f5d71Spbrook 
8380e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
8390e43e99cSbellard {
8400e43e99cSbellard     unsigned int b;
8410e43e99cSbellard     int dx1, dy1, dz1;
8420e43e99cSbellard 
8430e43e99cSbellard     dx1 = s->mouse_dx;
8440e43e99cSbellard     dy1 = s->mouse_dy;
8450e43e99cSbellard     dz1 = s->mouse_dz;
8460e43e99cSbellard     /* XXX: increase range to 8 bits ? */
8470e43e99cSbellard     if (dx1 > 127)
8480e43e99cSbellard         dx1 = 127;
8490e43e99cSbellard     else if (dx1 < -127)
8500e43e99cSbellard         dx1 = -127;
8510e43e99cSbellard     if (dy1 > 127)
8520e43e99cSbellard         dy1 = 127;
8530e43e99cSbellard     else if (dy1 < -127)
8540e43e99cSbellard         dy1 = -127;
8550e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
8560e43e99cSbellard     ps2_queue(&s->common, b);
8570e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
8580e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
8590e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
8600e43e99cSbellard     switch(s->mouse_type) {
8610e43e99cSbellard     default:
8620e43e99cSbellard         break;
8630e43e99cSbellard     case 3:
8640e43e99cSbellard         if (dz1 > 127)
8650e43e99cSbellard             dz1 = 127;
8660e43e99cSbellard         else if (dz1 < -127)
8670e43e99cSbellard                 dz1 = -127;
8680e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
8690e43e99cSbellard         break;
8700e43e99cSbellard     case 4:
8710e43e99cSbellard         if (dz1 > 7)
8720e43e99cSbellard             dz1 = 7;
8730e43e99cSbellard         else if (dz1 < -7)
8740e43e99cSbellard             dz1 = -7;
8750e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
8760e43e99cSbellard         ps2_queue(&s->common, b);
8770e43e99cSbellard         break;
8780e43e99cSbellard     }
8790e43e99cSbellard 
8805edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
8810e43e99cSbellard     /* update deltas */
8820e43e99cSbellard     s->mouse_dx -= dx1;
8830e43e99cSbellard     s->mouse_dy -= dy1;
8840e43e99cSbellard     s->mouse_dz -= dz1;
8850e43e99cSbellard }
8860e43e99cSbellard 
8872a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
8882a766d29SGerd Hoffmann                             InputEvent *evt)
8890e43e99cSbellard {
8907fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
8918b0caab0SFabian Lesniak         [INPUT_BUTTON_LEFT]   = PS2_MOUSE_BUTTON_LEFT,
8928b0caab0SFabian Lesniak         [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
8938b0caab0SFabian Lesniak         [INPUT_BUTTON_RIGHT]  = PS2_MOUSE_BUTTON_RIGHT,
8948b0caab0SFabian Lesniak         [INPUT_BUTTON_SIDE]   = PS2_MOUSE_BUTTON_SIDE,
8958b0caab0SFabian Lesniak         [INPUT_BUTTON_EXTRA]  = PS2_MOUSE_BUTTON_EXTRA,
8962a766d29SGerd Hoffmann     };
8972a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
898b5a1b443SEric Blake     InputMoveEvent *move;
899b5a1b443SEric Blake     InputBtnEvent *btn;
9000e43e99cSbellard 
9010e43e99cSbellard     /* check if deltas are recorded when disabled */
9020e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
9030e43e99cSbellard         return;
9040e43e99cSbellard 
905568c73a4SEric Blake     switch (evt->type) {
9062a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
90732bafa8fSEric Blake         move = evt->u.rel.data;
908b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
909b5a1b443SEric Blake             s->mouse_dx += move->value;
910b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
911b5a1b443SEric Blake             s->mouse_dy -= move->value;
9122a766d29SGerd Hoffmann         }
9132a766d29SGerd Hoffmann         break;
9140e43e99cSbellard 
9152a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
91632bafa8fSEric Blake         btn = evt->u.btn.data;
917b5a1b443SEric Blake         if (btn->down) {
918b5a1b443SEric Blake             s->mouse_buttons |= bmap[btn->button];
919b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
9202a766d29SGerd Hoffmann                 s->mouse_dz--;
921b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
9222a766d29SGerd Hoffmann                 s->mouse_dz++;
9232a766d29SGerd Hoffmann             }
9242a766d29SGerd Hoffmann         } else {
925b5a1b443SEric Blake             s->mouse_buttons &= ~bmap[btn->button];
9262a766d29SGerd Hoffmann         }
9272a766d29SGerd Hoffmann         break;
9282a766d29SGerd Hoffmann 
9292a766d29SGerd Hoffmann     default:
9302a766d29SGerd Hoffmann         /* keep gcc happy */
9312a766d29SGerd Hoffmann         break;
9322a766d29SGerd Hoffmann     }
933fd214d18SGerd Hoffmann }
934fd214d18SGerd Hoffmann 
9352a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
9362a766d29SGerd Hoffmann {
9372a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
9382a766d29SGerd Hoffmann 
9392a766d29SGerd Hoffmann     if (s->mouse_buttons) {
9402a766d29SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
9412a766d29SGerd Hoffmann     }
9422858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
9432858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
9440e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
9450e43e99cSbellard                too big deltas */
9460e43e99cSbellard             ps2_mouse_send_packet(s);
9470e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
9480e43e99cSbellard                 break;
9490e43e99cSbellard         }
9500e43e99cSbellard     }
9510e43e99cSbellard }
9520e43e99cSbellard 
953548df2acSths void ps2_mouse_fake_event(void *opaque)
954548df2acSths {
9552a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
9565edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
9572a766d29SGerd Hoffmann     s->mouse_dx++;
9582a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
959548df2acSths }
960548df2acSths 
9610e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
9620e43e99cSbellard {
9630e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
9645edab03dSDon Koch 
9655edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
9660e43e99cSbellard #ifdef DEBUG_MOUSE
9670e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
9680e43e99cSbellard #endif
9690e43e99cSbellard     switch(s->common.write_cmd) {
9700e43e99cSbellard     default:
9710e43e99cSbellard     case -1:
9720e43e99cSbellard         /* mouse command */
9730e43e99cSbellard         if (s->mouse_wrap) {
9740e43e99cSbellard             if (val == AUX_RESET_WRAP) {
9750e43e99cSbellard                 s->mouse_wrap = 0;
9760e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
9770e43e99cSbellard                 return;
9780e43e99cSbellard             } else if (val != AUX_RESET) {
9790e43e99cSbellard                 ps2_queue(&s->common, val);
9800e43e99cSbellard                 return;
9810e43e99cSbellard             }
9820e43e99cSbellard         }
9830e43e99cSbellard         switch(val) {
9840e43e99cSbellard         case AUX_SET_SCALE11:
9850e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
9860e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9870e43e99cSbellard             break;
9880e43e99cSbellard         case AUX_SET_SCALE21:
9890e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
9900e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9910e43e99cSbellard             break;
9920e43e99cSbellard         case AUX_SET_STREAM:
9930e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
9940e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9950e43e99cSbellard             break;
9960e43e99cSbellard         case AUX_SET_WRAP:
9970e43e99cSbellard             s->mouse_wrap = 1;
9980e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9990e43e99cSbellard             break;
10000e43e99cSbellard         case AUX_SET_REMOTE:
10010e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
10020e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10030e43e99cSbellard             break;
10040e43e99cSbellard         case AUX_GET_TYPE:
10050e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10060e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
10070e43e99cSbellard             break;
10080e43e99cSbellard         case AUX_SET_RES:
10090e43e99cSbellard         case AUX_SET_SAMPLE:
10100e43e99cSbellard             s->common.write_cmd = val;
10110e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10120e43e99cSbellard             break;
10130e43e99cSbellard         case AUX_GET_SCALE:
10140e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10150e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
10160e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
10170e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
10180e43e99cSbellard             break;
10190e43e99cSbellard         case AUX_POLL:
10200e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10210e43e99cSbellard             ps2_mouse_send_packet(s);
10220e43e99cSbellard             break;
10230e43e99cSbellard         case AUX_ENABLE_DEV:
10240e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
10250e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10260e43e99cSbellard             break;
10270e43e99cSbellard         case AUX_DISABLE_DEV:
10280e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
10290e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10300e43e99cSbellard             break;
10310e43e99cSbellard         case AUX_SET_DEFAULT:
10320e43e99cSbellard             s->mouse_sample_rate = 100;
10330e43e99cSbellard             s->mouse_resolution = 2;
10340e43e99cSbellard             s->mouse_status = 0;
10350e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10360e43e99cSbellard             break;
10370e43e99cSbellard         case AUX_RESET:
10380e43e99cSbellard             s->mouse_sample_rate = 100;
10390e43e99cSbellard             s->mouse_resolution = 2;
10400e43e99cSbellard             s->mouse_status = 0;
10410e43e99cSbellard             s->mouse_type = 0;
10420e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
10430e43e99cSbellard             ps2_queue(&s->common, 0xaa);
10440e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
10450e43e99cSbellard             break;
10460e43e99cSbellard         default:
10470e43e99cSbellard             break;
10480e43e99cSbellard         }
10490e43e99cSbellard         break;
10500e43e99cSbellard     case AUX_SET_SAMPLE:
10510e43e99cSbellard         s->mouse_sample_rate = val;
10520e43e99cSbellard         /* detect IMPS/2 or IMEX */
10530e43e99cSbellard         switch(s->mouse_detect_state) {
10540e43e99cSbellard         default:
10550e43e99cSbellard         case 0:
10560e43e99cSbellard             if (val == 200)
10570e43e99cSbellard                 s->mouse_detect_state = 1;
10580e43e99cSbellard             break;
10590e43e99cSbellard         case 1:
10600e43e99cSbellard             if (val == 100)
10610e43e99cSbellard                 s->mouse_detect_state = 2;
10620e43e99cSbellard             else if (val == 200)
10630e43e99cSbellard                 s->mouse_detect_state = 3;
10640e43e99cSbellard             else
10650e43e99cSbellard                 s->mouse_detect_state = 0;
10660e43e99cSbellard             break;
10670e43e99cSbellard         case 2:
10680e43e99cSbellard             if (val == 80)
10690e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
10700e43e99cSbellard             s->mouse_detect_state = 0;
10710e43e99cSbellard             break;
10720e43e99cSbellard         case 3:
10730e43e99cSbellard             if (val == 80)
10740e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
10750e43e99cSbellard             s->mouse_detect_state = 0;
10760e43e99cSbellard             break;
10770e43e99cSbellard         }
10780e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
10790e43e99cSbellard         s->common.write_cmd = -1;
10800e43e99cSbellard         break;
10810e43e99cSbellard     case AUX_SET_RES:
10820e43e99cSbellard         s->mouse_resolution = val;
10830e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
10840e43e99cSbellard         s->common.write_cmd = -1;
10850e43e99cSbellard         break;
10860e43e99cSbellard     }
10870e43e99cSbellard }
10880e43e99cSbellard 
1089ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
10900e43e99cSbellard {
10910e43e99cSbellard     s->write_cmd = -1;
1092*954ee55bSGerd Hoffmann     ps2_reset_queue(s);
1093deeccef3Saliguori     s->update_irq(s->update_arg, 0);
10940e43e99cSbellard }
10950e43e99cSbellard 
10962858ab09SGonglei static void ps2_common_post_load(PS2State *s)
10972858ab09SGonglei {
10982858ab09SGonglei     PS2Queue *q = &s->queue;
10992858ab09SGonglei     int size;
11002858ab09SGonglei     int i;
11012858ab09SGonglei     int tmp_data[PS2_QUEUE_SIZE];
11022858ab09SGonglei 
11032858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
11042858ab09SGonglei     size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
11052858ab09SGonglei 
11062858ab09SGonglei     /* move the queue elements to the start of data array */
11072858ab09SGonglei     if (size > 0) {
11082858ab09SGonglei         for (i = 0; i < size; i++) {
11092858ab09SGonglei             /* move the queue elements to the temporary buffer */
11102858ab09SGonglei             tmp_data[i] = q->data[q->rptr];
11112858ab09SGonglei             if (++q->rptr == 256) {
11122858ab09SGonglei                 q->rptr = 0;
11132858ab09SGonglei             }
11142858ab09SGonglei         }
11152858ab09SGonglei         memcpy(q->data, tmp_data, size);
11162858ab09SGonglei     }
11172858ab09SGonglei     /* reset rptr/wptr/count */
11182858ab09SGonglei     q->rptr = 0;
11192858ab09SGonglei     q->wptr = size;
11202858ab09SGonglei     q->count = size;
11212858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
11222858ab09SGonglei }
11232858ab09SGonglei 
1124ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
1125ef74679aSDinesh Subhraveti {
1126ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
1127ef74679aSDinesh Subhraveti 
11285edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
1129ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
1130ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
1131ef74679aSDinesh Subhraveti     s->translate = 0;
1132089adafdSHervé Poussineau     s->scancode_set = 2;
1133ef74679aSDinesh Subhraveti }
1134ef74679aSDinesh Subhraveti 
1135ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
1136ef74679aSDinesh Subhraveti {
1137ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
1138ef74679aSDinesh Subhraveti 
11395edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
1140ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
1141ef74679aSDinesh Subhraveti     s->mouse_status = 0;
1142ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
1143ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
1144ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
1145ef74679aSDinesh Subhraveti     s->mouse_type = 0;
1146ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
1147ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
1148ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
1149ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
1150ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
1151ef74679aSDinesh Subhraveti }
1152ef74679aSDinesh Subhraveti 
1153b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
1154b31442c3SJuan Quintela     .name = "PS2 Common State",
1155b31442c3SJuan Quintela     .version_id = 3,
1156b31442c3SJuan Quintela     .minimum_version_id = 2,
1157b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1158b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
1159b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
1160b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
1161b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
1162b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
1163b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
11647783e9f0Spbrook     }
1165b31442c3SJuan Quintela };
11667783e9f0Spbrook 
11677f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
11687f540ab5SChristophe Fergeau {
11697f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
11707f540ab5SChristophe Fergeau 
11717f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
11727f540ab5SChristophe Fergeau }
11737f540ab5SChristophe Fergeau 
11747f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
11757f540ab5SChristophe Fergeau {
11767f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
11777f540ab5SChristophe Fergeau 
11787f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
11797f540ab5SChristophe Fergeau     return 0;
11807f540ab5SChristophe Fergeau }
11817f540ab5SChristophe Fergeau 
11827f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
11837f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
11847f540ab5SChristophe Fergeau     .version_id = 3,
11857f540ab5SChristophe Fergeau     .minimum_version_id = 2,
11867f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
11875cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
11887f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
11897f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
11907f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
11917f540ab5SChristophe Fergeau     }
11927f540ab5SChristophe Fergeau };
11937f540ab5SChristophe Fergeau 
119457d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque)
119557d5c005SHervé Poussineau {
119657d5c005SHervé Poussineau     PS2KbdState *s = opaque;
119757d5c005SHervé Poussineau     return s->need_high_bit != 0; /* 0 is the usual state */
119857d5c005SHervé Poussineau }
119957d5c005SHervé Poussineau 
120057d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
120157d5c005SHervé Poussineau     .name = "ps2kbd/need_high_bit",
120257d5c005SHervé Poussineau     .version_id = 1,
120357d5c005SHervé Poussineau     .minimum_version_id = 1,
120457d5c005SHervé Poussineau     .needed = ps2_keyboard_need_high_bit_needed,
120557d5c005SHervé Poussineau     .fields = (VMStateField[]) {
120657d5c005SHervé Poussineau         VMSTATE_BOOL(need_high_bit, PS2KbdState),
120757d5c005SHervé Poussineau         VMSTATE_END_OF_LIST()
120857d5c005SHervé Poussineau     }
120957d5c005SHervé Poussineau };
121057d5c005SHervé Poussineau 
1211db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
12120e43e99cSbellard {
12130e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
12142858ab09SGonglei     PS2State *ps2 = &s->common;
12150e43e99cSbellard 
1216db596c53SJuan Quintela     if (version_id == 2)
1217e7d93956Saurel32         s->scancode_set=2;
12182858ab09SGonglei 
12192858ab09SGonglei     ps2_common_post_load(ps2);
12202858ab09SGonglei 
12210e43e99cSbellard     return 0;
12220e43e99cSbellard }
12230e43e99cSbellard 
12242858ab09SGonglei static void ps2_kbd_pre_save(void *opaque)
12252858ab09SGonglei {
12262858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
12272858ab09SGonglei     PS2State *ps2 = &s->common;
12282858ab09SGonglei 
12292858ab09SGonglei     ps2_common_post_load(ps2);
12302858ab09SGonglei }
12312858ab09SGonglei 
1232b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
1233b31442c3SJuan Quintela     .name = "ps2kbd",
1234b31442c3SJuan Quintela     .version_id = 3,
1235db596c53SJuan Quintela     .minimum_version_id = 2,
1236db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
12372858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
1238b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1239b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
1240b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
1241b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
1242b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
1243b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
12447f540ab5SChristophe Fergeau     },
12455cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
12465cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
124757d5c005SHervé Poussineau         &vmstate_ps2_keyboard_need_high_bit,
12485cd8cadaSJuan Quintela         NULL
12490e43e99cSbellard     }
1250b31442c3SJuan Quintela };
1251b31442c3SJuan Quintela 
12522858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
12532858ab09SGonglei {
12542858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
12552858ab09SGonglei     PS2State *ps2 = &s->common;
12562858ab09SGonglei 
12572858ab09SGonglei     ps2_common_post_load(ps2);
12582858ab09SGonglei 
12592858ab09SGonglei     return 0;
12602858ab09SGonglei }
12612858ab09SGonglei 
12622858ab09SGonglei static void ps2_mouse_pre_save(void *opaque)
12632858ab09SGonglei {
12642858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
12652858ab09SGonglei     PS2State *ps2 = &s->common;
12662858ab09SGonglei 
12672858ab09SGonglei     ps2_common_post_load(ps2);
12682858ab09SGonglei }
12692858ab09SGonglei 
1270b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
1271b31442c3SJuan Quintela     .name = "ps2mouse",
1272b31442c3SJuan Quintela     .version_id = 2,
1273b31442c3SJuan Quintela     .minimum_version_id = 2,
12742858ab09SGonglei     .post_load = ps2_mouse_post_load,
12752858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
1276b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1277b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
1278b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
1279b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1280b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1281b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1282b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
1283b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1284b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
1285b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
1286b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
1287b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1288b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
1289b31442c3SJuan Quintela     }
1290b31442c3SJuan Quintela };
12910e43e99cSbellard 
129266e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
129366e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
129466e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
129566e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
129666e6536eSGerd Hoffmann };
129766e6536eSGerd Hoffmann 
12980e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
12990e43e99cSbellard {
13007267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
13010e43e99cSbellard 
13025edab03dSDon Koch     trace_ps2_kbd_init(s);
13030e43e99cSbellard     s->common.update_irq = update_irq;
13040e43e99cSbellard     s->common.update_arg = update_arg;
1305e7d93956Saurel32     s->scancode_set = 2;
13060be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
130766e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
130866e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
1309ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
13100e43e99cSbellard     return s;
13110e43e99cSbellard }
13120e43e99cSbellard 
13132a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
13142a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
13152a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
13162a766d29SGerd Hoffmann     .event = ps2_mouse_event,
13172a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
13182a766d29SGerd Hoffmann };
13192a766d29SGerd Hoffmann 
13200e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
13210e43e99cSbellard {
13227267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
13230e43e99cSbellard 
13245edab03dSDon Koch     trace_ps2_mouse_init(s);
13250e43e99cSbellard     s->common.update_irq = update_irq;
13260e43e99cSbellard     s->common.update_arg = update_arg;
13270be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
13282a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
13292a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
1330ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
13310e43e99cSbellard     return s;
13320e43e99cSbellard }
1333