13
#include "qemu/osdep.h"
14
#include "chardev/char-fe.h"
15
#include "qemu/error-report.h"
16
#include "qemu/module.h"
18
#include "hw/qdev-properties.h"
19
#include "hw/qdev-properties-system.h"
20
#include "hw/virtio/virtio-serial.h"
21
#include "qapi/error.h"
22
#include "qapi/qapi-events-char.h"
23
#include "qom/object.h"
25
#define TYPE_VIRTIO_CONSOLE_SERIAL_PORT "virtserialport"
26
typedef struct VirtConsole VirtConsole;
27
DECLARE_INSTANCE_CHECKER(VirtConsole, VIRTIO_CONSOLE,
28
TYPE_VIRTIO_CONSOLE_SERIAL_PORT)
31
VirtIOSerialPort parent_obj;
41
static gboolean chr_write_unblocked(void *do_not_use, GIOCondition cond,
44
VirtConsole *vcon = opaque;
47
virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), false);
48
return G_SOURCE_REMOVE;
52
static ssize_t flush_buf(VirtIOSerialPort *port,
53
const uint8_t *buf, ssize_t len)
55
VirtConsole *vcon = VIRTIO_CONSOLE(port);
58
if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
63
ret = qemu_chr_fe_write(&vcon->chr, buf, len);
64
trace_virtio_console_flush_buf(port->id, len, ret);
67
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
99
virtio_serial_throttle_port(port, true);
101
vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
103
chr_write_unblocked, vcon);
111
static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
113
VirtConsole *vcon = VIRTIO_CONSOLE(port);
114
DeviceState *dev = DEVICE(port);
115
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
117
if (!k->is_console) {
118
qemu_chr_fe_set_open(&vcon->chr, guest_connected);
122
qapi_event_send_vserport_change(dev->id, guest_connected);
126
static void guest_writable(VirtIOSerialPort *port)
128
VirtConsole *vcon = VIRTIO_CONSOLE(port);
130
qemu_chr_fe_accept_input(&vcon->chr);
134
static int chr_can_read(void *opaque)
136
VirtConsole *vcon = opaque;
138
return virtio_serial_guest_ready(VIRTIO_SERIAL_PORT(vcon));
142
static void chr_read(void *opaque, const uint8_t *buf, int size)
144
VirtConsole *vcon = opaque;
145
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
147
trace_virtio_console_chr_read(port->id, size);
148
virtio_serial_write(port, buf, size);
151
static void chr_event(void *opaque, QEMUChrEvent event)
153
VirtConsole *vcon = opaque;
154
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
156
trace_virtio_console_chr_event(port->id, event);
158
case CHR_EVENT_OPENED:
159
virtio_serial_open(port);
161
case CHR_EVENT_CLOSED:
163
g_source_remove(vcon->watch);
166
virtio_serial_close(port);
168
case CHR_EVENT_BREAK:
169
case CHR_EVENT_MUX_IN:
170
case CHR_EVENT_MUX_OUT:
176
static int chr_be_change(void *opaque)
178
VirtConsole *vcon = opaque;
179
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
180
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
183
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
184
NULL, chr_be_change, vcon, NULL, true);
186
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
187
chr_event, chr_be_change, vcon, NULL, false);
191
g_source_remove(vcon->watch);
192
vcon->watch = qemu_chr_fe_add_watch(&vcon->chr,
194
chr_write_unblocked, vcon);
200
static void virtconsole_enable_backend(VirtIOSerialPort *port, bool enable)
202
VirtConsole *vcon = VIRTIO_CONSOLE(port);
204
if (!qemu_chr_fe_backend_connected(&vcon->chr)) {
209
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
211
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
212
k->is_console ? NULL : chr_event,
213
chr_be_change, vcon, NULL, false);
215
qemu_chr_fe_set_handlers(&vcon->chr, NULL, NULL, NULL,
216
NULL, NULL, NULL, false);
220
static void virtconsole_realize(DeviceState *dev, Error **errp)
222
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
223
VirtConsole *vcon = VIRTIO_CONSOLE(dev);
224
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
226
if (port->id == 0 && !k->is_console) {
227
error_setg(errp, "Port number 0 on virtio-serial devices reserved "
228
"for virtconsole devices for backward compatibility.");
232
if (qemu_chr_fe_backend_connected(&vcon->chr)) {
243
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
246
virtio_serial_open(port);
248
qemu_chr_fe_set_handlers(&vcon->chr, chr_can_read, chr_read,
249
chr_event, chr_be_change,
255
static void virtconsole_unrealize(DeviceState *dev)
257
VirtConsole *vcon = VIRTIO_CONSOLE(dev);
260
g_source_remove(vcon->watch);
264
static void virtconsole_class_init(ObjectClass *klass, void *data)
266
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
268
k->is_console = true;
271
static const TypeInfo virtconsole_info = {
272
.name = "virtconsole",
273
.parent = TYPE_VIRTIO_CONSOLE_SERIAL_PORT,
274
.class_init = virtconsole_class_init,
277
static Property virtserialport_properties[] = {
278
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
279
DEFINE_PROP_END_OF_LIST(),
282
static void virtserialport_class_init(ObjectClass *klass, void *data)
284
DeviceClass *dc = DEVICE_CLASS(klass);
285
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
287
k->realize = virtconsole_realize;
288
k->unrealize = virtconsole_unrealize;
289
k->have_data = flush_buf;
290
k->set_guest_connected = set_guest_connected;
291
k->enable_backend = virtconsole_enable_backend;
292
k->guest_writable = guest_writable;
293
device_class_set_props(dc, virtserialport_properties);
296
static const TypeInfo virtserialport_info = {
297
.name = TYPE_VIRTIO_CONSOLE_SERIAL_PORT,
298
.parent = TYPE_VIRTIO_SERIAL_PORT,
299
.instance_size = sizeof(VirtConsole),
300
.class_init = virtserialport_class_init,
303
static void virtconsole_register_types(void)
305
type_register_static(&virtserialport_info);
306
type_register_static(&virtconsole_info);
309
type_init(virtconsole_register_types)