Statistics
| Branch: | Revision:

root / hw / char / virtio-console.c @ f487b677

History | View | Annotate | Download (5.5 kB)

1 98b19252 Amit Shah
/*
2 98b19252 Amit Shah
 * Virtio Console and Generic Serial Port Devices
3 98b19252 Amit Shah
 *
4 71c092e9 Amit Shah
 * Copyright Red Hat, Inc. 2009, 2010
5 98b19252 Amit Shah
 *
6 98b19252 Amit Shah
 * Authors:
7 98b19252 Amit Shah
 *  Amit Shah <amit.shah@redhat.com>
8 98b19252 Amit Shah
 *
9 98b19252 Amit Shah
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10 98b19252 Amit Shah
 * the COPYING file in the top-level directory.
11 98b19252 Amit Shah
 */
12 98b19252 Amit Shah
13 dccfcd0e Paolo Bonzini
#include "sysemu/char.h"
14 1de7afc9 Paolo Bonzini
#include "qemu/error-report.h"
15 d02e4fa4 Amit Shah
#include "trace.h"
16 0d09e41a Paolo Bonzini
#include "hw/virtio/virtio-serial.h"
17 98b19252 Amit Shah
18 98b19252 Amit Shah
typedef struct VirtConsole {
19 98b19252 Amit Shah
    VirtIOSerialPort port;
20 98b19252 Amit Shah
    CharDriverState *chr;
21 c3d6b96e Hans de Goede
    guint watch;
22 98b19252 Amit Shah
} VirtConsole;
23 98b19252 Amit Shah
24 7df4d457 Amit Shah
/*
25 7df4d457 Amit Shah
 * Callback function that's called from chardevs when backend becomes
26 7df4d457 Amit Shah
 * writable.
27 7df4d457 Amit Shah
 */
28 7df4d457 Amit Shah
static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
29 7df4d457 Amit Shah
                                    void *opaque)
30 7df4d457 Amit Shah
{
31 7df4d457 Amit Shah
    VirtConsole *vcon = opaque;
32 7df4d457 Amit Shah
33 c3d6b96e Hans de Goede
    vcon->watch = 0;
34 7df4d457 Amit Shah
    virtio_serial_throttle_port(&vcon->port, false);
35 7df4d457 Amit Shah
    return FALSE;
36 7df4d457 Amit Shah
}
37 98b19252 Amit Shah
38 98b19252 Amit Shah
/* Callback function that's called when the guest sends us data */
39 f9fb0532 Hans de Goede
static ssize_t flush_buf(VirtIOSerialPort *port,
40 f9fb0532 Hans de Goede
                         const uint8_t *buf, ssize_t len)
41 98b19252 Amit Shah
{
42 98b19252 Amit Shah
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
43 d02e4fa4 Amit Shah
    ssize_t ret;
44 98b19252 Amit Shah
45 6640422c Amit Shah
    if (!vcon->chr) {
46 6640422c Amit Shah
        /* If there's no backend, we can just say we consumed all data. */
47 6640422c Amit Shah
        return len;
48 6640422c Amit Shah
    }
49 6640422c Amit Shah
50 2cc6e0a1 Anthony Liguori
    ret = qemu_chr_fe_write(vcon->chr, buf, len);
51 d02e4fa4 Amit Shah
    trace_virtio_console_flush_buf(port->id, len, ret);
52 0219d732 Amit Shah
53 f9fb0532 Hans de Goede
    if (ret < len) {
54 d6258c93 Amit Shah
        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
55 d6258c93 Amit Shah
56 0219d732 Amit Shah
        /*
57 0219d732 Amit Shah
         * Ideally we'd get a better error code than just -1, but
58 0219d732 Amit Shah
         * that's what the chardev interface gives us right now.  If
59 0219d732 Amit Shah
         * we had a finer-grained message, like -EPIPE, we could close
60 d6258c93 Amit Shah
         * this connection.
61 0219d732 Amit Shah
         */
62 f9fb0532 Hans de Goede
        if (ret < 0)
63 f9fb0532 Hans de Goede
            ret = 0;
64 d6258c93 Amit Shah
        if (!k->is_console) {
65 d6258c93 Amit Shah
            virtio_serial_throttle_port(port, true);
66 c3d6b96e Hans de Goede
            if (!vcon->watch) {
67 c3d6b96e Hans de Goede
                vcon->watch = qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT,
68 c3d6b96e Hans de Goede
                                                    chr_write_unblocked, vcon);
69 c3d6b96e Hans de Goede
            }
70 d6258c93 Amit Shah
        }
71 0219d732 Amit Shah
    }
