Statistics
| Branch: | Revision:

root / hw / char / virtio-console.c @ 81069b20

History | View | Annotate | Download (5.5 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 "sysemu/char.h"
14
#include "qemu/error-report.h"
15
#include "trace.h"
16
#include "hw/virtio/virtio-serial.h"
17

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

    
24
/*
25
 * Callback function that's called from chardevs when backend becomes
26
 * writable.
27
 */
28
static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
29
                                    void *opaque)
30
{
31
    VirtConsole *vcon = opaque;
32

    
33
    vcon->watch = 0;
34
    virtio_serial_throttle_port(&vcon->port, false);
35
    return FALSE;
36
}
37

    
38
/* Callback function that's called when the guest sends us data */
39
static ssize_t flush_buf(VirtIOSerialPort *port,
40
                         const uint8_t *buf, ssize_t len)
41
{
42
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
43
    ssize_t ret;
44

    
45
    if (!vcon->chr) {
46
        /* If there's no backend, we can just say we consumed all data. */
47
        return len;
48
    }
49

    
50
    ret = qemu_chr_fe_write(vcon->chr, buf, len);
51
    trace_virtio_console_flush_buf(port->id, len, ret);
52

    
53
    if (ret < len) {
54
        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
55

    
56
        /*
57
         * Ideally we'd get a better error code than just -1, but
58
         * that's what the chardev interface gives us right now.  If
59
         * we had a finer-grained message, like -EPIPE, we could close
60
         * this connection.
61
         */
62
        if (ret < 0)
63
            ret = 0;
64
        if (!k->is_console) {
65
            virtio_serial_throttle_port(port, true);
66
            if (!vcon->watch) {
67
                vcon->watch = qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT,
68
                                                    chr_write_unblocked, vcon);
69
            }
70
        }
71
    }
72
    return ret;
73
}
74

    
75
/* Callback function that's called when the guest opens/closes the port */
76
static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
77
{
78
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
79

    
80
    if (!vcon->chr) {
81
        return;
82
    }
83
    qemu_chr_fe_set_open(vcon->chr, guest_connected);
84
}
85

    
86
/* Readiness of the guest to accept data on a port */
87
static int chr_can_read(void *opaque)
88
{
89
    VirtConsole *vcon = opaque;
90

    
91
    return virtio_serial_guest_ready(&vcon->port);
92
}
93

    
94
/* Send data from a char device over to the guest */
95
static void chr_read(void *opaque, const uint8_t *buf, int size)
96
{
97
    VirtConsole *vcon = opaque;
98

    
99
    trace_virtio_console_chr_read(vcon->port.id, size);
100
    virtio_serial_write(&vcon->port, buf, size);
101
}
102

    
103
static void chr_event(void *opaque, int event)
104
{
105
    VirtConsole *vcon = opaque;
106

    
107
    trace_virtio_console_chr_event(vcon->port.id, event);
108
    switch (event) {
109
    case CHR_EVENT_OPENED:
110
        virtio_serial_open(&vcon->port);
111
        break;
112
    case CHR_EVENT_CLOSED:
113
        if (vcon->watch) {
114
            g_source_remove(vcon->watch);
115
            vcon->watch = 0;
116
        }
117
        virtio_serial_close(&vcon->port);
118
        break;
119
    }
120
}
121

    
122
static int virtconsole_initfn(VirtIOSerialPort *port)
123
{
124
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
125
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
126

    
127
    if (port->id == 0 && !k->is_console) {
128
        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
129
        return -1;
130
    }
131

    
132
    if (vcon->chr) {
133
        vcon->chr->explicit_fe_open = 1;
134
        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
135
                              vcon);
136
    }
137

    
138
    return 0;
139
}
140

    
141
static int virtconsole_exitfn(VirtIOSerialPort *port)
142
{
143
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
144

    
145
    if (vcon->watch) {
146
        g_source_remove(vcon->watch);
147
    }
148

    
149
    return 0;
150
}
151

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

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

    
162
    k->is_console = true;
163
    k->init = virtconsole_initfn;
164
    k->exit = virtconsole_exitfn;
165
    k->have_data = flush_buf;
166
    k->set_guest_connected = set_guest_connected;
167
    dc->props = virtconsole_properties;
168
}
169

    
170
static const TypeInfo virtconsole_info = {
171
    .name          = "virtconsole",
172
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
173
    .instance_size = sizeof(VirtConsole),
174
    .class_init    = virtconsole_class_init,
175
};
176

    
177
static Property virtserialport_properties[] = {
178
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
179
    DEFINE_PROP_END_OF_LIST(),
180
};
181

    
182
static void virtserialport_class_init(ObjectClass *klass, void *data)
183
{
184
    DeviceClass *dc = DEVICE_CLASS(klass);
185
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
186

    
187
    k->init = virtconsole_initfn;
188
    k->have_data = flush_buf;
189
    k->set_guest_connected = set_guest_connected;
190
    dc->props = virtserialport_properties;
191
}
192

    
193
static const TypeInfo virtserialport_info = {
194
    .name          = "virtserialport",
195
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
196
    .instance_size = sizeof(VirtConsole),
197
    .class_init    = virtserialport_class_init,
198
};
199

    
200
static void virtconsole_register_types(void)
201
{
202
    type_register_static(&virtconsole_info);
203
    type_register_static(&virtserialport_info);
204
}
205

    
206
type_init(virtconsole_register_types)