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