72 d02e4fa4 Amit Shah
    return ret;
73 98b19252 Amit Shah
}
74 98b19252 Amit Shah
75 b2c1394a Hans de Goede
/* Callback function that's called when the guest opens/closes the port */
76 b2c1394a Hans de Goede
static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
77 0b6d2266 Hans de Goede
{
78 0b6d2266 Hans de Goede
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
79 0b6d2266 Hans de Goede
80 6640422c Amit Shah
    if (!vcon->chr) {
81 6640422c Amit Shah
        return;
82 6640422c Amit Shah
    }
83 b2c1394a Hans de Goede
    qemu_chr_fe_set_open(vcon->chr, guest_connected);
84 0b6d2266 Hans de Goede
}
85 0b6d2266 Hans de Goede
86 98b19252 Amit Shah
/* Readiness of the guest to accept data on a port */
87 98b19252 Amit Shah
static int chr_can_read(void *opaque)
88 98b19252 Amit Shah
{
89 98b19252 Amit Shah
    VirtConsole *vcon = opaque;
90 98b19252 Amit Shah
91 98b19252 Amit Shah
    return virtio_serial_guest_ready(&vcon->port);
92 98b19252 Amit Shah
}
93 98b19252 Amit Shah
94 98b19252 Amit Shah
/* Send data from a char device over to the guest */
95 98b19252 Amit Shah
static void chr_read(void *opaque, const uint8_t *buf, int size)
96 98b19252 Amit Shah
{
97 98b19252 Amit Shah
    VirtConsole *vcon = opaque;
98 98b19252 Amit Shah
99 d02e4fa4 Amit Shah
    trace_virtio_console_chr_read(vcon->port.id, size);
100 98b19252 Amit Shah
    virtio_serial_write(&vcon->port, buf, size);
101 98b19252 Amit Shah
}
102 98b19252 Amit Shah
103 98b19252 Amit Shah
static void chr_event(void *opaque, int event)
104 98b19252 Amit Shah
{
105 98b19252 Amit Shah
    VirtConsole *vcon = opaque;
106 98b19252 Amit Shah
107 d02e4fa4 Amit Shah
    trace_virtio_console_chr_event(vcon->port.id, event);
108 98b19252 Amit Shah
    switch (event) {
109 28eaf465 Amit Shah
    case CHR_EVENT_OPENED:
110 98b19252 Amit Shah
        virtio_serial_open(&vcon->port);
111 98b19252 Amit Shah
        break;
112 98b19252 Amit Shah
    case CHR_EVENT_CLOSED:
113 c3d6b96e Hans de Goede
        if (vcon->watch) {
114 c3d6b96e Hans de Goede
            g_source_remove(vcon->watch);
115 c3d6b96e Hans de Goede
            vcon->watch = 0;
116 c3d6b96e Hans de Goede
        }
117 98b19252 Amit Shah
        virtio_serial_close(&vcon->port);
118 98b19252 Amit Shah
        break;
119 98b19252 Amit Shah
    }
120 98b19252 Amit Shah
}
121 98b19252 Amit Shah
122 7edfe652 Markus Armbruster
static int virtconsole_initfn(VirtIOSerialPort *port)
123 98b19252 Amit Shah
{
124 7edfe652 Markus Armbruster
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
125 f82e35e3 Anthony Liguori
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
126 a15bb0d6 Markus Armbruster
127 f82e35e3 Anthony Liguori
    if (port->id == 0 && !k->is_console) {
128 7edfe652 Markus Armbruster
        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
129 7edfe652 Markus Armbruster
        return -1;
130 7edfe652 Markus Armbruster
    }
131 7edfe652 Markus Armbruster
132 98b19252 Amit Shah
    if (vcon->chr) {
133 19083228 Hans de Goede
        vcon->chr->explicit_fe_open = 1;
134 98b19252 Amit Shah
        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
135 98b19252 Amit Shah
                              vcon);
136 98b19252 Amit Shah
    }
137 cbe77b61 Amit Shah
138 7edfe652 Markus Armbruster
    return 0;
