2 * SPDX-License-Identifier: GPL-2.0-or-later
6 * (c) 2020 Laurent Vivier <laurent@vivier.eu>
10 #include "qemu/osdep.h"
12 #include "hw/qdev-properties-system.h"
13 #include "hw/sysbus.h"
14 #include "migration/vmstate.h"
15 #include "chardev/char-fe.h"
18 #include "exec/address-spaces.h"
19 #include "hw/char/goldfish_tty.h"
21 #define GOLDFISH_TTY_VERSION 1
27 REG_BYTES_READY
= 0x04,
31 REG_DATA_PTR_HIGH
= 0x18,
38 CMD_INT_DISABLE
= 0x00,
39 CMD_INT_ENABLE
= 0x01,
40 CMD_WRITE_BUFFER
= 0x02,
41 CMD_READ_BUFFER
= 0x03,
44 static uint64_t goldfish_tty_read(void *opaque
, hwaddr addr
,
47 GoldfishTTYState
*s
= opaque
;
52 value
= fifo8_num_used(&s
->rx_fifo
);
55 value
= GOLDFISH_TTY_VERSION
;
58 qemu_log_mask(LOG_UNIMP
,
59 "%s: unimplemented register read 0x%02"HWADDR_PRIx
"\n",
64 trace_goldfish_tty_read(s
, addr
, size
, value
);
69 static void goldfish_tty_cmd(GoldfishTTYState
*s
, uint32_t cmd
)
73 uint8_t data_out
[GOLFISH_TTY_BUFFER_SIZE
];
80 if (!fifo8_is_empty(&s
->rx_fifo
)) {
81 qemu_set_irq(s
->irq
, 0);
83 s
->int_enabled
= false;
87 if (!s
->int_enabled
) {
88 if (!fifo8_is_empty(&s
->rx_fifo
)) {
89 qemu_set_irq(s
->irq
, 1);
91 s
->int_enabled
= true;
94 case CMD_WRITE_BUFFER
:
98 to_copy
= MIN(GOLFISH_TTY_BUFFER_SIZE
, len
);
100 address_space_rw(&address_space_memory
, ptr
,
101 MEMTXATTRS_UNSPECIFIED
, data_out
, to_copy
, 0);
102 qemu_chr_fe_write_all(&s
->chr
, data_out
, to_copy
);
108 case CMD_READ_BUFFER
:
111 while (len
&& !fifo8_is_empty(&s
->rx_fifo
)) {
112 buf
= (uint8_t *)fifo8_pop_buf(&s
->rx_fifo
, len
, &to_copy
);
113 address_space_rw(&address_space_memory
, ptr
,
114 MEMTXATTRS_UNSPECIFIED
, buf
, to_copy
, 1);
119 if (s
->int_enabled
&& fifo8_is_empty(&s
->rx_fifo
)) {
120 qemu_set_irq(s
->irq
, 0);
126 static void goldfish_tty_write(void *opaque
, hwaddr addr
,
127 uint64_t value
, unsigned size
)
129 GoldfishTTYState
*s
= opaque
;
132 trace_goldfish_tty_write(s
, addr
, size
, value
);
137 qemu_chr_fe_write_all(&s
->chr
, &c
, sizeof(c
));
140 goldfish_tty_cmd(s
, value
);
145 case REG_DATA_PTR_HIGH
:
146 s
->data_ptr
= deposit64(s
->data_ptr
, 32, 32, value
);
152 qemu_log_mask(LOG_UNIMP
,
153 "%s: unimplemented register write 0x%02"HWADDR_PRIx
"\n",
159 static const MemoryRegionOps goldfish_tty_ops
= {
160 .read
= goldfish_tty_read
,
161 .write
= goldfish_tty_write
,
162 .endianness
= DEVICE_NATIVE_ENDIAN
,
163 .valid
.max_access_size
= 4,
164 .impl
.max_access_size
= 4,
165 .impl
.min_access_size
= 4,
168 static int goldfish_tty_can_receive(void *opaque
)
170 GoldfishTTYState
*s
= opaque
;
171 int available
= fifo8_num_free(&s
->rx_fifo
);
173 trace_goldfish_tty_can_receive(s
, available
);
178 static void goldfish_tty_receive(void *opaque
, const uint8_t *buffer
, int size
)
180 GoldfishTTYState
*s
= opaque
;
182 trace_goldfish_tty_receive(s
, size
);
184 g_assert(size
<= fifo8_num_free(&s
->rx_fifo
));
186 fifo8_push_all(&s
->rx_fifo
, buffer
, size
);
188 if (s
->int_enabled
&& !fifo8_is_empty(&s
->rx_fifo
)) {
189 qemu_set_irq(s
->irq
, 1);
193 static void goldfish_tty_reset(DeviceState
*dev
)
195 GoldfishTTYState
*s
= GOLDFISH_TTY(dev
);
197 trace_goldfish_tty_reset(s
);
199 fifo8_reset(&s
->rx_fifo
);
200 s
->int_enabled
= false;
205 static void goldfish_tty_realize(DeviceState
*dev
, Error
**errp
)
207 GoldfishTTYState
*s
= GOLDFISH_TTY(dev
);
209 trace_goldfish_tty_realize(s
);
211 fifo8_create(&s
->rx_fifo
, GOLFISH_TTY_BUFFER_SIZE
);
212 memory_region_init_io(&s
->iomem
, OBJECT(s
), &goldfish_tty_ops
, s
,
213 "goldfish_tty", 0x24);
215 if (qemu_chr_fe_backend_connected(&s
->chr
)) {
216 qemu_chr_fe_set_handlers(&s
->chr
, goldfish_tty_can_receive
,
217 goldfish_tty_receive
, NULL
, NULL
,
222 static void goldfish_tty_unrealize(DeviceState
*dev
)
224 GoldfishTTYState
*s
= GOLDFISH_TTY(dev
);
226 trace_goldfish_tty_unrealize(s
);
228 fifo8_destroy(&s
->rx_fifo
);
231 static const VMStateDescription vmstate_goldfish_tty
= {
232 .name
= "goldfish_tty",
234 .minimum_version_id
= 1,
235 .fields
= (VMStateField
[]) {
236 VMSTATE_UINT32(data_len
, GoldfishTTYState
),
237 VMSTATE_UINT64(data_ptr
, GoldfishTTYState
),
238 VMSTATE_BOOL(int_enabled
, GoldfishTTYState
),
239 VMSTATE_FIFO8(rx_fifo
, GoldfishTTYState
),
240 VMSTATE_END_OF_LIST()
244 static Property goldfish_tty_properties
[] = {
245 DEFINE_PROP_CHR("chardev", GoldfishTTYState
, chr
),
246 DEFINE_PROP_END_OF_LIST(),
249 static void goldfish_tty_instance_init(Object
*obj
)
251 SysBusDevice
*dev
= SYS_BUS_DEVICE(obj
);
252 GoldfishTTYState
*s
= GOLDFISH_TTY(obj
);
254 trace_goldfish_tty_instance_init(s
);
256 sysbus_init_mmio(dev
, &s
->iomem
);
257 sysbus_init_irq(dev
, &s
->irq
);
260 static void goldfish_tty_class_init(ObjectClass
*oc
, void *data
)
262 DeviceClass
*dc
= DEVICE_CLASS(oc
);
264 device_class_set_props(dc
, goldfish_tty_properties
);
265 dc
->reset
= goldfish_tty_reset
;
266 dc
->realize
= goldfish_tty_realize
;
267 dc
->unrealize
= goldfish_tty_unrealize
;
268 dc
->vmsd
= &vmstate_goldfish_tty
;
269 set_bit(DEVICE_CATEGORY_INPUT
, dc
->categories
);
272 static const TypeInfo goldfish_tty_info
= {
273 .name
= TYPE_GOLDFISH_TTY
,
274 .parent
= TYPE_SYS_BUS_DEVICE
,
275 .class_init
= goldfish_tty_class_init
,
276 .instance_init
= goldfish_tty_instance_init
,
277 .instance_size
= sizeof(GoldfishTTYState
),
280 static void goldfish_tty_register_types(void)
282 type_register_static(&goldfish_tty_info
);
285 type_init(goldfish_tty_register_types
)