xref: /qemu/hw/input/ps2.c (revision 143c04c7e0639e53086519592ead15d2556bfbf2)
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 
12757d5c005SHervé Poussineau static uint8_t translate_table[256] = {
12857d5c005SHervé Poussineau     0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
12957d5c005SHervé Poussineau     0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
13057d5c005SHervé Poussineau     0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
13157d5c005SHervé Poussineau     0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
13257d5c005SHervé Poussineau     0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
13357d5c005SHervé Poussineau     0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
13457d5c005SHervé Poussineau     0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
13557d5c005SHervé Poussineau     0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
13657d5c005SHervé Poussineau     0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
13757d5c005SHervé Poussineau     0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
13857d5c005SHervé Poussineau     0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
13957d5c005SHervé Poussineau     0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
14057d5c005SHervé Poussineau     0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
14157d5c005SHervé Poussineau     0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
14257d5c005SHervé Poussineau     0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
14357d5c005SHervé Poussineau     0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
14457d5c005SHervé Poussineau     0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
14557d5c005SHervé Poussineau     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
14657d5c005SHervé Poussineau     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
14757d5c005SHervé Poussineau     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
14857d5c005SHervé Poussineau     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
14957d5c005SHervé Poussineau     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
15057d5c005SHervé Poussineau     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
15157d5c005SHervé Poussineau     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
15257d5c005SHervé Poussineau     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
15357d5c005SHervé Poussineau     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
15457d5c005SHervé Poussineau     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
15557d5c005SHervé Poussineau     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
15657d5c005SHervé Poussineau     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
15757d5c005SHervé Poussineau     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
15857d5c005SHervé Poussineau     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
15957d5c005SHervé Poussineau     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
16057d5c005SHervé Poussineau };
16157d5c005SHervé Poussineau 
162620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key)
163620775d1SDaniel P. Berrange {
164620775d1SDaniel P. Berrange     switch (key) {
165620775d1SDaniel P. Berrange     case Q_KEY_CODE_CTRL:
166620775d1SDaniel P. Berrange         return MOD_CTRL_L;
167620775d1SDaniel P. Berrange     case Q_KEY_CODE_CTRL_R:
168620775d1SDaniel P. Berrange         return MOD_CTRL_R;
169620775d1SDaniel P. Berrange     case Q_KEY_CODE_SHIFT:
170620775d1SDaniel P. Berrange         return MOD_SHIFT_L;
171620775d1SDaniel P. Berrange     case Q_KEY_CODE_SHIFT_R:
172620775d1SDaniel P. Berrange         return MOD_SHIFT_R;
173620775d1SDaniel P. Berrange     case Q_KEY_CODE_ALT:
174620775d1SDaniel P. Berrange         return MOD_ALT_L;
175620775d1SDaniel P. Berrange     case Q_KEY_CODE_ALT_R:
176620775d1SDaniel P. Berrange         return MOD_ALT_R;
177620775d1SDaniel P. Berrange     default:
178620775d1SDaniel P. Berrange         return 0;
179620775d1SDaniel P. Berrange     }
180620775d1SDaniel P. Berrange }
181620775d1SDaniel P. Berrange 
182954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s)
183954ee55bSGerd Hoffmann {
184954ee55bSGerd Hoffmann     PS2Queue *q = &s->queue;
185954ee55bSGerd Hoffmann 
186954ee55bSGerd Hoffmann     q->rptr = 0;
187954ee55bSGerd Hoffmann     q->wptr = 0;
188954ee55bSGerd Hoffmann     q->count = 0;
189954ee55bSGerd Hoffmann }
190954ee55bSGerd Hoffmann 
1918498bb8dSGerd Hoffmann void ps2_queue(PS2State *s, int b)
1920e43e99cSbellard {
1930e43e99cSbellard     PS2Queue *q = &s->queue;
1940e43e99cSbellard 
1952858ab09SGonglei     if (q->count >= PS2_QUEUE_SIZE - 1)
1960e43e99cSbellard         return;
1970e43e99cSbellard     q->data[q->wptr] = b;
1980e43e99cSbellard     if (++q->wptr == PS2_QUEUE_SIZE)
1990e43e99cSbellard         q->wptr = 0;
2000e43e99cSbellard     q->count++;
2010e43e99cSbellard     s->update_irq(s->update_arg, 1);
2020e43e99cSbellard }
2030e43e99cSbellard 
20457d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */
2050e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
2060e43e99cSbellard {
207f94f5d71Spbrook     PS2KbdState *s = opaque;
208e7d93956Saurel32 
2095edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
210fd214d18SGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
21157d5c005SHervé Poussineau 
21257d5c005SHervé Poussineau     if (s->translate) {
21357d5c005SHervé Poussineau         if (keycode == 0xf0) {
21457d5c005SHervé Poussineau             s->need_high_bit = true;
21557d5c005SHervé Poussineau         } else if (s->need_high_bit) {
21657d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode] | 0x80);
21757d5c005SHervé Poussineau             s->need_high_bit = false;
21857d5c005SHervé Poussineau         } else {
21957d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode]);
2207096a96dSRoy Tam         }
22157d5c005SHervé Poussineau     } else {
2220e43e99cSbellard         ps2_queue(&s->common, keycode);
2230e43e99cSbellard     }
22457d5c005SHervé Poussineau }
2250e43e99cSbellard 
22666e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
22766e6536eSGerd Hoffmann                                InputEvent *evt)
22866e6536eSGerd Hoffmann {
22966e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
23032bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
2318c10e0baSHervé Poussineau     int qcode;
232ab8f9d49SDaniel P. Berrange     uint16_t keycode = 0;
233620775d1SDaniel P. Berrange     int mod;
23466e6536eSGerd Hoffmann 
235*143c04c7SGeoffrey McRae     /* do not process events while disabled to prevent stream corruption */
236*143c04c7SGeoffrey McRae     if (!s->scan_enabled) {
237*143c04c7SGeoffrey McRae         return;
238*143c04c7SGeoffrey McRae     }
239*143c04c7SGeoffrey McRae 
24066e6536eSGerd Hoffmann     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
2418c10e0baSHervé Poussineau     assert(evt->type == INPUT_EVENT_KIND_KEY);
2428c10e0baSHervé Poussineau     qcode = qemu_input_key_value_to_qcode(key->key);
24357d5c005SHervé Poussineau 
244620775d1SDaniel P. Berrange     mod = ps2_modifier_bit(qcode);
245620775d1SDaniel P. Berrange     trace_ps2_keyboard_event(s, qcode, key->down, mod, s->modifiers);
246620775d1SDaniel P. Berrange     if (key->down) {
247620775d1SDaniel P. Berrange         s->modifiers |= mod;
248620775d1SDaniel P. Berrange     } else {
249620775d1SDaniel P. Berrange         s->modifiers &= ~mod;
250620775d1SDaniel P. Berrange     }
251620775d1SDaniel P. Berrange 
2528c10e0baSHervé Poussineau     if (s->scancode_set == 1) {
2538c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
25429fd23a5SDaniel P. Berrange             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
25529fd23a5SDaniel P. Berrange                 if (key->down) {
25629fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
25729fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0x46);
25829fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
25929fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xc6);
26029fd23a5SDaniel P. Berrange                 }
26129fd23a5SDaniel P. Berrange             } else {
2628c10e0baSHervé Poussineau                 if (key->down) {
2638c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe1);
2648c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x1d);
2658c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x45);
266927f0425SDaniel P. Berrange                     ps2_put_keycode(s, 0xe1);
2678c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x9d);
2688c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xc5);
2698c10e0baSHervé Poussineau                 }
27029fd23a5SDaniel P. Berrange             }
2718c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
272620775d1SDaniel P. Berrange             if (s->modifiers & MOD_ALT_L) {
273620775d1SDaniel P. Berrange                 if (key->down) {
274620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
275620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
276620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x54);
277620775d1SDaniel P. Berrange                 } else {
278620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xd4);
279620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
280620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
281620775d1SDaniel P. Berrange                 }
282620775d1SDaniel P. Berrange             } else if (s->modifiers & MOD_ALT_R) {
283620775d1SDaniel P. Berrange                 if (key->down) {
284620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
285620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
286620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
287620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
288620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x54);
289620775d1SDaniel P. Berrange                 } else {
290620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xd4);
291620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
292620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
293620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
294620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
295620775d1SDaniel P. Berrange                 }
2968f63458fSDaniel P. Berrange             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
2978f63458fSDaniel P. Berrange                                        MOD_SHIFT_R | MOD_CTRL_R)) {
2988f63458fSDaniel P. Berrange                 if (key->down) {
2998f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
3008f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x37);
3018f63458fSDaniel P. Berrange                 } else {
3028f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
3038f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xb7);
3048f63458fSDaniel P. Berrange                 }
305620775d1SDaniel P. Berrange             } else {
3068c10e0baSHervé Poussineau                 if (key->down) {
3078c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
3088c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x2a);
3098c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
3108c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x37);
3118c10e0baSHervé Poussineau                 } else {
3128c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
3138c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xb7);
3148c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
3158c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xaa);
3168c10e0baSHervé Poussineau                 }
317620775d1SDaniel P. Berrange             }
3188c10e0baSHervé Poussineau         } else {
319ab8f9d49SDaniel P. Berrange             if (qcode < qemu_input_map_qcode_to_atset1_len)
320ab8f9d49SDaniel P. Berrange                 keycode = qemu_input_map_qcode_to_atset1[qcode];
3218c10e0baSHervé Poussineau             if (keycode) {
3228c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
3238c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
3248c10e0baSHervé Poussineau                 }
3258c10e0baSHervé Poussineau                 if (!key->down) {
3268c10e0baSHervé Poussineau                     keycode |= 0x80;
3278c10e0baSHervé Poussineau                 }
3288c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
3298c10e0baSHervé Poussineau             } else {
330ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
331ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
3328c10e0baSHervé Poussineau             }
3338c10e0baSHervé Poussineau         }
3348c10e0baSHervé Poussineau     } else if (s->scancode_set == 2) {
3358c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
33629fd23a5SDaniel P. Berrange             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
33729fd23a5SDaniel P. Berrange                 if (key->down) {
33829fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
33929fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0x7e);
34029fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
34129fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
34229fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0x7e);
34329fd23a5SDaniel P. Berrange                 }
34429fd23a5SDaniel P. Berrange             } else {
3458c10e0baSHervé Poussineau                 if (key->down) {
3468c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe1);
3478c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x14);
3488c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x77);
3498c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe1);
3508c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
3518c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x14);
3528c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
3538c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x77);
3548c10e0baSHervé Poussineau                 }
35529fd23a5SDaniel P. Berrange             }
3568c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
357620775d1SDaniel P. Berrange             if (s->modifiers & MOD_ALT_L) {
358620775d1SDaniel P. Berrange                 if (key->down) {
359620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
360620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
361620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
362620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
363620775d1SDaniel P. Berrange                 } else {
364620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
365620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
366620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
367620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
368620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
369620775d1SDaniel P. Berrange                 }
370620775d1SDaniel P. Berrange             } else if (s->modifiers & MOD_ALT_R) {
371620775d1SDaniel P. Berrange                 if (key->down) {
372620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
373620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
374620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
375620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
376620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
377620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
378620775d1SDaniel P. Berrange                 } else {
379620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
380620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
381620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
382620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
383620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
384620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
385620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
386620775d1SDaniel P. Berrange                 }
3878f63458fSDaniel P. Berrange             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
3888f63458fSDaniel P. Berrange                                        MOD_SHIFT_R | MOD_CTRL_R)) {
3898f63458fSDaniel P. Berrange                 if (key->down) {
3908f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
3918f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x7c);
3928f63458fSDaniel P. Berrange                 } else {
3938f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
3948f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
3958f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x7c);
3968f63458fSDaniel P. Berrange                 }
397620775d1SDaniel P. Berrange             } else {
3988c10e0baSHervé Poussineau                 if (key->down) {
3998c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4008c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x12);
4018c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4028c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x7c);
4038c10e0baSHervé Poussineau                 } else {
4048c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4058c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
4068c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x7c);
4078c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4088c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
4098c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x12);
4108c10e0baSHervé Poussineau                 }
411620775d1SDaniel P. Berrange             }
4128c10e0baSHervé Poussineau         } else {
413ab8f9d49SDaniel P. Berrange             if (qcode < qemu_input_map_qcode_to_atset2_len)
414ab8f9d49SDaniel P. Berrange                 keycode = qemu_input_map_qcode_to_atset2[qcode];
4158c10e0baSHervé Poussineau             if (keycode) {
4168c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
4178c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
4188c10e0baSHervé Poussineau                 }
4198c10e0baSHervé Poussineau                 if (!key->down) {
4208c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
4218c10e0baSHervé Poussineau                 }
4228c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
42357d5c005SHervé Poussineau             } else {
424ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
425ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
42657d5c005SHervé Poussineau             }
42757d5c005SHervé Poussineau         }
42857d5c005SHervé Poussineau     } else if (s->scancode_set == 3) {
429ab8f9d49SDaniel P. Berrange         if (qcode < qemu_input_map_qcode_to_atset3_len)
430ab8f9d49SDaniel P. Berrange             keycode = qemu_input_map_qcode_to_atset3[qcode];
4318c10e0baSHervé Poussineau         if (keycode) {
4328c10e0baSHervé Poussineau             /* FIXME: break code should be configured on a key by key basis */
4338c10e0baSHervé Poussineau             if (!key->down) {
4348c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
43557d5c005SHervé Poussineau             }
43657d5c005SHervé Poussineau             ps2_put_keycode(s, keycode);
4378c10e0baSHervé Poussineau         } else {
438ec044a80SHervé Poussineau             qemu_log_mask(LOG_UNIMP,
439ec044a80SHervé Poussineau                           "ps2: ignoring key with qcode %d\n", qcode);
4408c10e0baSHervé Poussineau         }
44166e6536eSGerd Hoffmann     }
44266e6536eSGerd Hoffmann }
44366e6536eSGerd Hoffmann 
4448498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s)
4450e43e99cSbellard {
4460e43e99cSbellard     PS2Queue *q;
4470e43e99cSbellard     int val, index;
4480e43e99cSbellard 
4498498bb8dSGerd Hoffmann     trace_ps2_read_data(s);
4500e43e99cSbellard     q = &s->queue;
4510e43e99cSbellard     if (q->count == 0) {
4520e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
4530e43e99cSbellard            (needed for EMM386) */
4540e43e99cSbellard         /* XXX: need a timer to do things correctly */
4550e43e99cSbellard         index = q->rptr - 1;
4560e43e99cSbellard         if (index < 0)
4570e43e99cSbellard             index = PS2_QUEUE_SIZE - 1;
4580e43e99cSbellard         val = q->data[index];
4590e43e99cSbellard     } else {
4600e43e99cSbellard         val = q->data[q->rptr];
4610e43e99cSbellard         if (++q->rptr == PS2_QUEUE_SIZE)
4620e43e99cSbellard             q->rptr = 0;
4630e43e99cSbellard         q->count--;
4640e43e99cSbellard         /* reading deasserts IRQ */
4650e43e99cSbellard         s->update_irq(s->update_arg, 0);
4660e43e99cSbellard         /* reassert IRQs if data left */
4670e43e99cSbellard         s->update_irq(s->update_arg, q->count != 0);
4680e43e99cSbellard     }
4690e43e99cSbellard     return val;
4700e43e99cSbellard }
4710e43e99cSbellard 
4727f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
4737f540ab5SChristophe Fergeau {
4745edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
4757f540ab5SChristophe Fergeau     s->ledstate = ledstate;
4767f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
4777f540ab5SChristophe Fergeau }
4787f540ab5SChristophe Fergeau 
4790e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
4800e43e99cSbellard {
4815edab03dSDon Koch     trace_ps2_reset_keyboard(s);
4820e43e99cSbellard     s->scan_enabled = 1;
483e7d93956Saurel32     s->scancode_set = 2;
4846e24ee0cSGerd Hoffmann     ps2_reset_queue(&s->common);
4857f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
4860e43e99cSbellard }
4870e43e99cSbellard 
4880e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
4890e43e99cSbellard {
4900e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
4910e43e99cSbellard 
4925edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
4930e43e99cSbellard     switch(s->common.write_cmd) {
4940e43e99cSbellard     default:
4950e43e99cSbellard     case -1:
4960e43e99cSbellard         switch(val) {
4970e43e99cSbellard         case 0x00:
4980e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
4990e43e99cSbellard             break;
5000e43e99cSbellard         case 0x05:
5010e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_RESEND);
5020e43e99cSbellard             break;
5030e43e99cSbellard         case KBD_CMD_GET_ID:
5040e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
505e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
50635c4d671Saurel32             ps2_queue(&s->common, KBD_REPLY_ID);
50735c4d671Saurel32             if (s->translate)
50835c4d671Saurel32                 ps2_queue(&s->common, 0x41);
50935c4d671Saurel32             else
51035c4d671Saurel32                 ps2_queue(&s->common, 0x83);
5110e43e99cSbellard             break;
5120e43e99cSbellard         case KBD_CMD_ECHO:
5130e43e99cSbellard             ps2_queue(&s->common, KBD_CMD_ECHO);
5140e43e99cSbellard             break;
5150e43e99cSbellard         case KBD_CMD_ENABLE:
5160e43e99cSbellard             s->scan_enabled = 1;
5170e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
5180e43e99cSbellard             break;
519e7d93956Saurel32         case KBD_CMD_SCANCODE:
5200e43e99cSbellard         case KBD_CMD_SET_LEDS:
5210e43e99cSbellard         case KBD_CMD_SET_RATE:
5220e43e99cSbellard             s->common.write_cmd = val;
5230e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
5240e43e99cSbellard             break;
5250e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
5260e43e99cSbellard             ps2_reset_keyboard(s);
5270e43e99cSbellard             s->scan_enabled = 0;
5280e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
5290e43e99cSbellard             break;
5300e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
5310e43e99cSbellard             ps2_reset_keyboard(s);
5320e43e99cSbellard             s->scan_enabled = 1;
5330e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
5340e43e99cSbellard             break;
5350e43e99cSbellard         case KBD_CMD_RESET:
5360e43e99cSbellard             ps2_reset_keyboard(s);
5370e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_ACK);
5380e43e99cSbellard             ps2_queue(&s->common, KBD_REPLY_POR);
5390e43e99cSbellard             break;
5400e43e99cSbellard         default:
54106b3611fSHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
5420e43e99cSbellard             break;
5430e43e99cSbellard         }
5440e43e99cSbellard         break;
545e7d93956Saurel32     case KBD_CMD_SCANCODE:
546e7d93956Saurel32         if (val == 0) {
5474df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_ACK);
54857d5c005SHervé Poussineau             ps2_put_keycode(s, s->scancode_set);
5494df23b64SHervé Poussineau         } else if (val >= 1 && val <= 3) {
550e7d93956Saurel32             s->scancode_set = val;
551e7d93956Saurel32             ps2_queue(&s->common, KBD_REPLY_ACK);
5524df23b64SHervé Poussineau         } else {
5534df23b64SHervé Poussineau             ps2_queue(&s->common, KBD_REPLY_RESEND);
554e7d93956Saurel32         }
555e7d93956Saurel32         s->common.write_cmd = -1;
556e7d93956Saurel32         break;
5570e43e99cSbellard     case KBD_CMD_SET_LEDS:
5587f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
5590e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
5600e43e99cSbellard         s->common.write_cmd = -1;
5610e43e99cSbellard         break;
5620e43e99cSbellard     case KBD_CMD_SET_RATE:
5630e43e99cSbellard         ps2_queue(&s->common, KBD_REPLY_ACK);
5640e43e99cSbellard         s->common.write_cmd = -1;
5650e43e99cSbellard         break;
5660e43e99cSbellard     }
5670e43e99cSbellard }
5680e43e99cSbellard 
569f94f5d71Spbrook /* Set the scancode translation mode.
570f94f5d71Spbrook    0 = raw scancodes.
571f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
572f94f5d71Spbrook 
573f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
574f94f5d71Spbrook {
575f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
5765edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
577f94f5d71Spbrook     s->translate = mode;
578f94f5d71Spbrook }
579f94f5d71Spbrook 
5800e43e99cSbellard static void ps2_mouse_send_packet(PS2MouseState *s)
5810e43e99cSbellard {
5820e43e99cSbellard     unsigned int b;
5830e43e99cSbellard     int dx1, dy1, dz1;
5840e43e99cSbellard 
5850e43e99cSbellard     dx1 = s->mouse_dx;
5860e43e99cSbellard     dy1 = s->mouse_dy;
5870e43e99cSbellard     dz1 = s->mouse_dz;
5880e43e99cSbellard     /* XXX: increase range to 8 bits ? */
5890e43e99cSbellard     if (dx1 > 127)
5900e43e99cSbellard         dx1 = 127;
5910e43e99cSbellard     else if (dx1 < -127)
5920e43e99cSbellard         dx1 = -127;
5930e43e99cSbellard     if (dy1 > 127)
5940e43e99cSbellard         dy1 = 127;
5950e43e99cSbellard     else if (dy1 < -127)
5960e43e99cSbellard         dy1 = -127;
5970e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
5980e43e99cSbellard     ps2_queue(&s->common, b);
5990e43e99cSbellard     ps2_queue(&s->common, dx1 & 0xff);
6000e43e99cSbellard     ps2_queue(&s->common, dy1 & 0xff);
6010e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
6020e43e99cSbellard     switch(s->mouse_type) {
6030e43e99cSbellard     default:
6040e43e99cSbellard         break;
6050e43e99cSbellard     case 3:
6060e43e99cSbellard         if (dz1 > 127)
6070e43e99cSbellard             dz1 = 127;
6080e43e99cSbellard         else if (dz1 < -127)
6090e43e99cSbellard                 dz1 = -127;
6100e43e99cSbellard         ps2_queue(&s->common, dz1 & 0xff);
6110e43e99cSbellard         break;
6120e43e99cSbellard     case 4:
6130e43e99cSbellard         if (dz1 > 7)
6140e43e99cSbellard             dz1 = 7;
6150e43e99cSbellard         else if (dz1 < -7)
6160e43e99cSbellard             dz1 = -7;
6170e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
6180e43e99cSbellard         ps2_queue(&s->common, b);
6190e43e99cSbellard         break;
6200e43e99cSbellard     }
6210e43e99cSbellard 
6225edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
6230e43e99cSbellard     /* update deltas */
6240e43e99cSbellard     s->mouse_dx -= dx1;
6250e43e99cSbellard     s->mouse_dy -= dy1;
6260e43e99cSbellard     s->mouse_dz -= dz1;
6270e43e99cSbellard }
6280e43e99cSbellard 
6292a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
6302a766d29SGerd Hoffmann                             InputEvent *evt)
6310e43e99cSbellard {
6327fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
6338b0caab0SFabian Lesniak         [INPUT_BUTTON_LEFT]   = PS2_MOUSE_BUTTON_LEFT,
6348b0caab0SFabian Lesniak         [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
6358b0caab0SFabian Lesniak         [INPUT_BUTTON_RIGHT]  = PS2_MOUSE_BUTTON_RIGHT,
6368b0caab0SFabian Lesniak         [INPUT_BUTTON_SIDE]   = PS2_MOUSE_BUTTON_SIDE,
6378b0caab0SFabian Lesniak         [INPUT_BUTTON_EXTRA]  = PS2_MOUSE_BUTTON_EXTRA,
6382a766d29SGerd Hoffmann     };
6392a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
640b5a1b443SEric Blake     InputMoveEvent *move;
641b5a1b443SEric Blake     InputBtnEvent *btn;
6420e43e99cSbellard 
6430e43e99cSbellard     /* check if deltas are recorded when disabled */
6440e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
6450e43e99cSbellard         return;
6460e43e99cSbellard 
647568c73a4SEric Blake     switch (evt->type) {
6482a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
64932bafa8fSEric Blake         move = evt->u.rel.data;
650b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
651b5a1b443SEric Blake             s->mouse_dx += move->value;
652b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
653b5a1b443SEric Blake             s->mouse_dy -= move->value;
6542a766d29SGerd Hoffmann         }
6552a766d29SGerd Hoffmann         break;
6560e43e99cSbellard 
6572a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
65832bafa8fSEric Blake         btn = evt->u.btn.data;
659b5a1b443SEric Blake         if (btn->down) {
660b5a1b443SEric Blake             s->mouse_buttons |= bmap[btn->button];
661b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
6622a766d29SGerd Hoffmann                 s->mouse_dz--;
663b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
6642a766d29SGerd Hoffmann                 s->mouse_dz++;
6652a766d29SGerd Hoffmann             }
6662a766d29SGerd Hoffmann         } else {
667b5a1b443SEric Blake             s->mouse_buttons &= ~bmap[btn->button];
6682a766d29SGerd Hoffmann         }
6692a766d29SGerd Hoffmann         break;
6702a766d29SGerd Hoffmann 
6712a766d29SGerd Hoffmann     default:
6722a766d29SGerd Hoffmann         /* keep gcc happy */
6732a766d29SGerd Hoffmann         break;
6742a766d29SGerd Hoffmann     }
675fd214d18SGerd Hoffmann }
676fd214d18SGerd Hoffmann 
6772a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
6782a766d29SGerd Hoffmann {
6792a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
6802a766d29SGerd Hoffmann 
681*143c04c7SGeoffrey McRae     /* do not sync while disabled to prevent stream corruption */
682*143c04c7SGeoffrey McRae     if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
683*143c04c7SGeoffrey McRae         return;
684*143c04c7SGeoffrey McRae     }
685*143c04c7SGeoffrey McRae 
6862a766d29SGerd Hoffmann     if (s->mouse_buttons) {
6872a766d29SGerd Hoffmann         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
6882a766d29SGerd Hoffmann     }
6892858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
6902858ab09SGonglei         while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
6910e43e99cSbellard             /* if not remote, send event. Multiple events are sent if
6920e43e99cSbellard                too big deltas */
6930e43e99cSbellard             ps2_mouse_send_packet(s);
6940e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
6950e43e99cSbellard                 break;
6960e43e99cSbellard         }
6970e43e99cSbellard     }
6980e43e99cSbellard }
6990e43e99cSbellard 
700548df2acSths void ps2_mouse_fake_event(void *opaque)
701548df2acSths {
7022a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
7035edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
7042a766d29SGerd Hoffmann     s->mouse_dx++;
7052a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
706548df2acSths }
707548df2acSths 
7080e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
7090e43e99cSbellard {
7100e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
7115edab03dSDon Koch 
7125edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
7130e43e99cSbellard #ifdef DEBUG_MOUSE
7140e43e99cSbellard     printf("kbd: write mouse 0x%02x\n", val);
7150e43e99cSbellard #endif
7160e43e99cSbellard     switch(s->common.write_cmd) {
7170e43e99cSbellard     default:
7180e43e99cSbellard     case -1:
7190e43e99cSbellard         /* mouse command */
7200e43e99cSbellard         if (s->mouse_wrap) {
7210e43e99cSbellard             if (val == AUX_RESET_WRAP) {
7220e43e99cSbellard                 s->mouse_wrap = 0;
7230e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
7240e43e99cSbellard                 return;
7250e43e99cSbellard             } else if (val != AUX_RESET) {
7260e43e99cSbellard                 ps2_queue(&s->common, val);
7270e43e99cSbellard                 return;
7280e43e99cSbellard             }
7290e43e99cSbellard         }
7300e43e99cSbellard         switch(val) {
7310e43e99cSbellard         case AUX_SET_SCALE11:
7320e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
7330e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7340e43e99cSbellard             break;
7350e43e99cSbellard         case AUX_SET_SCALE21:
7360e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
7370e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7380e43e99cSbellard             break;
7390e43e99cSbellard         case AUX_SET_STREAM:
7400e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
7410e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7420e43e99cSbellard             break;
7430e43e99cSbellard         case AUX_SET_WRAP:
7440e43e99cSbellard             s->mouse_wrap = 1;
7450e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7460e43e99cSbellard             break;
7470e43e99cSbellard         case AUX_SET_REMOTE:
7480e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
7490e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7500e43e99cSbellard             break;
7510e43e99cSbellard         case AUX_GET_TYPE:
7520e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7530e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
7540e43e99cSbellard             break;
7550e43e99cSbellard         case AUX_SET_RES:
7560e43e99cSbellard         case AUX_SET_SAMPLE:
7570e43e99cSbellard             s->common.write_cmd = val;
7580e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7590e43e99cSbellard             break;
7600e43e99cSbellard         case AUX_GET_SCALE:
7610e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7620e43e99cSbellard             ps2_queue(&s->common, s->mouse_status);
7630e43e99cSbellard             ps2_queue(&s->common, s->mouse_resolution);
7640e43e99cSbellard             ps2_queue(&s->common, s->mouse_sample_rate);
7650e43e99cSbellard             break;
7660e43e99cSbellard         case AUX_POLL:
7670e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7680e43e99cSbellard             ps2_mouse_send_packet(s);
7690e43e99cSbellard             break;
7700e43e99cSbellard         case AUX_ENABLE_DEV:
7710e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
7720e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7730e43e99cSbellard             break;
7740e43e99cSbellard         case AUX_DISABLE_DEV:
7750e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
7760e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7770e43e99cSbellard             break;
7780e43e99cSbellard         case AUX_SET_DEFAULT:
7790e43e99cSbellard             s->mouse_sample_rate = 100;
7800e43e99cSbellard             s->mouse_resolution = 2;
7810e43e99cSbellard             s->mouse_status = 0;
7820e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7830e43e99cSbellard             break;
7840e43e99cSbellard         case AUX_RESET:
7850e43e99cSbellard             s->mouse_sample_rate = 100;
7860e43e99cSbellard             s->mouse_resolution = 2;
7870e43e99cSbellard             s->mouse_status = 0;
7880e43e99cSbellard             s->mouse_type = 0;
789*143c04c7SGeoffrey McRae             ps2_reset_queue(&s->common);
7900e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
7910e43e99cSbellard             ps2_queue(&s->common, 0xaa);
7920e43e99cSbellard             ps2_queue(&s->common, s->mouse_type);
7930e43e99cSbellard             break;
7940e43e99cSbellard         default:
7950e43e99cSbellard             break;
7960e43e99cSbellard         }
7970e43e99cSbellard         break;
7980e43e99cSbellard     case AUX_SET_SAMPLE:
7990e43e99cSbellard         s->mouse_sample_rate = val;
8000e43e99cSbellard         /* detect IMPS/2 or IMEX */
8010e43e99cSbellard         switch(s->mouse_detect_state) {
8020e43e99cSbellard         default:
8030e43e99cSbellard         case 0:
8040e43e99cSbellard             if (val == 200)
8050e43e99cSbellard                 s->mouse_detect_state = 1;
8060e43e99cSbellard             break;
8070e43e99cSbellard         case 1:
8080e43e99cSbellard             if (val == 100)
8090e43e99cSbellard                 s->mouse_detect_state = 2;
8100e43e99cSbellard             else if (val == 200)
8110e43e99cSbellard                 s->mouse_detect_state = 3;
8120e43e99cSbellard             else
8130e43e99cSbellard                 s->mouse_detect_state = 0;
8140e43e99cSbellard             break;
8150e43e99cSbellard         case 2:
8160e43e99cSbellard             if (val == 80)
8170e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
8180e43e99cSbellard             s->mouse_detect_state = 0;
8190e43e99cSbellard             break;
8200e43e99cSbellard         case 3:
8210e43e99cSbellard             if (val == 80)
8220e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
8230e43e99cSbellard             s->mouse_detect_state = 0;
8240e43e99cSbellard             break;
8250e43e99cSbellard         }
8260e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
8270e43e99cSbellard         s->common.write_cmd = -1;
8280e43e99cSbellard         break;
8290e43e99cSbellard     case AUX_SET_RES:
8300e43e99cSbellard         s->mouse_resolution = val;
8310e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
8320e43e99cSbellard         s->common.write_cmd = -1;
8330e43e99cSbellard         break;
8340e43e99cSbellard     }
8350e43e99cSbellard }
8360e43e99cSbellard 
837ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
8380e43e99cSbellard {
8390e43e99cSbellard     s->write_cmd = -1;
840954ee55bSGerd Hoffmann     ps2_reset_queue(s);
841deeccef3Saliguori     s->update_irq(s->update_arg, 0);
8420e43e99cSbellard }
8430e43e99cSbellard 
8442858ab09SGonglei static void ps2_common_post_load(PS2State *s)
8452858ab09SGonglei {
8462858ab09SGonglei     PS2Queue *q = &s->queue;
847802cbcb7SPrasad J Pandit     uint8_t i, size;
848802cbcb7SPrasad J Pandit     uint8_t tmp_data[PS2_QUEUE_SIZE];
8492858ab09SGonglei 
8502858ab09SGonglei     /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
851802cbcb7SPrasad J Pandit     size = (q->count < 0 || q->count > PS2_QUEUE_SIZE) ? 0 : q->count;
8522858ab09SGonglei 
8532858ab09SGonglei     /* move the queue elements to the start of data array */
8542858ab09SGonglei     for (i = 0; i < size; i++) {
855802cbcb7SPrasad J Pandit         if (q->rptr < 0 || q->rptr >= sizeof(q->data)) {
8562858ab09SGonglei             q->rptr = 0;
8572858ab09SGonglei         }
858802cbcb7SPrasad J Pandit         tmp_data[i] = q->data[q->rptr++];
8592858ab09SGonglei     }
8602858ab09SGonglei     memcpy(q->data, tmp_data, size);
861802cbcb7SPrasad J Pandit 
8622858ab09SGonglei     /* reset rptr/wptr/count */
8632858ab09SGonglei     q->rptr = 0;
8642858ab09SGonglei     q->wptr = size;
8652858ab09SGonglei     q->count = size;
8662858ab09SGonglei     s->update_irq(s->update_arg, q->count != 0);
8672858ab09SGonglei }
8682858ab09SGonglei 
869ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
870ef74679aSDinesh Subhraveti {
871ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
872ef74679aSDinesh Subhraveti 
8735edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
874ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
875ef74679aSDinesh Subhraveti     s->scan_enabled = 0;
876ef74679aSDinesh Subhraveti     s->translate = 0;
877089adafdSHervé Poussineau     s->scancode_set = 2;
878620775d1SDaniel P. Berrange     s->modifiers = 0;
879ef74679aSDinesh Subhraveti }
880ef74679aSDinesh Subhraveti 
881ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
882ef74679aSDinesh Subhraveti {
883ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
884ef74679aSDinesh Subhraveti 
8855edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
886ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
887ef74679aSDinesh Subhraveti     s->mouse_status = 0;
888ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
889ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
890ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
891ef74679aSDinesh Subhraveti     s->mouse_type = 0;
892ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
893ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
894ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
895ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
896ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
897ef74679aSDinesh Subhraveti }
898ef74679aSDinesh Subhraveti 
899b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
900b31442c3SJuan Quintela     .name = "PS2 Common State",
901b31442c3SJuan Quintela     .version_id = 3,
902b31442c3SJuan Quintela     .minimum_version_id = 2,
903b31442c3SJuan Quintela     .fields = (VMStateField[]) {
904b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
905b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
906b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
907b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
908b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
909b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
9107783e9f0Spbrook     }
911b31442c3SJuan Quintela };
9127783e9f0Spbrook 
9137f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
9147f540ab5SChristophe Fergeau {
9157f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
9167f540ab5SChristophe Fergeau 
9177f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
9187f540ab5SChristophe Fergeau }
9197f540ab5SChristophe Fergeau 
9207f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
9217f540ab5SChristophe Fergeau {
9227f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
9237f540ab5SChristophe Fergeau 
9247f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
9257f540ab5SChristophe Fergeau     return 0;
9267f540ab5SChristophe Fergeau }
9277f540ab5SChristophe Fergeau 
9287f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
9297f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
9307f540ab5SChristophe Fergeau     .version_id = 3,
9317f540ab5SChristophe Fergeau     .minimum_version_id = 2,
9327f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
9335cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
9347f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
9357f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
9367f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
9377f540ab5SChristophe Fergeau     }
9387f540ab5SChristophe Fergeau };
9397f540ab5SChristophe Fergeau 
94057d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque)
94157d5c005SHervé Poussineau {
94257d5c005SHervé Poussineau     PS2KbdState *s = opaque;
94357d5c005SHervé Poussineau     return s->need_high_bit != 0; /* 0 is the usual state */
94457d5c005SHervé Poussineau }
94557d5c005SHervé Poussineau 
94657d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
94757d5c005SHervé Poussineau     .name = "ps2kbd/need_high_bit",
94857d5c005SHervé Poussineau     .version_id = 1,
94957d5c005SHervé Poussineau     .minimum_version_id = 1,
95057d5c005SHervé Poussineau     .needed = ps2_keyboard_need_high_bit_needed,
95157d5c005SHervé Poussineau     .fields = (VMStateField[]) {
95257d5c005SHervé Poussineau         VMSTATE_BOOL(need_high_bit, PS2KbdState),
95357d5c005SHervé Poussineau         VMSTATE_END_OF_LIST()
95457d5c005SHervé Poussineau     }
95557d5c005SHervé Poussineau };
95657d5c005SHervé Poussineau 
957db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
9580e43e99cSbellard {
9590e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
9602858ab09SGonglei     PS2State *ps2 = &s->common;
9610e43e99cSbellard 
962db596c53SJuan Quintela     if (version_id == 2)
963e7d93956Saurel32         s->scancode_set=2;
9642858ab09SGonglei 
9652858ab09SGonglei     ps2_common_post_load(ps2);
9662858ab09SGonglei 
9670e43e99cSbellard     return 0;
9680e43e99cSbellard }
9690e43e99cSbellard 
97044b1ff31SDr. David Alan Gilbert static int ps2_kbd_pre_save(void *opaque)
9712858ab09SGonglei {
9722858ab09SGonglei     PS2KbdState *s = (PS2KbdState *)opaque;
9732858ab09SGonglei     PS2State *ps2 = &s->common;
9742858ab09SGonglei 
9752858ab09SGonglei     ps2_common_post_load(ps2);
97644b1ff31SDr. David Alan Gilbert 
97744b1ff31SDr. David Alan Gilbert     return 0;
9782858ab09SGonglei }
9792858ab09SGonglei 
980b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
981b31442c3SJuan Quintela     .name = "ps2kbd",
982b31442c3SJuan Quintela     .version_id = 3,
983db596c53SJuan Quintela     .minimum_version_id = 2,
984db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
9852858ab09SGonglei     .pre_save = ps2_kbd_pre_save,
986b31442c3SJuan Quintela     .fields = (VMStateField[]) {
987b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
988b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
989b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
990b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
991b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
9927f540ab5SChristophe Fergeau     },
9935cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
9945cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
99557d5c005SHervé Poussineau         &vmstate_ps2_keyboard_need_high_bit,
9965cd8cadaSJuan Quintela         NULL
9970e43e99cSbellard     }
998b31442c3SJuan Quintela };
999b31442c3SJuan Quintela 
10002858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
10012858ab09SGonglei {
10022858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
10032858ab09SGonglei     PS2State *ps2 = &s->common;
10042858ab09SGonglei 
10052858ab09SGonglei     ps2_common_post_load(ps2);
10062858ab09SGonglei 
10072858ab09SGonglei     return 0;
10082858ab09SGonglei }
10092858ab09SGonglei 
101044b1ff31SDr. David Alan Gilbert static int ps2_mouse_pre_save(void *opaque)
10112858ab09SGonglei {
10122858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
10132858ab09SGonglei     PS2State *ps2 = &s->common;
10142858ab09SGonglei 
10152858ab09SGonglei     ps2_common_post_load(ps2);
101644b1ff31SDr. David Alan Gilbert 
101744b1ff31SDr. David Alan Gilbert     return 0;
10182858ab09SGonglei }
10192858ab09SGonglei 
1020b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
1021b31442c3SJuan Quintela     .name = "ps2mouse",
1022b31442c3SJuan Quintela     .version_id = 2,
1023b31442c3SJuan Quintela     .minimum_version_id = 2,
10242858ab09SGonglei     .post_load = ps2_mouse_post_load,
10252858ab09SGonglei     .pre_save = ps2_mouse_pre_save,
1026b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1027b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
1028b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
1029b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1030b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1031b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1032b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
1033b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1034b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
1035b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
1036b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
1037b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1038b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
1039b31442c3SJuan Quintela     }
1040b31442c3SJuan Quintela };
10410e43e99cSbellard 
104266e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
104366e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
104466e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
104566e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
104666e6536eSGerd Hoffmann };
104766e6536eSGerd Hoffmann 
10480e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
10490e43e99cSbellard {
10507267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
10510e43e99cSbellard 
10525edab03dSDon Koch     trace_ps2_kbd_init(s);
10530e43e99cSbellard     s->common.update_irq = update_irq;
10540e43e99cSbellard     s->common.update_arg = update_arg;
1055e7d93956Saurel32     s->scancode_set = 2;
10560be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
105766e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
105866e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
1059ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
10600e43e99cSbellard     return s;
10610e43e99cSbellard }
10620e43e99cSbellard 
10632a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
10642a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
10652a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
10662a766d29SGerd Hoffmann     .event = ps2_mouse_event,
10672a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
10682a766d29SGerd Hoffmann };
10692a766d29SGerd Hoffmann 
10700e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
10710e43e99cSbellard {
10727267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
10730e43e99cSbellard 
10745edab03dSDon Koch     trace_ps2_mouse_init(s);
10750e43e99cSbellard     s->common.update_irq = update_irq;
10760e43e99cSbellard     s->common.update_arg = update_arg;
10770be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
10782a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
10792a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
1080ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
10810e43e99cSbellard     return s;
10820e43e99cSbellard }
1083