virtio-serial: convert to QEMU Object Model
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
3954d33ab7
commit
f82e35e38c
|
@ -109,10 +109,9 @@ static void chr_event(void *opaque, int event)
|
||||||
static int virtconsole_initfn(VirtIOSerialPort *port)
|
static int virtconsole_initfn(VirtIOSerialPort *port)
|
||||||
{
|
{
|
||||||
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
||||||
VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
|
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
qdev_get_info(&vcon->port.dev));
|
|
||||||
|
|
||||||
if (port->id == 0 && !info->is_console) {
|
if (port->id == 0 && !k->is_console) {
|
||||||
error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
|
error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -125,18 +124,27 @@ static int virtconsole_initfn(VirtIOSerialPort *port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VirtIOSerialPortInfo virtconsole_info = {
|
static Property virtconsole_properties[] = {
|
||||||
.qdev.name = "virtconsole",
|
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
|
||||||
.qdev.size = sizeof(VirtConsole),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
.is_console = true,
|
};
|
||||||
.init = virtconsole_initfn,
|
|
||||||
.have_data = flush_buf,
|
static void virtconsole_class_init(ObjectClass *klass, void *data)
|
||||||
.guest_open = guest_open,
|
{
|
||||||
.guest_close = guest_close,
|
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
|
||||||
.qdev.props = (Property[]) {
|
|
||||||
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
|
k->is_console = true;
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
k->init = virtconsole_initfn;
|
||||||
},
|
k->have_data = flush_buf;
|
||||||
|
k->guest_open = guest_open;
|
||||||
|
k->guest_close = guest_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DeviceInfo virtconsole_info = {
|
||||||
|
.name = "virtconsole",
|
||||||
|
.size = sizeof(VirtConsole),
|
||||||
|
.props = virtconsole_properties,
|
||||||
|
.class_init = virtconsole_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void virtconsole_register(void)
|
static void virtconsole_register(void)
|
||||||
|
@ -145,17 +153,26 @@ static void virtconsole_register(void)
|
||||||
}
|
}
|
||||||
device_init(virtconsole_register)
|
device_init(virtconsole_register)
|
||||||
|
|
||||||
static VirtIOSerialPortInfo virtserialport_info = {
|
static Property virtserialport_properties[] = {
|
||||||
.qdev.name = "virtserialport",
|
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
|
||||||
.qdev.size = sizeof(VirtConsole),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
.init = virtconsole_initfn,
|
};
|
||||||
.have_data = flush_buf,
|
|
||||||
.guest_open = guest_open,
|
static void virtserialport_class_init(ObjectClass *klass, void *data)
|
||||||
.guest_close = guest_close,
|
{
|
||||||
.qdev.props = (Property[]) {
|
VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
|
||||||
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
|
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
k->init = virtconsole_initfn;
|
||||||
},
|
k->have_data = flush_buf;
|
||||||
|
k->guest_open = guest_open;
|
||||||
|
k->guest_close = guest_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DeviceInfo virtserialport_info = {
|
||||||
|
.name = "virtserialport",
|
||||||
|
.size = sizeof(VirtConsole),
|
||||||
|
.props = virtserialport_properties,
|
||||||
|
.class_init = virtserialport_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void virtserialport_register(void)
|
static void virtserialport_register(void)
|
||||||
|
|
|
@ -133,12 +133,12 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
|
||||||
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||||
VirtIODevice *vdev)
|
VirtIODevice *vdev)
|
||||||
{
|
{
|
||||||
VirtIOSerialPortInfo *info;
|
VirtIOSerialPortClass *vsc;
|
||||||
|
|
||||||
assert(port);
|
assert(port);
|
||||||
assert(virtio_queue_ready(vq));
|
assert(virtio_queue_ready(vq));
|
||||||
|
|
||||||
info = DO_UPCAST(VirtIOSerialPortInfo, qdev, qdev_get_info(&port->dev));
|
vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
|
|
||||||
while (!port->throttled) {
|
while (!port->throttled) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -157,7 +157,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
|
buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
|
||||||
ret = info->have_data(port,
|
ret = vsc->have_data(port,
|
||||||
port->elem.out_sg[i].iov_base
|
port->elem.out_sg[i].iov_base
|
||||||
+ port->iov_offset,
|
+ port->iov_offset,
|
||||||
buf_size);
|
buf_size);
|
||||||
|
@ -176,7 +176,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||||
* 1: chardevs can notify frondends
|
* 1: chardevs can notify frondends
|
||||||
* 2: the guest driver does not spin in these cases
|
* 2: the guest driver does not spin in these cases
|
||||||
*/
|
*/
|
||||||
if (!info->is_console) {
|
if (!vsc->is_console) {
|
||||||
virtio_serial_throttle_port(port, true);
|
virtio_serial_throttle_port(port, true);
|
||||||
}
|
}
|
||||||
port->iov_idx = i;
|
port->iov_idx = i;
|
||||||
|
@ -331,7 +331,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
|
||||||
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct VirtIOSerialPort *port;
|
struct VirtIOSerialPort *port;
|
||||||
struct VirtIOSerialPortInfo *info;
|
VirtIOSerialPortClass *vsc;
|
||||||
struct virtio_console_control cpkt, *gcpkt;
|
struct virtio_console_control cpkt, *gcpkt;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
size_t buffer_len;
|
size_t buffer_len;
|
||||||
|
@ -373,7 +373,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
||||||
|
|
||||||
trace_virtio_serial_handle_control_message_port(port->id);
|
trace_virtio_serial_handle_control_message_port(port->id);
|
||||||
|
|
||||||
info = DO_UPCAST(VirtIOSerialPortInfo, qdev, qdev_get_info(&port->dev));
|
vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
|
|
||||||
switch(cpkt.event) {
|
switch(cpkt.event) {
|
||||||
case VIRTIO_CONSOLE_PORT_READY:
|
case VIRTIO_CONSOLE_PORT_READY:
|
||||||
|
@ -389,7 +389,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
||||||
* this port is a console port so that the guest can hook it
|
* this port is a console port so that the guest can hook it
|
||||||
* up to hvc.
|
* up to hvc.
|
||||||
*/
|
*/
|
||||||
if (info->is_console) {
|
if (vsc->is_console) {
|
||||||
send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
|
send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,21 +418,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
||||||
* initialised. If some app is interested in knowing about
|
* initialised. If some app is interested in knowing about
|
||||||
* this event, let it know.
|
* this event, let it know.
|
||||||
*/
|
*/
|
||||||
if (info->guest_ready) {
|
if (vsc->guest_ready) {
|
||||||
info->guest_ready(port);
|
vsc->guest_ready(port);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIRTIO_CONSOLE_PORT_OPEN:
|
case VIRTIO_CONSOLE_PORT_OPEN:
|
||||||
port->guest_connected = cpkt.value;
|
port->guest_connected = cpkt.value;
|
||||||
if (cpkt.value && info->guest_open) {
|
if (cpkt.value && vsc->guest_open) {
|
||||||
/* Send the guest opened notification if an app is interested */
|
/* Send the guest opened notification if an app is interested */
|
||||||
info->guest_open(port);
|
vsc->guest_open(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpkt.value && info->guest_close) {
|
if (!cpkt.value && vsc->guest_close) {
|
||||||
/* Send the guest closed notification if an app is interested */
|
/* Send the guest closed notification if an app is interested */
|
||||||
info->guest_close(port);
|
vsc->guest_close(port);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -751,7 +751,7 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
|
||||||
static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||||
{
|
{
|
||||||
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
||||||
VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
|
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
|
VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
|
||||||
int ret, max_nr_ports;
|
int ret, max_nr_ports;
|
||||||
bool plugging_port0;
|
bool plugging_port0;
|
||||||
|
@ -759,14 +759,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||||
port->vser = bus->vser;
|
port->vser = bus->vser;
|
||||||
port->bh = qemu_bh_new(flush_queued_data_bh, port);
|
port->bh = qemu_bh_new(flush_queued_data_bh, port);
|
||||||
|
|
||||||
assert(info->have_data);
|
assert(vsc->have_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is the first console port we're seeing? If so, put it up at
|
* Is the first console port we're seeing? If so, put it up at
|
||||||
* location 0. This is done for backward compatibility (old
|
* location 0. This is done for backward compatibility (old
|
||||||
* kernel, new qemu).
|
* kernel, new qemu).
|
||||||
*/
|
*/
|
||||||
plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
|
plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
|
||||||
|
|
||||||
if (find_port_by_id(port->vser, port->id)) {
|
if (find_port_by_id(port->vser, port->id)) {
|
||||||
error_report("virtio-serial-bus: A port already exists at id %u",
|
error_report("virtio-serial-bus: A port already exists at id %u",
|
||||||
|
@ -793,7 +793,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = info->init(port);
|
ret = vsc->init(port);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -823,8 +823,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||||
static int virtser_port_qdev_exit(DeviceState *qdev)
|
static int virtser_port_qdev_exit(DeviceState *qdev)
|
||||||
{
|
{
|
||||||
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
||||||
VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
|
VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
|
||||||
qdev_get_info(&port->dev));
|
|
||||||
VirtIOSerial *vser = port->vser;
|
VirtIOSerial *vser = port->vser;
|
||||||
|
|
||||||
qemu_bh_delete(port->bh);
|
qemu_bh_delete(port->bh);
|
||||||
|
@ -832,19 +831,19 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
|
||||||
|
|
||||||
QTAILQ_REMOVE(&vser->ports, port, next);
|
QTAILQ_REMOVE(&vser->ports, port, next);
|
||||||
|
|
||||||
if (info->exit) {
|
if (vsc->exit) {
|
||||||
info->exit(port);
|
vsc->exit(port);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
|
void virtio_serial_port_qdev_register(DeviceInfo *info)
|
||||||
{
|
{
|
||||||
info->qdev.init = virtser_port_qdev_init;
|
info->init = virtser_port_qdev_init;
|
||||||
info->qdev.bus_info = &virtser_bus_info;
|
info->bus_info = &virtser_bus_info;
|
||||||
info->qdev.exit = virtser_port_qdev_exit;
|
info->exit = virtser_port_qdev_exit;
|
||||||
info->qdev.unplug = qdev_simple_unplug_cb;
|
info->unplug = qdev_simple_unplug_cb;
|
||||||
qdev_register(&info->qdev);
|
qdev_register_subclass(info, TYPE_VIRTIO_SERIAL_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
|
VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
|
||||||
|
@ -940,3 +939,18 @@ void virtio_serial_exit(VirtIODevice *vdev)
|
||||||
|
|
||||||
virtio_cleanup(vdev);
|
virtio_cleanup(vdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TypeInfo virtio_serial_port_type_info = {
|
||||||
|
.name = TYPE_VIRTIO_SERIAL_PORT,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(VirtIOSerialPort),
|
||||||
|
.abstract = true,
|
||||||
|
.class_size = sizeof(VirtIOSerialPortClass),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void virtio_serial_register_devices(void)
|
||||||
|
{
|
||||||
|
type_register_static(&virtio_serial_port_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_init(virtio_serial_register_devices);
|
||||||
|
|
|
@ -62,10 +62,52 @@ struct virtio_serial_conf {
|
||||||
|
|
||||||
/* == In-qemu interface == */
|
/* == In-qemu interface == */
|
||||||
|
|
||||||
|
#define TYPE_VIRTIO_SERIAL_PORT "virtio-serial-port"
|
||||||
|
#define VIRTIO_SERIAL_PORT(obj) \
|
||||||
|
OBJECT_CHECK(VirtIOSerialPort, (obj), TYPE_VIRTIO_SERIAL_PORT)
|
||||||
|
#define VIRTIO_SERIAL_PORT_CLASS(klass) \
|
||||||
|
OBJECT_CLASS_CHECK(VirtIOSerialPortClass, (klass), TYPE_VIRTIO_SERIAL_PORT)
|
||||||
|
#define VIRTIO_SERIAL_PORT_GET_CLASS(obj) \
|
||||||
|
OBJECT_GET_CLASS(VirtIOSerialPortClass, (obj), TYPE_VIRTIO_SERIAL_PORT)
|
||||||
|
|
||||||
typedef struct VirtIOSerial VirtIOSerial;
|
typedef struct VirtIOSerial VirtIOSerial;
|
||||||
typedef struct VirtIOSerialBus VirtIOSerialBus;
|
typedef struct VirtIOSerialBus VirtIOSerialBus;
|
||||||
typedef struct VirtIOSerialPort VirtIOSerialPort;
|
typedef struct VirtIOSerialPort VirtIOSerialPort;
|
||||||
typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
|
|
||||||
|
typedef struct VirtIOSerialPortClass {
|
||||||
|
DeviceClass parent_class;
|
||||||
|
|
||||||
|
/* Is this a device that binds with hvc in the guest? */
|
||||||
|
bool is_console;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The per-port (or per-app) init function that's called when a
|
||||||
|
* new device is found on the bus.
|
||||||
|
*/
|
||||||
|
int (*init)(VirtIOSerialPort *port);
|
||||||
|
/*
|
||||||
|
* Per-port exit function that's called when a port gets
|
||||||
|
* hot-unplugged or removed.
|
||||||
|
*/
|
||||||
|
int (*exit)(VirtIOSerialPort *port);
|
||||||
|
|
||||||
|
/* Callbacks for guest events */
|
||||||
|
/* Guest opened device. */
|
||||||
|
void (*guest_open)(VirtIOSerialPort *port);
|
||||||
|
/* Guest closed device. */
|
||||||
|
void (*guest_close)(VirtIOSerialPort *port);
|
||||||
|
|
||||||
|
/* Guest is now ready to accept data (virtqueues set up). */
|
||||||
|
void (*guest_ready)(VirtIOSerialPort *port);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Guest wrote some data to the port. This data is handed over to
|
||||||
|
* the app via this callback. The app can return a size less than
|
||||||
|
* 'len'. In this case, throttling will be enabled for this port.
|
||||||
|
*/
|
||||||
|
ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
|
||||||
|
size_t len);
|
||||||
|
} VirtIOSerialPortClass;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the state that's shared between all the ports. Some of the
|
* This is the state that's shared between all the ports. Some of the
|
||||||
|
@ -131,48 +173,13 @@ struct VirtIOSerialPort {
|
||||||
bool throttled;
|
bool throttled;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VirtIOSerialPortInfo {
|
|
||||||
DeviceInfo qdev;
|
|
||||||
|
|
||||||
/* Is this a device that binds with hvc in the guest? */
|
|
||||||
bool is_console;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The per-port (or per-app) init function that's called when a
|
|
||||||
* new device is found on the bus.
|
|
||||||
*/
|
|
||||||
int (*init)(VirtIOSerialPort *port);
|
|
||||||
/*
|
|
||||||
* Per-port exit function that's called when a port gets
|
|
||||||
* hot-unplugged or removed.
|
|
||||||
*/
|
|
||||||
int (*exit)(VirtIOSerialPort *port);
|
|
||||||
|
|
||||||
/* Callbacks for guest events */
|
|
||||||
/* Guest opened device. */
|
|
||||||
void (*guest_open)(VirtIOSerialPort *port);
|
|
||||||
/* Guest closed device. */
|
|
||||||
void (*guest_close)(VirtIOSerialPort *port);
|
|
||||||
|
|
||||||
/* Guest is now ready to accept data (virtqueues set up). */
|
|
||||||
void (*guest_ready)(VirtIOSerialPort *port);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Guest wrote some data to the port. This data is handed over to
|
|
||||||
* the app via this callback. The app can return a size less than
|
|
||||||
* 'len'. In this case, throttling will be enabled for this port.
|
|
||||||
*/
|
|
||||||
ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
|
|
||||||
size_t len);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Interface to the virtio-serial bus */
|
/* Interface to the virtio-serial bus */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Individual ports/apps should call this function to register the port
|
* Individual ports/apps should call this function to register the port
|
||||||
* with the virtio-serial bus
|
* with the virtio-serial bus
|
||||||
*/
|
*/
|
||||||
void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
|
void virtio_serial_port_qdev_register(DeviceInfo *info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open a connection to the port
|
* Open a connection to the port
|
||||||
|
|
Loading…
Reference in a new issue