xref: /qemu/hw/input/pckbd.c (revision 40f27a78)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU PC keyboard emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2003 Fabrice Bellard
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini  *
1349ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini  * THE SOFTWARE.
2349ab747fSPaolo Bonzini  */
2471e8a915SMarkus Armbruster 
250430891cSPeter Maydell #include "qemu/osdep.h"
26d1e45668SVolker Rümelin #include "qemu/error-report.h"
27c2e846bbSPhilippe Mathieu-Daudé #include "qemu/log.h"
28d1e45668SVolker Rümelin #include "qemu/timer.h"
29b86ce7a6SBernhard Beschow #include "qapi/error.h"
3049ab747fSPaolo Bonzini #include "hw/isa/isa.h"
31d6454270SMarkus Armbruster #include "migration/vmstate.h"
3268f01317SIgor Mammedov #include "hw/acpi/acpi_aml_interface.h"
3349ab747fSPaolo Bonzini #include "hw/input/ps2.h"
3464552b6bSMarkus Armbruster #include "hw/irq.h"
3547973a2dSPhilippe Mathieu-Daudé #include "hw/input/i8042.h"
36ff6e1624SVolker Rümelin #include "hw/qdev-properties.h"
3771e8a915SMarkus Armbruster #include "sysemu/reset.h"
3854d31236SMarkus Armbruster #include "sysemu/runstate.h"
3949ab747fSPaolo Bonzini 
4065b182c3SDr. David Alan Gilbert #include "trace.h"
4149ab747fSPaolo Bonzini 
4249ab747fSPaolo Bonzini /* Keyboard Controller Commands */
4332be0157SMark Cave-Ayland 
4432be0157SMark Cave-Ayland /* Read mode bits */
4532be0157SMark Cave-Ayland #define KBD_CCMD_READ_MODE         0x20
4632be0157SMark Cave-Ayland /* Write mode bits */
4732be0157SMark Cave-Ayland #define KBD_CCMD_WRITE_MODE        0x60
4832be0157SMark Cave-Ayland /* Get controller version */
4932be0157SMark Cave-Ayland #define KBD_CCMD_GET_VERSION       0xA1
5032be0157SMark Cave-Ayland /* Disable mouse interface */
5132be0157SMark Cave-Ayland #define KBD_CCMD_MOUSE_DISABLE     0xA7
5232be0157SMark Cave-Ayland /* Enable mouse interface */
5332be0157SMark Cave-Ayland #define KBD_CCMD_MOUSE_ENABLE      0xA8
5432be0157SMark Cave-Ayland /* Mouse interface test */
5532be0157SMark Cave-Ayland #define KBD_CCMD_TEST_MOUSE        0xA9
5632be0157SMark Cave-Ayland /* Controller self test */
5732be0157SMark Cave-Ayland #define KBD_CCMD_SELF_TEST         0xAA
5832be0157SMark Cave-Ayland /* Keyboard interface test */
5932be0157SMark Cave-Ayland #define KBD_CCMD_KBD_TEST          0xAB
6032be0157SMark Cave-Ayland /* Keyboard interface disable */
6132be0157SMark Cave-Ayland #define KBD_CCMD_KBD_DISABLE       0xAD
6232be0157SMark Cave-Ayland /* Keyboard interface enable */
6332be0157SMark Cave-Ayland #define KBD_CCMD_KBD_ENABLE        0xAE
6432be0157SMark Cave-Ayland /* read input port */
6532be0157SMark Cave-Ayland #define KBD_CCMD_READ_INPORT       0xC0
6632be0157SMark Cave-Ayland /* read output port */
6732be0157SMark Cave-Ayland #define KBD_CCMD_READ_OUTPORT      0xD0
6832be0157SMark Cave-Ayland /* write output port */
6932be0157SMark Cave-Ayland #define KBD_CCMD_WRITE_OUTPORT     0xD1
7049ab747fSPaolo Bonzini #define KBD_CCMD_WRITE_OBUF        0xD2
7132be0157SMark Cave-Ayland /* Write to output buffer as if initiated by the auxiliary device */
7232be0157SMark Cave-Ayland #define KBD_CCMD_WRITE_AUX_OBUF    0xD3
7332be0157SMark Cave-Ayland /* Write the following byte to the mouse */
7432be0157SMark Cave-Ayland #define KBD_CCMD_WRITE_MOUSE       0xD4
7532be0157SMark Cave-Ayland /* HP vectra only ? */
7632be0157SMark Cave-Ayland #define KBD_CCMD_DISABLE_A20       0xDD
7732be0157SMark Cave-Ayland /* HP vectra only ? */
7832be0157SMark Cave-Ayland #define KBD_CCMD_ENABLE_A20        0xDF
7932be0157SMark Cave-Ayland /* Pulse bits 3-0 of the output port P2. */
8032be0157SMark Cave-Ayland #define KBD_CCMD_PULSE_BITS_3_0    0xF0
8132be0157SMark Cave-Ayland /* Pulse bit 0 of the output port P2 = CPU reset. */
8232be0157SMark Cave-Ayland #define KBD_CCMD_RESET             0xFE
8332be0157SMark Cave-Ayland /* Pulse no bits of the output port P2. */
8432be0157SMark Cave-Ayland #define KBD_CCMD_NO_OP             0xFF
8549ab747fSPaolo Bonzini 
8649ab747fSPaolo Bonzini /* Status Register Bits */
8732be0157SMark Cave-Ayland 
8832be0157SMark Cave-Ayland /* Keyboard output buffer full */
8932be0157SMark Cave-Ayland #define KBD_STAT_OBF           0x01
9032be0157SMark Cave-Ayland /* Keyboard input buffer full */
9132be0157SMark Cave-Ayland #define KBD_STAT_IBF           0x02
9232be0157SMark Cave-Ayland /* Self test successful */
9332be0157SMark Cave-Ayland #define KBD_STAT_SELFTEST      0x04
9432be0157SMark Cave-Ayland /* Last write was a command write (0=data) */
9532be0157SMark Cave-Ayland #define KBD_STAT_CMD           0x08
9632be0157SMark Cave-Ayland /* Zero if keyboard locked */
9732be0157SMark Cave-Ayland #define KBD_STAT_UNLOCKED      0x10
9832be0157SMark Cave-Ayland /* Mouse output buffer full */
9932be0157SMark Cave-Ayland #define KBD_STAT_MOUSE_OBF     0x20
10032be0157SMark Cave-Ayland /* General receive/xmit timeout */
10132be0157SMark Cave-Ayland #define KBD_STAT_GTO           0x40
10232be0157SMark Cave-Ayland /* Parity error */
10332be0157SMark Cave-Ayland #define KBD_STAT_PERR          0x80
10449ab747fSPaolo Bonzini 
10549ab747fSPaolo Bonzini /* Controller Mode Register Bits */
10632be0157SMark Cave-Ayland 
10732be0157SMark Cave-Ayland /* Keyboard data generate IRQ1 */
10832be0157SMark Cave-Ayland #define KBD_MODE_KBD_INT       0x01
10932be0157SMark Cave-Ayland /* Mouse data generate IRQ12 */
11032be0157SMark Cave-Ayland #define KBD_MODE_MOUSE_INT     0x02
11132be0157SMark Cave-Ayland /* The system flag (?) */
11232be0157SMark Cave-Ayland #define KBD_MODE_SYS           0x04
11332be0157SMark Cave-Ayland /* The keylock doesn't affect the keyboard if set */
11432be0157SMark Cave-Ayland #define KBD_MODE_NO_KEYLOCK    0x08
11532be0157SMark Cave-Ayland /* Disable keyboard interface */
11632be0157SMark Cave-Ayland #define KBD_MODE_DISABLE_KBD   0x10
11732be0157SMark Cave-Ayland /* Disable mouse interface */
11832be0157SMark Cave-Ayland #define KBD_MODE_DISABLE_MOUSE 0x20
11932be0157SMark Cave-Ayland /* Scan code conversion to PC format */
12032be0157SMark Cave-Ayland #define KBD_MODE_KCC           0x40
12149ab747fSPaolo Bonzini #define KBD_MODE_RFU           0x80
12249ab747fSPaolo Bonzini 
12349ab747fSPaolo Bonzini /* Output Port Bits */
12449ab747fSPaolo Bonzini #define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
12549ab747fSPaolo Bonzini #define KBD_OUT_A20             0x02    /* x86 only */
12649ab747fSPaolo Bonzini #define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
12749ab747fSPaolo Bonzini #define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
12849ab747fSPaolo Bonzini 
12932be0157SMark Cave-Ayland /*
13032be0157SMark Cave-Ayland  * OSes typically write 0xdd/0xdf to turn the A20 line off and on.
131d13c0404SPaolo Bonzini  * We make the default value of the outport include these four bits,
132d13c0404SPaolo Bonzini  * so that the subsection is rarely necessary.
133d13c0404SPaolo Bonzini  */
134d13c0404SPaolo Bonzini #define KBD_OUT_ONES            0xcc
135d13c0404SPaolo Bonzini 
136f6f57a82SVolker Rümelin #define KBD_PENDING_KBD_COMPAT  0x01
137f6f57a82SVolker Rümelin #define KBD_PENDING_AUX_COMPAT  0x02
138aa67a42fSVolker Rümelin #define KBD_PENDING_CTRL_KBD    0x04
139aa67a42fSVolker Rümelin #define KBD_PENDING_CTRL_AUX    0x08
140f6f57a82SVolker Rümelin #define KBD_PENDING_KBD         KBD_MODE_DISABLE_KBD    /* 0x10 */
141f6f57a82SVolker Rümelin #define KBD_PENDING_AUX         KBD_MODE_DISABLE_MOUSE  /* 0x20 */
14249ab747fSPaolo Bonzini 
143d1e45668SVolker Rümelin #define KBD_MIGR_TIMER_PENDING  0x1
144d1e45668SVolker Rümelin 
145ac9192bdSVolker Rümelin #define KBD_OBSRC_KBD           0x01
146ac9192bdSVolker Rümelin #define KBD_OBSRC_MOUSE         0x02
147aa67a42fSVolker Rümelin #define KBD_OBSRC_CTRL          0x04
148ac9192bdSVolker Rümelin 
14949ab747fSPaolo Bonzini 
15032be0157SMark Cave-Ayland /*
15132be0157SMark Cave-Ayland  * XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
15232be0157SMark Cave-Ayland  * incorrect, but it avoids having to simulate exact delays
15332be0157SMark Cave-Ayland  */
kbd_update_irq_lines(KBDState * s)154c3c4a961SVolker Rümelin static void kbd_update_irq_lines(KBDState *s)
15549ab747fSPaolo Bonzini {
15649ab747fSPaolo Bonzini     int irq_kbd_level, irq_mouse_level;
15749ab747fSPaolo Bonzini 
15849ab747fSPaolo Bonzini     irq_kbd_level = 0;
15949ab747fSPaolo Bonzini     irq_mouse_level = 0;
160c3c4a961SVolker Rümelin 
161c3c4a961SVolker Rümelin     if (s->status & KBD_STAT_OBF) {
162c3c4a961SVolker Rümelin         if (s->status & KBD_STAT_MOUSE_OBF) {
163c3c4a961SVolker Rümelin             if (s->mode & KBD_MODE_MOUSE_INT) {
164c3c4a961SVolker Rümelin                 irq_mouse_level = 1;
165c3c4a961SVolker Rümelin             }
166c3c4a961SVolker Rümelin         } else {
167c3c4a961SVolker Rümelin             if ((s->mode & KBD_MODE_KBD_INT) &&
168c3c4a961SVolker Rümelin                 !(s->mode & KBD_MODE_DISABLE_KBD)) {
169c3c4a961SVolker Rümelin                 irq_kbd_level = 1;
170c3c4a961SVolker Rümelin             }
171c3c4a961SVolker Rümelin         }
172c3c4a961SVolker Rümelin     }
173c2b17479SMark Cave-Ayland     qemu_set_irq(s->irqs[I8042_KBD_IRQ], irq_kbd_level);
174c2b17479SMark Cave-Ayland     qemu_set_irq(s->irqs[I8042_MOUSE_IRQ], irq_mouse_level);
175c3c4a961SVolker Rümelin }
176c3c4a961SVolker Rümelin 
kbd_deassert_irq(KBDState * s)177ff6e1624SVolker Rümelin static void kbd_deassert_irq(KBDState *s)
178ff6e1624SVolker Rümelin {
179ff6e1624SVolker Rümelin     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
180ff6e1624SVolker Rümelin     s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
181ff6e1624SVolker Rümelin     kbd_update_irq_lines(s);
182ff6e1624SVolker Rümelin }
183ff6e1624SVolker Rümelin 
kbd_pending(KBDState * s)184e4697fabSVolker Rümelin static uint8_t kbd_pending(KBDState *s)
185e4697fabSVolker Rümelin {
186f6f57a82SVolker Rümelin     if (s->extended_state) {
187f6f57a82SVolker Rümelin         return s->pending & (~s->mode | ~(KBD_PENDING_KBD | KBD_PENDING_AUX));
188f6f57a82SVolker Rümelin     } else {
189e4697fabSVolker Rümelin         return s->pending;
190e4697fabSVolker Rümelin     }
191f6f57a82SVolker Rümelin }
192e4697fabSVolker Rümelin 
193c3c4a961SVolker Rümelin /* update irq and KBD_STAT_[MOUSE_]OBF */
kbd_update_irq(KBDState * s)194c3c4a961SVolker Rümelin static void kbd_update_irq(KBDState *s)
195c3c4a961SVolker Rümelin {
196e4697fabSVolker Rümelin     uint8_t pending = kbd_pending(s);
197e4697fabSVolker Rümelin 
19849ab747fSPaolo Bonzini     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
19949ab747fSPaolo Bonzini     s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
200e4697fabSVolker Rümelin     if (pending) {
20149ab747fSPaolo Bonzini         s->status |= KBD_STAT_OBF;
20249ab747fSPaolo Bonzini         s->outport |= KBD_OUT_OBF;
203e4697fabSVolker Rümelin         if (pending & KBD_PENDING_CTRL_KBD) {
204aa67a42fSVolker Rümelin             s->obsrc = KBD_OBSRC_CTRL;
205e4697fabSVolker Rümelin         } else if (pending & KBD_PENDING_CTRL_AUX) {
206aa67a42fSVolker Rümelin             s->status |= KBD_STAT_MOUSE_OBF;
207aa67a42fSVolker Rümelin             s->outport |= KBD_OUT_MOUSE_OBF;
208aa67a42fSVolker Rümelin             s->obsrc = KBD_OBSRC_CTRL;
209e4697fabSVolker Rümelin         } else if (pending & KBD_PENDING_KBD) {
210aa67a42fSVolker Rümelin             s->obsrc = KBD_OBSRC_KBD;
211aa67a42fSVolker Rümelin         } else {
21249ab747fSPaolo Bonzini             s->status |= KBD_STAT_MOUSE_OBF;
21349ab747fSPaolo Bonzini             s->outport |= KBD_OUT_MOUSE_OBF;
214ac9192bdSVolker Rümelin             s->obsrc = KBD_OBSRC_MOUSE;
21549ab747fSPaolo Bonzini         }
21649ab747fSPaolo Bonzini     }
217c3c4a961SVolker Rümelin     kbd_update_irq_lines(s);
21849ab747fSPaolo Bonzini }
21949ab747fSPaolo Bonzini 
kbd_safe_update_irq(KBDState * s)220ff6e1624SVolker Rümelin static void kbd_safe_update_irq(KBDState *s)
221ff6e1624SVolker Rümelin {
222ff6e1624SVolker Rümelin     /*
223ff6e1624SVolker Rümelin      * with KBD_STAT_OBF set, a call to kbd_read_data() will eventually call
224ff6e1624SVolker Rümelin      * kbd_update_irq()
225ff6e1624SVolker Rümelin      */
226ff6e1624SVolker Rümelin     if (s->status & KBD_STAT_OBF) {
227ff6e1624SVolker Rümelin         return;
228ff6e1624SVolker Rümelin     }
229d1e45668SVolker Rümelin     /* the throttle timer is pending and will call kbd_update_irq() */
230d1e45668SVolker Rümelin     if (s->throttle_timer && timer_pending(s->throttle_timer)) {
231d1e45668SVolker Rümelin         return;
232d1e45668SVolker Rümelin     }
233e4697fabSVolker Rümelin     if (kbd_pending(s)) {
234ff6e1624SVolker Rümelin         kbd_update_irq(s);
235ff6e1624SVolker Rümelin     }
236ff6e1624SVolker Rümelin }
237ff6e1624SVolker Rümelin 
kbd_update_kbd_irq(void * opaque,int level)23849ab747fSPaolo Bonzini static void kbd_update_kbd_irq(void *opaque, int level)
23949ab747fSPaolo Bonzini {
240ff6e1624SVolker Rümelin     KBDState *s = opaque;
24149ab747fSPaolo Bonzini 
242ff6e1624SVolker Rümelin     if (level) {
24349ab747fSPaolo Bonzini         s->pending |= KBD_PENDING_KBD;
244ff6e1624SVolker Rümelin     } else {
24549ab747fSPaolo Bonzini         s->pending &= ~KBD_PENDING_KBD;
246ff6e1624SVolker Rümelin     }
247ff6e1624SVolker Rümelin     kbd_safe_update_irq(s);
24849ab747fSPaolo Bonzini }
24949ab747fSPaolo Bonzini 
kbd_update_aux_irq(void * opaque,int level)25049ab747fSPaolo Bonzini static void kbd_update_aux_irq(void *opaque, int level)
25149ab747fSPaolo Bonzini {
252ff6e1624SVolker Rümelin     KBDState *s = opaque;
25349ab747fSPaolo Bonzini 
254ff6e1624SVolker Rümelin     if (level) {
25549ab747fSPaolo Bonzini         s->pending |= KBD_PENDING_AUX;
256ff6e1624SVolker Rümelin     } else {
25749ab747fSPaolo Bonzini         s->pending &= ~KBD_PENDING_AUX;
258ff6e1624SVolker Rümelin     }
259ff6e1624SVolker Rümelin     kbd_safe_update_irq(s);
26049ab747fSPaolo Bonzini }
26149ab747fSPaolo Bonzini 
kbd_throttle_timeout(void * opaque)262d1e45668SVolker Rümelin static void kbd_throttle_timeout(void *opaque)
263d1e45668SVolker Rümelin {
264d1e45668SVolker Rümelin     KBDState *s = opaque;
265d1e45668SVolker Rümelin 
266e4697fabSVolker Rümelin     if (kbd_pending(s)) {
267d1e45668SVolker Rümelin         kbd_update_irq(s);
268d1e45668SVolker Rümelin     }
269d1e45668SVolker Rümelin }
270d1e45668SVolker Rümelin 
kbd_read_status(void * opaque,hwaddr addr,unsigned size)27149ab747fSPaolo Bonzini static uint64_t kbd_read_status(void *opaque, hwaddr addr,
27249ab747fSPaolo Bonzini                                 unsigned size)
27349ab747fSPaolo Bonzini {
27449ab747fSPaolo Bonzini     KBDState *s = opaque;
27549ab747fSPaolo Bonzini     int val;
27649ab747fSPaolo Bonzini     val = s->status;
27765b182c3SDr. David Alan Gilbert     trace_pckbd_kbd_read_status(val);
27849ab747fSPaolo Bonzini     return val;
27949ab747fSPaolo Bonzini }
28049ab747fSPaolo Bonzini 
kbd_queue(KBDState * s,int b,int aux)28149ab747fSPaolo Bonzini static void kbd_queue(KBDState *s, int b, int aux)
28249ab747fSPaolo Bonzini {
283aa67a42fSVolker Rümelin     if (s->extended_state) {
284aa67a42fSVolker Rümelin         s->cbdata = b;
285aa67a42fSVolker Rümelin         s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX;
286aa67a42fSVolker Rümelin         s->pending |= aux ? KBD_PENDING_CTRL_AUX : KBD_PENDING_CTRL_KBD;
287aa67a42fSVolker Rümelin         kbd_safe_update_irq(s);
288aa67a42fSVolker Rümelin     } else {
2899d1a4250SMark Cave-Ayland         ps2_queue(aux ? PS2_DEVICE(&s->ps2mouse) : PS2_DEVICE(&s->ps2kbd), b);
290aa67a42fSVolker Rümelin     }
291aa67a42fSVolker Rümelin }
292aa67a42fSVolker Rümelin 
kbd_dequeue(KBDState * s)293aa67a42fSVolker Rümelin static uint8_t kbd_dequeue(KBDState *s)
294aa67a42fSVolker Rümelin {
295aa67a42fSVolker Rümelin     uint8_t b = s->cbdata;
296aa67a42fSVolker Rümelin 
297aa67a42fSVolker Rümelin     s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX;
298e4697fabSVolker Rümelin     if (kbd_pending(s)) {
299aa67a42fSVolker Rümelin         kbd_update_irq(s);
300aa67a42fSVolker Rümelin     }
301aa67a42fSVolker Rümelin     return b;
30249ab747fSPaolo Bonzini }
30349ab747fSPaolo Bonzini 
outport_write(KBDState * s,uint32_t val)30449ab747fSPaolo Bonzini static void outport_write(KBDState *s, uint32_t val)
30549ab747fSPaolo Bonzini {
30665b182c3SDr. David Alan Gilbert     trace_pckbd_outport_write(val);
30749ab747fSPaolo Bonzini     s->outport = val;
3083115b9e2SEfimov Vasily     qemu_set_irq(s->a20_out, (val >> 1) & 1);
30949ab747fSPaolo Bonzini     if (!(val & 1)) {
310cf83f140SEric Blake         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
31149ab747fSPaolo Bonzini     }
31249ab747fSPaolo Bonzini }
31349ab747fSPaolo Bonzini 
kbd_write_command(void * opaque,hwaddr addr,uint64_t val,unsigned size)31449ab747fSPaolo Bonzini static void kbd_write_command(void *opaque, hwaddr addr,
31549ab747fSPaolo Bonzini                               uint64_t val, unsigned size)
31649ab747fSPaolo Bonzini {
31749ab747fSPaolo Bonzini     KBDState *s = opaque;
31849ab747fSPaolo Bonzini 
31965b182c3SDr. David Alan Gilbert     trace_pckbd_kbd_write_command(val);
32049ab747fSPaolo Bonzini 
32132be0157SMark Cave-Ayland     /*
32232be0157SMark Cave-Ayland      * Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
32349ab747fSPaolo Bonzini      * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
32449ab747fSPaolo Bonzini      * command specify the output port bits to be pulsed.
32549ab747fSPaolo Bonzini      * 0: Bit should be pulsed. 1: Bit should not be modified.
32649ab747fSPaolo Bonzini      * The only useful version of this command is pulsing bit 0,
32749ab747fSPaolo Bonzini      * which does a CPU reset.
32849ab747fSPaolo Bonzini      */
32949ab747fSPaolo Bonzini     if ((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
33032be0157SMark Cave-Ayland         if (!(val & 1)) {
33149ab747fSPaolo Bonzini             val = KBD_CCMD_RESET;
33232be0157SMark Cave-Ayland         } else {
33349ab747fSPaolo Bonzini             val = KBD_CCMD_NO_OP;
33449ab747fSPaolo Bonzini         }
33532be0157SMark Cave-Ayland     }
33649ab747fSPaolo Bonzini 
33749ab747fSPaolo Bonzini     switch (val) {
33849ab747fSPaolo Bonzini     case KBD_CCMD_READ_MODE:
33949ab747fSPaolo Bonzini         kbd_queue(s, s->mode, 0);
34049ab747fSPaolo Bonzini         break;
34149ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_MODE:
34249ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_OBUF:
34349ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_AUX_OBUF:
34449ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_MOUSE:
34549ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_OUTPORT:
34649ab747fSPaolo Bonzini         s->write_cmd = val;
34749ab747fSPaolo Bonzini         break;
34849ab747fSPaolo Bonzini     case KBD_CCMD_MOUSE_DISABLE:
34949ab747fSPaolo Bonzini         s->mode |= KBD_MODE_DISABLE_MOUSE;
35049ab747fSPaolo Bonzini         break;
35149ab747fSPaolo Bonzini     case KBD_CCMD_MOUSE_ENABLE:
35249ab747fSPaolo Bonzini         s->mode &= ~KBD_MODE_DISABLE_MOUSE;
353f6f57a82SVolker Rümelin         kbd_safe_update_irq(s);
35449ab747fSPaolo Bonzini         break;
35549ab747fSPaolo Bonzini     case KBD_CCMD_TEST_MOUSE:
35649ab747fSPaolo Bonzini         kbd_queue(s, 0x00, 0);
35749ab747fSPaolo Bonzini         break;
35849ab747fSPaolo Bonzini     case KBD_CCMD_SELF_TEST:
35949ab747fSPaolo Bonzini         s->status |= KBD_STAT_SELFTEST;
36049ab747fSPaolo Bonzini         kbd_queue(s, 0x55, 0);
36149ab747fSPaolo Bonzini         break;
36249ab747fSPaolo Bonzini     case KBD_CCMD_KBD_TEST:
36349ab747fSPaolo Bonzini         kbd_queue(s, 0x00, 0);
36449ab747fSPaolo Bonzini         break;
36549ab747fSPaolo Bonzini     case KBD_CCMD_KBD_DISABLE:
36649ab747fSPaolo Bonzini         s->mode |= KBD_MODE_DISABLE_KBD;
36749ab747fSPaolo Bonzini         break;
36849ab747fSPaolo Bonzini     case KBD_CCMD_KBD_ENABLE:
36949ab747fSPaolo Bonzini         s->mode &= ~KBD_MODE_DISABLE_KBD;
370ff6e1624SVolker Rümelin         kbd_safe_update_irq(s);
37149ab747fSPaolo Bonzini         break;
37249ab747fSPaolo Bonzini     case KBD_CCMD_READ_INPORT:
373f1b7e0e4SHervé Poussineau         kbd_queue(s, 0x80, 0);
37449ab747fSPaolo Bonzini         break;
37549ab747fSPaolo Bonzini     case KBD_CCMD_READ_OUTPORT:
37649ab747fSPaolo Bonzini         kbd_queue(s, s->outport, 0);
37749ab747fSPaolo Bonzini         break;
37849ab747fSPaolo Bonzini     case KBD_CCMD_ENABLE_A20:
3793115b9e2SEfimov Vasily         qemu_irq_raise(s->a20_out);
38049ab747fSPaolo Bonzini         s->outport |= KBD_OUT_A20;
38149ab747fSPaolo Bonzini         break;
38249ab747fSPaolo Bonzini     case KBD_CCMD_DISABLE_A20:
3833115b9e2SEfimov Vasily         qemu_irq_lower(s->a20_out);
38449ab747fSPaolo Bonzini         s->outport &= ~KBD_OUT_A20;
38549ab747fSPaolo Bonzini         break;
38649ab747fSPaolo Bonzini     case KBD_CCMD_RESET:
387cf83f140SEric Blake         qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
38849ab747fSPaolo Bonzini         break;
38949ab747fSPaolo Bonzini     case KBD_CCMD_NO_OP:
39049ab747fSPaolo Bonzini         /* ignore that */
39149ab747fSPaolo Bonzini         break;
39249ab747fSPaolo Bonzini     default:
393c2e846bbSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
394c2e846bbSPhilippe Mathieu-Daudé                       "unsupported keyboard cmd=0x%02" PRIx64 "\n", val);
39549ab747fSPaolo Bonzini         break;
39649ab747fSPaolo Bonzini     }
39749ab747fSPaolo Bonzini }
39849ab747fSPaolo Bonzini 
kbd_read_data(void * opaque,hwaddr addr,unsigned size)39949ab747fSPaolo Bonzini static uint64_t kbd_read_data(void *opaque, hwaddr addr,
40049ab747fSPaolo Bonzini                               unsigned size)
40149ab747fSPaolo Bonzini {
40249ab747fSPaolo Bonzini     KBDState *s = opaque;
40349ab747fSPaolo Bonzini 
404ac9192bdSVolker Rümelin     if (s->status & KBD_STAT_OBF) {
405ff6e1624SVolker Rümelin         kbd_deassert_irq(s);
406ac9192bdSVolker Rümelin         if (s->obsrc & KBD_OBSRC_KBD) {
407d1e45668SVolker Rümelin             if (s->throttle_timer) {
408d1e45668SVolker Rümelin                 timer_mod(s->throttle_timer,
409d1e45668SVolker Rümelin                           qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000);
410d1e45668SVolker Rümelin             }
411652fbff4SMark Cave-Ayland             s->obdata = ps2_read_data(PS2_DEVICE(&s->ps2kbd));
412ac9192bdSVolker Rümelin         } else if (s->obsrc & KBD_OBSRC_MOUSE) {
4139d1a4250SMark Cave-Ayland             s->obdata = ps2_read_data(PS2_DEVICE(&s->ps2mouse));
414aa67a42fSVolker Rümelin         } else if (s->obsrc & KBD_OBSRC_CTRL) {
415aa67a42fSVolker Rümelin             s->obdata = kbd_dequeue(s);
416ff6e1624SVolker Rümelin         }
417ff6e1624SVolker Rümelin     }
41849ab747fSPaolo Bonzini 
419ff6e1624SVolker Rümelin     trace_pckbd_kbd_read_data(s->obdata);
420ff6e1624SVolker Rümelin     return s->obdata;
42149ab747fSPaolo Bonzini }
42249ab747fSPaolo Bonzini 
kbd_write_data(void * opaque,hwaddr addr,uint64_t val,unsigned size)42349ab747fSPaolo Bonzini static void kbd_write_data(void *opaque, hwaddr addr,
42449ab747fSPaolo Bonzini                            uint64_t val, unsigned size)
42549ab747fSPaolo Bonzini {
42649ab747fSPaolo Bonzini     KBDState *s = opaque;
42749ab747fSPaolo Bonzini 
42865b182c3SDr. David Alan Gilbert     trace_pckbd_kbd_write_data(val);
42949ab747fSPaolo Bonzini 
43049ab747fSPaolo Bonzini     switch (s->write_cmd) {
43149ab747fSPaolo Bonzini     case 0:
432652fbff4SMark Cave-Ayland         ps2_write_keyboard(&s->ps2kbd, val);
433f6f57a82SVolker Rümelin         /* sending data to the keyboard reenables PS/2 communication */
434f6f57a82SVolker Rümelin         s->mode &= ~KBD_MODE_DISABLE_KBD;
435f6f57a82SVolker Rümelin         kbd_safe_update_irq(s);
43649ab747fSPaolo Bonzini         break;
43749ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_MODE:
43849ab747fSPaolo Bonzini         s->mode = val;
439652fbff4SMark Cave-Ayland         ps2_keyboard_set_translation(&s->ps2kbd,
440652fbff4SMark Cave-Ayland                                      (s->mode & KBD_MODE_KCC) != 0);
441ff6e1624SVolker Rümelin         /*
442ff6e1624SVolker Rümelin          * a write to the mode byte interrupt enable flags directly updates
443ff6e1624SVolker Rümelin          * the irq lines
444ff6e1624SVolker Rümelin          */
445ff6e1624SVolker Rümelin         kbd_update_irq_lines(s);
446ff6e1624SVolker Rümelin         /*
447ff6e1624SVolker Rümelin          * a write to the mode byte disable interface flags may raise
448ff6e1624SVolker Rümelin          * an irq if there is pending data in the PS/2 queues.
449ff6e1624SVolker Rümelin          */
450ff6e1624SVolker Rümelin         kbd_safe_update_irq(s);
45149ab747fSPaolo Bonzini         break;
45249ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_OBUF:
45349ab747fSPaolo Bonzini         kbd_queue(s, val, 0);
45449ab747fSPaolo Bonzini         break;
45549ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_AUX_OBUF:
45649ab747fSPaolo Bonzini         kbd_queue(s, val, 1);
45749ab747fSPaolo Bonzini         break;
45849ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_OUTPORT:
45949ab747fSPaolo Bonzini         outport_write(s, val);
46049ab747fSPaolo Bonzini         break;
46149ab747fSPaolo Bonzini     case KBD_CCMD_WRITE_MOUSE:
4629d1a4250SMark Cave-Ayland         ps2_write_mouse(&s->ps2mouse, val);
463f6f57a82SVolker Rümelin         /* sending data to the mouse reenables PS/2 communication */
464f6f57a82SVolker Rümelin         s->mode &= ~KBD_MODE_DISABLE_MOUSE;
465f6f57a82SVolker Rümelin         kbd_safe_update_irq(s);
46649ab747fSPaolo Bonzini         break;
46749ab747fSPaolo Bonzini     default:
46849ab747fSPaolo Bonzini         break;
46949ab747fSPaolo Bonzini     }
47049ab747fSPaolo Bonzini     s->write_cmd = 0;
47149ab747fSPaolo Bonzini }
47249ab747fSPaolo Bonzini 
kbd_reset(void * opaque)47349ab747fSPaolo Bonzini static void kbd_reset(void *opaque)
47449ab747fSPaolo Bonzini {
47549ab747fSPaolo Bonzini     KBDState *s = opaque;
47649ab747fSPaolo Bonzini 
47749ab747fSPaolo Bonzini     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
47849ab747fSPaolo Bonzini     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
479d13c0404SPaolo Bonzini     s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES;
480ff6e1624SVolker Rümelin     s->pending = 0;
481ff6e1624SVolker Rümelin     kbd_deassert_irq(s);
482d1e45668SVolker Rümelin     if (s->throttle_timer) {
483d1e45668SVolker Rümelin         timer_del(s->throttle_timer);
484d1e45668SVolker Rümelin     }
485a28fe7e3SPavel Dovgalyuk }
486a28fe7e3SPavel Dovgalyuk 
kbd_outport_default(KBDState * s)487a28fe7e3SPavel Dovgalyuk static uint8_t kbd_outport_default(KBDState *s)
488a28fe7e3SPavel Dovgalyuk {
489d13c0404SPaolo Bonzini     return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES
490a28fe7e3SPavel Dovgalyuk            | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0)
491a28fe7e3SPavel Dovgalyuk            | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0);
492a28fe7e3SPavel Dovgalyuk }
493a28fe7e3SPavel Dovgalyuk 
kbd_outport_post_load(void * opaque,int version_id)494a28fe7e3SPavel Dovgalyuk static int kbd_outport_post_load(void *opaque, int version_id)
495a28fe7e3SPavel Dovgalyuk {
496a28fe7e3SPavel Dovgalyuk     KBDState *s = opaque;
497a28fe7e3SPavel Dovgalyuk     s->outport_present = true;
498a28fe7e3SPavel Dovgalyuk     return 0;
499a28fe7e3SPavel Dovgalyuk }
500a28fe7e3SPavel Dovgalyuk 
kbd_outport_needed(void * opaque)501a28fe7e3SPavel Dovgalyuk static bool kbd_outport_needed(void *opaque)
502a28fe7e3SPavel Dovgalyuk {
503a28fe7e3SPavel Dovgalyuk     KBDState *s = opaque;
504a28fe7e3SPavel Dovgalyuk     return s->outport != kbd_outport_default(s);
505a28fe7e3SPavel Dovgalyuk }
506a28fe7e3SPavel Dovgalyuk 
5075cd8cadaSJuan Quintela static const VMStateDescription vmstate_kbd_outport = {
5085cd8cadaSJuan Quintela     .name = "pckbd_outport",
5095cd8cadaSJuan Quintela     .version_id = 1,
5105cd8cadaSJuan Quintela     .minimum_version_id = 1,
5115cd8cadaSJuan Quintela     .post_load = kbd_outport_post_load,
5125cd8cadaSJuan Quintela     .needed = kbd_outport_needed,
513*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
5145cd8cadaSJuan Quintela         VMSTATE_UINT8(outport, KBDState),
5155cd8cadaSJuan Quintela         VMSTATE_END_OF_LIST()
5165cd8cadaSJuan Quintela     }
5175cd8cadaSJuan Quintela };
5185cd8cadaSJuan Quintela 
kbd_extended_state_pre_save(void * opaque)519d1e45668SVolker Rümelin static int kbd_extended_state_pre_save(void *opaque)
520d1e45668SVolker Rümelin {
521d1e45668SVolker Rümelin     KBDState *s = opaque;
522d1e45668SVolker Rümelin 
523d1e45668SVolker Rümelin     s->migration_flags = 0;
524d1e45668SVolker Rümelin     if (s->throttle_timer && timer_pending(s->throttle_timer)) {
525d1e45668SVolker Rümelin         s->migration_flags |= KBD_MIGR_TIMER_PENDING;
526d1e45668SVolker Rümelin     }
527d1e45668SVolker Rümelin 
528d1e45668SVolker Rümelin     return 0;
529d1e45668SVolker Rümelin }
530d1e45668SVolker Rümelin 
kbd_extended_state_post_load(void * opaque,int version_id)531d1e45668SVolker Rümelin static int kbd_extended_state_post_load(void *opaque, int version_id)
532d1e45668SVolker Rümelin {
533d1e45668SVolker Rümelin     KBDState *s = opaque;
534d1e45668SVolker Rümelin 
535d1e45668SVolker Rümelin     if (s->migration_flags & KBD_MIGR_TIMER_PENDING) {
536d1e45668SVolker Rümelin         kbd_throttle_timeout(s);
537d1e45668SVolker Rümelin     }
538ac9192bdSVolker Rümelin     s->extended_state_loaded = true;
539d1e45668SVolker Rümelin 
540d1e45668SVolker Rümelin     return 0;
541d1e45668SVolker Rümelin }
542d1e45668SVolker Rümelin 
kbd_extended_state_needed(void * opaque)543ff6e1624SVolker Rümelin static bool kbd_extended_state_needed(void *opaque)
544ff6e1624SVolker Rümelin {
545ff6e1624SVolker Rümelin     KBDState *s = opaque;
546ff6e1624SVolker Rümelin 
547ff6e1624SVolker Rümelin     return s->extended_state;
548ff6e1624SVolker Rümelin }
549ff6e1624SVolker Rümelin 
550ff6e1624SVolker Rümelin static const VMStateDescription vmstate_kbd_extended_state = {
551ff6e1624SVolker Rümelin     .name = "pckbd/extended_state",
552d1e45668SVolker Rümelin     .post_load = kbd_extended_state_post_load,
553d1e45668SVolker Rümelin     .pre_save = kbd_extended_state_pre_save,
554ff6e1624SVolker Rümelin     .needed = kbd_extended_state_needed,
555*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
556d1e45668SVolker Rümelin         VMSTATE_UINT32(migration_flags, KBDState),
557ac9192bdSVolker Rümelin         VMSTATE_UINT32(obsrc, KBDState),
558ff6e1624SVolker Rümelin         VMSTATE_UINT8(obdata, KBDState),
559aa67a42fSVolker Rümelin         VMSTATE_UINT8(cbdata, KBDState),
560ff6e1624SVolker Rümelin         VMSTATE_END_OF_LIST()
561ff6e1624SVolker Rümelin     }
562ff6e1624SVolker Rümelin };
563ff6e1624SVolker Rümelin 
kbd_pre_save(void * opaque)564f6f57a82SVolker Rümelin static int kbd_pre_save(void *opaque)
565f6f57a82SVolker Rümelin {
566f6f57a82SVolker Rümelin     KBDState *s = opaque;
567f6f57a82SVolker Rümelin 
568f6f57a82SVolker Rümelin     if (s->extended_state) {
569f6f57a82SVolker Rümelin         s->pending_tmp = s->pending;
570f6f57a82SVolker Rümelin     } else {
571f6f57a82SVolker Rümelin         s->pending_tmp = 0;
572f6f57a82SVolker Rümelin         if (s->pending & KBD_PENDING_KBD) {
573f6f57a82SVolker Rümelin             s->pending_tmp |= KBD_PENDING_KBD_COMPAT;
574f6f57a82SVolker Rümelin         }
575f6f57a82SVolker Rümelin         if (s->pending & KBD_PENDING_AUX) {
576f6f57a82SVolker Rümelin             s->pending_tmp |= KBD_PENDING_AUX_COMPAT;
577f6f57a82SVolker Rümelin         }
578f6f57a82SVolker Rümelin     }
579f6f57a82SVolker Rümelin     return 0;
580f6f57a82SVolker Rümelin }
581f6f57a82SVolker Rümelin 
kbd_pre_load(void * opaque)582ac9192bdSVolker Rümelin static int kbd_pre_load(void *opaque)
583ac9192bdSVolker Rümelin {
584ac9192bdSVolker Rümelin     KBDState *s = opaque;
585ac9192bdSVolker Rümelin 
5869d74e6c3SVolker Rümelin     s->outport_present = false;
587ac9192bdSVolker Rümelin     s->extended_state_loaded = false;
588ac9192bdSVolker Rümelin     return 0;
589ac9192bdSVolker Rümelin }
590ac9192bdSVolker Rümelin 
kbd_post_load(void * opaque,int version_id)591a28fe7e3SPavel Dovgalyuk static int kbd_post_load(void *opaque, int version_id)
592a28fe7e3SPavel Dovgalyuk {
593a28fe7e3SPavel Dovgalyuk     KBDState *s = opaque;
594a28fe7e3SPavel Dovgalyuk     if (!s->outport_present) {
595a28fe7e3SPavel Dovgalyuk         s->outport = kbd_outport_default(s);
596a28fe7e3SPavel Dovgalyuk     }
597f6f57a82SVolker Rümelin     s->pending = s->pending_tmp;
598ac9192bdSVolker Rümelin     if (!s->extended_state_loaded) {
599ac9192bdSVolker Rümelin         s->obsrc = s->status & KBD_STAT_OBF ?
600ac9192bdSVolker Rümelin             (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) :
601ac9192bdSVolker Rümelin             0;
602f6f57a82SVolker Rümelin         if (s->pending & KBD_PENDING_KBD_COMPAT) {
603f6f57a82SVolker Rümelin             s->pending |= KBD_PENDING_KBD;
604ac9192bdSVolker Rümelin         }
605f6f57a82SVolker Rümelin         if (s->pending & KBD_PENDING_AUX_COMPAT) {
606f6f57a82SVolker Rümelin             s->pending |= KBD_PENDING_AUX;
607f6f57a82SVolker Rümelin         }
608f6f57a82SVolker Rümelin     }
609f6f57a82SVolker Rümelin     /* clear all unused flags */
610f6f57a82SVolker Rümelin     s->pending &= KBD_PENDING_CTRL_KBD | KBD_PENDING_CTRL_AUX |
611f6f57a82SVolker Rümelin                   KBD_PENDING_KBD | KBD_PENDING_AUX;
612a28fe7e3SPavel Dovgalyuk     return 0;
61349ab747fSPaolo Bonzini }
61449ab747fSPaolo Bonzini 
61549ab747fSPaolo Bonzini static const VMStateDescription vmstate_kbd = {
61649ab747fSPaolo Bonzini     .name = "pckbd",
61749ab747fSPaolo Bonzini     .version_id = 3,
61849ab747fSPaolo Bonzini     .minimum_version_id = 3,
619ac9192bdSVolker Rümelin     .pre_load = kbd_pre_load,
620a28fe7e3SPavel Dovgalyuk     .post_load = kbd_post_load,
621f6f57a82SVolker Rümelin     .pre_save = kbd_pre_save,
622*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
62349ab747fSPaolo Bonzini         VMSTATE_UINT8(write_cmd, KBDState),
62449ab747fSPaolo Bonzini         VMSTATE_UINT8(status, KBDState),
62549ab747fSPaolo Bonzini         VMSTATE_UINT8(mode, KBDState),
626f6f57a82SVolker Rümelin         VMSTATE_UINT8(pending_tmp, KBDState),
62749ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
628a28fe7e3SPavel Dovgalyuk     },
629*af0f07dfSRichard Henderson     .subsections = (const VMStateDescription * const []) {
6305cd8cadaSJuan Quintela         &vmstate_kbd_outport,
631ff6e1624SVolker Rümelin         &vmstate_kbd_extended_state,
6325cd8cadaSJuan Quintela         NULL
63349ab747fSPaolo Bonzini     }
63449ab747fSPaolo Bonzini };
63549ab747fSPaolo Bonzini 
63649ab747fSPaolo Bonzini /* Memory mapped interface */
kbd_mm_readfn(void * opaque,hwaddr addr,unsigned size)6375876503cSPeter Maydell static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size)
63849ab747fSPaolo Bonzini {
63949ab747fSPaolo Bonzini     KBDState *s = opaque;
64049ab747fSPaolo Bonzini 
64132be0157SMark Cave-Ayland     if (addr & s->mask) {
64249ab747fSPaolo Bonzini         return kbd_read_status(s, 0, 1) & 0xff;
64332be0157SMark Cave-Ayland     } else {
64449ab747fSPaolo Bonzini         return kbd_read_data(s, 0, 1) & 0xff;
64549ab747fSPaolo Bonzini     }
64632be0157SMark Cave-Ayland }
64749ab747fSPaolo Bonzini 
kbd_mm_writefn(void * opaque,hwaddr addr,uint64_t value,unsigned size)6485876503cSPeter Maydell static void kbd_mm_writefn(void *opaque, hwaddr addr,
6495876503cSPeter Maydell                            uint64_t value, unsigned size)
65049ab747fSPaolo Bonzini {
65149ab747fSPaolo Bonzini     KBDState *s = opaque;
65249ab747fSPaolo Bonzini 
65332be0157SMark Cave-Ayland     if (addr & s->mask) {
65449ab747fSPaolo Bonzini         kbd_write_command(s, 0, value & 0xff, 1);
65532be0157SMark Cave-Ayland     } else {
65649ab747fSPaolo Bonzini         kbd_write_data(s, 0, value & 0xff, 1);
65749ab747fSPaolo Bonzini     }
65832be0157SMark Cave-Ayland }
65949ab747fSPaolo Bonzini 
6605876503cSPeter Maydell 
66149ab747fSPaolo Bonzini static const MemoryRegionOps i8042_mmio_ops = {
6625876503cSPeter Maydell     .read = kbd_mm_readfn,
6635876503cSPeter Maydell     .write = kbd_mm_writefn,
6645876503cSPeter Maydell     .valid.min_access_size = 1,
6655876503cSPeter Maydell     .valid.max_access_size = 4,
66649ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
66749ab747fSPaolo Bonzini };
66849ab747fSPaolo Bonzini 
i8042_mmio_set_kbd_irq(void * opaque,int n,int level)669cb663a81SMark Cave-Ayland static void i8042_mmio_set_kbd_irq(void *opaque, int n, int level)
670cb663a81SMark Cave-Ayland {
671cb663a81SMark Cave-Ayland     MMIOKBDState *s = I8042_MMIO(opaque);
672cb663a81SMark Cave-Ayland     KBDState *ks = &s->kbd;
673cb663a81SMark Cave-Ayland 
674cb663a81SMark Cave-Ayland     kbd_update_kbd_irq(ks, level);
675cb663a81SMark Cave-Ayland }
676cb663a81SMark Cave-Ayland 
i8042_mmio_set_mouse_irq(void * opaque,int n,int level)677cb663a81SMark Cave-Ayland static void i8042_mmio_set_mouse_irq(void *opaque, int n, int level)
678cb663a81SMark Cave-Ayland {
679cb663a81SMark Cave-Ayland     MMIOKBDState *s = I8042_MMIO(opaque);
680cb663a81SMark Cave-Ayland     KBDState *ks = &s->kbd;
681cb663a81SMark Cave-Ayland 
682cb663a81SMark Cave-Ayland     kbd_update_aux_irq(ks, level);
683cb663a81SMark Cave-Ayland }
684cb663a81SMark Cave-Ayland 
i8042_mmio_reset(DeviceState * dev)68557f6c3aaSMark Cave-Ayland static void i8042_mmio_reset(DeviceState *dev)
68657f6c3aaSMark Cave-Ayland {
68757f6c3aaSMark Cave-Ayland     MMIOKBDState *s = I8042_MMIO(dev);
68857f6c3aaSMark Cave-Ayland     KBDState *ks = &s->kbd;
68957f6c3aaSMark Cave-Ayland 
69057f6c3aaSMark Cave-Ayland     kbd_reset(ks);
69157f6c3aaSMark Cave-Ayland }
69257f6c3aaSMark Cave-Ayland 
i8042_mmio_realize(DeviceState * dev,Error ** errp)693f4de68d1SMark Cave-Ayland static void i8042_mmio_realize(DeviceState *dev, Error **errp)
694f4de68d1SMark Cave-Ayland {
695f4de68d1SMark Cave-Ayland     MMIOKBDState *s = I8042_MMIO(dev);
696f4de68d1SMark Cave-Ayland     KBDState *ks = &s->kbd;
697f4de68d1SMark Cave-Ayland 
698f4de68d1SMark Cave-Ayland     memory_region_init_io(&s->region, OBJECT(dev), &i8042_mmio_ops, ks,
699f4de68d1SMark Cave-Ayland                           "i8042", s->size);
700f4de68d1SMark Cave-Ayland 
701f4de68d1SMark Cave-Ayland     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->region);
70275877e93SMark Cave-Ayland 
703652fbff4SMark Cave-Ayland     if (!sysbus_realize(SYS_BUS_DEVICE(&ks->ps2kbd), errp)) {
704652fbff4SMark Cave-Ayland         return;
705652fbff4SMark Cave-Ayland     }
706652fbff4SMark Cave-Ayland 
7079d1a4250SMark Cave-Ayland     if (!sysbus_realize(SYS_BUS_DEVICE(&ks->ps2mouse), errp)) {
7089d1a4250SMark Cave-Ayland         return;
7099d1a4250SMark Cave-Ayland     }
7109d1a4250SMark Cave-Ayland 
711652fbff4SMark Cave-Ayland     qdev_connect_gpio_out(DEVICE(&ks->ps2kbd), PS2_DEVICE_IRQ,
712cb663a81SMark Cave-Ayland                           qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
713cb663a81SMark Cave-Ayland                                                  0));
714652fbff4SMark Cave-Ayland 
7159d1a4250SMark Cave-Ayland     qdev_connect_gpio_out(DEVICE(&ks->ps2mouse), PS2_DEVICE_IRQ,
716cb663a81SMark Cave-Ayland                           qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
717cb663a81SMark Cave-Ayland                                                  0));
718f4de68d1SMark Cave-Ayland }
719f4de68d1SMark Cave-Ayland 
i8042_mmio_init(Object * obj)72047fc7415SMark Cave-Ayland static void i8042_mmio_init(Object *obj)
72147fc7415SMark Cave-Ayland {
72247fc7415SMark Cave-Ayland     MMIOKBDState *s = I8042_MMIO(obj);
72347fc7415SMark Cave-Ayland     KBDState *ks = &s->kbd;
72447fc7415SMark Cave-Ayland 
72547fc7415SMark Cave-Ayland     ks->extended_state = true;
726cb663a81SMark Cave-Ayland 
727652fbff4SMark Cave-Ayland     object_initialize_child(obj, "ps2kbd", &ks->ps2kbd, TYPE_PS2_KBD_DEVICE);
7289d1a4250SMark Cave-Ayland     object_initialize_child(obj, "ps2mouse", &ks->ps2mouse,
7299d1a4250SMark Cave-Ayland                             TYPE_PS2_MOUSE_DEVICE);
730652fbff4SMark Cave-Ayland 
731cb663a81SMark Cave-Ayland     qdev_init_gpio_out(DEVICE(obj), ks->irqs, 2);
732cb663a81SMark Cave-Ayland     qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_kbd_irq,
733cb663a81SMark Cave-Ayland                             "ps2-kbd-input-irq", 1);
734cb663a81SMark Cave-Ayland     qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_mouse_irq,
735cb663a81SMark Cave-Ayland                             "ps2-mouse-input-irq", 1);
73647fc7415SMark Cave-Ayland }
73747fc7415SMark Cave-Ayland 
738d4f5b4d8SMark Cave-Ayland static Property i8042_mmio_properties[] = {
739d4f5b4d8SMark Cave-Ayland     DEFINE_PROP_UINT64("mask", MMIOKBDState, kbd.mask, UINT64_MAX),
7407b9fff29SMark Cave-Ayland     DEFINE_PROP_UINT32("size", MMIOKBDState, size, -1),
741d4f5b4d8SMark Cave-Ayland     DEFINE_PROP_END_OF_LIST(),
742d4f5b4d8SMark Cave-Ayland };
743d4f5b4d8SMark Cave-Ayland 
744abcacb20SMark Cave-Ayland static const VMStateDescription vmstate_kbd_mmio = {
745abcacb20SMark Cave-Ayland     .name = "pckbd-mmio",
746abcacb20SMark Cave-Ayland     .version_id = 1,
747abcacb20SMark Cave-Ayland     .minimum_version_id = 1,
748*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
749abcacb20SMark Cave-Ayland         VMSTATE_STRUCT(kbd, MMIOKBDState, 0, vmstate_kbd, KBDState),
750abcacb20SMark Cave-Ayland         VMSTATE_END_OF_LIST()
751abcacb20SMark Cave-Ayland     }
752abcacb20SMark Cave-Ayland };
753abcacb20SMark Cave-Ayland 
i8042_mmio_class_init(ObjectClass * klass,void * data)754150ee013SMark Cave-Ayland static void i8042_mmio_class_init(ObjectClass *klass, void *data)
755150ee013SMark Cave-Ayland {
756150ee013SMark Cave-Ayland     DeviceClass *dc = DEVICE_CLASS(klass);
757150ee013SMark Cave-Ayland 
758f4de68d1SMark Cave-Ayland     dc->realize = i8042_mmio_realize;
75957f6c3aaSMark Cave-Ayland     dc->reset = i8042_mmio_reset;
760abcacb20SMark Cave-Ayland     dc->vmsd = &vmstate_kbd_mmio;
761d4f5b4d8SMark Cave-Ayland     device_class_set_props(dc, i8042_mmio_properties);
762150ee013SMark Cave-Ayland     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
763150ee013SMark Cave-Ayland }
764150ee013SMark Cave-Ayland 
765150ee013SMark Cave-Ayland static const TypeInfo i8042_mmio_info = {
766150ee013SMark Cave-Ayland     .name          = TYPE_I8042_MMIO,
767150ee013SMark Cave-Ayland     .parent        = TYPE_SYS_BUS_DEVICE,
76847fc7415SMark Cave-Ayland     .instance_init = i8042_mmio_init,
769150ee013SMark Cave-Ayland     .instance_size = sizeof(MMIOKBDState),
770150ee013SMark Cave-Ayland     .class_init    = i8042_mmio_class_init
771150ee013SMark Cave-Ayland };
772150ee013SMark Cave-Ayland 
i8042_isa_mouse_fake_event(ISAKBDState * isa)7730fe4bb32SMarc-André Lureau void i8042_isa_mouse_fake_event(ISAKBDState *isa)
77449ab747fSPaolo Bonzini {
775a2e0b863SAndreas Färber     KBDState *s = &isa->kbd;
77649ab747fSPaolo Bonzini 
7779d1a4250SMark Cave-Ayland     ps2_mouse_fake_event(&s->ps2mouse);
77849ab747fSPaolo Bonzini }
77949ab747fSPaolo Bonzini 
78049ab747fSPaolo Bonzini static const VMStateDescription vmstate_kbd_isa = {
78149ab747fSPaolo Bonzini     .name = "pckbd",
78249ab747fSPaolo Bonzini     .version_id = 3,
78349ab747fSPaolo Bonzini     .minimum_version_id = 3,
784*af0f07dfSRichard Henderson     .fields = (const VMStateField[]) {
78549ab747fSPaolo Bonzini         VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
78649ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
78749ab747fSPaolo Bonzini     }
78849ab747fSPaolo Bonzini };
78949ab747fSPaolo Bonzini 
79049ab747fSPaolo Bonzini static const MemoryRegionOps i8042_data_ops = {
79149ab747fSPaolo Bonzini     .read = kbd_read_data,
79249ab747fSPaolo Bonzini     .write = kbd_write_data,
79349ab747fSPaolo Bonzini     .impl = {
79449ab747fSPaolo Bonzini         .min_access_size = 1,
79549ab747fSPaolo Bonzini         .max_access_size = 1,
79649ab747fSPaolo Bonzini     },
79749ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
79849ab747fSPaolo Bonzini };
79949ab747fSPaolo Bonzini 
80049ab747fSPaolo Bonzini static const MemoryRegionOps i8042_cmd_ops = {
80149ab747fSPaolo Bonzini     .read = kbd_read_status,
80249ab747fSPaolo Bonzini     .write = kbd_write_command,
80349ab747fSPaolo Bonzini     .impl = {
80449ab747fSPaolo Bonzini         .min_access_size = 1,
80549ab747fSPaolo Bonzini         .max_access_size = 1,
80649ab747fSPaolo Bonzini     },
80749ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
80849ab747fSPaolo Bonzini };
80949ab747fSPaolo Bonzini 
i8042_set_kbd_irq(void * opaque,int n,int level)8106eb252d5SMark Cave-Ayland static void i8042_set_kbd_irq(void *opaque, int n, int level)
8116eb252d5SMark Cave-Ayland {
8126eb252d5SMark Cave-Ayland     ISAKBDState *s = I8042(opaque);
8136eb252d5SMark Cave-Ayland     KBDState *ks = &s->kbd;
8146eb252d5SMark Cave-Ayland 
8156eb252d5SMark Cave-Ayland     kbd_update_kbd_irq(ks, level);
8166eb252d5SMark Cave-Ayland }
8176eb252d5SMark Cave-Ayland 
i8042_set_mouse_irq(void * opaque,int n,int level)8186eb252d5SMark Cave-Ayland static void i8042_set_mouse_irq(void *opaque, int n, int level)
8196eb252d5SMark Cave-Ayland {
8206eb252d5SMark Cave-Ayland     ISAKBDState *s = I8042(opaque);
8216eb252d5SMark Cave-Ayland     KBDState *ks = &s->kbd;
8226eb252d5SMark Cave-Ayland 
8236eb252d5SMark Cave-Ayland     kbd_update_aux_irq(ks, level);
8246eb252d5SMark Cave-Ayland }
8256eb252d5SMark Cave-Ayland 
8266eb252d5SMark Cave-Ayland 
i8042_reset(DeviceState * dev)82755870d6fSMark Cave-Ayland static void i8042_reset(DeviceState *dev)
82855870d6fSMark Cave-Ayland {
82955870d6fSMark Cave-Ayland     ISAKBDState *s = I8042(dev);
83055870d6fSMark Cave-Ayland     KBDState *ks = &s->kbd;
83155870d6fSMark Cave-Ayland 
83255870d6fSMark Cave-Ayland     kbd_reset(ks);
83355870d6fSMark Cave-Ayland }
83455870d6fSMark Cave-Ayland 
i8042_initfn(Object * obj)835db895a1eSAndreas Färber static void i8042_initfn(Object *obj)
83649ab747fSPaolo Bonzini {
837db895a1eSAndreas Färber     ISAKBDState *isa_s = I8042(obj);
838db895a1eSAndreas Färber     KBDState *s = &isa_s->kbd;
839db895a1eSAndreas Färber 
8401437c94bSPaolo Bonzini     memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s,
8411437c94bSPaolo Bonzini                           "i8042-data", 1);
8421437c94bSPaolo Bonzini     memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s,
8431437c94bSPaolo Bonzini                           "i8042-cmd", 1);
8443115b9e2SEfimov Vasily 
845652fbff4SMark Cave-Ayland     object_initialize_child(obj, "ps2kbd", &s->ps2kbd, TYPE_PS2_KBD_DEVICE);
8469d1a4250SMark Cave-Ayland     object_initialize_child(obj, "ps2mouse", &s->ps2mouse,
8479d1a4250SMark Cave-Ayland                             TYPE_PS2_MOUSE_DEVICE);
848652fbff4SMark Cave-Ayland 
8493115b9e2SEfimov Vasily     qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1);
8506eb252d5SMark Cave-Ayland 
8516eb252d5SMark Cave-Ayland     qdev_init_gpio_out(DEVICE(obj), s->irqs, 2);
8526eb252d5SMark Cave-Ayland     qdev_init_gpio_in_named(DEVICE(obj), i8042_set_kbd_irq,
8536eb252d5SMark Cave-Ayland                             "ps2-kbd-input-irq", 1);
8546eb252d5SMark Cave-Ayland     qdev_init_gpio_in_named(DEVICE(obj), i8042_set_mouse_irq,
8556eb252d5SMark Cave-Ayland                             "ps2-mouse-input-irq", 1);
856db895a1eSAndreas Färber }
857db895a1eSAndreas Färber 
i8042_realizefn(DeviceState * dev,Error ** errp)858db895a1eSAndreas Färber static void i8042_realizefn(DeviceState *dev, Error **errp)
859db895a1eSAndreas Färber {
860db895a1eSAndreas Färber     ISADevice *isadev = ISA_DEVICE(dev);
861a2e0b863SAndreas Färber     ISAKBDState *isa_s = I8042(dev);
86249ab747fSPaolo Bonzini     KBDState *s = &isa_s->kbd;
86349ab747fSPaolo Bonzini 
864b86ce7a6SBernhard Beschow     if (isa_s->kbd_irq >= ISA_NUM_IRQS) {
865b86ce7a6SBernhard Beschow         error_setg(errp, "Maximum value for \"kbd-irq\" is: %u",
866b86ce7a6SBernhard Beschow                    ISA_NUM_IRQS - 1);
867b86ce7a6SBernhard Beschow         return;
868b86ce7a6SBernhard Beschow     }
869b86ce7a6SBernhard Beschow 
870b86ce7a6SBernhard Beschow     if (isa_s->mouse_irq >= ISA_NUM_IRQS) {
871b86ce7a6SBernhard Beschow         error_setg(errp, "Maximum value for \"mouse-irq\" is: %u",
872b86ce7a6SBernhard Beschow                    ISA_NUM_IRQS - 1);
873b86ce7a6SBernhard Beschow         return;
874b86ce7a6SBernhard Beschow     }
875b86ce7a6SBernhard Beschow 
8766eb252d5SMark Cave-Ayland     isa_connect_gpio_out(isadev, I8042_KBD_IRQ, isa_s->kbd_irq);
8776eb252d5SMark Cave-Ayland     isa_connect_gpio_out(isadev, I8042_MOUSE_IRQ, isa_s->mouse_irq);
87849ab747fSPaolo Bonzini 
879db895a1eSAndreas Färber     isa_register_ioport(isadev, isa_s->io + 0, 0x60);
880db895a1eSAndreas Färber     isa_register_ioport(isadev, isa_s->io + 1, 0x64);
88149ab747fSPaolo Bonzini 
882652fbff4SMark Cave-Ayland     if (!sysbus_realize(SYS_BUS_DEVICE(&s->ps2kbd), errp)) {
883652fbff4SMark Cave-Ayland         return;
884652fbff4SMark Cave-Ayland     }
885652fbff4SMark Cave-Ayland 
886652fbff4SMark Cave-Ayland     qdev_connect_gpio_out(DEVICE(&s->ps2kbd), PS2_DEVICE_IRQ,
8876eb252d5SMark Cave-Ayland                           qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
8886eb252d5SMark Cave-Ayland                                                  0));
889652fbff4SMark Cave-Ayland 
8909d1a4250SMark Cave-Ayland     if (!sysbus_realize(SYS_BUS_DEVICE(&s->ps2mouse), errp)) {
8919d1a4250SMark Cave-Ayland         return;
8929d1a4250SMark Cave-Ayland     }
8939d1a4250SMark Cave-Ayland 
8949d1a4250SMark Cave-Ayland     qdev_connect_gpio_out(DEVICE(&s->ps2mouse), PS2_DEVICE_IRQ,
8956eb252d5SMark Cave-Ayland                           qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
8966eb252d5SMark Cave-Ayland                                                  0));
8979d1a4250SMark Cave-Ayland 
898d1e45668SVolker Rümelin     if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) {
899d1e45668SVolker Rümelin         warn_report(TYPE_I8042 ": can't enable kbd-throttle without"
900d1e45668SVolker Rümelin                     " extended-state, disabling kbd-throttle");
901d1e45668SVolker Rümelin     } else if (isa_s->kbd_throttle) {
902d1e45668SVolker Rümelin         s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL,
903d1e45668SVolker Rümelin                                          kbd_throttle_timeout, s);
904d1e45668SVolker Rümelin     }
90549ab747fSPaolo Bonzini }
90649ab747fSPaolo Bonzini 
i8042_build_aml(AcpiDevAmlIf * adev,Aml * scope)90768f01317SIgor Mammedov static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope)
908df0f3d13SGerd Hoffmann {
90968f01317SIgor Mammedov     ISAKBDState *isa_s = I8042(adev);
910df0f3d13SGerd Hoffmann     Aml *kbd;
911df0f3d13SGerd Hoffmann     Aml *mou;
912df0f3d13SGerd Hoffmann     Aml *crs;
913df0f3d13SGerd Hoffmann 
914df0f3d13SGerd Hoffmann     crs = aml_resource_template();
915df0f3d13SGerd Hoffmann     aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
916df0f3d13SGerd Hoffmann     aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
917b86ce7a6SBernhard Beschow     aml_append(crs, aml_irq_no_flags(isa_s->kbd_irq));
918df0f3d13SGerd Hoffmann 
919df0f3d13SGerd Hoffmann     kbd = aml_device("KBD");
920df0f3d13SGerd Hoffmann     aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303")));
921df0f3d13SGerd Hoffmann     aml_append(kbd, aml_name_decl("_STA", aml_int(0xf)));
922df0f3d13SGerd Hoffmann     aml_append(kbd, aml_name_decl("_CRS", crs));
923df0f3d13SGerd Hoffmann 
924df0f3d13SGerd Hoffmann     crs = aml_resource_template();
925b86ce7a6SBernhard Beschow     aml_append(crs, aml_irq_no_flags(isa_s->mouse_irq));
926df0f3d13SGerd Hoffmann 
927df0f3d13SGerd Hoffmann     mou = aml_device("MOU");
928df0f3d13SGerd Hoffmann     aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
929df0f3d13SGerd Hoffmann     aml_append(mou, aml_name_decl("_STA", aml_int(0xf)));
930df0f3d13SGerd Hoffmann     aml_append(mou, aml_name_decl("_CRS", crs));
931df0f3d13SGerd Hoffmann 
932df0f3d13SGerd Hoffmann     aml_append(scope, kbd);
933df0f3d13SGerd Hoffmann     aml_append(scope, mou);
934df0f3d13SGerd Hoffmann }
935df0f3d13SGerd Hoffmann 
936ff6e1624SVolker Rümelin static Property i8042_properties[] = {
937ff6e1624SVolker Rümelin     DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true),
938d1e45668SVolker Rümelin     DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false),
939b86ce7a6SBernhard Beschow     DEFINE_PROP_UINT8("kbd-irq", ISAKBDState, kbd_irq, 1),
940b86ce7a6SBernhard Beschow     DEFINE_PROP_UINT8("mouse-irq", ISAKBDState, mouse_irq, 12),
941ff6e1624SVolker Rümelin     DEFINE_PROP_END_OF_LIST(),
942ff6e1624SVolker Rümelin };
943ff6e1624SVolker Rümelin 
i8042_class_initfn(ObjectClass * klass,void * data)94449ab747fSPaolo Bonzini static void i8042_class_initfn(ObjectClass *klass, void *data)
94549ab747fSPaolo Bonzini {
94649ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
94768f01317SIgor Mammedov     AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
948db895a1eSAndreas Färber 
949ff6e1624SVolker Rümelin     device_class_set_props(dc, i8042_properties);
95055870d6fSMark Cave-Ayland     dc->reset = i8042_reset;
951db895a1eSAndreas Färber     dc->realize = i8042_realizefn;
95249ab747fSPaolo Bonzini     dc->vmsd = &vmstate_kbd_isa;
95368f01317SIgor Mammedov     adevc->build_dev_aml = i8042_build_aml;
954cbe9ed73Skumar sourav     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
95549ab747fSPaolo Bonzini }
95649ab747fSPaolo Bonzini 
95749ab747fSPaolo Bonzini static const TypeInfo i8042_info = {
958a2e0b863SAndreas Färber     .name          = TYPE_I8042,
95949ab747fSPaolo Bonzini     .parent        = TYPE_ISA_DEVICE,
96049ab747fSPaolo Bonzini     .instance_size = sizeof(ISAKBDState),
961db895a1eSAndreas Färber     .instance_init = i8042_initfn,
96249ab747fSPaolo Bonzini     .class_init    = i8042_class_initfn,
96368f01317SIgor Mammedov     .interfaces = (InterfaceInfo[]) {
96468f01317SIgor Mammedov         { TYPE_ACPI_DEV_AML_IF },
96568f01317SIgor Mammedov         { },
96668f01317SIgor Mammedov     },
96749ab747fSPaolo Bonzini };
96849ab747fSPaolo Bonzini 
i8042_register_types(void)96949ab747fSPaolo Bonzini static void i8042_register_types(void)
97049ab747fSPaolo Bonzini {
97149ab747fSPaolo Bonzini     type_register_static(&i8042_info);
972150ee013SMark Cave-Ayland     type_register_static(&i8042_mmio_info);
97349ab747fSPaolo Bonzini }
97449ab747fSPaolo Bonzini 
97549ab747fSPaolo Bonzini type_init(i8042_register_types)
976