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,
513af0f07dfSRichard 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,
555af0f07dfSRichard 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,
622af0f07dfSRichard 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 },
629af0f07dfSRichard 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,
748af0f07dfSRichard 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;
759*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, 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,
784af0f07dfSRichard 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);
950*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, 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