Statistics
| Branch: | Revision:

root / hw / virtio-console.c @ d6258c93

History | View | Annotate | Download (5.2 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 from chardevs when backend becomes
25
 * writable.
26
 */
27
static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
28
                                    void *opaque)
29
{
30
    VirtConsole *vcon = opaque;
31

    
32
    virtio_serial_throttle_port(&vcon->port, false);
33
    return FALSE;
34
}
35

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

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

    
47
    ret = qemu_chr_fe_write(vcon->chr, buf, len);
48
    trace_virtio_console_flush_buf(port->id, len, ret);
49

    
50
    if (ret <= 0) {
51
        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
52

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

    
69
/* Callback function that's called when the guest opens the port */
70
static void guest_open(VirtIOSerialPort *port)
71
{
72
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
73

    
74
    if (!vcon->chr) {
75
        return;
76
    }
77
    qemu_chr_fe_open(vcon->chr);
78
}
79

    
80
/* Callback function that's called when the guest closes the port */
81
static void guest_close(VirtIOSerialPort *port)
82
{
83
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
84

    
85
    if (!vcon->chr) {
86
        return;
87
    }
88
    qemu_chr_fe_close(vcon->chr);
89
}
90

    
91
/* Readiness of the guest to accept data on a port */
92
static int chr_can_read(void *opaque)
93
{
94
    VirtConsole *vcon = opaque;
95

    
96
    return virtio_serial_guest_ready(&vcon->port);
97
}
98

    
99
/* Send data from a char device over to the guest */
100
static void chr_read(void *opaque, const uint8_t *buf, int size)
101
{
102
    VirtConsole *vcon = opaque;
103

    
104
    trace_virtio_console_chr_read(vcon->port.id, size);
105
    virtio_serial_write(&vcon->port, buf, size);
106
}
107

    
108
static void chr_event(void *opaque, int event)
109
{
110
    VirtConsole *vcon = opaque;
111

    
112
    trace_virtio_console_chr_event(vcon->port.id, event);
113
    switch (event) {
114
    case CHR_EVENT_OPENED:
115
        virtio_serial_open(&vcon->port);
116
        break;
117
    case CHR_EVENT_CLOSED:
118
        virtio_serial_close(&vcon->port);
119
        break;
120
    }
121
}
122

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

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

    
133
    if (vcon->chr) {
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 Property virtconsole_properties[] = {
142
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
143
    DEFINE_PROP_END_OF_LIST(),
144
};
145

    
146
static void virtconsole_class_init(ObjectClass *klass, void *data)
147
{
148
    DeviceClass *dc = DEVICE_CLASS(klass);
149
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
150

    
151
    k->is_console = true;
152
    k->init = virtconsole_initfn;
153
    k->have_data = flush_buf;
154
    k->guest_open = guest_open;
155
    k->guest_close = guest_close;
156
    dc->props = virtconsole_properties;
157
}
158

    
159
static const TypeInfo virtconsole_info = {
160
    .name          = "virtconsole",
161
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
162
    .instance_size = sizeof(VirtConsole),
163
    .class_init    = virtconsole_class_init,
164
};
165

    
166
static Property virtserialport_properties[] = {
167
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
168
    DEFINE_PROP_END_OF_LIST(),
169
};
170

    
171
static void virtserialport_class_init(ObjectClass *klass, void *data)
172
{
173
    DeviceClass *dc = DEVICE_CLASS(klass);
174
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
175

    
176
    k->init = virtconsole_initfn;
177
    k->have_data = flush_buf;
178
    k->guest_open = guest_open;
179
    k->guest_close = guest_close;
180
    dc->props = virtserialport_properties;
181
}
182

    
183
static const TypeInfo virtserialport_info = {
184
    .name          = "virtserialport",
185
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
186
    .instance_size = sizeof(VirtConsole),
187
    .class_init    = virtserialport_class_init,
188
};
189

    
190
static void virtconsole_register_types(void)
191
{
192
    type_register_static(&virtconsole_info);
193
    type_register_static(&virtserialport_info);
194
}
195

    
196
type_init(virtconsole_register_types)