xref: /openbmc/qemu/hw/input/pckbd.c (revision 803ca43e)
1 /*
2  * QEMU PC keyboard emulation
3  *
4  * Copyright (c) 2003 Fabrice Bellard
5  *
6  * 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  */
24 
25 #include "qemu/osdep.h"
26 #include "qemu/error-report.h"
27 #include "qemu/log.h"
28 #include "qemu/timer.h"
29 #include "qapi/error.h"
30 #include "hw/isa/isa.h"
31 #include "migration/vmstate.h"
32 #include "hw/acpi/acpi_aml_interface.h"
33 #include "hw/input/ps2.h"
34 #include "hw/irq.h"
35 #include "hw/input/i8042.h"
36 #include "hw/qdev-properties.h"
37 #include "sysemu/reset.h"
38 #include "sysemu/runstate.h"
39 
40 #include "trace.h"
41 
42 /*	Keyboard Controller Commands */
43 #define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
44 #define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
45 #define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
46 #define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
47 #define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
48 #define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
49 #define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
50 #define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
51 #define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
52 #define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
53 #define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
54 #define KBD_CCMD_READ_OUTPORT	0xD0    /* read output port */
55 #define KBD_CCMD_WRITE_OUTPORT	0xD1    /* write output port */
56 #define KBD_CCMD_WRITE_OBUF	0xD2
57 #define KBD_CCMD_WRITE_AUX_OBUF	0xD3    /* Write to output buffer as if
58                                            initiated by the auxiliary device */
59 #define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
60 #define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
61 #define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
62 #define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
63 #define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
64 #define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
65 
66 /* Status Register Bits */
67 #define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
68 #define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
69 #define KBD_STAT_SELFTEST	0x04	/* Self test successful */
70 #define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
71 #define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
72 #define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
73 #define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
74 #define KBD_STAT_PERR 		0x80	/* Parity error */
75 
76 /* Controller Mode Register Bits */
77 #define KBD_MODE_KBD_INT	0x01	/* Keyboard data generate IRQ1 */
78 #define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
79 #define KBD_MODE_SYS 		0x04	/* The system flag (?) */
80 #define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
81 #define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
82 #define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
83 #define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
84 #define KBD_MODE_RFU		0x80
85 
86 /* Output Port Bits */
87 #define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
88 #define KBD_OUT_A20             0x02    /* x86 only */
89 #define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
90 #define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
91 
92 /* OSes typically write 0xdd/0xdf to turn the A20 line off and on.
93  * We make the default value of the outport include these four bits,
94  * so that the subsection is rarely necessary.
95  */
96 #define KBD_OUT_ONES            0xcc
97 
98 #define KBD_PENDING_KBD_COMPAT  0x01
99 #define KBD_PENDING_AUX_COMPAT  0x02
100 #define KBD_PENDING_CTRL_KBD    0x04
101 #define KBD_PENDING_CTRL_AUX    0x08
102 #define KBD_PENDING_KBD         KBD_MODE_DISABLE_KBD    /* 0x10 */
103 #define KBD_PENDING_AUX         KBD_MODE_DISABLE_MOUSE  /* 0x20 */
104 
105 #define KBD_MIGR_TIMER_PENDING  0x1
106 
107 #define KBD_OBSRC_KBD           0x01
108 #define KBD_OBSRC_MOUSE         0x02
109 #define KBD_OBSRC_CTRL          0x04
110 
111 typedef struct KBDState {
112     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
113     uint8_t status;
114     uint8_t mode;
115     uint8_t outport;
116     uint32_t migration_flags;
117     uint32_t obsrc;
118     bool outport_present;
119     bool extended_state;
120     bool extended_state_loaded;
121     /* Bitmask of devices with data available.  */
122     uint8_t pending;
123     uint8_t obdata;
124     uint8_t cbdata;
125     uint8_t pending_tmp;
126     void *kbd;
127     void *mouse;
128     QEMUTimer *throttle_timer;
129 
130     qemu_irq irq_kbd;
131     qemu_irq irq_mouse;
132     qemu_irq a20_out;
133     hwaddr mask;
134 } KBDState;
135 
136 /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
137    incorrect, but it avoids having to simulate exact delays */
138 static void kbd_update_irq_lines(KBDState *s)
139 {
140     int irq_kbd_level, irq_mouse_level;
141 
142     irq_kbd_level = 0;
143     irq_mouse_level = 0;
144 
145     if (s->status & KBD_STAT_OBF) {
146         if (s->status & KBD_STAT_MOUSE_OBF) {
147             if (s->mode & KBD_MODE_MOUSE_INT) {
148                 irq_mouse_level = 1;
149             }
150         } else {
151             if ((s->mode & KBD_MODE_KBD_INT) &&
152                 !(s->mode & KBD_MODE_DISABLE_KBD)) {
153                 irq_kbd_level = 1;
154             }
155         }
156     }
157     qemu_set_irq(s->irq_kbd, irq_kbd_level);
158     qemu_set_irq(s->irq_mouse, irq_mouse_level);
159 }
160 
161 static void kbd_deassert_irq(KBDState *s)
162 {
163     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
164     s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
165     kbd_update_irq_lines(s);
166 }
167 
168 static uint8_t kbd_pending(KBDState *s)
169 {
170     if (s->extended_state) {
171         return s->pending & (~s->mode | ~(KBD_PENDING_KBD | KBD_PENDING_AUX));
172     } else {
173         return s->pending;
174     }
175 }
176 
177 /* update irq and KBD_STAT_[MOUSE_]OBF */
178 static void kbd_update_irq(KBDState *s)
179 {
180     uint8_t pending = kbd_pending(s);
181 
182     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
183     s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
184     if (pending) {
185         s->status |= KBD_STAT_OBF;
186         s->outport |= KBD_OUT_OBF;
187         if (pending & KBD_PENDING_CTRL_KBD) {
188             s->obsrc = KBD_OBSRC_CTRL;
189         } else if (pending & KBD_PENDING_CTRL_AUX) {
190             s->status |= KBD_STAT_MOUSE_OBF;
191             s->outport |= KBD_OUT_MOUSE_OBF;
192             s->obsrc = KBD_OBSRC_CTRL;
193         } else if (pending & KBD_PENDING_KBD) {
194             s->obsrc = KBD_OBSRC_KBD;
195         } else {
196             s->status |= KBD_STAT_MOUSE_OBF;
197             s->outport |= KBD_OUT_MOUSE_OBF;
198             s->obsrc = KBD_OBSRC_MOUSE;
199         }
200     }
201     kbd_update_irq_lines(s);
202 }
203 
204 static void kbd_safe_update_irq(KBDState *s)
205 {
206     /*
207      * with KBD_STAT_OBF set, a call to kbd_read_data() will eventually call
208      * kbd_update_irq()
209      */
210     if (s->status & KBD_STAT_OBF) {
211         return;
212     }
213     /* the throttle timer is pending and will call kbd_update_irq() */
214     if (s->throttle_timer && timer_pending(s->throttle_timer)) {
215         return;
216     }
217     if (kbd_pending(s)) {
218         kbd_update_irq(s);
219     }
220 }
221 
222 static void kbd_update_kbd_irq(void *opaque, int level)
223 {
224     KBDState *s = opaque;
225 
226     if (level) {
227         s->pending |= KBD_PENDING_KBD;
228     } else {
229         s->pending &= ~KBD_PENDING_KBD;
230     }
231     kbd_safe_update_irq(s);
232 }
233 
234 static void kbd_update_aux_irq(void *opaque, int level)
235 {
236     KBDState *s = opaque;
237 
238     if (level) {
239         s->pending |= KBD_PENDING_AUX;
240     } else {
241         s->pending &= ~KBD_PENDING_AUX;
242     }
243     kbd_safe_update_irq(s);
244 }
245 
246 static void kbd_throttle_timeout(void *opaque)
247 {
248     KBDState *s = opaque;
249 
250     if (kbd_pending(s)) {
251         kbd_update_irq(s);
252     }
253 }
254 
255 static uint64_t kbd_read_status(void *opaque, hwaddr addr,
256                                 unsigned size)
257 {
258     KBDState *s = opaque;
259     int val;
260     val = s->status;
261     trace_pckbd_kbd_read_status(val);
262     return val;
263 }
264 
265 static void kbd_queue(KBDState *s, int b, int aux)
266 {
267     if (s->extended_state) {
268         s->cbdata = b;
269         s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX;
270         s->pending |= aux ? KBD_PENDING_CTRL_AUX : KBD_PENDING_CTRL_KBD;
271         kbd_safe_update_irq(s);
272     } else {
273         ps2_queue(aux ? s->mouse : s->kbd, b);
274     }
275 }
276 
277 static uint8_t kbd_dequeue(KBDState *s)
278 {
279     uint8_t b = s->cbdata;
280 
281     s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX;
282     if (kbd_pending(s)) {
283         kbd_update_irq(s);
284     }
285     return b;
286 }
287 
288 static void outport_write(KBDState *s, uint32_t val)
289 {
290     trace_pckbd_outport_write(val);
291     s->outport = val;
292     qemu_set_irq(s->a20_out, (val >> 1) & 1);
293     if (!(val & 1)) {
294         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
295     }
296 }
297 
298 static void kbd_write_command(void *opaque, hwaddr addr,
299                               uint64_t val, unsigned size)
300 {
301     KBDState *s = opaque;
302 
303     trace_pckbd_kbd_write_command(val);
304 
305     /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
306      * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
307      * command specify the output port bits to be pulsed.
308      * 0: Bit should be pulsed. 1: Bit should not be modified.
309      * The only useful version of this command is pulsing bit 0,
310      * which does a CPU reset.
311      */
312     if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
313         if(!(val & 1))
314             val = KBD_CCMD_RESET;
315         else
316             val = KBD_CCMD_NO_OP;
317     }
318 
319     switch(val) {
320     case KBD_CCMD_READ_MODE:
321         kbd_queue(s, s->mode, 0);
322         break;
323     case KBD_CCMD_WRITE_MODE:
324     case KBD_CCMD_WRITE_OBUF:
325     case KBD_CCMD_WRITE_AUX_OBUF:
326     case KBD_CCMD_WRITE_MOUSE:
327     case KBD_CCMD_WRITE_OUTPORT:
328         s->write_cmd = val;
329         break;
330     case KBD_CCMD_MOUSE_DISABLE:
331         s->mode |= KBD_MODE_DISABLE_MOUSE;
332         break;
333     case KBD_CCMD_MOUSE_ENABLE:
334         s->mode &= ~KBD_MODE_DISABLE_MOUSE;
335         kbd_safe_update_irq(s);
336         break;
337     case KBD_CCMD_TEST_MOUSE:
338         kbd_queue(s, 0x00, 0);
339         break;
340     case KBD_CCMD_SELF_TEST:
341         s->status |= KBD_STAT_SELFTEST;
342         kbd_queue(s, 0x55, 0);
343         break;
344     case KBD_CCMD_KBD_TEST:
345         kbd_queue(s, 0x00, 0);
346         break;
347     case KBD_CCMD_KBD_DISABLE:
348         s->mode |= KBD_MODE_DISABLE_KBD;
349         break;
350     case KBD_CCMD_KBD_ENABLE:
351         s->mode &= ~KBD_MODE_DISABLE_KBD;
352         kbd_safe_update_irq(s);
353         break;
354     case KBD_CCMD_READ_INPORT:
355         kbd_queue(s, 0x80, 0);
356         break;
357     case KBD_CCMD_READ_OUTPORT:
358         kbd_queue(s, s->outport, 0);
359         break;
360     case KBD_CCMD_ENABLE_A20:
361         qemu_irq_raise(s->a20_out);
362         s->outport |= KBD_OUT_A20;
363         break;
364     case KBD_CCMD_DISABLE_A20:
365         qemu_irq_lower(s->a20_out);
366         s->outport &= ~KBD_OUT_A20;
367         break;
368     case KBD_CCMD_RESET:
369         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
370         break;
371     case KBD_CCMD_NO_OP:
372         /* ignore that */
373         break;
374     default:
375         qemu_log_mask(LOG_GUEST_ERROR,
376                       "unsupported keyboard cmd=0x%02" PRIx64 "\n", val);
377         break;
378     }
379 }
380 
381 static uint64_t kbd_read_data(void *opaque, hwaddr addr,
382                               unsigned size)
383 {
384     KBDState *s = opaque;
385 
386     if (s->status & KBD_STAT_OBF) {
387         kbd_deassert_irq(s);
388         if (s->obsrc & KBD_OBSRC_KBD) {
389             if (s->throttle_timer) {
390                 timer_mod(s->throttle_timer,
391                           qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000);
392             }
393             s->obdata = ps2_read_data(s->kbd);
394         } else if (s->obsrc & KBD_OBSRC_MOUSE) {
395             s->obdata = ps2_read_data(s->mouse);
396         } else if (s->obsrc & KBD_OBSRC_CTRL) {
397             s->obdata = kbd_dequeue(s);
398         }
399     }
400 
401     trace_pckbd_kbd_read_data(s->obdata);
402     return s->obdata;
403 }
404 
405 static void kbd_write_data(void *opaque, hwaddr addr,
406                            uint64_t val, unsigned size)
407 {
408     KBDState *s = opaque;
409 
410     trace_pckbd_kbd_write_data(val);
411 
412     switch(s->write_cmd) {
413     case 0:
414         ps2_write_keyboard(s->kbd, val);
415         /* sending data to the keyboard reenables PS/2 communication */
416         s->mode &= ~KBD_MODE_DISABLE_KBD;
417         kbd_safe_update_irq(s);
418         break;
419     case KBD_CCMD_WRITE_MODE:
420         s->mode = val;
421         ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
422         /*
423          * a write to the mode byte interrupt enable flags directly updates
424          * the irq lines
425          */
426         kbd_update_irq_lines(s);
427         /*
428          * a write to the mode byte disable interface flags may raise
429          * an irq if there is pending data in the PS/2 queues.
430          */
431         kbd_safe_update_irq(s);
432         break;
433     case KBD_CCMD_WRITE_OBUF:
434         kbd_queue(s, val, 0);
435         break;
436     case KBD_CCMD_WRITE_AUX_OBUF:
437         kbd_queue(s, val, 1);
438         break;
439     case KBD_CCMD_WRITE_OUTPORT:
440         outport_write(s, val);
441         break;
442     case KBD_CCMD_WRITE_MOUSE:
443         ps2_write_mouse(s->mouse, val);
444         /* sending data to the mouse reenables PS/2 communication */
445         s->mode &= ~KBD_MODE_DISABLE_MOUSE;
446         kbd_safe_update_irq(s);
447         break;
448     default:
449         break;
450     }
451     s->write_cmd = 0;
452 }
453 
454 static void kbd_reset(void *opaque)
455 {
456     KBDState *s = opaque;
457 
458     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
459     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
460     s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES;
461     s->pending = 0;
462     kbd_deassert_irq(s);
463     if (s->throttle_timer) {
464         timer_del(s->throttle_timer);
465     }
466 }
467 
468 static uint8_t kbd_outport_default(KBDState *s)
469 {
470     return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES
471            | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0)
472            | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0);
473 }
474 
475 static int kbd_outport_post_load(void *opaque, int version_id)
476 {
477     KBDState *s = opaque;
478     s->outport_present = true;
479     return 0;
480 }
481 
482 static bool kbd_outport_needed(void *opaque)
483 {
484     KBDState *s = opaque;
485     return s->outport != kbd_outport_default(s);
486 }
487 
488 static const VMStateDescription vmstate_kbd_outport = {
489     .name = "pckbd_outport",
490     .version_id = 1,
491     .minimum_version_id = 1,
492     .post_load = kbd_outport_post_load,
493     .needed = kbd_outport_needed,
494     .fields = (VMStateField[]) {
495         VMSTATE_UINT8(outport, KBDState),
496         VMSTATE_END_OF_LIST()
497     }
498 };
499 
500 static int kbd_extended_state_pre_save(void *opaque)
501 {
502     KBDState *s = opaque;
503 
504     s->migration_flags = 0;
505     if (s->throttle_timer && timer_pending(s->throttle_timer)) {
506         s->migration_flags |= KBD_MIGR_TIMER_PENDING;
507     }
508 
509     return 0;
510 }
511 
512 static int kbd_extended_state_post_load(void *opaque, int version_id)
513 {
514     KBDState *s = opaque;
515 
516     if (s->migration_flags & KBD_MIGR_TIMER_PENDING) {
517         kbd_throttle_timeout(s);
518     }
519     s->extended_state_loaded = true;
520 
521     return 0;
522 }
523 
524 static bool kbd_extended_state_needed(void *opaque)
525 {
526     KBDState *s = opaque;
527 
528     return s->extended_state;
529 }
530 
531 static const VMStateDescription vmstate_kbd_extended_state = {
532     .name = "pckbd/extended_state",
533     .post_load = kbd_extended_state_post_load,
534     .pre_save = kbd_extended_state_pre_save,
535     .needed = kbd_extended_state_needed,
536     .fields = (VMStateField[]) {
537         VMSTATE_UINT32(migration_flags, KBDState),
538         VMSTATE_UINT32(obsrc, KBDState),
539         VMSTATE_UINT8(obdata, KBDState),
540         VMSTATE_UINT8(cbdata, KBDState),
541         VMSTATE_END_OF_LIST()
542     }
543 };
544 
545 static int kbd_pre_save(void *opaque)
546 {
547     KBDState *s = opaque;
548 
549     if (s->extended_state) {
550         s->pending_tmp = s->pending;
551     } else {
552         s->pending_tmp = 0;
553         if (s->pending & KBD_PENDING_KBD) {
554             s->pending_tmp |= KBD_PENDING_KBD_COMPAT;
555         }
556         if (s->pending & KBD_PENDING_AUX) {
557             s->pending_tmp |= KBD_PENDING_AUX_COMPAT;
558         }
559     }
560     return 0;
561 }
562 
563 static int kbd_pre_load(void *opaque)
564 {
565     KBDState *s = opaque;
566 
567     s->outport_present = false;
568     s->extended_state_loaded = false;
569     return 0;
570 }
571 
572 static int kbd_post_load(void *opaque, int version_id)
573 {
574     KBDState *s = opaque;
575     if (!s->outport_present) {
576         s->outport = kbd_outport_default(s);
577     }
578     s->pending = s->pending_tmp;
579     if (!s->extended_state_loaded) {
580         s->obsrc = s->status & KBD_STAT_OBF ?
581             (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) :
582             0;
583         if (s->pending & KBD_PENDING_KBD_COMPAT) {
584             s->pending |= KBD_PENDING_KBD;
585         }
586         if (s->pending & KBD_PENDING_AUX_COMPAT) {
587             s->pending |= KBD_PENDING_AUX;
588         }
589     }
590     /* clear all unused flags */
591     s->pending &= KBD_PENDING_CTRL_KBD | KBD_PENDING_CTRL_AUX |
592                   KBD_PENDING_KBD | KBD_PENDING_AUX;
593     return 0;
594 }
595 
596 static const VMStateDescription vmstate_kbd = {
597     .name = "pckbd",
598     .version_id = 3,
599     .minimum_version_id = 3,
600     .pre_load = kbd_pre_load,
601     .post_load = kbd_post_load,
602     .pre_save = kbd_pre_save,
603     .fields = (VMStateField[]) {
604         VMSTATE_UINT8(write_cmd, KBDState),
605         VMSTATE_UINT8(status, KBDState),
606         VMSTATE_UINT8(mode, KBDState),
607         VMSTATE_UINT8(pending_tmp, KBDState),
608         VMSTATE_END_OF_LIST()
609     },
610     .subsections = (const VMStateDescription*[]) {
611         &vmstate_kbd_outport,
612         &vmstate_kbd_extended_state,
613         NULL
614     }
615 };
616 
617 /* Memory mapped interface */
618 static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size)
619 {
620     KBDState *s = opaque;
621 
622     if (addr & s->mask)
623         return kbd_read_status(s, 0, 1) & 0xff;
624     else
625         return kbd_read_data(s, 0, 1) & 0xff;
626 }
627 
628 static void kbd_mm_writefn(void *opaque, hwaddr addr,
629                            uint64_t value, unsigned size)
630 {
631     KBDState *s = opaque;
632 
633     if (addr & s->mask)
634         kbd_write_command(s, 0, value & 0xff, 1);
635     else
636         kbd_write_data(s, 0, value & 0xff, 1);
637 }
638 
639 
640 static const MemoryRegionOps i8042_mmio_ops = {
641     .read = kbd_mm_readfn,
642     .write = kbd_mm_writefn,
643     .valid.min_access_size = 1,
644     .valid.max_access_size = 4,
645     .endianness = DEVICE_NATIVE_ENDIAN,
646 };
647 
648 void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
649                    MemoryRegion *region, ram_addr_t size,
650                    hwaddr mask)
651 {
652     KBDState *s = g_new0(KBDState, 1);
653 
654     s->irq_kbd = kbd_irq;
655     s->irq_mouse = mouse_irq;
656     s->mask = mask;
657 
658     s->extended_state = true;
659 
660     vmstate_register(NULL, 0, &vmstate_kbd, s);
661 
662     memory_region_init_io(region, NULL, &i8042_mmio_ops, s, "i8042", size);
663 
664     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
665     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
666     qemu_register_reset(kbd_reset, s);
667 }
668 
669 struct ISAKBDState {
670     ISADevice parent_obj;
671 
672     KBDState kbd;
673     bool kbd_throttle;
674     MemoryRegion io[2];
675     uint8_t kbd_irq;
676     uint8_t mouse_irq;
677 };
678 
679 void i8042_isa_mouse_fake_event(ISAKBDState *isa)
680 {
681     KBDState *s = &isa->kbd;
682 
683     ps2_mouse_fake_event(s->mouse);
684 }
685 
686 void i8042_setup_a20_line(ISADevice *dev, qemu_irq a20_out)
687 {
688     qdev_connect_gpio_out_named(DEVICE(dev), I8042_A20_LINE, 0, a20_out);
689 }
690 
691 static const VMStateDescription vmstate_kbd_isa = {
692     .name = "pckbd",
693     .version_id = 3,
694     .minimum_version_id = 3,
695     .fields = (VMStateField[]) {
696         VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
697         VMSTATE_END_OF_LIST()
698     }
699 };
700 
701 static const MemoryRegionOps i8042_data_ops = {
702     .read = kbd_read_data,
703     .write = kbd_write_data,
704     .impl = {
705         .min_access_size = 1,
706         .max_access_size = 1,
707     },
708     .endianness = DEVICE_LITTLE_ENDIAN,
709 };
710 
711 static const MemoryRegionOps i8042_cmd_ops = {
712     .read = kbd_read_status,
713     .write = kbd_write_command,
714     .impl = {
715         .min_access_size = 1,
716         .max_access_size = 1,
717     },
718     .endianness = DEVICE_LITTLE_ENDIAN,
719 };
720 
721 static void i8042_initfn(Object *obj)
722 {
723     ISAKBDState *isa_s = I8042(obj);
724     KBDState *s = &isa_s->kbd;
725 
726     memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s,
727                           "i8042-data", 1);
728     memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s,
729                           "i8042-cmd", 1);
730 
731     qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1);
732 }
733 
734 static void i8042_realizefn(DeviceState *dev, Error **errp)
735 {
736     ISADevice *isadev = ISA_DEVICE(dev);
737     ISAKBDState *isa_s = I8042(dev);
738     KBDState *s = &isa_s->kbd;
739 
740     if (isa_s->kbd_irq >= ISA_NUM_IRQS) {
741         error_setg(errp, "Maximum value for \"kbd-irq\" is: %u",
742                    ISA_NUM_IRQS - 1);
743         return;
744     }
745 
746     if (isa_s->mouse_irq >= ISA_NUM_IRQS) {
747         error_setg(errp, "Maximum value for \"mouse-irq\" is: %u",
748                    ISA_NUM_IRQS - 1);
749         return;
750     }
751 
752     s->irq_kbd = isa_get_irq(isadev, isa_s->kbd_irq);
753     s->irq_mouse = isa_get_irq(isadev, isa_s->mouse_irq);
754 
755     isa_register_ioport(isadev, isa_s->io + 0, 0x60);
756     isa_register_ioport(isadev, isa_s->io + 1, 0x64);
757 
758     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
759     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
760     if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) {
761         warn_report(TYPE_I8042 ": can't enable kbd-throttle without"
762                     " extended-state, disabling kbd-throttle");
763     } else if (isa_s->kbd_throttle) {
764         s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL,
765                                          kbd_throttle_timeout, s);
766     }
767     qemu_register_reset(kbd_reset, s);
768 }
769 
770 static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope)
771 {
772     ISAKBDState *isa_s = I8042(adev);
773     Aml *kbd;
774     Aml *mou;
775     Aml *crs;
776 
777     crs = aml_resource_template();
778     aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
779     aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
780     aml_append(crs, aml_irq_no_flags(isa_s->kbd_irq));
781 
782     kbd = aml_device("KBD");
783     aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303")));
784     aml_append(kbd, aml_name_decl("_STA", aml_int(0xf)));
785     aml_append(kbd, aml_name_decl("_CRS", crs));
786 
787     crs = aml_resource_template();
788     aml_append(crs, aml_irq_no_flags(isa_s->mouse_irq));
789 
790     mou = aml_device("MOU");
791     aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
792     aml_append(mou, aml_name_decl("_STA", aml_int(0xf)));
793     aml_append(mou, aml_name_decl("_CRS", crs));
794 
795     aml_append(scope, kbd);
796     aml_append(scope, mou);
797 }
798 
799 static Property i8042_properties[] = {
800     DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true),
801     DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false),
802     DEFINE_PROP_UINT8("kbd-irq", ISAKBDState, kbd_irq, 1),
803     DEFINE_PROP_UINT8("mouse-irq", ISAKBDState, mouse_irq, 12),
804     DEFINE_PROP_END_OF_LIST(),
805 };
806 
807 static void i8042_class_initfn(ObjectClass *klass, void *data)
808 {
809     DeviceClass *dc = DEVICE_CLASS(klass);
810     AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
811 
812     device_class_set_props(dc, i8042_properties);
813     dc->realize = i8042_realizefn;
814     dc->vmsd = &vmstate_kbd_isa;
815     adevc->build_dev_aml = i8042_build_aml;
816     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
817 }
818 
819 static const TypeInfo i8042_info = {
820     .name          = TYPE_I8042,
821     .parent        = TYPE_ISA_DEVICE,
822     .instance_size = sizeof(ISAKBDState),
823     .instance_init = i8042_initfn,
824     .class_init    = i8042_class_initfn,
825     .interfaces = (InterfaceInfo[]) {
826         { TYPE_ACPI_DEV_AML_IF },
827         { },
828     },
829 };
830 
831 static void i8042_register_types(void)
832 {
833     type_register_static(&i8042_info);
834 }
835 
836 type_init(i8042_register_types)
837