Statistics
| Branch: | Revision:

root / hw / virtio-console.c @ 927d4878

History | View | Annotate | Download (4.8 kB)

1
/*
2
 * Virtio Console and Generic Serial Port Devices
3
 *
4
 * Copyright Red Hat, Inc. 2009, 2010
5
 *
6
 * Authors:
7
 *  Amit Shah <amit.shah@redhat.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 */
12

    
13
#include "char/char.h"
14
#include "qemu/error-report.h"
15
#include "trace.h"
16
#include "virtio-serial.h"
17

    
18
typedef struct VirtConsole {
19
    VirtIOSerialPort port;
20
    CharDriverState *chr;
21
} VirtConsole;
22

    
23

    
24
/* Callback function that's called when the guest sends us data */
25
static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
26
{
27
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
28
    ssize_t ret;
29

    
30
    if (!vcon->chr) {
31
        /* If there's no backend, we can just say we consumed all data. */
32
        return len;
33
    }
34

    
35
    ret = qemu_chr_fe_write(vcon->chr, buf, len);
36
    trace_virtio_console_flush_buf(port->id, len, ret);
37

    
38
    if (ret < 0) {
39
        /*
40
         * Ideally we'd get a better error code than just -1, but
41
         * that's what the chardev interface gives us right now.  If
42
         * we had a finer-grained message, like -EPIPE, we could close
43
         * this connection.  Absent such error messages, the most we
44
         * can do is to return 0 here.
45
         *
46
         * This will prevent stray -1 values to go to
47
         * virtio-serial-bus.c and cause abort()s in
48
         * do_flush_queued_data().
49
         */
50
        ret = 0;
51
    }
52
    return ret;
53
}
54

    
55
/* Callback function that's called when the guest opens the port */
56
static void guest_open(VirtIOSerialPort *port)
57
{
58
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
59

    
60
    if (!vcon->chr) {
61
        return;
62
    }
63
    qemu_chr_fe_open(vcon->chr);
64
}
65

    
66
/* Callback function that's called when the guest closes the port */
67
static void guest_close(VirtIOSerialPort *port)
68
{
69
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
70

    
71
    if (!vcon->chr) {
72
        return;
73
    }
74
    qemu_chr_fe_close(vcon->chr);
75
}
76

    
77
/* Readiness of the guest to accept data on a port */
78
static int chr_can_read(void *opaque)
79
{
80
    VirtConsole *vcon = opaque;
81

    
82
    return virtio_serial_guest_ready(&vcon->port);
83
}
84

    
85
/* Send data from a char device over to the guest */
86
static void chr_read(void *opaque, const uint8_t *buf, int size)
87
{
88
    VirtConsole *vcon = opaque;
89

    
90
    trace_virtio_console_chr_read(vcon->port.id, size);
91
    virtio_serial_write(&vcon->port, buf, size);
92
}
93

    
94
static void chr_event(void *opaque, int event)
95
{
96
    VirtConsole *vcon = opaque;
97

    
98
    trace_virtio_console_chr_event(vcon->port.id, event);
99
    switch (event) {
100
    case CHR_EVENT_OPENED:
101
        virtio_serial_open(&vcon->port);
102
        break;
103
    case CHR_EVENT_CLOSED:
104
        virtio_serial_close(&vcon->port);
105
        break;
106
    }
107
}
108

    
109
static int virtconsole_initfn(VirtIOSerialPort *port)
110
{
111
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
112
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
113

    
114
    if (port->id == 0 && !k->is_console) {
115
        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
116
        return -1;
117
    }
118

    
119
    if (vcon->chr) {
120
        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
121
                              vcon);
122
    }
123

    
124
    return 0;
125
}
126

    
127
static Property virtconsole_properties[] = {
128
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
129
    DEFINE_PROP_END_OF_LIST(),
130
};
131

    
132
static void virtconsole_class_init(ObjectClass *klass, void *data)
133
{
134
    DeviceClass *dc = DEVICE_CLASS(klass);
135
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
136

    
137
    k->is_console = true;
138
    k->init = virtconsole_initfn;
139
    k->have_data = flush_buf;
140
    k->guest_open = guest_open;
141
    k->guest_close = guest_close;
142
    dc->props = virtconsole_properties;
143
}
144

    
145
static TypeInfo virtconsole_info = {
146
    .name          = "virtconsole",
147
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
148
    .instance_size = sizeof(VirtConsole),
149
    .class_init    = virtconsole_class_init,
150
};
151

    
152
static Property virtserialport_properties[] = {
153
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
154
    DEFINE_PROP_END_OF_LIST(),
155
};
156

    
157
static void virtserialport_class_init(ObjectClass *klass, void *data)
158
{
159
    DeviceClass *dc = DEVICE_CLASS(klass);
160
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
161

    
162
    k->init = virtconsole_initfn;
163
    k->have_data = flush_buf;
164
    k->guest_open = guest_open;
165
    k->guest_close = guest_close;
166
    dc->props = virtserialport_properties;
167
}
168

    
169
static TypeInfo virtserialport_info = {
170
    .name          = "virtserialport",
171
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
172
    .instance_size = sizeof(VirtConsole),
173
    .class_init    = virtserialport_class_init,
174
};
175

    
176
static void virtconsole_register_types(void)
177
{
178
    type_register_static(&virtconsole_info);
179
    type_register_static(&virtserialport_info);
180
}
181

    
182
type_init(virtconsole_register_types)