xref: /qemu/hw/input/ps2.c (revision 9e24b2dd77da42bbba39ef5c44c757132017910b)
10e43e99cSbellard /*
20e43e99cSbellard  * QEMU PS/2 keyboard/mouse emulation
30e43e99cSbellard  *
40e43e99cSbellard  * Copyright (c) 2003 Fabrice Bellard
50e43e99cSbellard  *
60e43e99cSbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
70e43e99cSbellard  * of this software and associated documentation files (the "Software"), to deal
80e43e99cSbellard  * in the Software without restriction, including without limitation the rights
90e43e99cSbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100e43e99cSbellard  * copies of the Software, and to permit persons to whom the Software is
110e43e99cSbellard  * furnished to do so, subject to the following conditions:
120e43e99cSbellard  *
130e43e99cSbellard  * The above copyright notice and this permission notice shall be included in
140e43e99cSbellard  * all copies or substantial portions of the Software.
150e43e99cSbellard  *
160e43e99cSbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170e43e99cSbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180e43e99cSbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
190e43e99cSbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200e43e99cSbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210e43e99cSbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
220e43e99cSbellard  * THE SOFTWARE.
230e43e99cSbellard  */
2471e8a915SMarkus Armbruster 
250430891cSPeter Maydell #include "qemu/osdep.h"
26ec044a80SHervé Poussineau #include "qemu/log.h"
270d09e41aSPaolo Bonzini #include "hw/input/ps2.h"
28d6454270SMarkus Armbruster #include "migration/vmstate.h"
2928ecbaeeSPaolo Bonzini #include "ui/console.h"
3066e6536eSGerd Hoffmann #include "ui/input.h"
3171e8a915SMarkus Armbruster #include "sysemu/reset.h"
3254d31236SMarkus Armbruster #include "sysemu/runstate.h"
330e43e99cSbellard 
345edab03dSDon Koch #include "trace.h"
355edab03dSDon Koch 
360e43e99cSbellard /* Keyboard Commands */
370e43e99cSbellard #define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
380e43e99cSbellard #define KBD_CMD_ECHO     	0xEE
39e7d93956Saurel32 #define KBD_CMD_SCANCODE	0xF0	/* Get/set scancode set */
400e43e99cSbellard #define KBD_CMD_GET_ID 	        0xF2	/* get keyboard ID */
410e43e99cSbellard #define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
420e43e99cSbellard #define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
430e43e99cSbellard #define KBD_CMD_RESET_DISABLE	0xF5	/* reset and disable scanning */
440e43e99cSbellard #define KBD_CMD_RESET_ENABLE   	0xF6    /* reset and enable scanning */
450e43e99cSbellard #define KBD_CMD_RESET		0xFF	/* Reset */
46c56b6209SSven Schnelle #define KBD_CMD_SET_MAKE_BREAK  0xFC    /* Set Make and Break mode */
47c56b6209SSven Schnelle #define KBD_CMD_SET_TYPEMATIC   0xFA    /* Set Typematic Make and Break mode */
480e43e99cSbellard 
490e43e99cSbellard /* Keyboard Replies */
500e43e99cSbellard #define KBD_REPLY_POR		0xAA	/* Power on reset */
5135c4d671Saurel32 #define KBD_REPLY_ID		0xAB	/* Keyboard ID */
520e43e99cSbellard #define KBD_REPLY_ACK		0xFA	/* Command ACK */
530e43e99cSbellard #define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
540e43e99cSbellard 
550e43e99cSbellard /* Mouse Commands */
560e43e99cSbellard #define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
570e43e99cSbellard #define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
580e43e99cSbellard #define AUX_SET_RES		0xE8	/* Set resolution */
590e43e99cSbellard #define AUX_GET_SCALE		0xE9	/* Get scaling factor */
600e43e99cSbellard #define AUX_SET_STREAM		0xEA	/* Set stream mode */
610e43e99cSbellard #define AUX_POLL		0xEB	/* Poll */
620e43e99cSbellard #define AUX_RESET_WRAP		0xEC	/* Reset wrap mode */
630e43e99cSbellard #define AUX_SET_WRAP		0xEE	/* Set wrap mode */
640e43e99cSbellard #define AUX_SET_REMOTE		0xF0	/* Set remote mode */
650e43e99cSbellard #define AUX_GET_TYPE		0xF2	/* Get type */
660e43e99cSbellard #define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
670e43e99cSbellard #define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
680e43e99cSbellard #define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
690e43e99cSbellard #define AUX_SET_DEFAULT		0xF6
700e43e99cSbellard #define AUX_RESET		0xFF	/* Reset aux device */
710e43e99cSbellard #define AUX_ACK			0xFA	/* Command byte ACK. */
720e43e99cSbellard 
730e43e99cSbellard #define MOUSE_STATUS_REMOTE     0x40
740e43e99cSbellard #define MOUSE_STATUS_ENABLED    0x20
750e43e99cSbellard #define MOUSE_STATUS_SCALE21    0x10
760e43e99cSbellard 
7747db2432SVolker Rümelin /*
7847db2432SVolker Rümelin  * PS/2 buffer size. Keep 256 bytes for compatibility with
7947db2432SVolker Rümelin  * older QEMU versions.
8047db2432SVolker Rümelin  */
8147db2432SVolker Rümelin #define PS2_BUFFER_SIZE     256
8247db2432SVolker Rümelin #define PS2_QUEUE_SIZE      16  /* Queue size required by PS/2 protocol */
830e43e99cSbellard 
84620775d1SDaniel P. Berrange /* Bits for 'modifiers' field in PS2KbdState */
85620775d1SDaniel P. Berrange #define MOD_CTRL_L  (1 << 0)
86620775d1SDaniel P. Berrange #define MOD_SHIFT_L (1 << 1)
87620775d1SDaniel P. Berrange #define MOD_ALT_L   (1 << 2)
88620775d1SDaniel P. Berrange #define MOD_CTRL_R  (1 << 3)
89620775d1SDaniel P. Berrange #define MOD_SHIFT_R (1 << 4)
90620775d1SDaniel P. Berrange #define MOD_ALT_R   (1 << 5)
91620775d1SDaniel P. Berrange 
920e43e99cSbellard typedef struct {
9347db2432SVolker Rümelin     uint8_t data[PS2_BUFFER_SIZE];
94*9e24b2ddSVolker Rümelin     int rptr, wptr, cwptr, count;
950e43e99cSbellard } PS2Queue;
960e43e99cSbellard 
978498bb8dSGerd Hoffmann struct PS2State {
980e43e99cSbellard     PS2Queue queue;
990e43e99cSbellard     int32_t write_cmd;
1000e43e99cSbellard     void (*update_irq)(void *, int);
1010e43e99cSbellard     void *update_arg;
1028498bb8dSGerd Hoffmann };
1030e43e99cSbellard 
1040e43e99cSbellard typedef struct {
1050e43e99cSbellard     PS2State common;
1060e43e99cSbellard     int scan_enabled;
107f94f5d71Spbrook     int translate;
108e7d93956Saurel32     int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
1097f540ab5SChristophe Fergeau     int ledstate;
11057d5c005SHervé Poussineau     bool need_high_bit;
111620775d1SDaniel P. Berrange     unsigned int modifiers; /* bitmask of MOD_* constants above */
1120e43e99cSbellard } PS2KbdState;
1130e43e99cSbellard 
1140e43e99cSbellard typedef struct {
1150e43e99cSbellard     PS2State common;
1160e43e99cSbellard     uint8_t mouse_status;
1170e43e99cSbellard     uint8_t mouse_resolution;
1180e43e99cSbellard     uint8_t mouse_sample_rate;
1190e43e99cSbellard     uint8_t mouse_wrap;
1200e43e99cSbellard     uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
1210e43e99cSbellard     uint8_t mouse_detect_state;
1220e43e99cSbellard     int mouse_dx; /* current values, needed for 'poll' mode */
1230e43e99cSbellard     int mouse_dy;
1240e43e99cSbellard     int mouse_dz;
1250e43e99cSbellard     uint8_t mouse_buttons;
1260e43e99cSbellard } PS2MouseState;
1270e43e99cSbellard 
12857d5c005SHervé Poussineau static uint8_t translate_table[256] = {
12957d5c005SHervé Poussineau     0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
13057d5c005SHervé Poussineau     0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
13157d5c005SHervé Poussineau     0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
13257d5c005SHervé Poussineau     0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
13357d5c005SHervé Poussineau     0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
13457d5c005SHervé Poussineau     0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
13557d5c005SHervé Poussineau     0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
13657d5c005SHervé Poussineau     0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
13757d5c005SHervé Poussineau     0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
13857d5c005SHervé Poussineau     0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
13957d5c005SHervé Poussineau     0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
14057d5c005SHervé Poussineau     0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
14157d5c005SHervé Poussineau     0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
14257d5c005SHervé Poussineau     0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
14357d5c005SHervé Poussineau     0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
14457d5c005SHervé Poussineau     0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
14557d5c005SHervé Poussineau     0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
14657d5c005SHervé Poussineau     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
14757d5c005SHervé Poussineau     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
14857d5c005SHervé Poussineau     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
14957d5c005SHervé Poussineau     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
15057d5c005SHervé Poussineau     0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
15157d5c005SHervé Poussineau     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
15257d5c005SHervé Poussineau     0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
15357d5c005SHervé Poussineau     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
15457d5c005SHervé Poussineau     0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
15557d5c005SHervé Poussineau     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
15657d5c005SHervé Poussineau     0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
15757d5c005SHervé Poussineau     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
15857d5c005SHervé Poussineau     0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
15957d5c005SHervé Poussineau     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
16057d5c005SHervé Poussineau     0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
16157d5c005SHervé Poussineau };
16257d5c005SHervé Poussineau 
163620775d1SDaniel P. Berrange static unsigned int ps2_modifier_bit(QKeyCode key)
164620775d1SDaniel P. Berrange {
165620775d1SDaniel P. Berrange     switch (key) {
166620775d1SDaniel P. Berrange     case Q_KEY_CODE_CTRL:
167620775d1SDaniel P. Berrange         return MOD_CTRL_L;
168620775d1SDaniel P. Berrange     case Q_KEY_CODE_CTRL_R:
169620775d1SDaniel P. Berrange         return MOD_CTRL_R;
170620775d1SDaniel P. Berrange     case Q_KEY_CODE_SHIFT:
171620775d1SDaniel P. Berrange         return MOD_SHIFT_L;
172620775d1SDaniel P. Berrange     case Q_KEY_CODE_SHIFT_R:
173620775d1SDaniel P. Berrange         return MOD_SHIFT_R;
174620775d1SDaniel P. Berrange     case Q_KEY_CODE_ALT:
175620775d1SDaniel P. Berrange         return MOD_ALT_L;
176620775d1SDaniel P. Berrange     case Q_KEY_CODE_ALT_R:
177620775d1SDaniel P. Berrange         return MOD_ALT_R;
178620775d1SDaniel P. Berrange     default:
179620775d1SDaniel P. Berrange         return 0;
180620775d1SDaniel P. Berrange     }
181620775d1SDaniel P. Berrange }
182620775d1SDaniel P. Berrange 
183954ee55bSGerd Hoffmann static void ps2_reset_queue(PS2State *s)
184954ee55bSGerd Hoffmann {
185954ee55bSGerd Hoffmann     PS2Queue *q = &s->queue;
186954ee55bSGerd Hoffmann 
187954ee55bSGerd Hoffmann     q->rptr = 0;
188954ee55bSGerd Hoffmann     q->wptr = 0;
189*9e24b2ddSVolker Rümelin     q->cwptr = -1;
190954ee55bSGerd Hoffmann     q->count = 0;
191954ee55bSGerd Hoffmann }
192954ee55bSGerd Hoffmann 
1932a6505b0SSven Schnelle int ps2_queue_empty(PS2State *s)
1942a6505b0SSven Schnelle {
1952a6505b0SSven Schnelle     return s->queue.count == 0;
1962a6505b0SSven Schnelle }
1972a6505b0SSven Schnelle 
1987abe7eb2SGeoffrey McRae void ps2_queue_noirq(PS2State *s, int b)
1990e43e99cSbellard {
2000e43e99cSbellard     PS2Queue *q = &s->queue;
2010e43e99cSbellard 
202*9e24b2ddSVolker Rümelin     if (q->count >= PS2_QUEUE_SIZE) {
2030e43e99cSbellard         return;
2047abe7eb2SGeoffrey McRae     }
2057abe7eb2SGeoffrey McRae 
2060e43e99cSbellard     q->data[q->wptr] = b;
20747db2432SVolker Rümelin     if (++q->wptr == PS2_BUFFER_SIZE) {
2080e43e99cSbellard         q->wptr = 0;
20947db2432SVolker Rümelin     }
2100e43e99cSbellard     q->count++;
2117abe7eb2SGeoffrey McRae }
2127abe7eb2SGeoffrey McRae 
2137abe7eb2SGeoffrey McRae void ps2_raise_irq(PS2State *s)
2147abe7eb2SGeoffrey McRae {
2157abe7eb2SGeoffrey McRae     s->update_irq(s->update_arg, 1);
2167abe7eb2SGeoffrey McRae }
2177abe7eb2SGeoffrey McRae 
2187abe7eb2SGeoffrey McRae void ps2_queue(PS2State *s, int b)
2197abe7eb2SGeoffrey McRae {
2207704bb02SVolker Rümelin     if (PS2_QUEUE_SIZE - s->queue.count < 1) {
2217704bb02SVolker Rümelin         return;
2227704bb02SVolker Rümelin     }
2237704bb02SVolker Rümelin 
2247abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b);
22596376ab1SPhilippe Mathieu-Daudé     ps2_raise_irq(s);
2267abe7eb2SGeoffrey McRae }
2277abe7eb2SGeoffrey McRae 
2287abe7eb2SGeoffrey McRae void ps2_queue_2(PS2State *s, int b1, int b2)
2297abe7eb2SGeoffrey McRae {
2307abe7eb2SGeoffrey McRae     if (PS2_QUEUE_SIZE - s->queue.count < 2) {
2317abe7eb2SGeoffrey McRae         return;
2327abe7eb2SGeoffrey McRae     }
2337abe7eb2SGeoffrey McRae 
2347abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b1);
2357abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b2);
23696376ab1SPhilippe Mathieu-Daudé     ps2_raise_irq(s);
2377abe7eb2SGeoffrey McRae }
2387abe7eb2SGeoffrey McRae 
2397abe7eb2SGeoffrey McRae void ps2_queue_3(PS2State *s, int b1, int b2, int b3)
2407abe7eb2SGeoffrey McRae {
2417abe7eb2SGeoffrey McRae     if (PS2_QUEUE_SIZE - s->queue.count < 3) {
2427abe7eb2SGeoffrey McRae         return;
2437abe7eb2SGeoffrey McRae     }
2447abe7eb2SGeoffrey McRae 
2457abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b1);
2467abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b2);
2477abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b3);
24896376ab1SPhilippe Mathieu-Daudé     ps2_raise_irq(s);
2497abe7eb2SGeoffrey McRae }
2507abe7eb2SGeoffrey McRae 
2517abe7eb2SGeoffrey McRae void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4)
2527abe7eb2SGeoffrey McRae {
2537abe7eb2SGeoffrey McRae     if (PS2_QUEUE_SIZE - s->queue.count < 4) {
2547abe7eb2SGeoffrey McRae         return;
2557abe7eb2SGeoffrey McRae     }
2567abe7eb2SGeoffrey McRae 
2577abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b1);
2587abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b2);
2597abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b3);
2607abe7eb2SGeoffrey McRae     ps2_queue_noirq(s, b4);
26196376ab1SPhilippe Mathieu-Daudé     ps2_raise_irq(s);
2620e43e99cSbellard }
2630e43e99cSbellard 
264*9e24b2ddSVolker Rümelin static void ps2_cqueue_data(PS2Queue *q, int b)
265*9e24b2ddSVolker Rümelin {
266*9e24b2ddSVolker Rümelin     q->data[q->cwptr] = b;
267*9e24b2ddSVolker Rümelin     if (++q->cwptr >= PS2_BUFFER_SIZE) {
268*9e24b2ddSVolker Rümelin         q->cwptr = 0;
269*9e24b2ddSVolker Rümelin     }
270*9e24b2ddSVolker Rümelin     q->count++;
271*9e24b2ddSVolker Rümelin }
272*9e24b2ddSVolker Rümelin 
273*9e24b2ddSVolker Rümelin static void ps2_cqueue_1(PS2State *s, int b1)
274*9e24b2ddSVolker Rümelin {
275*9e24b2ddSVolker Rümelin     PS2Queue *q = &s->queue;
276*9e24b2ddSVolker Rümelin 
277*9e24b2ddSVolker Rümelin     q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1);
278*9e24b2ddSVolker Rümelin     q->cwptr = q->rptr;
279*9e24b2ddSVolker Rümelin     ps2_cqueue_data(q, b1);
280*9e24b2ddSVolker Rümelin     ps2_raise_irq(s);
281*9e24b2ddSVolker Rümelin }
282*9e24b2ddSVolker Rümelin 
283*9e24b2ddSVolker Rümelin static void ps2_cqueue_2(PS2State *s, int b1, int b2)
284*9e24b2ddSVolker Rümelin {
285*9e24b2ddSVolker Rümelin     PS2Queue *q = &s->queue;
286*9e24b2ddSVolker Rümelin 
287*9e24b2ddSVolker Rümelin     q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1);
288*9e24b2ddSVolker Rümelin     q->cwptr = q->rptr;
289*9e24b2ddSVolker Rümelin     ps2_cqueue_data(q, b1);
290*9e24b2ddSVolker Rümelin     ps2_cqueue_data(q, b2);
291*9e24b2ddSVolker Rümelin     ps2_raise_irq(s);
292*9e24b2ddSVolker Rümelin }
293*9e24b2ddSVolker Rümelin 
294*9e24b2ddSVolker Rümelin static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3)
295*9e24b2ddSVolker Rümelin {
296*9e24b2ddSVolker Rümelin     PS2Queue *q = &s->queue;
297*9e24b2ddSVolker Rümelin 
298*9e24b2ddSVolker Rümelin     q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1);
299*9e24b2ddSVolker Rümelin     q->cwptr = q->rptr;
300*9e24b2ddSVolker Rümelin     ps2_cqueue_data(q, b1);
301*9e24b2ddSVolker Rümelin     ps2_cqueue_data(q, b2);
302*9e24b2ddSVolker Rümelin     ps2_cqueue_data(q, b3);
303*9e24b2ddSVolker Rümelin     ps2_raise_irq(s);
304*9e24b2ddSVolker Rümelin }
305*9e24b2ddSVolker Rümelin 
306*9e24b2ddSVolker Rümelin static void ps2_cqueue_reset(PS2State *s)
307*9e24b2ddSVolker Rümelin {
308*9e24b2ddSVolker Rümelin     PS2Queue *q = &s->queue;
309*9e24b2ddSVolker Rümelin     int ccount;
310*9e24b2ddSVolker Rümelin 
311*9e24b2ddSVolker Rümelin     if (q->cwptr == -1) {
312*9e24b2ddSVolker Rümelin         return;
313*9e24b2ddSVolker Rümelin     }
314*9e24b2ddSVolker Rümelin 
315*9e24b2ddSVolker Rümelin     ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
316*9e24b2ddSVolker Rümelin     q->count -= ccount;
317*9e24b2ddSVolker Rümelin     q->rptr = q->cwptr;
318*9e24b2ddSVolker Rümelin     q->cwptr = -1;
319*9e24b2ddSVolker Rümelin }
320*9e24b2ddSVolker Rümelin 
32157d5c005SHervé Poussineau /* keycode is the untranslated scancode in the current scancode set. */
3220e43e99cSbellard static void ps2_put_keycode(void *opaque, int keycode)
3230e43e99cSbellard {
324f94f5d71Spbrook     PS2KbdState *s = opaque;
325e7d93956Saurel32 
3265edab03dSDon Koch     trace_ps2_put_keycode(opaque, keycode);
327fb064112SDaniel Henrique Barboza     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
32857d5c005SHervé Poussineau 
32957d5c005SHervé Poussineau     if (s->translate) {
33057d5c005SHervé Poussineau         if (keycode == 0xf0) {
33157d5c005SHervé Poussineau             s->need_high_bit = true;
33257d5c005SHervé Poussineau         } else if (s->need_high_bit) {
33357d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode] | 0x80);
33457d5c005SHervé Poussineau             s->need_high_bit = false;
33557d5c005SHervé Poussineau         } else {
33657d5c005SHervé Poussineau             ps2_queue(&s->common, translate_table[keycode]);
3377096a96dSRoy Tam         }
33857d5c005SHervé Poussineau     } else {
3390e43e99cSbellard         ps2_queue(&s->common, keycode);
3400e43e99cSbellard     }
34157d5c005SHervé Poussineau }
3420e43e99cSbellard 
34366e6536eSGerd Hoffmann static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
34466e6536eSGerd Hoffmann                                InputEvent *evt)
34566e6536eSGerd Hoffmann {
34666e6536eSGerd Hoffmann     PS2KbdState *s = (PS2KbdState *)dev;
34732bafa8fSEric Blake     InputKeyEvent *key = evt->u.key.data;
3488c10e0baSHervé Poussineau     int qcode;
349ab8f9d49SDaniel P. Berrange     uint16_t keycode = 0;
350620775d1SDaniel P. Berrange     int mod;
35166e6536eSGerd Hoffmann 
352143c04c7SGeoffrey McRae     /* do not process events while disabled to prevent stream corruption */
353143c04c7SGeoffrey McRae     if (!s->scan_enabled) {
354143c04c7SGeoffrey McRae         return;
355143c04c7SGeoffrey McRae     }
356143c04c7SGeoffrey McRae 
357fb064112SDaniel Henrique Barboza     qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
3588c10e0baSHervé Poussineau     assert(evt->type == INPUT_EVENT_KIND_KEY);
3598c10e0baSHervé Poussineau     qcode = qemu_input_key_value_to_qcode(key->key);
36057d5c005SHervé Poussineau 
361620775d1SDaniel P. Berrange     mod = ps2_modifier_bit(qcode);
362644f66bfSDaniel P. Berrangé     trace_ps2_keyboard_event(s, qcode, key->down, mod,
363644f66bfSDaniel P. Berrangé                              s->modifiers, s->scancode_set, s->translate);
364620775d1SDaniel P. Berrange     if (key->down) {
365620775d1SDaniel P. Berrange         s->modifiers |= mod;
366620775d1SDaniel P. Berrange     } else {
367620775d1SDaniel P. Berrange         s->modifiers &= ~mod;
368620775d1SDaniel P. Berrange     }
369620775d1SDaniel P. Berrange 
3708c10e0baSHervé Poussineau     if (s->scancode_set == 1) {
3718c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
37229fd23a5SDaniel P. Berrange             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
37329fd23a5SDaniel P. Berrange                 if (key->down) {
37429fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
37529fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0x46);
37629fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
37729fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xc6);
37829fd23a5SDaniel P. Berrange                 }
37929fd23a5SDaniel P. Berrange             } else {
3808c10e0baSHervé Poussineau                 if (key->down) {
3818c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe1);
3828c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x1d);
3838c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x45);
384927f0425SDaniel P. Berrange                     ps2_put_keycode(s, 0xe1);
3858c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x9d);
3868c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xc5);
3878c10e0baSHervé Poussineau                 }
38829fd23a5SDaniel P. Berrange             }
3898c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
390620775d1SDaniel P. Berrange             if (s->modifiers & MOD_ALT_L) {
391620775d1SDaniel P. Berrange                 if (key->down) {
392620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
393620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
394620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x54);
395620775d1SDaniel P. Berrange                 } else {
396620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xd4);
397620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
398620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
399620775d1SDaniel P. Berrange                 }
400620775d1SDaniel P. Berrange             } else if (s->modifiers & MOD_ALT_R) {
401620775d1SDaniel P. Berrange                 if (key->down) {
402620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
403620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
404620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
405620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
406620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x54);
407620775d1SDaniel P. Berrange                 } else {
408620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xd4);
409620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
410620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xb8);
411620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
412620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x38);
413620775d1SDaniel P. Berrange                 }
4148f63458fSDaniel P. Berrange             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
4158f63458fSDaniel P. Berrange                                        MOD_SHIFT_R | MOD_CTRL_R)) {
4168f63458fSDaniel P. Berrange                 if (key->down) {
4178f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
4188f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x37);
4198f63458fSDaniel P. Berrange                 } else {
4208f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
4218f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xb7);
4228f63458fSDaniel P. Berrange                 }
423620775d1SDaniel P. Berrange             } else {
4248c10e0baSHervé Poussineau                 if (key->down) {
4258c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4268c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x2a);
4278c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4288c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x37);
4298c10e0baSHervé Poussineau                 } else {
4308c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4318c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xb7);
4328c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
4338c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xaa);
4348c10e0baSHervé Poussineau                 }
435620775d1SDaniel P. Berrange             }
4368c10e0baSHervé Poussineau         } else {
437ab8f9d49SDaniel P. Berrange             if (qcode < qemu_input_map_qcode_to_atset1_len)
438ab8f9d49SDaniel P. Berrange                 keycode = qemu_input_map_qcode_to_atset1[qcode];
4398c10e0baSHervé Poussineau             if (keycode) {
4408c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
4418c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
4428c10e0baSHervé Poussineau                 }
4438c10e0baSHervé Poussineau                 if (!key->down) {
4448c10e0baSHervé Poussineau                     keycode |= 0x80;
4458c10e0baSHervé Poussineau                 }
4468c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
4478c10e0baSHervé Poussineau             } else {
448ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
449ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
4508c10e0baSHervé Poussineau             }
4518c10e0baSHervé Poussineau         }
4528c10e0baSHervé Poussineau     } else if (s->scancode_set == 2) {
4538c10e0baSHervé Poussineau         if (qcode == Q_KEY_CODE_PAUSE) {
45429fd23a5SDaniel P. Berrange             if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
45529fd23a5SDaniel P. Berrange                 if (key->down) {
45629fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
45729fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0x7e);
45829fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
45929fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
46029fd23a5SDaniel P. Berrange                     ps2_put_keycode(s, 0x7e);
46129fd23a5SDaniel P. Berrange                 }
46229fd23a5SDaniel P. Berrange             } else {
4638c10e0baSHervé Poussineau                 if (key->down) {
4648c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe1);
4658c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x14);
4668c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x77);
4678c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe1);
4688c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
4698c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x14);
4708c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
4718c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x77);
4728c10e0baSHervé Poussineau                 }
47329fd23a5SDaniel P. Berrange             }
4748c10e0baSHervé Poussineau         } else if (qcode == Q_KEY_CODE_PRINT) {
475620775d1SDaniel P. Berrange             if (s->modifiers & MOD_ALT_L) {
476620775d1SDaniel P. Berrange                 if (key->down) {
477620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
478620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
479620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
480620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
481620775d1SDaniel P. Berrange                 } else {
482620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
483620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
484620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
485620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
486620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
487620775d1SDaniel P. Berrange                 }
488620775d1SDaniel P. Berrange             } else if (s->modifiers & MOD_ALT_R) {
489620775d1SDaniel P. Berrange                 if (key->down) {
490620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
491620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
492620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
493620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
494620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
495620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
496620775d1SDaniel P. Berrange                 } else {
497620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
498620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x84);
499620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
500620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
501620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
502620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
503620775d1SDaniel P. Berrange                     ps2_put_keycode(s, 0x11);
504620775d1SDaniel P. Berrange                 }
5058f63458fSDaniel P. Berrange             } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
5068f63458fSDaniel P. Berrange                                        MOD_SHIFT_R | MOD_CTRL_R)) {
5078f63458fSDaniel P. Berrange                 if (key->down) {
5088f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
5098f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x7c);
5108f63458fSDaniel P. Berrange                 } else {
5118f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xe0);
5128f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0xf0);
5138f63458fSDaniel P. Berrange                     ps2_put_keycode(s, 0x7c);
5148f63458fSDaniel P. Berrange                 }
515620775d1SDaniel P. Berrange             } else {
5168c10e0baSHervé Poussineau                 if (key->down) {
5178c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
5188c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x12);
5198c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
5208c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x7c);
5218c10e0baSHervé Poussineau                 } else {
5228c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
5238c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
5248c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x7c);
5258c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xe0);
5268c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
5278c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0x12);
5288c10e0baSHervé Poussineau                 }
529620775d1SDaniel P. Berrange             }
5308c10e0baSHervé Poussineau         } else {
531ab8f9d49SDaniel P. Berrange             if (qcode < qemu_input_map_qcode_to_atset2_len)
532ab8f9d49SDaniel P. Berrange                 keycode = qemu_input_map_qcode_to_atset2[qcode];
5338c10e0baSHervé Poussineau             if (keycode) {
5348c10e0baSHervé Poussineau                 if (keycode & 0xff00) {
5358c10e0baSHervé Poussineau                     ps2_put_keycode(s, keycode >> 8);
5368c10e0baSHervé Poussineau                 }
5378c10e0baSHervé Poussineau                 if (!key->down) {
5388c10e0baSHervé Poussineau                     ps2_put_keycode(s, 0xf0);
5398c10e0baSHervé Poussineau                 }
5408c10e0baSHervé Poussineau                 ps2_put_keycode(s, keycode & 0xff);
54157d5c005SHervé Poussineau             } else {
542ec044a80SHervé Poussineau                 qemu_log_mask(LOG_UNIMP,
543ec044a80SHervé Poussineau                               "ps2: ignoring key with qcode %d\n", qcode);
54457d5c005SHervé Poussineau             }
54557d5c005SHervé Poussineau         }
54657d5c005SHervé Poussineau     } else if (s->scancode_set == 3) {
547ab8f9d49SDaniel P. Berrange         if (qcode < qemu_input_map_qcode_to_atset3_len)
548ab8f9d49SDaniel P. Berrange             keycode = qemu_input_map_qcode_to_atset3[qcode];
5498c10e0baSHervé Poussineau         if (keycode) {
5508c10e0baSHervé Poussineau             /* FIXME: break code should be configured on a key by key basis */
5518c10e0baSHervé Poussineau             if (!key->down) {
5528c10e0baSHervé Poussineau                 ps2_put_keycode(s, 0xf0);
55357d5c005SHervé Poussineau             }
55457d5c005SHervé Poussineau             ps2_put_keycode(s, keycode);
5558c10e0baSHervé Poussineau         } else {
556ec044a80SHervé Poussineau             qemu_log_mask(LOG_UNIMP,
557ec044a80SHervé Poussineau                           "ps2: ignoring key with qcode %d\n", qcode);
5588c10e0baSHervé Poussineau         }
55966e6536eSGerd Hoffmann     }
56066e6536eSGerd Hoffmann }
56166e6536eSGerd Hoffmann 
5628498bb8dSGerd Hoffmann uint32_t ps2_read_data(PS2State *s)
5630e43e99cSbellard {
5640e43e99cSbellard     PS2Queue *q;
5650e43e99cSbellard     int val, index;
5660e43e99cSbellard 
5678498bb8dSGerd Hoffmann     trace_ps2_read_data(s);
5680e43e99cSbellard     q = &s->queue;
5690e43e99cSbellard     if (q->count == 0) {
5700e43e99cSbellard         /* NOTE: if no data left, we return the last keyboard one
5710e43e99cSbellard            (needed for EMM386) */
5720e43e99cSbellard         /* XXX: need a timer to do things correctly */
5730e43e99cSbellard         index = q->rptr - 1;
57447db2432SVolker Rümelin         if (index < 0) {
57547db2432SVolker Rümelin             index = PS2_BUFFER_SIZE - 1;
57647db2432SVolker Rümelin         }
5770e43e99cSbellard         val = q->data[index];
5780e43e99cSbellard     } else {
5790e43e99cSbellard         val = q->data[q->rptr];
58047db2432SVolker Rümelin         if (++q->rptr == PS2_BUFFER_SIZE) {
5810e43e99cSbellard             q->rptr = 0;
58247db2432SVolker Rümelin         }
5830e43e99cSbellard         q->count--;
584*9e24b2ddSVolker Rümelin         if (q->rptr == q->cwptr) {
585*9e24b2ddSVolker Rümelin             /* command reply queue is empty */
586*9e24b2ddSVolker Rümelin             q->cwptr = -1;
587*9e24b2ddSVolker Rümelin         }
5880e43e99cSbellard         /* reading deasserts IRQ */
5890e43e99cSbellard         s->update_irq(s->update_arg, 0);
5900e43e99cSbellard         /* reassert IRQs if data left */
591cec32524SVolker Rümelin         if (q->count) {
592cec32524SVolker Rümelin             s->update_irq(s->update_arg, 1);
593cec32524SVolker Rümelin         }
5940e43e99cSbellard     }
5950e43e99cSbellard     return val;
5960e43e99cSbellard }
5970e43e99cSbellard 
5987f540ab5SChristophe Fergeau static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
5997f540ab5SChristophe Fergeau {
6005edab03dSDon Koch     trace_ps2_set_ledstate(s, ledstate);
6017f540ab5SChristophe Fergeau     s->ledstate = ledstate;
6027f540ab5SChristophe Fergeau     kbd_put_ledstate(ledstate);
6037f540ab5SChristophe Fergeau }
6047f540ab5SChristophe Fergeau 
6050e43e99cSbellard static void ps2_reset_keyboard(PS2KbdState *s)
6060e43e99cSbellard {
6075edab03dSDon Koch     trace_ps2_reset_keyboard(s);
6080e43e99cSbellard     s->scan_enabled = 1;
609e7d93956Saurel32     s->scancode_set = 2;
6106e24ee0cSGerd Hoffmann     ps2_reset_queue(&s->common);
6117f540ab5SChristophe Fergeau     ps2_set_ledstate(s, 0);
6120e43e99cSbellard }
6130e43e99cSbellard 
6140e43e99cSbellard void ps2_write_keyboard(void *opaque, int val)
6150e43e99cSbellard {
6160e43e99cSbellard     PS2KbdState *s = (PS2KbdState *)opaque;
6170e43e99cSbellard 
6185edab03dSDon Koch     trace_ps2_write_keyboard(opaque, val);
619*9e24b2ddSVolker Rümelin     ps2_cqueue_reset(&s->common);
6200e43e99cSbellard     switch(s->common.write_cmd) {
6210e43e99cSbellard     default:
6220e43e99cSbellard     case -1:
6230e43e99cSbellard         switch(val) {
6240e43e99cSbellard         case 0x00:
625*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6260e43e99cSbellard             break;
6270e43e99cSbellard         case 0x05:
628*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
6290e43e99cSbellard             break;
6300e43e99cSbellard         case KBD_CMD_GET_ID:
631e7d93956Saurel32             /* We emulate a MF2 AT keyboard here */
632*9e24b2ddSVolker Rümelin             ps2_cqueue_3(&s->common, KBD_REPLY_ACK, KBD_REPLY_ID,
633*9e24b2ddSVolker Rümelin                 s->translate ? 0x41 : 0x83);
6340e43e99cSbellard             break;
6350e43e99cSbellard         case KBD_CMD_ECHO:
636*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_CMD_ECHO);
6370e43e99cSbellard             break;
6380e43e99cSbellard         case KBD_CMD_ENABLE:
6390e43e99cSbellard             s->scan_enabled = 1;
640*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6410e43e99cSbellard             break;
642e7d93956Saurel32         case KBD_CMD_SCANCODE:
6430e43e99cSbellard         case KBD_CMD_SET_LEDS:
6440e43e99cSbellard         case KBD_CMD_SET_RATE:
645c56b6209SSven Schnelle         case KBD_CMD_SET_MAKE_BREAK:
6460e43e99cSbellard             s->common.write_cmd = val;
647*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6480e43e99cSbellard             break;
6490e43e99cSbellard         case KBD_CMD_RESET_DISABLE:
6500e43e99cSbellard             ps2_reset_keyboard(s);
6510e43e99cSbellard             s->scan_enabled = 0;
652*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6530e43e99cSbellard             break;
6540e43e99cSbellard         case KBD_CMD_RESET_ENABLE:
6550e43e99cSbellard             ps2_reset_keyboard(s);
6560e43e99cSbellard             s->scan_enabled = 1;
657*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6580e43e99cSbellard             break;
6590e43e99cSbellard         case KBD_CMD_RESET:
6600e43e99cSbellard             ps2_reset_keyboard(s);
661*9e24b2ddSVolker Rümelin             ps2_cqueue_2(&s->common,
6627abe7eb2SGeoffrey McRae                 KBD_REPLY_ACK,
6637abe7eb2SGeoffrey McRae                 KBD_REPLY_POR);
6640e43e99cSbellard             break;
665c56b6209SSven Schnelle         case KBD_CMD_SET_TYPEMATIC:
666*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
667c56b6209SSven Schnelle             break;
6680e43e99cSbellard         default:
669*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
6700e43e99cSbellard             break;
6710e43e99cSbellard         }
6720e43e99cSbellard         break;
673c56b6209SSven Schnelle     case KBD_CMD_SET_MAKE_BREAK:
674*9e24b2ddSVolker Rümelin         ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
675c56b6209SSven Schnelle         s->common.write_cmd = -1;
676c56b6209SSven Schnelle         break;
677e7d93956Saurel32     case KBD_CMD_SCANCODE:
678e7d93956Saurel32         if (val == 0) {
679*9e24b2ddSVolker Rümelin             ps2_cqueue_2(&s->common, KBD_REPLY_ACK, s->translate ?
680*9e24b2ddSVolker Rümelin                 translate_table[s->scancode_set] : s->scancode_set);
6814df23b64SHervé Poussineau         } else if (val >= 1 && val <= 3) {
682e7d93956Saurel32             s->scancode_set = val;
683*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6844df23b64SHervé Poussineau         } else {
685*9e24b2ddSVolker Rümelin             ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
686e7d93956Saurel32         }
687e7d93956Saurel32         s->common.write_cmd = -1;
688e7d93956Saurel32         break;
6890e43e99cSbellard     case KBD_CMD_SET_LEDS:
6907f540ab5SChristophe Fergeau         ps2_set_ledstate(s, val);
691*9e24b2ddSVolker Rümelin         ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6920e43e99cSbellard         s->common.write_cmd = -1;
6930e43e99cSbellard         break;
6940e43e99cSbellard     case KBD_CMD_SET_RATE:
695*9e24b2ddSVolker Rümelin         ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
6960e43e99cSbellard         s->common.write_cmd = -1;
6970e43e99cSbellard         break;
6980e43e99cSbellard     }
6990e43e99cSbellard }
7000e43e99cSbellard 
701f94f5d71Spbrook /* Set the scancode translation mode.
702f94f5d71Spbrook    0 = raw scancodes.
703f94f5d71Spbrook    1 = translated scancodes (used by qemu internally).  */
704f94f5d71Spbrook 
705f94f5d71Spbrook void ps2_keyboard_set_translation(void *opaque, int mode)
706f94f5d71Spbrook {
707f94f5d71Spbrook     PS2KbdState *s = (PS2KbdState *)opaque;
7085edab03dSDon Koch     trace_ps2_keyboard_set_translation(opaque, mode);
709f94f5d71Spbrook     s->translate = mode;
710f94f5d71Spbrook }
711f94f5d71Spbrook 
7127abe7eb2SGeoffrey McRae static int ps2_mouse_send_packet(PS2MouseState *s)
7130e43e99cSbellard {
71476968101SVolker Rümelin     /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */
71576968101SVolker Rümelin     const int needed = s->mouse_type ? 4 : 3;
7160e43e99cSbellard     unsigned int b;
7170e43e99cSbellard     int dx1, dy1, dz1;
7180e43e99cSbellard 
7197abe7eb2SGeoffrey McRae     if (PS2_QUEUE_SIZE - s->common.queue.count < needed) {
7207abe7eb2SGeoffrey McRae         return 0;
7217abe7eb2SGeoffrey McRae     }
7227abe7eb2SGeoffrey McRae 
7230e43e99cSbellard     dx1 = s->mouse_dx;
7240e43e99cSbellard     dy1 = s->mouse_dy;
7250e43e99cSbellard     dz1 = s->mouse_dz;
7260e43e99cSbellard     /* XXX: increase range to 8 bits ? */
7270e43e99cSbellard     if (dx1 > 127)
7280e43e99cSbellard         dx1 = 127;
7290e43e99cSbellard     else if (dx1 < -127)
7300e43e99cSbellard         dx1 = -127;
7310e43e99cSbellard     if (dy1 > 127)
7320e43e99cSbellard         dy1 = 127;
7330e43e99cSbellard     else if (dy1 < -127)
7340e43e99cSbellard         dy1 = -127;
7350e43e99cSbellard     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
7367abe7eb2SGeoffrey McRae     ps2_queue_noirq(&s->common, b);
7377abe7eb2SGeoffrey McRae     ps2_queue_noirq(&s->common, dx1 & 0xff);
7387abe7eb2SGeoffrey McRae     ps2_queue_noirq(&s->common, dy1 & 0xff);
7390e43e99cSbellard     /* extra byte for IMPS/2 or IMEX */
7400e43e99cSbellard     switch(s->mouse_type) {
7410e43e99cSbellard     default:
7420e43e99cSbellard         break;
7430e43e99cSbellard     case 3:
7440e43e99cSbellard         if (dz1 > 127)
7450e43e99cSbellard             dz1 = 127;
7460e43e99cSbellard         else if (dz1 < -127)
7470e43e99cSbellard                 dz1 = -127;
7487abe7eb2SGeoffrey McRae         ps2_queue_noirq(&s->common, dz1 & 0xff);
7490e43e99cSbellard         break;
7500e43e99cSbellard     case 4:
7510e43e99cSbellard         if (dz1 > 7)
7520e43e99cSbellard             dz1 = 7;
7530e43e99cSbellard         else if (dz1 < -7)
7540e43e99cSbellard             dz1 = -7;
7550e43e99cSbellard         b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
7567abe7eb2SGeoffrey McRae         ps2_queue_noirq(&s->common, b);
7570e43e99cSbellard         break;
7580e43e99cSbellard     }
7590e43e99cSbellard 
7607abe7eb2SGeoffrey McRae     ps2_raise_irq(&s->common);
7617abe7eb2SGeoffrey McRae 
7625edab03dSDon Koch     trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
7630e43e99cSbellard     /* update deltas */
7640e43e99cSbellard     s->mouse_dx -= dx1;
7650e43e99cSbellard     s->mouse_dy -= dy1;
7660e43e99cSbellard     s->mouse_dz -= dz1;
7677abe7eb2SGeoffrey McRae 
7687abe7eb2SGeoffrey McRae     return 1;
7690e43e99cSbellard }
7700e43e99cSbellard 
7712a766d29SGerd Hoffmann static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
7722a766d29SGerd Hoffmann                             InputEvent *evt)
7730e43e99cSbellard {
7747fb1cf16SEric Blake     static const int bmap[INPUT_BUTTON__MAX] = {
7758b0caab0SFabian Lesniak         [INPUT_BUTTON_LEFT]   = PS2_MOUSE_BUTTON_LEFT,
7768b0caab0SFabian Lesniak         [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
7778b0caab0SFabian Lesniak         [INPUT_BUTTON_RIGHT]  = PS2_MOUSE_BUTTON_RIGHT,
7788b0caab0SFabian Lesniak         [INPUT_BUTTON_SIDE]   = PS2_MOUSE_BUTTON_SIDE,
7798b0caab0SFabian Lesniak         [INPUT_BUTTON_EXTRA]  = PS2_MOUSE_BUTTON_EXTRA,
7802a766d29SGerd Hoffmann     };
7812a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
782b5a1b443SEric Blake     InputMoveEvent *move;
783b5a1b443SEric Blake     InputBtnEvent *btn;
7840e43e99cSbellard 
7850e43e99cSbellard     /* check if deltas are recorded when disabled */
7860e43e99cSbellard     if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
7870e43e99cSbellard         return;
7880e43e99cSbellard 
789568c73a4SEric Blake     switch (evt->type) {
7902a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
79132bafa8fSEric Blake         move = evt->u.rel.data;
792b5a1b443SEric Blake         if (move->axis == INPUT_AXIS_X) {
793b5a1b443SEric Blake             s->mouse_dx += move->value;
794b5a1b443SEric Blake         } else if (move->axis == INPUT_AXIS_Y) {
795b5a1b443SEric Blake             s->mouse_dy -= move->value;
7962a766d29SGerd Hoffmann         }
7972a766d29SGerd Hoffmann         break;
7980e43e99cSbellard 
7992a766d29SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
80032bafa8fSEric Blake         btn = evt->u.btn.data;
801b5a1b443SEric Blake         if (btn->down) {
802b5a1b443SEric Blake             s->mouse_buttons |= bmap[btn->button];
803b5a1b443SEric Blake             if (btn->button == INPUT_BUTTON_WHEEL_UP) {
8042a766d29SGerd Hoffmann                 s->mouse_dz--;
805b5a1b443SEric Blake             } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
8062a766d29SGerd Hoffmann                 s->mouse_dz++;
8072a766d29SGerd Hoffmann             }
8082a766d29SGerd Hoffmann         } else {
809b5a1b443SEric Blake             s->mouse_buttons &= ~bmap[btn->button];
8102a766d29SGerd Hoffmann         }
8112a766d29SGerd Hoffmann         break;
8122a766d29SGerd Hoffmann 
8132a766d29SGerd Hoffmann     default:
8142a766d29SGerd Hoffmann         /* keep gcc happy */
8152a766d29SGerd Hoffmann         break;
8162a766d29SGerd Hoffmann     }
817fd214d18SGerd Hoffmann }
818fd214d18SGerd Hoffmann 
8192a766d29SGerd Hoffmann static void ps2_mouse_sync(DeviceState *dev)
8202a766d29SGerd Hoffmann {
8212a766d29SGerd Hoffmann     PS2MouseState *s = (PS2MouseState *)dev;
8222a766d29SGerd Hoffmann 
823143c04c7SGeoffrey McRae     /* do not sync while disabled to prevent stream corruption */
824143c04c7SGeoffrey McRae     if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
825143c04c7SGeoffrey McRae         return;
826143c04c7SGeoffrey McRae     }
827143c04c7SGeoffrey McRae 
8282a766d29SGerd Hoffmann     if (s->mouse_buttons) {
829fb064112SDaniel Henrique Barboza         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
8302a766d29SGerd Hoffmann     }
8312858ab09SGonglei     if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
8320e43e99cSbellard         /* if not remote, send event. Multiple events are sent if
8330e43e99cSbellard            too big deltas */
8347abe7eb2SGeoffrey McRae         while (ps2_mouse_send_packet(s)) {
8350e43e99cSbellard             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
8360e43e99cSbellard                 break;
8370e43e99cSbellard         }
8380e43e99cSbellard     }
8390e43e99cSbellard }
8400e43e99cSbellard 
841548df2acSths void ps2_mouse_fake_event(void *opaque)
842548df2acSths {
8432a766d29SGerd Hoffmann     PS2MouseState *s = opaque;
8445edab03dSDon Koch     trace_ps2_mouse_fake_event(opaque);
8452a766d29SGerd Hoffmann     s->mouse_dx++;
8462a766d29SGerd Hoffmann     ps2_mouse_sync(opaque);
847548df2acSths }
848548df2acSths 
8490e43e99cSbellard void ps2_write_mouse(void *opaque, int val)
8500e43e99cSbellard {
8510e43e99cSbellard     PS2MouseState *s = (PS2MouseState *)opaque;
8525edab03dSDon Koch 
8535edab03dSDon Koch     trace_ps2_write_mouse(opaque, val);
8540e43e99cSbellard     switch(s->common.write_cmd) {
8550e43e99cSbellard     default:
8560e43e99cSbellard     case -1:
8570e43e99cSbellard         /* mouse command */
8580e43e99cSbellard         if (s->mouse_wrap) {
8590e43e99cSbellard             if (val == AUX_RESET_WRAP) {
8600e43e99cSbellard                 s->mouse_wrap = 0;
8610e43e99cSbellard                 ps2_queue(&s->common, AUX_ACK);
8620e43e99cSbellard                 return;
8630e43e99cSbellard             } else if (val != AUX_RESET) {
8640e43e99cSbellard                 ps2_queue(&s->common, val);
8650e43e99cSbellard                 return;
8660e43e99cSbellard             }
8670e43e99cSbellard         }
8680e43e99cSbellard         switch(val) {
8690e43e99cSbellard         case AUX_SET_SCALE11:
8700e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_SCALE21;
8710e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
8720e43e99cSbellard             break;
8730e43e99cSbellard         case AUX_SET_SCALE21:
8740e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_SCALE21;
8750e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
8760e43e99cSbellard             break;
8770e43e99cSbellard         case AUX_SET_STREAM:
8780e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_REMOTE;
8790e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
8800e43e99cSbellard             break;
8810e43e99cSbellard         case AUX_SET_WRAP:
8820e43e99cSbellard             s->mouse_wrap = 1;
8830e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
8840e43e99cSbellard             break;
8850e43e99cSbellard         case AUX_SET_REMOTE:
8860e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_REMOTE;
8870e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
8880e43e99cSbellard             break;
8890e43e99cSbellard         case AUX_GET_TYPE:
8907abe7eb2SGeoffrey McRae             ps2_queue_2(&s->common,
8917abe7eb2SGeoffrey McRae                 AUX_ACK,
8927abe7eb2SGeoffrey McRae                 s->mouse_type);
8930e43e99cSbellard             break;
8940e43e99cSbellard         case AUX_SET_RES:
8950e43e99cSbellard         case AUX_SET_SAMPLE:
8960e43e99cSbellard             s->common.write_cmd = val;
8970e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
8980e43e99cSbellard             break;
8990e43e99cSbellard         case AUX_GET_SCALE:
9007abe7eb2SGeoffrey McRae             ps2_queue_4(&s->common,
9017abe7eb2SGeoffrey McRae                 AUX_ACK,
9027abe7eb2SGeoffrey McRae                 s->mouse_status,
9037abe7eb2SGeoffrey McRae                 s->mouse_resolution,
9047abe7eb2SGeoffrey McRae                 s->mouse_sample_rate);
9050e43e99cSbellard             break;
9060e43e99cSbellard         case AUX_POLL:
9070e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9080e43e99cSbellard             ps2_mouse_send_packet(s);
9090e43e99cSbellard             break;
9100e43e99cSbellard         case AUX_ENABLE_DEV:
9110e43e99cSbellard             s->mouse_status |= MOUSE_STATUS_ENABLED;
9120e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9130e43e99cSbellard             break;
9140e43e99cSbellard         case AUX_DISABLE_DEV:
9150e43e99cSbellard             s->mouse_status &= ~MOUSE_STATUS_ENABLED;
9160e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9170e43e99cSbellard             break;
9180e43e99cSbellard         case AUX_SET_DEFAULT:
9190e43e99cSbellard             s->mouse_sample_rate = 100;
9200e43e99cSbellard             s->mouse_resolution = 2;
9210e43e99cSbellard             s->mouse_status = 0;
9220e43e99cSbellard             ps2_queue(&s->common, AUX_ACK);
9230e43e99cSbellard             break;
9240e43e99cSbellard         case AUX_RESET:
9250e43e99cSbellard             s->mouse_sample_rate = 100;
9260e43e99cSbellard             s->mouse_resolution = 2;
9270e43e99cSbellard             s->mouse_status = 0;
9280e43e99cSbellard             s->mouse_type = 0;
929143c04c7SGeoffrey McRae             ps2_reset_queue(&s->common);
9307abe7eb2SGeoffrey McRae             ps2_queue_3(&s->common,
9317abe7eb2SGeoffrey McRae                 AUX_ACK,
9327abe7eb2SGeoffrey McRae                 0xaa,
9337abe7eb2SGeoffrey McRae                 s->mouse_type);
9340e43e99cSbellard             break;
9350e43e99cSbellard         default:
9360e43e99cSbellard             break;
9370e43e99cSbellard         }
9380e43e99cSbellard         break;
9390e43e99cSbellard     case AUX_SET_SAMPLE:
9400e43e99cSbellard         s->mouse_sample_rate = val;
9410e43e99cSbellard         /* detect IMPS/2 or IMEX */
9420e43e99cSbellard         switch(s->mouse_detect_state) {
9430e43e99cSbellard         default:
9440e43e99cSbellard         case 0:
9450e43e99cSbellard             if (val == 200)
9460e43e99cSbellard                 s->mouse_detect_state = 1;
9470e43e99cSbellard             break;
9480e43e99cSbellard         case 1:
9490e43e99cSbellard             if (val == 100)
9500e43e99cSbellard                 s->mouse_detect_state = 2;
9510e43e99cSbellard             else if (val == 200)
9520e43e99cSbellard                 s->mouse_detect_state = 3;
9530e43e99cSbellard             else
9540e43e99cSbellard                 s->mouse_detect_state = 0;
9550e43e99cSbellard             break;
9560e43e99cSbellard         case 2:
9570e43e99cSbellard             if (val == 80)
9580e43e99cSbellard                 s->mouse_type = 3; /* IMPS/2 */
9590e43e99cSbellard             s->mouse_detect_state = 0;
9600e43e99cSbellard             break;
9610e43e99cSbellard         case 3:
9620e43e99cSbellard             if (val == 80)
9630e43e99cSbellard                 s->mouse_type = 4; /* IMEX */
9640e43e99cSbellard             s->mouse_detect_state = 0;
9650e43e99cSbellard             break;
9660e43e99cSbellard         }
9670e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
9680e43e99cSbellard         s->common.write_cmd = -1;
9690e43e99cSbellard         break;
9700e43e99cSbellard     case AUX_SET_RES:
9710e43e99cSbellard         s->mouse_resolution = val;
9720e43e99cSbellard         ps2_queue(&s->common, AUX_ACK);
9730e43e99cSbellard         s->common.write_cmd = -1;
9740e43e99cSbellard         break;
9750e43e99cSbellard     }
9760e43e99cSbellard }
9770e43e99cSbellard 
978ef74679aSDinesh Subhraveti static void ps2_common_reset(PS2State *s)
9790e43e99cSbellard {
9800e43e99cSbellard     s->write_cmd = -1;
981954ee55bSGerd Hoffmann     ps2_reset_queue(s);
982deeccef3Saliguori     s->update_irq(s->update_arg, 0);
9830e43e99cSbellard }
9840e43e99cSbellard 
9852858ab09SGonglei static void ps2_common_post_load(PS2State *s)
9862858ab09SGonglei {
9872858ab09SGonglei     PS2Queue *q = &s->queue;
9882858ab09SGonglei 
98947db2432SVolker Rümelin     /* set the useful data buffer queue size <= PS2_QUEUE_SIZE */
990a1f2ed2aSPavel Dovgalyuk     if (q->count < 0) {
99147db2432SVolker Rümelin         q->count = 0;
992a1f2ed2aSPavel Dovgalyuk     } else if (q->count > PS2_QUEUE_SIZE) {
99347db2432SVolker Rümelin         q->count = PS2_QUEUE_SIZE;
994a1f2ed2aSPavel Dovgalyuk     }
9952858ab09SGonglei 
99647db2432SVolker Rümelin     /* sanitize rptr and recalculate wptr */
99747db2432SVolker Rümelin     q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1);
99847db2432SVolker Rümelin     q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1);
9992858ab09SGonglei }
10002858ab09SGonglei 
1001ef74679aSDinesh Subhraveti static void ps2_kbd_reset(void *opaque)
1002ef74679aSDinesh Subhraveti {
1003ef74679aSDinesh Subhraveti     PS2KbdState *s = (PS2KbdState *) opaque;
1004ef74679aSDinesh Subhraveti 
10055edab03dSDon Koch     trace_ps2_kbd_reset(opaque);
1006ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
1007d2e550a8SHervé Poussineau     s->scan_enabled = 1;
1008ef74679aSDinesh Subhraveti     s->translate = 0;
1009089adafdSHervé Poussineau     s->scancode_set = 2;
1010620775d1SDaniel P. Berrange     s->modifiers = 0;
1011ef74679aSDinesh Subhraveti }
1012ef74679aSDinesh Subhraveti 
1013ef74679aSDinesh Subhraveti static void ps2_mouse_reset(void *opaque)
1014ef74679aSDinesh Subhraveti {
1015ef74679aSDinesh Subhraveti     PS2MouseState *s = (PS2MouseState *) opaque;
1016ef74679aSDinesh Subhraveti 
10175edab03dSDon Koch     trace_ps2_mouse_reset(opaque);
1018ef74679aSDinesh Subhraveti     ps2_common_reset(&s->common);
1019ef74679aSDinesh Subhraveti     s->mouse_status = 0;
1020ef74679aSDinesh Subhraveti     s->mouse_resolution = 0;
1021ef74679aSDinesh Subhraveti     s->mouse_sample_rate = 0;
1022ef74679aSDinesh Subhraveti     s->mouse_wrap = 0;
1023ef74679aSDinesh Subhraveti     s->mouse_type = 0;
1024ef74679aSDinesh Subhraveti     s->mouse_detect_state = 0;
1025ef74679aSDinesh Subhraveti     s->mouse_dx = 0;
1026ef74679aSDinesh Subhraveti     s->mouse_dy = 0;
1027ef74679aSDinesh Subhraveti     s->mouse_dz = 0;
1028ef74679aSDinesh Subhraveti     s->mouse_buttons = 0;
1029ef74679aSDinesh Subhraveti }
1030ef74679aSDinesh Subhraveti 
1031b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_common = {
1032b31442c3SJuan Quintela     .name = "PS2 Common State",
1033b31442c3SJuan Quintela     .version_id = 3,
1034b31442c3SJuan Quintela     .minimum_version_id = 2,
1035b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1036b31442c3SJuan Quintela         VMSTATE_INT32(write_cmd, PS2State),
1037b31442c3SJuan Quintela         VMSTATE_INT32(queue.rptr, PS2State),
1038b31442c3SJuan Quintela         VMSTATE_INT32(queue.wptr, PS2State),
1039b31442c3SJuan Quintela         VMSTATE_INT32(queue.count, PS2State),
1040b31442c3SJuan Quintela         VMSTATE_BUFFER(queue.data, PS2State),
1041b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
10427783e9f0Spbrook     }
1043b31442c3SJuan Quintela };
10447783e9f0Spbrook 
10457f540ab5SChristophe Fergeau static bool ps2_keyboard_ledstate_needed(void *opaque)
10467f540ab5SChristophe Fergeau {
10477f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
10487f540ab5SChristophe Fergeau 
10497f540ab5SChristophe Fergeau     return s->ledstate != 0; /* 0 is default state */
10507f540ab5SChristophe Fergeau }
10517f540ab5SChristophe Fergeau 
10527f540ab5SChristophe Fergeau static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
10537f540ab5SChristophe Fergeau {
10547f540ab5SChristophe Fergeau     PS2KbdState *s = opaque;
10557f540ab5SChristophe Fergeau 
10567f540ab5SChristophe Fergeau     kbd_put_ledstate(s->ledstate);
10577f540ab5SChristophe Fergeau     return 0;
10587f540ab5SChristophe Fergeau }
10597f540ab5SChristophe Fergeau 
10607f540ab5SChristophe Fergeau static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
10617f540ab5SChristophe Fergeau     .name = "ps2kbd/ledstate",
10627f540ab5SChristophe Fergeau     .version_id = 3,
10637f540ab5SChristophe Fergeau     .minimum_version_id = 2,
10647f540ab5SChristophe Fergeau     .post_load = ps2_kbd_ledstate_post_load,
10655cd8cadaSJuan Quintela     .needed = ps2_keyboard_ledstate_needed,
10667f540ab5SChristophe Fergeau     .fields = (VMStateField[]) {
10677f540ab5SChristophe Fergeau         VMSTATE_INT32(ledstate, PS2KbdState),
10687f540ab5SChristophe Fergeau         VMSTATE_END_OF_LIST()
10697f540ab5SChristophe Fergeau     }
10707f540ab5SChristophe Fergeau };
10717f540ab5SChristophe Fergeau 
107257d5c005SHervé Poussineau static bool ps2_keyboard_need_high_bit_needed(void *opaque)
107357d5c005SHervé Poussineau {
107457d5c005SHervé Poussineau     PS2KbdState *s = opaque;
107557d5c005SHervé Poussineau     return s->need_high_bit != 0; /* 0 is the usual state */
107657d5c005SHervé Poussineau }
107757d5c005SHervé Poussineau 
107857d5c005SHervé Poussineau static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
107957d5c005SHervé Poussineau     .name = "ps2kbd/need_high_bit",
108057d5c005SHervé Poussineau     .version_id = 1,
108157d5c005SHervé Poussineau     .minimum_version_id = 1,
108257d5c005SHervé Poussineau     .needed = ps2_keyboard_need_high_bit_needed,
108357d5c005SHervé Poussineau     .fields = (VMStateField[]) {
108457d5c005SHervé Poussineau         VMSTATE_BOOL(need_high_bit, PS2KbdState),
108557d5c005SHervé Poussineau         VMSTATE_END_OF_LIST()
108657d5c005SHervé Poussineau     }
108757d5c005SHervé Poussineau };
108857d5c005SHervé Poussineau 
1089db596c53SJuan Quintela static int ps2_kbd_post_load(void* opaque, int version_id)
10900e43e99cSbellard {
10910e43e99cSbellard     PS2KbdState *s = (PS2KbdState*)opaque;
10922858ab09SGonglei     PS2State *ps2 = &s->common;
10930e43e99cSbellard 
1094db596c53SJuan Quintela     if (version_id == 2)
1095e7d93956Saurel32         s->scancode_set=2;
10962858ab09SGonglei 
10972858ab09SGonglei     ps2_common_post_load(ps2);
10982858ab09SGonglei 
10990e43e99cSbellard     return 0;
11000e43e99cSbellard }
11010e43e99cSbellard 
1102b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_keyboard = {
1103b31442c3SJuan Quintela     .name = "ps2kbd",
1104b31442c3SJuan Quintela     .version_id = 3,
1105db596c53SJuan Quintela     .minimum_version_id = 2,
1106db596c53SJuan Quintela     .post_load = ps2_kbd_post_load,
1107b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1108b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
1109b31442c3SJuan Quintela         VMSTATE_INT32(scan_enabled, PS2KbdState),
1110b31442c3SJuan Quintela         VMSTATE_INT32(translate, PS2KbdState),
1111b31442c3SJuan Quintela         VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
1112b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
11137f540ab5SChristophe Fergeau     },
11145cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
11155cd8cadaSJuan Quintela         &vmstate_ps2_keyboard_ledstate,
111657d5c005SHervé Poussineau         &vmstate_ps2_keyboard_need_high_bit,
11175cd8cadaSJuan Quintela         NULL
11180e43e99cSbellard     }
1119b31442c3SJuan Quintela };
1120b31442c3SJuan Quintela 
11212858ab09SGonglei static int ps2_mouse_post_load(void *opaque, int version_id)
11222858ab09SGonglei {
11232858ab09SGonglei     PS2MouseState *s = (PS2MouseState *)opaque;
11242858ab09SGonglei     PS2State *ps2 = &s->common;
11252858ab09SGonglei 
11262858ab09SGonglei     ps2_common_post_load(ps2);
11272858ab09SGonglei 
11282858ab09SGonglei     return 0;
11292858ab09SGonglei }
11302858ab09SGonglei 
1131b31442c3SJuan Quintela static const VMStateDescription vmstate_ps2_mouse = {
1132b31442c3SJuan Quintela     .name = "ps2mouse",
1133b31442c3SJuan Quintela     .version_id = 2,
1134b31442c3SJuan Quintela     .minimum_version_id = 2,
11352858ab09SGonglei     .post_load = ps2_mouse_post_load,
1136b31442c3SJuan Quintela     .fields = (VMStateField[]) {
1137b31442c3SJuan Quintela         VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
1138b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_status, PS2MouseState),
1139b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1140b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1141b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1142b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_type, PS2MouseState),
1143b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1144b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dx, PS2MouseState),
1145b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dy, PS2MouseState),
1146b31442c3SJuan Quintela         VMSTATE_INT32(mouse_dz, PS2MouseState),
1147b31442c3SJuan Quintela         VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1148b31442c3SJuan Quintela         VMSTATE_END_OF_LIST()
1149b31442c3SJuan Quintela     }
1150b31442c3SJuan Quintela };
11510e43e99cSbellard 
115266e6536eSGerd Hoffmann static QemuInputHandler ps2_keyboard_handler = {
115366e6536eSGerd Hoffmann     .name  = "QEMU PS/2 Keyboard",
115466e6536eSGerd Hoffmann     .mask  = INPUT_EVENT_MASK_KEY,
115566e6536eSGerd Hoffmann     .event = ps2_keyboard_event,
115666e6536eSGerd Hoffmann };
115766e6536eSGerd Hoffmann 
11580e43e99cSbellard void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
11590e43e99cSbellard {
11607267c094SAnthony Liguori     PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
11610e43e99cSbellard 
11625edab03dSDon Koch     trace_ps2_kbd_init(s);
11630e43e99cSbellard     s->common.update_irq = update_irq;
11640e43e99cSbellard     s->common.update_arg = update_arg;
1165e7d93956Saurel32     s->scancode_set = 2;
11660be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
116766e6536eSGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
116866e6536eSGerd Hoffmann                                 &ps2_keyboard_handler);
1169ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_kbd_reset, s);
11700e43e99cSbellard     return s;
11710e43e99cSbellard }
11720e43e99cSbellard 
11732a766d29SGerd Hoffmann static QemuInputHandler ps2_mouse_handler = {
11742a766d29SGerd Hoffmann     .name  = "QEMU PS/2 Mouse",
11752a766d29SGerd Hoffmann     .mask  = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
11762a766d29SGerd Hoffmann     .event = ps2_mouse_event,
11772a766d29SGerd Hoffmann     .sync  = ps2_mouse_sync,
11782a766d29SGerd Hoffmann };
11792a766d29SGerd Hoffmann 
11800e43e99cSbellard void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
11810e43e99cSbellard {
11827267c094SAnthony Liguori     PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
11830e43e99cSbellard 
11845edab03dSDon Koch     trace_ps2_mouse_init(s);
11850e43e99cSbellard     s->common.update_irq = update_irq;
11860e43e99cSbellard     s->common.update_arg = update_arg;
11870be71e32SAlex Williamson     vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
11882a766d29SGerd Hoffmann     qemu_input_handler_register((DeviceState *)s,
11892a766d29SGerd Hoffmann                                 &ps2_mouse_handler);
1190ef74679aSDinesh Subhraveti     qemu_register_reset(ps2_mouse_reset, s);
11910e43e99cSbellard     return s;
11920e43e99cSbellard }
1193