139 cbe77b61 Amit Shah
}
140 cbe77b61 Amit Shah
141 c3d6b96e Hans de Goede
static int virtconsole_exitfn(VirtIOSerialPort *port)
142 c3d6b96e Hans de Goede
{
143 c3d6b96e Hans de Goede
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
144 c3d6b96e Hans de Goede
145 c3d6b96e Hans de Goede
    if (vcon->watch) {
146 c3d6b96e Hans de Goede
        g_source_remove(vcon->watch);
147 c3d6b96e Hans de Goede
    }
148 c3d6b96e Hans de Goede
149 c3d6b96e Hans de Goede
    return 0;
150 c3d6b96e Hans de Goede
}
151 c3d6b96e Hans de Goede
152 f82e35e3 Anthony Liguori
static Property virtconsole_properties[] = {
153 f82e35e3 Anthony Liguori
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
154 f82e35e3 Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
155 f82e35e3 Anthony Liguori
};
156 f82e35e3 Anthony Liguori
157 f82e35e3 Anthony Liguori
static void virtconsole_class_init(ObjectClass *klass, void *data)
158 f82e35e3 Anthony Liguori
{
159 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
160 f82e35e3 Anthony Liguori
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
161 f82e35e3 Anthony Liguori
162 f82e35e3 Anthony Liguori
    k->is_console = true;
163 f82e35e3 Anthony Liguori
    k->init = virtconsole_initfn;
164 c3d6b96e Hans de Goede
    k->exit = virtconsole_exitfn;
165 f82e35e3 Anthony Liguori
    k->have_data = flush_buf;
166 b2c1394a Hans de Goede
    k->set_guest_connected = set_guest_connected;
167 39bffca2 Anthony Liguori
    dc->props = virtconsole_properties;
168 f82e35e3 Anthony Liguori
}
169 f82e35e3 Anthony Liguori
170 8c43a6f0 Andreas Färber
static const TypeInfo virtconsole_info = {
171 39bffca2 Anthony Liguori
    .name          = "virtconsole",
172 39bffca2 Anthony Liguori
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
173 39bffca2 Anthony Liguori
    .instance_size = sizeof(VirtConsole),
174 39bffca2 Anthony Liguori
    .class_init    = virtconsole_class_init,
175 98b19252 Amit Shah
};
176 98b19252 Amit Shah
177 f82e35e3 Anthony Liguori
static Property virtserialport_properties[] = {
178 f82e35e3 Anthony Liguori
    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
179 f82e35e3 Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
180 f82e35e3 Anthony Liguori
};
181 f82e35e3 Anthony Liguori
182 f82e35e3 Anthony Liguori
static void virtserialport_class_init(ObjectClass *klass, void *data)
183 f82e35e3 Anthony Liguori
{
184 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
185 f82e35e3 Anthony Liguori
    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
186 f82e35e3 Anthony Liguori
187 f82e35e3 Anthony Liguori
    k->init = virtconsole_initfn;
188 f82e35e3 Anthony Liguori
    k->have_data = flush_buf;
189 b2c1394a Hans de Goede
    k->set_guest_connected = set_guest_connected;
190 39bffca2 Anthony Liguori
    dc->props = virtserialport_properties;
191 f82e35e3 Anthony Liguori
}
192 f82e35e3 Anthony Liguori
193 8c43a6f0 Andreas Färber
static const TypeInfo virtserialport_info = {
194 39bffca2 Anthony Liguori
    .name          = "virtserialport",
195 39bffca2 Anthony Liguori
    .parent        = TYPE_VIRTIO_SERIAL_PORT,
196 39bffca2 Anthony Liguori
    .instance_size = sizeof(VirtConsole),
197 39bffca2 Anthony Liguori
    .class_init    = virtserialport_class_init,
198 b60c470b Amit Shah
};
199 b60c470b Amit Shah
200 83f7d43a Andreas Färber
static void virtconsole_register_types(void)
201 b60c470b Amit Shah
{
202 83f7d43a Andreas Färber
    type_register_static(&virtconsole_info);
203 39bffca2 Anthony Liguori
    type_register_static(&virtserialport_info);
204 b60c470b Amit Shah
}
205 83f7d43a Andreas Färber
206 83f7d43a Andreas Färber
type_init(virtconsole_register_types)