2 * QEMU HP Lasi PS/2 interface emulation
4 * Copyright (c) 2019 Sven Schnelle
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "qemu/osdep.h"
26 #include "hw/qdev-properties.h"
27 #include "hw/sysbus.h"
28 #include "hw/input/ps2.h"
29 #include "hw/input/lasips2.h"
30 #include "exec/hwaddr.h"
32 #include "exec/address-spaces.h"
33 #include "migration/vmstate.h"
35 #include "qapi/error.h"
38 static const VMStateDescription vmstate_lasips2
= {
41 .minimum_version_id
= 0,
42 .fields
= (VMStateField
[]) {
43 VMSTATE_UINT8(kbd
.control
, LASIPS2State
),
44 VMSTATE_UINT8(kbd
.id
, LASIPS2State
),
45 VMSTATE_BOOL(kbd
.irq
, LASIPS2State
),
46 VMSTATE_UINT8(mouse
.control
, LASIPS2State
),
47 VMSTATE_UINT8(mouse
.id
, LASIPS2State
),
48 VMSTATE_BOOL(mouse
.irq
, LASIPS2State
),
63 } lasips2_write_reg_t
;
66 LASIPS2_CONTROL_ENABLE
= 0x01,
67 LASIPS2_CONTROL_LOOPBACK
= 0x02,
68 LASIPS2_CONTROL_DIAG
= 0x20,
69 LASIPS2_CONTROL_DATDIR
= 0x40,
70 LASIPS2_CONTROL_CLKDIR
= 0x80,
71 } lasips2_control_reg_t
;
74 LASIPS2_STATUS_RBNE
= 0x01,
75 LASIPS2_STATUS_TBNE
= 0x02,
76 LASIPS2_STATUS_TERR
= 0x04,
77 LASIPS2_STATUS_PERR
= 0x08,
78 LASIPS2_STATUS_CMPINTR
= 0x10,
79 LASIPS2_STATUS_DATSHD
= 0x40,
80 LASIPS2_STATUS_CLKSHD
= 0x80,
81 } lasips2_status_reg_t
;
83 static const char *lasips2_read_reg_name(uint64_t addr
)
90 return " PS2_RCVDATA";
93 return " PS2_CONTROL";
103 static const char *lasips2_write_reg_name(uint64_t addr
)
105 switch (addr
& 0x0c) {
109 case REG_PS2_XMTDATA
:
110 return " PS2_XMTDATA";
112 case REG_PS2_CONTROL
:
113 return " PS2_CONTROL";
120 static void lasips2_update_irq(LASIPS2State
*s
)
122 trace_lasips2_intr(s
->kbd
.irq
| s
->mouse
.irq
);
123 qemu_set_irq(s
->irq
, s
->kbd
.irq
| s
->mouse
.irq
);
126 static void lasips2_reg_write(void *opaque
, hwaddr addr
, uint64_t val
,
129 LASIPS2Port
*port
= opaque
;
131 trace_lasips2_reg_write(size
, port
->id
, addr
,
132 lasips2_write_reg_name(addr
), val
);
134 switch (addr
& 0xc) {
135 case REG_PS2_CONTROL
:
139 case REG_PS2_XMTDATA
:
140 if (port
->control
& LASIPS2_CONTROL_LOOPBACK
) {
143 port
->loopback_rbne
= true;
144 lasips2_update_irq(port
->parent
);
149 ps2_write_mouse(port
->dev
, val
);
151 ps2_write_keyboard(port
->dev
, val
);
159 qemu_log_mask(LOG_UNIMP
, "%s: unknown register 0x%02" HWADDR_PRIx
"\n",
165 static uint64_t lasips2_reg_read(void *opaque
, hwaddr addr
, unsigned size
)
167 LASIPS2Port
*port
= opaque
;
170 switch (addr
& 0xc) {
175 case REG_PS2_RCVDATA
:
176 if (port
->control
& LASIPS2_CONTROL_LOOPBACK
) {
178 port
->loopback_rbne
= false;
179 lasips2_update_irq(port
->parent
);
184 ret
= ps2_read_data(port
->dev
);
187 case REG_PS2_CONTROL
:
192 ret
= LASIPS2_STATUS_DATSHD
| LASIPS2_STATUS_CLKSHD
;
194 if (port
->control
& LASIPS2_CONTROL_DIAG
) {
195 if (!(port
->control
& LASIPS2_CONTROL_DATDIR
)) {
196 ret
&= ~LASIPS2_STATUS_DATSHD
;
199 if (!(port
->control
& LASIPS2_CONTROL_CLKDIR
)) {
200 ret
&= ~LASIPS2_STATUS_CLKSHD
;
204 if (port
->control
& LASIPS2_CONTROL_LOOPBACK
) {
205 if (port
->loopback_rbne
) {
206 ret
|= LASIPS2_STATUS_RBNE
;
209 if (!ps2_queue_empty(port
->dev
)) {
210 ret
|= LASIPS2_STATUS_RBNE
;
214 if (port
->parent
->kbd
.irq
|| port
->parent
->mouse
.irq
) {
215 ret
|= LASIPS2_STATUS_CMPINTR
;
220 qemu_log_mask(LOG_UNIMP
, "%s: unknown register 0x%02" HWADDR_PRIx
"\n",
225 trace_lasips2_reg_read(size
, port
->id
, addr
,
226 lasips2_read_reg_name(addr
), ret
);
230 static const MemoryRegionOps lasips2_reg_ops
= {
231 .read
= lasips2_reg_read
,
232 .write
= lasips2_reg_write
,
234 .min_access_size
= 1,
235 .max_access_size
= 4,
237 .endianness
= DEVICE_NATIVE_ENDIAN
,
240 static void lasips2_port_set_irq(void *opaque
, int level
)
242 LASIPS2Port
*port
= opaque
;
245 lasips2_update_irq(port
->parent
);
248 LASIPS2State
*lasips2_initfn(hwaddr base
, qemu_irq irq
)
253 dev
= qdev_new(TYPE_LASIPS2
);
254 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev
), &error_fatal
);
259 vmstate_register(NULL
, base
, &vmstate_lasips2
, s
);
261 s
->kbd
.dev
= ps2_kbd_init(lasips2_port_set_irq
, &s
->kbd
);
262 s
->mouse
.dev
= ps2_mouse_init(lasips2_port_set_irq
, &s
->mouse
);
267 static void lasips2_init(Object
*obj
)
269 LASIPS2State
*s
= LASIPS2(obj
);
276 memory_region_init_io(&s
->kbd
.reg
, obj
, &lasips2_reg_ops
, &s
->kbd
,
277 "lasips2-kbd", 0x100);
278 memory_region_init_io(&s
->mouse
.reg
, obj
, &lasips2_reg_ops
, &s
->mouse
,
279 "lasips2-mouse", 0x100);
281 sysbus_init_mmio(SYS_BUS_DEVICE(obj
), &s
->kbd
.reg
);
282 sysbus_init_mmio(SYS_BUS_DEVICE(obj
), &s
->mouse
.reg
);
285 static const TypeInfo lasips2_info
= {
286 .name
= TYPE_LASIPS2
,
287 .parent
= TYPE_SYS_BUS_DEVICE
,
288 .instance_init
= lasips2_init
,
289 .instance_size
= sizeof(LASIPS2State
)
292 static void lasips2_register_types(void)
294 type_register_static(&lasips2_info
);
297 type_init(lasips2_register_types
)