blob: 00b695a0b9758f1b36286b44972173f68c9ea2dc [file] [log] [blame]
bellard0e43e992005-11-26 10:36:25 +00001/*
2 * QEMU PS/2 keyboard/mouse emulation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard0e43e992005-11-26 10:36:25 +00004 * Copyright (c) 2003 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellard0e43e992005-11-26 10:36:25 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
Markus Armbruster71e8a912019-08-12 07:23:38 +020024
Peter Maydell04308912016-01-26 18:17:30 +000025#include "qemu/osdep.h"
Hervé Poussineauec044a82016-09-15 22:06:27 +020026#include "qemu/log.h"
Mark Cave-Ayland6beb79e2022-06-24 14:40:49 +010027#include "hw/irq.h"
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +010028#include "hw/sysbus.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010029#include "hw/input/ps2.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020030#include "migration/vmstate.h"
Paolo Bonzini28ecbae2012-11-28 12:06:30 +010031#include "ui/console.h"
Gerd Hoffmann66e65362014-03-13 12:39:38 +010032#include "ui/input.h"
Markus Armbruster71e8a912019-08-12 07:23:38 +020033#include "sysemu/reset.h"
Markus Armbruster54d31232019-08-12 07:23:59 +020034#include "sysemu/runstate.h"
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +010035#include "qapi/error.h"
bellard0e43e992005-11-26 10:36:25 +000036
Don Koch5edab032015-01-16 14:21:37 -050037#include "trace.h"
38
bellard0e43e992005-11-26 10:36:25 +000039/* Keyboard Commands */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +010040#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
41#define KBD_CMD_ECHO 0xEE
42#define KBD_CMD_SCANCODE 0xF0 /* Get/set scancode set */
43#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
44#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
45#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
46#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
47#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
48#define KBD_CMD_RESET 0xFF /* Reset */
Sven Schnellec56b6202019-12-20 22:15:09 +010049#define KBD_CMD_SET_MAKE_BREAK 0xFC /* Set Make and Break mode */
50#define KBD_CMD_SET_TYPEMATIC 0xFA /* Set Typematic Make and Break mode */
bellard0e43e992005-11-26 10:36:25 +000051
52/* Keyboard Replies */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +010053#define KBD_REPLY_POR 0xAA /* Power on reset */
54#define KBD_REPLY_ID 0xAB /* Keyboard ID */
55#define KBD_REPLY_ACK 0xFA /* Command ACK */
56#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
bellard0e43e992005-11-26 10:36:25 +000057
58/* Mouse Commands */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +010059#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
60#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
61#define AUX_SET_RES 0xE8 /* Set resolution */
62#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
63#define AUX_SET_STREAM 0xEA /* Set stream mode */
64#define AUX_POLL 0xEB /* Poll */
65#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
66#define AUX_SET_WRAP 0xEE /* Set wrap mode */
67#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
68#define AUX_GET_TYPE 0xF2 /* Get type */
69#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
70#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
71#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
72#define AUX_SET_DEFAULT 0xF6
73#define AUX_RESET 0xFF /* Reset aux device */
74#define AUX_ACK 0xFA /* Command byte ACK. */
bellard0e43e992005-11-26 10:36:25 +000075
76#define MOUSE_STATUS_REMOTE 0x40
77#define MOUSE_STATUS_ENABLED 0x20
78#define MOUSE_STATUS_SCALE21 0x10
79
Volker Rümelin47db2432021-08-10 15:32:56 +020080#define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */
Volker Rümelin4e9bddc2021-08-10 15:32:58 +020081#define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */
bellard0e43e992005-11-26 10:36:25 +000082
Daniel P. Berrange620775d2017-10-19 15:28:43 +010083/* Bits for 'modifiers' field in PS2KbdState */
84#define MOD_CTRL_L (1 << 0)
85#define MOD_SHIFT_L (1 << 1)
86#define MOD_ALT_L (1 << 2)
87#define MOD_CTRL_R (1 << 3)
88#define MOD_SHIFT_R (1 << 4)
89#define MOD_ALT_R (1 << 5)
90
Hervé Poussineau57d5c002016-09-15 22:06:25 +020091static uint8_t translate_table[256] = {
92 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
93 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
94 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
95 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
96 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
97 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
98 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
99 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
100 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
101 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
102 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
103 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
104 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
105 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
106 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
107 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
108 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
109 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
110 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
111 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
112 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
113 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
114 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
115 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
116 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
117 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
118 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
119 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
120 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
121 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
122 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
123 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
124};
125
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100126static unsigned int ps2_modifier_bit(QKeyCode key)
127{
128 switch (key) {
129 case Q_KEY_CODE_CTRL:
130 return MOD_CTRL_L;
131 case Q_KEY_CODE_CTRL_R:
132 return MOD_CTRL_R;
133 case Q_KEY_CODE_SHIFT:
134 return MOD_SHIFT_L;
135 case Q_KEY_CODE_SHIFT_R:
136 return MOD_SHIFT_R;
137 case Q_KEY_CODE_ALT:
138 return MOD_ALT_L;
139 case Q_KEY_CODE_ALT_R:
140 return MOD_ALT_R;
141 default:
142 return 0;
143 }
144}
145
Gerd Hoffmann954ee552017-06-06 13:21:04 +0200146static void ps2_reset_queue(PS2State *s)
147{
148 PS2Queue *q = &s->queue;
149
150 q->rptr = 0;
151 q->wptr = 0;
Volker Rümelin9e24b2d2021-08-10 15:32:57 +0200152 q->cwptr = -1;
Gerd Hoffmann954ee552017-06-06 13:21:04 +0200153 q->count = 0;
154}
155
Sven Schnelle2a6505b2019-12-20 22:15:10 +0100156int ps2_queue_empty(PS2State *s)
157{
158 return s->queue.count == 0;
159}
160
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000161void ps2_queue_noirq(PS2State *s, int b)
bellard0e43e992005-11-26 10:36:25 +0000162{
bellard0e43e992005-11-26 10:36:25 +0000163 PS2Queue *q = &s->queue;
164
Volker Rümelin9e24b2d2021-08-10 15:32:57 +0200165 if (q->count >= PS2_QUEUE_SIZE) {
bellard0e43e992005-11-26 10:36:25 +0000166 return;
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000167 }
168
bellard0e43e992005-11-26 10:36:25 +0000169 q->data[q->wptr] = b;
Volker Rümelin47db2432021-08-10 15:32:56 +0200170 if (++q->wptr == PS2_BUFFER_SIZE) {
bellard0e43e992005-11-26 10:36:25 +0000171 q->wptr = 0;
Volker Rümelin47db2432021-08-10 15:32:56 +0200172 }
bellard0e43e992005-11-26 10:36:25 +0000173 q->count++;
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000174}
175
Mark Cave-Ayland52b28f72022-06-24 14:40:46 +0100176static void ps2_raise_irq(PS2State *s)
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000177{
Mark Cave-Ayland7227de92022-06-24 14:41:09 +0100178 qemu_set_irq(s->irq, 1);
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000179}
180
Mark Cave-Ayland5cb6e552022-06-24 14:40:48 +0100181static void ps2_lower_irq(PS2State *s)
182{
Mark Cave-Ayland7227de92022-06-24 14:41:09 +0100183 qemu_set_irq(s->irq, 0);
Mark Cave-Ayland5cb6e552022-06-24 14:40:48 +0100184}
185
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000186void ps2_queue(PS2State *s, int b)
187{
Volker Rümelin7704bb02021-05-25 20:14:31 +0200188 if (PS2_QUEUE_SIZE - s->queue.count < 1) {
189 return;
190 }
191
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000192 ps2_queue_noirq(s, b);
Philippe Mathieu-Daudé96376ab2021-05-13 19:12:44 +0200193 ps2_raise_irq(s);
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000194}
195
196void ps2_queue_2(PS2State *s, int b1, int b2)
197{
198 if (PS2_QUEUE_SIZE - s->queue.count < 2) {
199 return;
200 }
201
202 ps2_queue_noirq(s, b1);
203 ps2_queue_noirq(s, b2);
Philippe Mathieu-Daudé96376ab2021-05-13 19:12:44 +0200204 ps2_raise_irq(s);
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000205}
206
207void ps2_queue_3(PS2State *s, int b1, int b2, int b3)
208{
209 if (PS2_QUEUE_SIZE - s->queue.count < 3) {
210 return;
211 }
212
213 ps2_queue_noirq(s, b1);
214 ps2_queue_noirq(s, b2);
215 ps2_queue_noirq(s, b3);
Philippe Mathieu-Daudé96376ab2021-05-13 19:12:44 +0200216 ps2_raise_irq(s);
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000217}
218
219void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4)
220{
221 if (PS2_QUEUE_SIZE - s->queue.count < 4) {
222 return;
223 }
224
225 ps2_queue_noirq(s, b1);
226 ps2_queue_noirq(s, b2);
227 ps2_queue_noirq(s, b3);
228 ps2_queue_noirq(s, b4);
Philippe Mathieu-Daudé96376ab2021-05-13 19:12:44 +0200229 ps2_raise_irq(s);
bellard0e43e992005-11-26 10:36:25 +0000230}
231
Volker Rümelin9e24b2d2021-08-10 15:32:57 +0200232static void ps2_cqueue_data(PS2Queue *q, int b)
233{
234 q->data[q->cwptr] = b;
235 if (++q->cwptr >= PS2_BUFFER_SIZE) {
236 q->cwptr = 0;
237 }
238 q->count++;
239}
240
241static void ps2_cqueue_1(PS2State *s, int b1)
242{
243 PS2Queue *q = &s->queue;
244
245 q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1);
246 q->cwptr = q->rptr;
247 ps2_cqueue_data(q, b1);
248 ps2_raise_irq(s);
249}
250
251static void ps2_cqueue_2(PS2State *s, int b1, int b2)
252{
253 PS2Queue *q = &s->queue;
254
255 q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1);
256 q->cwptr = q->rptr;
257 ps2_cqueue_data(q, b1);
258 ps2_cqueue_data(q, b2);
259 ps2_raise_irq(s);
260}
261
262static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3)
263{
264 PS2Queue *q = &s->queue;
265
266 q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1);
267 q->cwptr = q->rptr;
268 ps2_cqueue_data(q, b1);
269 ps2_cqueue_data(q, b2);
270 ps2_cqueue_data(q, b3);
271 ps2_raise_irq(s);
272}
273
274static void ps2_cqueue_reset(PS2State *s)
275{
276 PS2Queue *q = &s->queue;
277 int ccount;
278
279 if (q->cwptr == -1) {
280 return;
281 }
282
283 ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
284 q->count -= ccount;
285 q->rptr = q->cwptr;
286 q->cwptr = -1;
287}
288
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200289/* keycode is the untranslated scancode in the current scancode set. */
bellard0e43e992005-11-26 10:36:25 +0000290static void ps2_put_keycode(void *opaque, int keycode)
291{
pbrookf94f5d72006-02-08 04:42:17 +0000292 PS2KbdState *s = opaque;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100293 PS2State *ps = PS2_DEVICE(s);
aurel32e7d93952008-03-18 06:54:34 +0000294
Don Koch5edab032015-01-16 14:21:37 -0500295 trace_ps2_put_keycode(opaque, keycode);
Daniel Henrique Barbozafb064112018-12-05 17:47:01 -0200296 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200297
298 if (s->translate) {
299 if (keycode == 0xf0) {
300 s->need_high_bit = true;
301 } else if (s->need_high_bit) {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100302 ps2_queue(ps, translate_table[keycode] | 0x80);
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200303 s->need_high_bit = false;
304 } else {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100305 ps2_queue(ps, translate_table[keycode]);
Roy Tam7096a962011-02-21 08:06:32 +0800306 }
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200307 } else {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100308 ps2_queue(ps, keycode);
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200309 }
bellard0e43e992005-11-26 10:36:25 +0000310}
311
Gerd Hoffmann66e65362014-03-13 12:39:38 +0100312static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
313 InputEvent *evt)
314{
315 PS2KbdState *s = (PS2KbdState *)dev;
Eric Blake32bafa82016-03-17 16:48:37 -0600316 InputKeyEvent *key = evt->u.key.data;
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200317 int qcode;
Daniel P. Berrangeab8f9d42018-01-17 16:41:15 +0000318 uint16_t keycode = 0;
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100319 int mod;
Gerd Hoffmann66e65362014-03-13 12:39:38 +0100320
Geoffrey McRae143c04c2018-05-07 23:01:46 +1000321 /* do not process events while disabled to prevent stream corruption */
322 if (!s->scan_enabled) {
323 return;
324 }
325
Daniel Henrique Barbozafb064112018-12-05 17:47:01 -0200326 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200327 assert(evt->type == INPUT_EVENT_KIND_KEY);
328 qcode = qemu_input_key_value_to_qcode(key->key);
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200329
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100330 mod = ps2_modifier_bit(qcode);
Daniel P. Berrangé644f66b2021-03-09 15:58:04 +0000331 trace_ps2_keyboard_event(s, qcode, key->down, mod,
332 s->modifiers, s->scancode_set, s->translate);
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100333 if (key->down) {
334 s->modifiers |= mod;
335 } else {
336 s->modifiers &= ~mod;
337 }
338
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200339 if (s->scancode_set == 1) {
340 if (qcode == Q_KEY_CODE_PAUSE) {
Daniel P. Berrange29fd23a2017-10-19 15:28:46 +0100341 if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
342 if (key->down) {
343 ps2_put_keycode(s, 0xe0);
344 ps2_put_keycode(s, 0x46);
345 ps2_put_keycode(s, 0xe0);
346 ps2_put_keycode(s, 0xc6);
347 }
348 } else {
349 if (key->down) {
350 ps2_put_keycode(s, 0xe1);
351 ps2_put_keycode(s, 0x1d);
352 ps2_put_keycode(s, 0x45);
353 ps2_put_keycode(s, 0xe1);
354 ps2_put_keycode(s, 0x9d);
355 ps2_put_keycode(s, 0xc5);
356 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200357 }
358 } else if (qcode == Q_KEY_CODE_PRINT) {
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100359 if (s->modifiers & MOD_ALT_L) {
360 if (key->down) {
361 ps2_put_keycode(s, 0xb8);
362 ps2_put_keycode(s, 0x38);
363 ps2_put_keycode(s, 0x54);
364 } else {
365 ps2_put_keycode(s, 0xd4);
366 ps2_put_keycode(s, 0xb8);
367 ps2_put_keycode(s, 0x38);
368 }
369 } else if (s->modifiers & MOD_ALT_R) {
370 if (key->down) {
371 ps2_put_keycode(s, 0xe0);
372 ps2_put_keycode(s, 0xb8);
373 ps2_put_keycode(s, 0xe0);
374 ps2_put_keycode(s, 0x38);
375 ps2_put_keycode(s, 0x54);
376 } else {
377 ps2_put_keycode(s, 0xd4);
378 ps2_put_keycode(s, 0xe0);
379 ps2_put_keycode(s, 0xb8);
380 ps2_put_keycode(s, 0xe0);
381 ps2_put_keycode(s, 0x38);
382 }
Daniel P. Berrange8f634582017-10-19 15:28:44 +0100383 } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
384 MOD_SHIFT_R | MOD_CTRL_R)) {
385 if (key->down) {
386 ps2_put_keycode(s, 0xe0);
387 ps2_put_keycode(s, 0x37);
388 } else {
389 ps2_put_keycode(s, 0xe0);
390 ps2_put_keycode(s, 0xb7);
391 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200392 } else {
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100393 if (key->down) {
394 ps2_put_keycode(s, 0xe0);
395 ps2_put_keycode(s, 0x2a);
396 ps2_put_keycode(s, 0xe0);
397 ps2_put_keycode(s, 0x37);
398 } else {
399 ps2_put_keycode(s, 0xe0);
400 ps2_put_keycode(s, 0xb7);
401 ps2_put_keycode(s, 0xe0);
402 ps2_put_keycode(s, 0xaa);
403 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200404 }
Ross Lagerwall92f4a212023-02-27 17:33:08 +0000405 } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2)
406 && !key->down) {
407 /* Ignore release for these keys */
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200408 } else {
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100409 if (qcode < qemu_input_map_qcode_to_atset1_len) {
Daniel P. Berrangeab8f9d42018-01-17 16:41:15 +0000410 keycode = qemu_input_map_qcode_to_atset1[qcode];
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100411 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200412 if (keycode) {
413 if (keycode & 0xff00) {
414 ps2_put_keycode(s, keycode >> 8);
415 }
416 if (!key->down) {
417 keycode |= 0x80;
418 }
419 ps2_put_keycode(s, keycode & 0xff);
420 } else {
Hervé Poussineauec044a82016-09-15 22:06:27 +0200421 qemu_log_mask(LOG_UNIMP,
422 "ps2: ignoring key with qcode %d\n", qcode);
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200423 }
424 }
425 } else if (s->scancode_set == 2) {
426 if (qcode == Q_KEY_CODE_PAUSE) {
Daniel P. Berrange29fd23a2017-10-19 15:28:46 +0100427 if (s->modifiers & (MOD_CTRL_L | MOD_CTRL_R)) {
428 if (key->down) {
429 ps2_put_keycode(s, 0xe0);
430 ps2_put_keycode(s, 0x7e);
431 ps2_put_keycode(s, 0xe0);
432 ps2_put_keycode(s, 0xf0);
433 ps2_put_keycode(s, 0x7e);
434 }
435 } else {
436 if (key->down) {
437 ps2_put_keycode(s, 0xe1);
438 ps2_put_keycode(s, 0x14);
439 ps2_put_keycode(s, 0x77);
440 ps2_put_keycode(s, 0xe1);
441 ps2_put_keycode(s, 0xf0);
442 ps2_put_keycode(s, 0x14);
443 ps2_put_keycode(s, 0xf0);
444 ps2_put_keycode(s, 0x77);
445 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200446 }
447 } else if (qcode == Q_KEY_CODE_PRINT) {
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100448 if (s->modifiers & MOD_ALT_L) {
449 if (key->down) {
450 ps2_put_keycode(s, 0xf0);
451 ps2_put_keycode(s, 0x11);
452 ps2_put_keycode(s, 0x11);
453 ps2_put_keycode(s, 0x84);
454 } else {
455 ps2_put_keycode(s, 0xf0);
456 ps2_put_keycode(s, 0x84);
457 ps2_put_keycode(s, 0xf0);
458 ps2_put_keycode(s, 0x11);
459 ps2_put_keycode(s, 0x11);
460 }
461 } else if (s->modifiers & MOD_ALT_R) {
462 if (key->down) {
463 ps2_put_keycode(s, 0xe0);
464 ps2_put_keycode(s, 0xf0);
465 ps2_put_keycode(s, 0x11);
466 ps2_put_keycode(s, 0xe0);
467 ps2_put_keycode(s, 0x11);
468 ps2_put_keycode(s, 0x84);
469 } else {
470 ps2_put_keycode(s, 0xf0);
471 ps2_put_keycode(s, 0x84);
472 ps2_put_keycode(s, 0xe0);
473 ps2_put_keycode(s, 0xf0);
474 ps2_put_keycode(s, 0x11);
475 ps2_put_keycode(s, 0xe0);
476 ps2_put_keycode(s, 0x11);
477 }
Daniel P. Berrange8f634582017-10-19 15:28:44 +0100478 } else if (s->modifiers & (MOD_SHIFT_L | MOD_CTRL_L |
479 MOD_SHIFT_R | MOD_CTRL_R)) {
480 if (key->down) {
481 ps2_put_keycode(s, 0xe0);
482 ps2_put_keycode(s, 0x7c);
483 } else {
484 ps2_put_keycode(s, 0xe0);
485 ps2_put_keycode(s, 0xf0);
486 ps2_put_keycode(s, 0x7c);
487 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200488 } else {
Daniel P. Berrange620775d2017-10-19 15:28:43 +0100489 if (key->down) {
490 ps2_put_keycode(s, 0xe0);
491 ps2_put_keycode(s, 0x12);
492 ps2_put_keycode(s, 0xe0);
493 ps2_put_keycode(s, 0x7c);
494 } else {
495 ps2_put_keycode(s, 0xe0);
496 ps2_put_keycode(s, 0xf0);
497 ps2_put_keycode(s, 0x7c);
498 ps2_put_keycode(s, 0xe0);
499 ps2_put_keycode(s, 0xf0);
500 ps2_put_keycode(s, 0x12);
501 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200502 }
Ross Lagerwall92f4a212023-02-27 17:33:08 +0000503 } else if ((qcode == Q_KEY_CODE_LANG1 || qcode == Q_KEY_CODE_LANG2) &&
504 !key->down) {
505 /* Ignore release for these keys */
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200506 } else {
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100507 if (qcode < qemu_input_map_qcode_to_atset2_len) {
Daniel P. Berrangeab8f9d42018-01-17 16:41:15 +0000508 keycode = qemu_input_map_qcode_to_atset2[qcode];
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100509 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200510 if (keycode) {
511 if (keycode & 0xff00) {
512 ps2_put_keycode(s, keycode >> 8);
513 }
514 if (!key->down) {
515 ps2_put_keycode(s, 0xf0);
516 }
517 ps2_put_keycode(s, keycode & 0xff);
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200518 } else {
Hervé Poussineauec044a82016-09-15 22:06:27 +0200519 qemu_log_mask(LOG_UNIMP,
520 "ps2: ignoring key with qcode %d\n", qcode);
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200521 }
522 }
523 } else if (s->scancode_set == 3) {
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100524 if (qcode < qemu_input_map_qcode_to_atset3_len) {
Daniel P. Berrangeab8f9d42018-01-17 16:41:15 +0000525 keycode = qemu_input_map_qcode_to_atset3[qcode];
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100526 }
Hervé Poussineau8c10e0b2016-09-15 22:06:26 +0200527 if (keycode) {
528 /* FIXME: break code should be configured on a key by key basis */
529 if (!key->down) {
530 ps2_put_keycode(s, 0xf0);
531 }
532 ps2_put_keycode(s, keycode);
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200533 } else {
Hervé Poussineauec044a82016-09-15 22:06:27 +0200534 qemu_log_mask(LOG_UNIMP,
535 "ps2: ignoring key with qcode %d\n", qcode);
Hervé Poussineau57d5c002016-09-15 22:06:25 +0200536 }
Gerd Hoffmann66e65362014-03-13 12:39:38 +0100537 }
538}
539
Gerd Hoffmann8498bb82017-06-06 13:21:03 +0200540uint32_t ps2_read_data(PS2State *s)
bellard0e43e992005-11-26 10:36:25 +0000541{
bellard0e43e992005-11-26 10:36:25 +0000542 PS2Queue *q;
543 int val, index;
ths3b46e622007-09-17 08:09:54 +0000544
Gerd Hoffmann8498bb82017-06-06 13:21:03 +0200545 trace_ps2_read_data(s);
bellard0e43e992005-11-26 10:36:25 +0000546 q = &s->queue;
547 if (q->count == 0) {
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100548 /*
549 * NOTE: if no data left, we return the last keyboard one
550 * (needed for EMM386)
551 */
bellard0e43e992005-11-26 10:36:25 +0000552 /* XXX: need a timer to do things correctly */
553 index = q->rptr - 1;
Volker Rümelin47db2432021-08-10 15:32:56 +0200554 if (index < 0) {
555 index = PS2_BUFFER_SIZE - 1;
556 }
bellard0e43e992005-11-26 10:36:25 +0000557 val = q->data[index];
558 } else {
559 val = q->data[q->rptr];
Volker Rümelin47db2432021-08-10 15:32:56 +0200560 if (++q->rptr == PS2_BUFFER_SIZE) {
bellard0e43e992005-11-26 10:36:25 +0000561 q->rptr = 0;
Volker Rümelin47db2432021-08-10 15:32:56 +0200562 }
bellard0e43e992005-11-26 10:36:25 +0000563 q->count--;
Volker Rümelin9e24b2d2021-08-10 15:32:57 +0200564 if (q->rptr == q->cwptr) {
565 /* command reply queue is empty */
566 q->cwptr = -1;
567 }
bellard0e43e992005-11-26 10:36:25 +0000568 /* reading deasserts IRQ */
Mark Cave-Ayland5cb6e552022-06-24 14:40:48 +0100569 ps2_lower_irq(s);
bellard0e43e992005-11-26 10:36:25 +0000570 /* reassert IRQs if data left */
Volker Rümelincec32522021-05-25 20:14:32 +0200571 if (q->count) {
Mark Cave-Ayland892e9bb2022-06-24 14:40:47 +0100572 ps2_raise_irq(s);
Volker Rümelincec32522021-05-25 20:14:32 +0200573 }
bellard0e43e992005-11-26 10:36:25 +0000574 }
575 return val;
576}
577
Christophe Fergeau7f540ab2011-10-17 13:37:34 +0200578static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
579{
Don Koch5edab032015-01-16 14:21:37 -0500580 trace_ps2_set_ledstate(s, ledstate);
Christophe Fergeau7f540ab2011-10-17 13:37:34 +0200581 s->ledstate = ledstate;
582 kbd_put_ledstate(ledstate);
583}
584
bellard0e43e992005-11-26 10:36:25 +0000585static void ps2_reset_keyboard(PS2KbdState *s)
586{
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100587 PS2State *ps2 = PS2_DEVICE(s);
588
Don Koch5edab032015-01-16 14:21:37 -0500589 trace_ps2_reset_keyboard(s);
bellard0e43e992005-11-26 10:36:25 +0000590 s->scan_enabled = 1;
aurel32e7d93952008-03-18 06:54:34 +0000591 s->scancode_set = 2;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100592 ps2_reset_queue(ps2);
Christophe Fergeau7f540ab2011-10-17 13:37:34 +0200593 ps2_set_ledstate(s, 0);
bellard0e43e992005-11-26 10:36:25 +0000594}
595
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100596void ps2_write_keyboard(PS2KbdState *s, int val)
bellard0e43e992005-11-26 10:36:25 +0000597{
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100598 PS2State *ps2 = PS2_DEVICE(s);
bellard0e43e992005-11-26 10:36:25 +0000599
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100600 trace_ps2_write_keyboard(s, val);
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100601 ps2_cqueue_reset(ps2);
602 switch (ps2->write_cmd) {
bellard0e43e992005-11-26 10:36:25 +0000603 default:
604 case -1:
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100605 switch (val) {
bellard0e43e992005-11-26 10:36:25 +0000606 case 0x00:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100607 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
bellard0e43e992005-11-26 10:36:25 +0000608 break;
609 case 0x05:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100610 ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
bellard0e43e992005-11-26 10:36:25 +0000611 break;
612 case KBD_CMD_GET_ID:
aurel32e7d93952008-03-18 06:54:34 +0000613 /* We emulate a MF2 AT keyboard here */
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100614 ps2_cqueue_3(ps2, KBD_REPLY_ACK, KBD_REPLY_ID,
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100615 s->translate ? 0x41 : 0x83);
bellard0e43e992005-11-26 10:36:25 +0000616 break;
617 case KBD_CMD_ECHO:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100618 ps2_cqueue_1(ps2, KBD_CMD_ECHO);
bellard0e43e992005-11-26 10:36:25 +0000619 break;
620 case KBD_CMD_ENABLE:
621 s->scan_enabled = 1;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100622 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
bellard0e43e992005-11-26 10:36:25 +0000623 break;
aurel32e7d93952008-03-18 06:54:34 +0000624 case KBD_CMD_SCANCODE:
bellard0e43e992005-11-26 10:36:25 +0000625 case KBD_CMD_SET_LEDS:
626 case KBD_CMD_SET_RATE:
Sven Schnellec56b6202019-12-20 22:15:09 +0100627 case KBD_CMD_SET_MAKE_BREAK:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100628 ps2->write_cmd = val;
629 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
bellard0e43e992005-11-26 10:36:25 +0000630 break;
631 case KBD_CMD_RESET_DISABLE:
632 ps2_reset_keyboard(s);
633 s->scan_enabled = 0;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100634 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
bellard0e43e992005-11-26 10:36:25 +0000635 break;
636 case KBD_CMD_RESET_ENABLE:
637 ps2_reset_keyboard(s);
638 s->scan_enabled = 1;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100639 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
bellard0e43e992005-11-26 10:36:25 +0000640 break;
641 case KBD_CMD_RESET:
642 ps2_reset_keyboard(s);
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100643 ps2_cqueue_2(ps2,
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100644 KBD_REPLY_ACK,
645 KBD_REPLY_POR);
bellard0e43e992005-11-26 10:36:25 +0000646 break;
Sven Schnellec56b6202019-12-20 22:15:09 +0100647 case KBD_CMD_SET_TYPEMATIC:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100648 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
Sven Schnellec56b6202019-12-20 22:15:09 +0100649 break;
bellard0e43e992005-11-26 10:36:25 +0000650 default:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100651 ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
bellard0e43e992005-11-26 10:36:25 +0000652 break;
653 }
654 break;
Sven Schnellec56b6202019-12-20 22:15:09 +0100655 case KBD_CMD_SET_MAKE_BREAK:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100656 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
657 ps2->write_cmd = -1;
Sven Schnellec56b6202019-12-20 22:15:09 +0100658 break;
aurel32e7d93952008-03-18 06:54:34 +0000659 case KBD_CMD_SCANCODE:
660 if (val == 0) {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100661 ps2_cqueue_2(ps2, KBD_REPLY_ACK, s->translate ?
Volker Rümelin9e24b2d2021-08-10 15:32:57 +0200662 translate_table[s->scancode_set] : s->scancode_set);
Hervé Poussineau4df23b62016-09-15 22:06:24 +0200663 } else if (val >= 1 && val <= 3) {
664 s->scancode_set = val;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100665 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
Hervé Poussineau4df23b62016-09-15 22:06:24 +0200666 } else {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100667 ps2_cqueue_1(ps2, KBD_REPLY_RESEND);
aurel32e7d93952008-03-18 06:54:34 +0000668 }
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100669 ps2->write_cmd = -1;
aurel32e7d93952008-03-18 06:54:34 +0000670 break;
bellard0e43e992005-11-26 10:36:25 +0000671 case KBD_CMD_SET_LEDS:
Christophe Fergeau7f540ab2011-10-17 13:37:34 +0200672 ps2_set_ledstate(s, val);
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100673 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
674 ps2->write_cmd = -1;
bellard0e43e992005-11-26 10:36:25 +0000675 break;
676 case KBD_CMD_SET_RATE:
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +0100677 ps2_cqueue_1(ps2, KBD_REPLY_ACK);
678 ps2->write_cmd = -1;
bellard0e43e992005-11-26 10:36:25 +0000679 break;
680 }
681}
682
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100683/*
684 * Set the scancode translation mode.
685 * 0 = raw scancodes.
686 * 1 = translated scancodes (used by qemu internally).
687 */
pbrookf94f5d72006-02-08 04:42:17 +0000688
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100689void ps2_keyboard_set_translation(PS2KbdState *s, int mode)
pbrookf94f5d72006-02-08 04:42:17 +0000690{
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100691 trace_ps2_keyboard_set_translation(s, mode);
pbrookf94f5d72006-02-08 04:42:17 +0000692 s->translate = mode;
693}
694
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000695static int ps2_mouse_send_packet(PS2MouseState *s)
bellard0e43e992005-11-26 10:36:25 +0000696{
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100697 PS2State *ps2 = PS2_DEVICE(s);
Volker Rümelin76968102021-05-25 20:14:30 +0200698 /* IMPS/2 and IMEX send 4 bytes, PS2 sends 3 bytes */
699 const int needed = s->mouse_type ? 4 : 3;
bellard0e43e992005-11-26 10:36:25 +0000700 unsigned int b;
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100701 int dx1, dy1, dz1, dw1;
bellard0e43e992005-11-26 10:36:25 +0000702
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100703 if (PS2_QUEUE_SIZE - ps2->queue.count < needed) {
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000704 return 0;
705 }
706
bellard0e43e992005-11-26 10:36:25 +0000707 dx1 = s->mouse_dx;
708 dy1 = s->mouse_dy;
709 dz1 = s->mouse_dz;
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100710 dw1 = s->mouse_dw;
bellard0e43e992005-11-26 10:36:25 +0000711 /* XXX: increase range to 8 bits ? */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100712 if (dx1 > 127) {
bellard0e43e992005-11-26 10:36:25 +0000713 dx1 = 127;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100714 } else if (dx1 < -127) {
bellard0e43e992005-11-26 10:36:25 +0000715 dx1 = -127;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100716 }
717 if (dy1 > 127) {
bellard0e43e992005-11-26 10:36:25 +0000718 dy1 = 127;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100719 } else if (dy1 < -127) {
bellard0e43e992005-11-26 10:36:25 +0000720 dy1 = -127;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100721 }
bellard0e43e992005-11-26 10:36:25 +0000722 b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100723 ps2_queue_noirq(ps2, b);
724 ps2_queue_noirq(ps2, dx1 & 0xff);
725 ps2_queue_noirq(ps2, dy1 & 0xff);
bellard0e43e992005-11-26 10:36:25 +0000726 /* extra byte for IMPS/2 or IMEX */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100727 switch (s->mouse_type) {
bellard0e43e992005-11-26 10:36:25 +0000728 default:
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100729 /* Just ignore the wheels if not supported */
730 s->mouse_dz = 0;
731 s->mouse_dw = 0;
bellard0e43e992005-11-26 10:36:25 +0000732 break;
733 case 3:
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100734 if (dz1 > 127) {
bellard0e43e992005-11-26 10:36:25 +0000735 dz1 = 127;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100736 } else if (dz1 < -127) {
737 dz1 = -127;
738 }
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100739 ps2_queue_noirq(ps2, dz1 & 0xff);
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100740 s->mouse_dz -= dz1;
741 s->mouse_dw = 0;
bellard0e43e992005-11-26 10:36:25 +0000742 break;
743 case 4:
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100744 /*
745 * This matches what the Linux kernel expects for exps/2 in
746 * drivers/input/mouse/psmouse-base.c. Note, if you happen to
747 * press/release the 4th or 5th buttons at the same moment as a
748 * horizontal wheel scroll, those button presses will get lost. I'm not
749 * sure what to do about that, since by this point we don't know
750 * whether those buttons actually changed state.
751 */
752 if (dw1 != 0) {
753 if (dw1 > 31) {
754 dw1 = 31;
755 } else if (dw1 < -31) {
756 dw1 = -31;
757 }
758
759 /*
760 * linux kernel expects first 6 bits to represent the value
761 * for horizontal scroll
762 */
763 b = (dw1 & 0x3f) | 0x40;
764 s->mouse_dw -= dw1;
765 } else {
766 if (dz1 > 7) {
767 dz1 = 7;
768 } else if (dz1 < -7) {
769 dz1 = -7;
770 }
771
772 b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
773 s->mouse_dz -= dz1;
774 }
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100775 ps2_queue_noirq(ps2, b);
bellard0e43e992005-11-26 10:36:25 +0000776 break;
777 }
778
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100779 ps2_raise_irq(ps2);
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000780
Don Koch5edab032015-01-16 14:21:37 -0500781 trace_ps2_mouse_send_packet(s, dx1, dy1, dz1, b);
bellard0e43e992005-11-26 10:36:25 +0000782 /* update deltas */
783 s->mouse_dx -= dx1;
784 s->mouse_dy -= dy1;
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000785
786 return 1;
bellard0e43e992005-11-26 10:36:25 +0000787}
788
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100789static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
790 InputEvent *evt)
bellard0e43e992005-11-26 10:36:25 +0000791{
Eric Blake7fb1cf12015-11-18 01:52:57 -0700792 static const int bmap[INPUT_BUTTON__MAX] = {
Fabian Lesniak8b0caab2016-12-06 20:00:06 +0100793 [INPUT_BUTTON_LEFT] = PS2_MOUSE_BUTTON_LEFT,
794 [INPUT_BUTTON_MIDDLE] = PS2_MOUSE_BUTTON_MIDDLE,
795 [INPUT_BUTTON_RIGHT] = PS2_MOUSE_BUTTON_RIGHT,
796 [INPUT_BUTTON_SIDE] = PS2_MOUSE_BUTTON_SIDE,
797 [INPUT_BUTTON_EXTRA] = PS2_MOUSE_BUTTON_EXTRA,
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100798 };
799 PS2MouseState *s = (PS2MouseState *)dev;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700800 InputMoveEvent *move;
801 InputBtnEvent *btn;
bellard0e43e992005-11-26 10:36:25 +0000802
803 /* check if deltas are recorded when disabled */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100804 if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
bellard0e43e992005-11-26 10:36:25 +0000805 return;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100806 }
bellard0e43e992005-11-26 10:36:25 +0000807
Eric Blake568c73a2015-10-26 16:34:58 -0600808 switch (evt->type) {
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100809 case INPUT_EVENT_KIND_REL:
Eric Blake32bafa82016-03-17 16:48:37 -0600810 move = evt->u.rel.data;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700811 if (move->axis == INPUT_AXIS_X) {
812 s->mouse_dx += move->value;
813 } else if (move->axis == INPUT_AXIS_Y) {
814 s->mouse_dy -= move->value;
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100815 }
816 break;
ths3b46e622007-09-17 08:09:54 +0000817
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100818 case INPUT_EVENT_KIND_BTN:
Eric Blake32bafa82016-03-17 16:48:37 -0600819 btn = evt->u.btn.data;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700820 if (btn->down) {
821 s->mouse_buttons |= bmap[btn->button];
822 if (btn->button == INPUT_BUTTON_WHEEL_UP) {
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100823 s->mouse_dz--;
Eric Blakeb5a1b442016-03-03 09:16:49 -0700824 } else if (btn->button == INPUT_BUTTON_WHEEL_DOWN) {
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100825 s->mouse_dz++;
826 }
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100827
828 if (btn->button == INPUT_BUTTON_WHEEL_RIGHT) {
829 s->mouse_dw--;
830 } else if (btn->button == INPUT_BUTTON_WHEEL_LEFT) {
831 s->mouse_dw++;
832 }
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100833 } else {
Eric Blakeb5a1b442016-03-03 09:16:49 -0700834 s->mouse_buttons &= ~bmap[btn->button];
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100835 }
836 break;
837
838 default:
839 /* keep gcc happy */
840 break;
841 }
842}
843
844static void ps2_mouse_sync(DeviceState *dev)
845{
846 PS2MouseState *s = (PS2MouseState *)dev;
847
Geoffrey McRae143c04c2018-05-07 23:01:46 +1000848 /* do not sync while disabled to prevent stream corruption */
849 if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) {
850 return;
851 }
852
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100853 if (s->mouse_buttons) {
Daniel Henrique Barbozafb064112018-12-05 17:47:01 -0200854 qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
Gerd Hoffmannfd214d12012-02-23 13:45:22 +0100855 }
Gonglei2858ab02014-04-24 20:06:19 +0800856 if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100857 /*
858 * if not remote, send event. Multiple events are sent if
859 * too big deltas
860 */
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000861 while (ps2_mouse_send_packet(s)) {
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100862 if (s->mouse_dx == 0 && s->mouse_dy == 0
863 && s->mouse_dz == 0 && s->mouse_dw == 0) {
bellard0e43e992005-11-26 10:36:25 +0000864 break;
Dmitry Petrov64ebbb72022-01-08 16:39:43 +0100865 }
bellard0e43e992005-11-26 10:36:25 +0000866 }
867 }
868}
869
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100870void ps2_mouse_fake_event(PS2MouseState *s)
ths548df2a2007-03-20 16:45:27 +0000871{
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100872 trace_ps2_mouse_fake_event(s);
Gerd Hoffmann2a766d22014-03-13 12:58:29 +0100873 s->mouse_dx++;
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100874 ps2_mouse_sync(DEVICE(s));
ths548df2a2007-03-20 16:45:27 +0000875}
876
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100877void ps2_write_mouse(PS2MouseState *s, int val)
bellard0e43e992005-11-26 10:36:25 +0000878{
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100879 PS2State *ps2 = PS2_DEVICE(s);
Don Koch5edab032015-01-16 14:21:37 -0500880
Mark Cave-Ayland54334e72022-06-24 14:40:21 +0100881 trace_ps2_write_mouse(s, val);
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100882 switch (ps2->write_cmd) {
bellard0e43e992005-11-26 10:36:25 +0000883 default:
884 case -1:
885 /* mouse command */
886 if (s->mouse_wrap) {
887 if (val == AUX_RESET_WRAP) {
888 s->mouse_wrap = 0;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100889 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000890 return;
891 } else if (val != AUX_RESET) {
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100892 ps2_queue(ps2, val);
bellard0e43e992005-11-26 10:36:25 +0000893 return;
894 }
895 }
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100896 switch (val) {
bellard0e43e992005-11-26 10:36:25 +0000897 case AUX_SET_SCALE11:
898 s->mouse_status &= ~MOUSE_STATUS_SCALE21;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100899 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000900 break;
901 case AUX_SET_SCALE21:
902 s->mouse_status |= MOUSE_STATUS_SCALE21;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100903 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000904 break;
905 case AUX_SET_STREAM:
906 s->mouse_status &= ~MOUSE_STATUS_REMOTE;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100907 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000908 break;
909 case AUX_SET_WRAP:
910 s->mouse_wrap = 1;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100911 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000912 break;
913 case AUX_SET_REMOTE:
914 s->mouse_status |= MOUSE_STATUS_REMOTE;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100915 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000916 break;
917 case AUX_GET_TYPE:
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100918 ps2_queue_2(ps2,
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000919 AUX_ACK,
920 s->mouse_type);
bellard0e43e992005-11-26 10:36:25 +0000921 break;
922 case AUX_SET_RES:
923 case AUX_SET_SAMPLE:
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100924 ps2->write_cmd = val;
925 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000926 break;
927 case AUX_GET_SCALE:
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100928 ps2_queue_4(ps2,
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000929 AUX_ACK,
930 s->mouse_status,
931 s->mouse_resolution,
932 s->mouse_sample_rate);
bellard0e43e992005-11-26 10:36:25 +0000933 break;
934 case AUX_POLL:
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100935 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000936 ps2_mouse_send_packet(s);
937 break;
938 case AUX_ENABLE_DEV:
939 s->mouse_status |= MOUSE_STATUS_ENABLED;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100940 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000941 break;
942 case AUX_DISABLE_DEV:
943 s->mouse_status &= ~MOUSE_STATUS_ENABLED;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100944 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000945 break;
946 case AUX_SET_DEFAULT:
947 s->mouse_sample_rate = 100;
948 s->mouse_resolution = 2;
949 s->mouse_status = 0;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100950 ps2_queue(ps2, AUX_ACK);
bellard0e43e992005-11-26 10:36:25 +0000951 break;
952 case AUX_RESET:
953 s->mouse_sample_rate = 100;
954 s->mouse_resolution = 2;
955 s->mouse_status = 0;
956 s->mouse_type = 0;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100957 ps2_reset_queue(ps2);
958 ps2_queue_3(ps2,
Geoffrey McRae7abe7eb2018-05-07 23:13:12 +1000959 AUX_ACK,
960 0xaa,
961 s->mouse_type);
bellard0e43e992005-11-26 10:36:25 +0000962 break;
963 default:
964 break;
965 }
966 break;
967 case AUX_SET_SAMPLE:
968 s->mouse_sample_rate = val;
969 /* detect IMPS/2 or IMEX */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100970 switch (s->mouse_detect_state) {
bellard0e43e992005-11-26 10:36:25 +0000971 default:
972 case 0:
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100973 if (val == 200) {
bellard0e43e992005-11-26 10:36:25 +0000974 s->mouse_detect_state = 1;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100975 }
bellard0e43e992005-11-26 10:36:25 +0000976 break;
977 case 1:
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100978 if (val == 100) {
bellard0e43e992005-11-26 10:36:25 +0000979 s->mouse_detect_state = 2;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100980 } else if (val == 200) {
bellard0e43e992005-11-26 10:36:25 +0000981 s->mouse_detect_state = 3;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100982 } else {
bellard0e43e992005-11-26 10:36:25 +0000983 s->mouse_detect_state = 0;
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100984 }
bellard0e43e992005-11-26 10:36:25 +0000985 break;
986 case 2:
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100987 if (val == 80) {
bellard0e43e992005-11-26 10:36:25 +0000988 s->mouse_type = 3; /* IMPS/2 */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100989 }
bellard0e43e992005-11-26 10:36:25 +0000990 s->mouse_detect_state = 0;
991 break;
992 case 3:
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100993 if (val == 80) {
bellard0e43e992005-11-26 10:36:25 +0000994 s->mouse_type = 4; /* IMEX */
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +0100995 }
bellard0e43e992005-11-26 10:36:25 +0000996 s->mouse_detect_state = 0;
997 break;
998 }
Mark Cave-Ayland2d135402022-06-24 14:40:19 +0100999 ps2_queue(ps2, AUX_ACK);
1000 ps2->write_cmd = -1;
bellard0e43e992005-11-26 10:36:25 +00001001 break;
1002 case AUX_SET_RES:
1003 s->mouse_resolution = val;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +01001004 ps2_queue(ps2, AUX_ACK);
1005 ps2->write_cmd = -1;
bellard0e43e992005-11-26 10:36:25 +00001006 break;
1007 }
1008}
1009
Peter Maydell2bb3f932022-11-09 17:00:08 +00001010static void ps2_reset_hold(Object *obj)
bellard0e43e992005-11-26 10:36:25 +00001011{
Peter Maydell2bb3f932022-11-09 17:00:08 +00001012 PS2State *s = PS2_DEVICE(obj);
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001013
bellard0e43e992005-11-26 10:36:25 +00001014 s->write_cmd = -1;
Gerd Hoffmann954ee552017-06-06 13:21:04 +02001015 ps2_reset_queue(s);
Peter Maydell2bb3f932022-11-09 17:00:08 +00001016}
1017
1018static void ps2_reset_exit(Object *obj)
1019{
1020 PS2State *s = PS2_DEVICE(obj);
1021
Mark Cave-Ayland5cb6e552022-06-24 14:40:48 +01001022 ps2_lower_irq(s);
bellard0e43e992005-11-26 10:36:25 +00001023}
1024
Gonglei2858ab02014-04-24 20:06:19 +08001025static void ps2_common_post_load(PS2State *s)
1026{
1027 PS2Queue *q = &s->queue;
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001028 int ccount = 0;
Gonglei2858ab02014-04-24 20:06:19 +08001029
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001030 /* limit the number of queued command replies to PS2_QUEUE_HEADROOM */
1031 if (q->cwptr != -1) {
1032 ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
1033 if (ccount > PS2_QUEUE_HEADROOM) {
1034 ccount = PS2_QUEUE_HEADROOM;
1035 }
Pavel Dovgalyuka1f2ed22018-05-11 11:16:01 +03001036 }
Gonglei2858ab02014-04-24 20:06:19 +08001037
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001038 /* limit the scancode queue size to PS2_QUEUE_SIZE */
1039 if (q->count < ccount) {
1040 q->count = ccount;
1041 } else if (q->count > ccount + PS2_QUEUE_SIZE) {
1042 q->count = ccount + PS2_QUEUE_SIZE;
1043 }
1044
1045 /* sanitize rptr and recalculate wptr and cwptr */
Volker Rümelin47db2432021-08-10 15:32:56 +02001046 q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1);
1047 q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1);
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001048 q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1;
Gonglei2858ab02014-04-24 20:06:19 +08001049}
1050
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001051static void ps2_kbd_reset_hold(Object *obj)
Dinesh Subhravetief746792009-07-14 18:30:53 -07001052{
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001053 PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
1054 PS2KbdState *s = PS2_KBD_DEVICE(obj);
Dinesh Subhravetief746792009-07-14 18:30:53 -07001055
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001056 trace_ps2_kbd_reset(s);
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001057
1058 if (ps2dc->parent_phases.hold) {
1059 ps2dc->parent_phases.hold(obj);
1060 }
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001061
Hervé Poussineaud2e550a2018-10-21 21:07:21 +02001062 s->scan_enabled = 1;
Dinesh Subhravetief746792009-07-14 18:30:53 -07001063 s->translate = 0;
Hervé Poussineau089adaf2016-03-23 07:21:40 +01001064 s->scancode_set = 2;
Daniel P. Berrange620775d2017-10-19 15:28:43 +01001065 s->modifiers = 0;
Dinesh Subhravetief746792009-07-14 18:30:53 -07001066}
1067
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001068static void ps2_mouse_reset_hold(Object *obj)
Dinesh Subhravetief746792009-07-14 18:30:53 -07001069{
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001070 PS2DeviceClass *ps2dc = PS2_DEVICE_GET_CLASS(obj);
1071 PS2MouseState *s = PS2_MOUSE_DEVICE(obj);
Dinesh Subhravetief746792009-07-14 18:30:53 -07001072
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001073 trace_ps2_mouse_reset(s);
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001074
1075 if (ps2dc->parent_phases.hold) {
1076 ps2dc->parent_phases.hold(obj);
1077 }
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001078
Dinesh Subhravetief746792009-07-14 18:30:53 -07001079 s->mouse_status = 0;
1080 s->mouse_resolution = 0;
1081 s->mouse_sample_rate = 0;
1082 s->mouse_wrap = 0;
1083 s->mouse_type = 0;
1084 s->mouse_detect_state = 0;
1085 s->mouse_dx = 0;
1086 s->mouse_dy = 0;
1087 s->mouse_dz = 0;
Dmitry Petrov64ebbb72022-01-08 16:39:43 +01001088 s->mouse_dw = 0;
Dinesh Subhravetief746792009-07-14 18:30:53 -07001089 s->mouse_buttons = 0;
1090}
1091
Juan Quintelab31442c2009-08-20 19:42:36 +02001092static const VMStateDescription vmstate_ps2_common = {
1093 .name = "PS2 Common State",
1094 .version_id = 3,
1095 .minimum_version_id = 2,
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001096 .fields = (const VMStateField[]) {
Juan Quintelab31442c2009-08-20 19:42:36 +02001097 VMSTATE_INT32(write_cmd, PS2State),
1098 VMSTATE_INT32(queue.rptr, PS2State),
1099 VMSTATE_INT32(queue.wptr, PS2State),
1100 VMSTATE_INT32(queue.count, PS2State),
1101 VMSTATE_BUFFER(queue.data, PS2State),
1102 VMSTATE_END_OF_LIST()
1103 }
1104};
pbrook7783e9f2006-04-08 14:12:31 +00001105
Christophe Fergeau7f540ab2011-10-17 13:37:34 +02001106static bool ps2_keyboard_ledstate_needed(void *opaque)
1107{
1108 PS2KbdState *s = opaque;
1109
1110 return s->ledstate != 0; /* 0 is default state */
1111}
1112
1113static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
1114{
1115 PS2KbdState *s = opaque;
1116
1117 kbd_put_ledstate(s->ledstate);
1118 return 0;
1119}
1120
1121static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
1122 .name = "ps2kbd/ledstate",
1123 .version_id = 3,
1124 .minimum_version_id = 2,
Christophe Fergeau7f540ab2011-10-17 13:37:34 +02001125 .post_load = ps2_kbd_ledstate_post_load,
Juan Quintela5cd8cad2014-09-23 14:09:54 +02001126 .needed = ps2_keyboard_ledstate_needed,
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001127 .fields = (const VMStateField[]) {
Christophe Fergeau7f540ab2011-10-17 13:37:34 +02001128 VMSTATE_INT32(ledstate, PS2KbdState),
1129 VMSTATE_END_OF_LIST()
1130 }
1131};
1132
Hervé Poussineau57d5c002016-09-15 22:06:25 +02001133static bool ps2_keyboard_need_high_bit_needed(void *opaque)
1134{
1135 PS2KbdState *s = opaque;
1136 return s->need_high_bit != 0; /* 0 is the usual state */
1137}
1138
1139static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
1140 .name = "ps2kbd/need_high_bit",
1141 .version_id = 1,
1142 .minimum_version_id = 1,
1143 .needed = ps2_keyboard_need_high_bit_needed,
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001144 .fields = (const VMStateField[]) {
Hervé Poussineau57d5c002016-09-15 22:06:25 +02001145 VMSTATE_BOOL(need_high_bit, PS2KbdState),
1146 VMSTATE_END_OF_LIST()
1147 }
1148};
1149
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001150static bool ps2_keyboard_cqueue_needed(void *opaque)
1151{
1152 PS2KbdState *s = opaque;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001153 PS2State *ps2 = PS2_DEVICE(s);
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001154
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001155 return ps2->queue.cwptr != -1; /* the queue is mostly empty */
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001156}
1157
1158static const VMStateDescription vmstate_ps2_keyboard_cqueue = {
1159 .name = "ps2kbd/command_reply_queue",
1160 .needed = ps2_keyboard_cqueue_needed,
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001161 .fields = (const VMStateField[]) {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001162 VMSTATE_INT32(parent_obj.queue.cwptr, PS2KbdState),
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001163 VMSTATE_END_OF_LIST()
1164 }
1165};
1166
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +01001167static int ps2_kbd_post_load(void *opaque, int version_id)
bellard0e43e992005-11-26 10:36:25 +00001168{
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +01001169 PS2KbdState *s = (PS2KbdState *)opaque;
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001170 PS2State *ps2 = PS2_DEVICE(s);
pbrook7783e9f2006-04-08 14:12:31 +00001171
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +01001172 if (version_id == 2) {
1173 s->scancode_set = 2;
1174 }
Gonglei2858ab02014-04-24 20:06:19 +08001175
1176 ps2_common_post_load(ps2);
1177
bellard0e43e992005-11-26 10:36:25 +00001178 return 0;
1179}
1180
Juan Quintelab31442c2009-08-20 19:42:36 +02001181static const VMStateDescription vmstate_ps2_keyboard = {
1182 .name = "ps2kbd",
1183 .version_id = 3,
Juan Quinteladb596c52009-09-29 22:48:23 +02001184 .minimum_version_id = 2,
Juan Quinteladb596c52009-09-29 22:48:23 +02001185 .post_load = ps2_kbd_post_load,
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001186 .fields = (const VMStateField[]) {
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001187 VMSTATE_STRUCT(parent_obj, PS2KbdState, 0, vmstate_ps2_common,
1188 PS2State),
Juan Quintelab31442c2009-08-20 19:42:36 +02001189 VMSTATE_INT32(scan_enabled, PS2KbdState),
1190 VMSTATE_INT32(translate, PS2KbdState),
Mark Cave-Ayland545e5cf2022-06-24 14:40:16 +01001191 VMSTATE_INT32_V(scancode_set, PS2KbdState, 3),
Juan Quintelab31442c2009-08-20 19:42:36 +02001192 VMSTATE_END_OF_LIST()
Christophe Fergeau7f540ab2011-10-17 13:37:34 +02001193 },
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001194 .subsections = (const VMStateDescription * const []) {
Juan Quintela5cd8cad2014-09-23 14:09:54 +02001195 &vmstate_ps2_keyboard_ledstate,
Hervé Poussineau57d5c002016-09-15 22:06:25 +02001196 &vmstate_ps2_keyboard_need_high_bit,
Volker Rümelin4e9bddc2021-08-10 15:32:58 +02001197 &vmstate_ps2_keyboard_cqueue,
Juan Quintela5cd8cad2014-09-23 14:09:54 +02001198 NULL
Juan Quintelab31442c2009-08-20 19:42:36 +02001199 }
1200};
pbrook7783e9f2006-04-08 14:12:31 +00001201
Gonglei2858ab02014-04-24 20:06:19 +08001202static int ps2_mouse_post_load(void *opaque, int version_id)
1203{
1204 PS2MouseState *s = (PS2MouseState *)opaque;
Mark Cave-Ayland2d135402022-06-24 14:40:19 +01001205 PS2State *ps2 = PS2_DEVICE(s);
Gonglei2858ab02014-04-24 20:06:19 +08001206
1207 ps2_common_post_load(ps2);
1208
1209 return 0;
1210}
1211
Juan Quintelab31442c2009-08-20 19:42:36 +02001212static const VMStateDescription vmstate_ps2_mouse = {
1213 .name = "ps2mouse",
1214 .version_id = 2,
1215 .minimum_version_id = 2,
Gonglei2858ab02014-04-24 20:06:19 +08001216 .post_load = ps2_mouse_post_load,
Richard Hendersonaf0f07d2023-12-21 14:16:14 +11001217 .fields = (const VMStateField[]) {
Mark Cave-Ayland2d135402022-06-24 14:40:19 +01001218 VMSTATE_STRUCT(parent_obj, PS2MouseState, 0, vmstate_ps2_common,
1219 PS2State),
Juan Quintelab31442c2009-08-20 19:42:36 +02001220 VMSTATE_UINT8(mouse_status, PS2MouseState),
1221 VMSTATE_UINT8(mouse_resolution, PS2MouseState),
1222 VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
1223 VMSTATE_UINT8(mouse_wrap, PS2MouseState),
1224 VMSTATE_UINT8(mouse_type, PS2MouseState),
1225 VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
1226 VMSTATE_INT32(mouse_dx, PS2MouseState),
1227 VMSTATE_INT32(mouse_dy, PS2MouseState),
1228 VMSTATE_INT32(mouse_dz, PS2MouseState),
1229 VMSTATE_UINT8(mouse_buttons, PS2MouseState),
1230 VMSTATE_END_OF_LIST()
1231 }
1232};
bellard0e43e992005-11-26 10:36:25 +00001233
Philippe Mathieu-Daudéb1be65f2023-10-17 15:05:00 +02001234static const QemuInputHandler ps2_keyboard_handler = {
Gerd Hoffmann66e65362014-03-13 12:39:38 +01001235 .name = "QEMU PS/2 Keyboard",
1236 .mask = INPUT_EVENT_MASK_KEY,
1237 .event = ps2_keyboard_event,
1238};
1239
Mark Cave-Aylandea247a02022-06-24 14:40:25 +01001240static void ps2_kbd_realize(DeviceState *dev, Error **errp)
1241{
1242 qemu_input_handler_register(dev, &ps2_keyboard_handler);
1243}
1244
Philippe Mathieu-Daudéb1be65f2023-10-17 15:05:00 +02001245static const QemuInputHandler ps2_mouse_handler = {
Gerd Hoffmann2a766d22014-03-13 12:58:29 +01001246 .name = "QEMU PS/2 Mouse",
1247 .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
1248 .event = ps2_mouse_event,
1249 .sync = ps2_mouse_sync,
1250};
1251
Mark Cave-Ayland4a68b482022-06-24 14:40:26 +01001252static void ps2_mouse_realize(DeviceState *dev, Error **errp)
1253{
1254 qemu_input_handler_register(dev, &ps2_mouse_handler);
1255}
1256
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001257static void ps2_kbd_class_init(ObjectClass *klass, void *data)
1258{
1259 DeviceClass *dc = DEVICE_CLASS(klass);
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001260 ResettableClass *rc = RESETTABLE_CLASS(klass);
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001261 PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass);
1262
Mark Cave-Aylandea247a02022-06-24 14:40:25 +01001263 dc->realize = ps2_kbd_realize;
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001264 resettable_class_set_parent_phases(rc, NULL, ps2_kbd_reset_hold, NULL,
1265 &ps2dc->parent_phases);
Mark Cave-Aylandf055f502022-06-24 14:40:27 +01001266 dc->vmsd = &vmstate_ps2_keyboard;
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001267}
1268
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001269static const TypeInfo ps2_kbd_info = {
1270 .name = TYPE_PS2_KBD_DEVICE,
1271 .parent = TYPE_PS2_DEVICE,
1272 .instance_size = sizeof(PS2KbdState),
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001273 .class_init = ps2_kbd_class_init
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001274};
1275
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001276static void ps2_mouse_class_init(ObjectClass *klass, void *data)
1277{
1278 DeviceClass *dc = DEVICE_CLASS(klass);
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001279 ResettableClass *rc = RESETTABLE_CLASS(klass);
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001280 PS2DeviceClass *ps2dc = PS2_DEVICE_CLASS(klass);
1281
Mark Cave-Ayland4a68b482022-06-24 14:40:26 +01001282 dc->realize = ps2_mouse_realize;
Peter Maydellfc2fc3c2022-11-09 17:00:09 +00001283 resettable_class_set_parent_phases(rc, NULL, ps2_mouse_reset_hold, NULL,
1284 &ps2dc->parent_phases);
Mark Cave-Ayland97259e72022-06-24 14:40:28 +01001285 dc->vmsd = &vmstate_ps2_mouse;
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001286}
1287
Mark Cave-Ayland2d135402022-06-24 14:40:19 +01001288static const TypeInfo ps2_mouse_info = {
1289 .name = TYPE_PS2_MOUSE_DEVICE,
1290 .parent = TYPE_PS2_DEVICE,
1291 .instance_size = sizeof(PS2MouseState),
Mark Cave-Ayland108cb222022-06-24 14:40:23 +01001292 .class_init = ps2_mouse_class_init
Mark Cave-Ayland2d135402022-06-24 14:40:19 +01001293};
1294
Mark Cave-Ayland6beb79e2022-06-24 14:40:49 +01001295static void ps2_init(Object *obj)
1296{
1297 PS2State *s = PS2_DEVICE(obj);
1298
1299 qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
1300}
1301
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +01001302static void ps2_class_init(ObjectClass *klass, void *data)
1303{
1304 DeviceClass *dc = DEVICE_CLASS(klass);
Peter Maydell2bb3f932022-11-09 17:00:08 +00001305 ResettableClass *rc = RESETTABLE_CLASS(klass);
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +01001306
Peter Maydell2bb3f932022-11-09 17:00:08 +00001307 rc->phases.hold = ps2_reset_hold;
1308 rc->phases.exit = ps2_reset_exit;
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +01001309 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
1310}
1311
1312static const TypeInfo ps2_info = {
1313 .name = TYPE_PS2_DEVICE,
1314 .parent = TYPE_SYS_BUS_DEVICE,
Mark Cave-Ayland6beb79e2022-06-24 14:40:49 +01001315 .instance_init = ps2_init,
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +01001316 .instance_size = sizeof(PS2State),
1317 .class_init = ps2_class_init,
Mark Cave-Ayland494145b2022-06-24 14:40:22 +01001318 .class_size = sizeof(PS2DeviceClass),
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +01001319 .abstract = true
1320};
1321
1322static void ps2_register_types(void)
1323{
1324 type_register_static(&ps2_info);
Mark Cave-Ayland8f84e532022-06-24 14:40:18 +01001325 type_register_static(&ps2_kbd_info);
Mark Cave-Ayland2d135402022-06-24 14:40:19 +01001326 type_register_static(&ps2_mouse_info);
Mark Cave-Ayland64bbdd12022-06-24 14:40:17 +01001327}
1328
1329type_init(ps2_register_types)