[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 17/21] qom: add CharDriver class
From: |
Anthony Liguori |
Subject: |
[Qemu-devel] [PATCH 17/21] qom: add CharDriver class |
Date: |
Sun, 24 Jul 2011 20:44:49 -0500 |
The CharDriver type replaces the CharDriverState in QEMU today. Here's how
everything matches up:
1) qemu_chr_open() no longer exists. This function used to act as a factory
and used parsing of the filename to determine which type to create. A newer
version using QemuOpts was introduced, qemu_chr_open_opts() which eliminates
the filename in favor of typed key value pairs.
Now, plug_create() can be used to create CharDrivers using an explicit
type that subclasses CharDriver.
2) query-chardev is deprecated. This is replaced by
plug_list(type=char-driver) and plug_list_props().
3) We can now dynamically add and remove new CharDrivers
Signed-off-by: Anthony Liguori <address@hidden>
---
Makefile.qom | 3 +
Qconfig | 1 +
chrdrv/Makefile | 1 +
chrdrv/Qconfig | 5 +
chrdrv/chrdrv.c | 229 ++++++++++++++++++++++++++++++++++++++++
configure | 2 +-
include/qemu/chrdrv.h | 281 +++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 521 insertions(+), 1 deletions(-)
create mode 100644 chrdrv/Makefile
create mode 100644 chrdrv/Qconfig
create mode 100644 chrdrv/chrdrv.c
create mode 100644 include/qemu/chrdrv.h
diff --git a/Makefile.qom b/Makefile.qom
index c694cbb..02a5ca5 100644
--- a/Makefile.qom
+++ b/Makefile.qom
@@ -16,3 +16,6 @@ common-obj-y += $(addprefix qom/,$(qom-obj-y))
include $(SRC_PATH)/devices/Makefile
common-obj-y += $(addprefix devices/,$(devices-obj-y))
+include $(SRC_PATH)/chrdrv/Makefile
+common-obj-y += $(addprefix chrdrv/,$(chrdrv-obj-y))
+
diff --git a/Qconfig b/Qconfig
index 03f2a87..57c1c7d 100644
--- a/Qconfig
+++ b/Qconfig
@@ -1,3 +1,4 @@
source qapi/Qconfig
source qom/Qconfig
source devices/Qconfig
+source chrdrv/Qconfig
diff --git a/chrdrv/Makefile b/chrdrv/Makefile
new file mode 100644
index 0000000..43a51e7
--- /dev/null
+++ b/chrdrv/Makefile
@@ -0,0 +1 @@
+chrdrv-obj-$(CONFIG_CHRDRV) := chrdrv.o
diff --git a/chrdrv/Qconfig b/chrdrv/Qconfig
new file mode 100644
index 0000000..845c205
--- /dev/null
+++ b/chrdrv/Qconfig
@@ -0,0 +1,5 @@
+config CHRDRV
+ bool "QEMU Character Drivers"
+ default y
+ help
+ Character layer
diff --git a/chrdrv/chrdrv.c b/chrdrv/chrdrv.c
new file mode 100644
index 0000000..a9b8dc2
--- /dev/null
+++ b/chrdrv/chrdrv.c
@@ -0,0 +1,229 @@
+#include "qemu/chrdrv.h"
+
+int char_driver_write(CharDriver *s, const uint8_t *buf, int len)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ return cdc->write(s, buf, len);
+}
+
+int char_driver_ioctl(CharDriver *s, int cmd, void *arg)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ return cdc->ioctl(s, cmd, arg);
+}
+
+int char_driver_get_msgfd(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ return cdc->get_msgfd(s);
+}
+
+void char_driver_send_event(CharDriver *s, int event)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->send_event(s, event);
+}
+
+void char_driver_accept_input(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->accept_input(s);
+}
+
+void char_driver_set_echo(CharDriver *s, bool echo)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->set_echo(s, echo);
+}
+
+void char_driver_guest_open(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->guest_open(s);
+}
+
+void char_driver_guest_close(CharDriver *s)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ cdc->guest_close(s);
+}
+
+static int char_driver_def_write(CharDriver *s, const uint8_t *buf, int len)
+{
+ return -ENOTSUP;
+}
+
+static void char_driver_def_update_read_handler(CharDriver *s)
+{
+}
+
+static int char_driver_def_ioctl(CharDriver *s, int cmd, void *arg)
+{
+ return -ENOTSUP;
+}
+
+static int char_driver_def_get_msgfd(CharDriver *s)
+{
+ return -1;
+}
+
+static void char_driver_def_send_event(CharDriver *chr, int event)
+{
+}
+
+static void char_driver_def_close(CharDriver *chr)
+{
+ char_driver_send_event(chr, CHR_EVENT_CLOSED);
+}
+
+static void char_driver_def_accept_input(CharDriver *chr)
+{
+}
+
+static void char_driver_def_set_echo(CharDriver *chr, bool echo)
+{
+}
+
+static void char_driver_def_guest_open(CharDriver *chr)
+{
+}
+
+static void char_driver_def_guest_close(CharDriver *chr)
+{
+}
+
+static void char_driver_def_open(CharDriver *chr, Error **errp)
+{
+}
+
+static void char_driver_realize(Plug *plug)
+{
+ CharDriver *chr = CHAR_DRIVER(plug);
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(chr);
+
+ cdc->open(chr, NULL);
+}
+
+int char_driver_can_read(CharDriver *chr)
+{
+ if (!chr->chr_can_read) {
+ return 1024;
+ }
+
+ return chr->chr_can_read(chr->handler_opaque);
+}
+
+void char_driver_read(CharDriver *chr, uint8_t *buf, int len)
+{
+ if (!chr->chr_read) {
+ return;
+ }
+
+ chr->chr_read(chr->handler_opaque, buf, len);
+}
+
+void char_driver_event(CharDriver *chr, int event)
+{
+ /* Keep track if the char device is open */
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ chr->opened = 1;
+ break;
+ case CHR_EVENT_CLOSED:
+ chr->opened = 0;
+ break;
+ }
+
+ if (!chr->chr_event) {
+ return;
+ }
+
+ chr->chr_event(chr->handler_opaque, event);
+}
+
+static void char_driver_class_init(TypeClass *class)
+{
+ PlugClass *pc = PLUG_CLASS(class);
+ CharDriverClass *cdc = CHAR_DRIVER_CLASS(class);
+
+ pc->realize = char_driver_realize;
+ cdc->write = char_driver_def_write;
+ cdc->ioctl = char_driver_def_ioctl;
+ cdc->get_msgfd = char_driver_def_get_msgfd;
+ cdc->send_event = char_driver_def_send_event;
+ cdc->close = char_driver_def_close;
+ cdc->accept_input = char_driver_def_accept_input;
+ cdc->set_echo = char_driver_def_set_echo;
+ cdc->guest_open = char_driver_def_guest_open;
+ cdc->guest_close = char_driver_def_guest_close;
+ cdc->open = char_driver_def_open;
+ cdc->update_read_handler = char_driver_def_update_read_handler;
+
+}
+
+static void char_driver_generic_open(CharDriver *s)
+{
+ char_driver_event(s, CHR_EVENT_OPENED);
+}
+
+void char_driver_add_handlers(CharDriver *s,
+ IOCanReadHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque)
+{
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(s);
+
+ if (!opaque && !fd_can_read && !fd_read && !fd_event) {
+ /* chr driver being released. */
+ ++s->avail_connections;
+ }
+ s->chr_can_read = fd_can_read;
+ s->chr_read = fd_read;
+ s->chr_event = fd_event;
+ s->handler_opaque = opaque;
+ if (cdc->update_read_handler) {
+ cdc->update_read_handler(s);
+ }
+
+ /* We're connecting to an already opened device, so let's make sure we
+ also get the open event */
+ if (s->opened) {
+ char_driver_generic_open(s);
+ }
+}
+
+static void char_driver_fini(TypeInstance *inst)
+{
+ CharDriver *chr = CHAR_DRIVER(inst);
+ CharDriverClass *cdc = CHAR_DRIVER_GET_CLASS(chr);
+
+ if (cdc->close) {
+ cdc->close(chr);
+ }
+}
+
+static TypeInfo chrdrv_type_info = {
+ .name = TYPE_CHAR_DRIVER,
+ .parent = TYPE_PLUG,
+ .instance_size = sizeof(CharDriver),
+ .instance_finalize = char_driver_fini,
+ .class_size = sizeof(CharDriverClass),
+ .class_init = char_driver_class_init,
+ .abstract = true,
+};
+
+static void register_backends(void)
+{
+ type_register_static(&chrdrv_type_info);
+}
+
+device_init(register_backends);
diff --git a/configure b/configure
index 6ec1020..63c62b0 100755
--- a/configure
+++ b/configure
@@ -3516,7 +3516,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi"
-DIRS="$DIRS qga qom devices"
+DIRS="$DIRS qga qom devices chrdrv"
FILES="Makefile tests/Makefile"
FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/include/qemu/chrdrv.h b/include/qemu/chrdrv.h
new file mode 100644
index 0000000..075b589
--- /dev/null
+++ b/include/qemu/chrdrv.h
@@ -0,0 +1,281 @@
+#ifndef QEMU_CHAR_DRIVER
+#define QEMU_CHAR_DRIVER
+
+#include "qemu/plug.h"
+
+/* Temporarily for a couple of enum */
+#include "qemu-char.h"
+
+/**
+ * @CharDriver
+ *
+ * A streaming data connection, typically used to transfer data from a @Device
+ * to some process on the host.
+ *
+ * A @CharDriver subclass implements the driver. Typically, this is the host
+ * routine and may include a TCP, stdio, or fd transport. The @Device that is
+ * interacting with the driver is the client. This is typically a device that
+ * looks like a serial port including UARTs, virtio-serial, etc.
+ *
+ * @CharDriver also supports by direction messaging. These messages carry no
+ * data though.
+ */
+typedef struct CharDriver
+{
+ Plug parent;
+
+ /* Public */
+
+ /**
+ * @avail_connection used by qdev to keep track of how "connections" are
+ * available in the @CharDriver verses how many qdev are using. This is
+ * meant to ensure that the same @CharDriver isn't connected to multiple
+ * sockets at the same time.
+ *
+ * It's not well thought through though as there are other things that can
+ * use a @CharDriver and the attempt at supporting mux drivers results in
+ * this value just being ignored for mux (although not predictably).
+ *
+ * Sufficed to say, this needs to go away.
+ */
+ int avail_connections;
+
+ /**
+ * @opened despite what the name implies, this doesn't correspond to
whether
+ * the @CharDriver is opened. @CharDriver doesn't have a notion of opened,
+ * instead, @opened tracks whether the CHR_EVENT_OPEN event has been
+ * generated. The CHR_EVENT_CLOSED event will clear the @opened flag.
+ *
+ * The primary purpose of this flag is to ensure the CHR_EVENT_OPEN event
is
+ * not generated twice in a row.
+ */
+ int opened;
+
+ /* Private */
+
+ /**
+ * @chr_can_read when a client has added its handlers to a @CharDriver,
this
+ * contains the can read callback for the client.
+ */
+ IOCanReadHandler *chr_can_read;
+
+ /**
+ * @chr_read when a client has added its handlers to a @CharDriver, this
+ * contains the read callback for the client.
+ */
+ IOReadHandler *chr_read;
+
+ /**
+ * @chr_event when a client has added its handlers to a @CharDriver, this
+ * contains the event callback for the client.
+ */
+ IOEventHandler *chr_event;
+
+ /**
+ * @handler_opaque when a client has added its handlers to a @CharDriver,
+ * this contains the opaque associated with the callbacks for the client.
+ */
+ void *handler_opaque;
+} CharDriver;
+
+typedef struct CharDriverClass
+{
+ PlugClass parent_class;
+
+ /* Public */
+ int (*write)(CharDriver *s, const uint8_t *buf, int len);
+ int (*ioctl)(CharDriver *s, int cmd, void *arg);
+ int (*get_msgfd)(CharDriver *s);
+ void (*send_event)(CharDriver *chr, int event);
+ void (*accept_input)(CharDriver *chr);
+ void (*set_echo)(CharDriver *chr, bool echo);
+ void (*guest_open)(CharDriver *chr);
+ void (*guest_close)(CharDriver *chr);
+
+ /* Protected */
+ /**
+ * @open:
+ *
+ * This is called during realize to initialize the object. At this point,
+ * all of the properties should have been set.
+ */
+ void (*open)(CharDriver *s, Error **errp);
+
+ /**
+ * @update_read_handler:
+ *
+ * This is called after @char_driver_add_handlers is called to allow sub-
+ * classes to re-register their callbacks if necessary.
+ */
+ void (*update_read_handler)(CharDriver *s);
+
+ /**
+ * @close:
+ *
+ * Called during the finalize path. The default behavior sends a
+ * CHR_EVENT_CLOSED. It's generally better to use the classes destructor
to
+ * implement driver specific cleanup.
+ */
+ void (*close)(CharDriver *chr);
+} CharDriverClass;
+
+#define TYPE_CHAR_DRIVER "char-driver"
+#define CHAR_DRIVER(obj) TYPE_CHECK(CharDriver, obj, TYPE_CHAR_DRIVER)
+#define CHAR_DRIVER_CLASS(class) \
+ TYPE_CLASS_CHECK(CharDriverClass, class, TYPE_CHAR_DRIVER)
+#define CHAR_DRIVER_GET_CLASS(obj) \
+ TYPE_GET_CLASS(CharDriverClass, obj, TYPE_CHAR_DRIVER)
+
+/**
+ * @char_driver_write:
+ *
+ * Write data to a @CharDriver
+ *
+ * @buf The data to write
+ * @len The size of the data in buf
+ *
+ * Returns: The number of bytes written to the device
+ *
+ * Notes: Each backend deals with flow control on its own. Depending on the
+ * driver, this function may block execution or silently drop data.
+ *
+ * Dropping data may also occur if the backend uses a connection
+ * oriented transport and the transport is disconnected.
+ *
+ * The caller receives no indication that data was dropped. This
+ * function may return a partial write result.
+ */
+int char_driver_write(CharDriver *s, const uint8_t *buf, int len);
+
+/**
+ * @char_driver_ioctl:
+ *
+ * Performs a device specific ioctl.
+ *
+ * @cmd an ioctl, see CHR_IOCTL_*
+ * @arg values depends on @cmd
+ *
+ * Returns: The result of this depends on the @cmd. If @cmd is not supported
+ * by this device, -ENOTSUP.
+ */
+int char_driver_ioctl(CharDriver *s, int cmd, void *arg);
+
+/**
+ * @char_driver_get_msgfd:
+ *
+ * If the driver has received a file descriptor through its transport, this
+ * function will return the file descriptor.
+ *
+ * Returns: The file descriptor or -1 if transport doesn't support file
+ * descriptor passing or doesn't currently have a file descriptor.
+ */
+int char_driver_get_msgfd(CharDriver *s);
+
+/**
+ * @char_driver_send_event:
+ *
+ * Raise an event to a driver.
+ *
+ * @event see CHR_EVENT_*
+ *
+ * Notes: There is no way to determine if the driver successfully handled the
+ * event.
+ */
+void char_driver_send_event(CharDriver *chr, int event);
+
+/**
+ * @char_driver_accept_input:
+ *
+ * I honestly can't tell what this function is meant to do.
+ */
+void char_driver_accept_input(CharDriver *chr);
+
+/**
+ * @char_driver_set_echo:
+ *
+ * Requests to override the backends use of echo. This is really only
+ * applicable to the stdio backend but is a generic interface today.
+ *
+ * @echo true to enable echo
+ */
+void char_driver_set_echo(CharDriver *chr, bool echo);
+
+/**
+ * @char_driver_guest_open:
+ *
+ * If the client has a notion of a connection, this is invoked when the
+ * connection is created.
+ *
+ * Note: There is no way to determine if a client has the notion of a
+ * connection. A driver cannot rely on this function ever being called.
+ */
+void char_driver_guest_open(CharDriver *chr);
+
+/**
+ * @char_driver_guest_close:
+ *
+ * If the client has a notion of a connection, this is invoked when the
+ * connection is closed.
+ *
+ * Note: There is no way to determine if a client has the notion of a
+ * connection. A driver cannot rely on this function ever being called.
+ */
+void char_driver_guest_close(CharDriver *chr);
+
+/**
+ * @char_driver_can_read:
+ *
+ * Returns: The maximum number of bytes the client connected to the driver can
+ * receive at the moment.
+ */
+int char_driver_can_read(CharDriver *chr);
+
+/**
+ * @char_driver_read:
+ *
+ * This function transfers the contents of buf to the client.
+ *
+ * @buf the buffer to write to the client
+ * @len the number of bytes to write
+ *
+ * Notes: This function should only be invoked after receiving a non-zero
+ * value from @char_driver_can_read. @len may be larger than the
return
+ * value but the results are undefined. It may result in the entire
+ * message being dropped or the message being truncated.
+ */
+void char_driver_read(CharDriver *chr, uint8_t *buf, int len);
+
+/**
+ * @char_driver_event:
+ *
+ * Sends an event to the client of a driver.
+ *
+ * @event the CHR_EVENT_* to send to the client
+ */
+void char_driver_event(CharDriver *chr, int event);
+
+/**
+ * @char_driver_add_handlers:
+ *
+ * Connect a client to a @CharDriver. A connected client may send data to the
+ * driver by using the @char_driver_write function. Data is received from the
+ * driver to the client using the callbacks registered in this function.
+ *
+ * @fd_can_read This callback returns the maximum amount of data the client is
+ * prepared to receive from the driver.
+ *
+ * @fd_read This callback is used by the driver to pass data to the
client.
+ *
+ * @fd_event This callback is used to send events from the driver to the
+ * client.
+ *
+ * @opaque An opaque value that is passed with the registered callbacks
to
+ * form a closure.
+ */
+void char_driver_add_handlers(CharDriver *s,
+ IOCanReadHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque);
+
+#endif
--
1.7.4.1
- [Qemu-devel] [PATCH 06/21] plug: add socket property type, (continued)
- [Qemu-devel] [PATCH 06/21] plug: add socket property type, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 01/21] qom: add make infrastructure, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 07/21] plug: add generated property types, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 03/21] qom: Add core type system, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 05/21] plug: add Plug property type, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 10/21] qom: add plug_get QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 11/21] qom: add plug_set QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 08/21] qom: add plug_create QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 13/21] qom: add plug_destroy command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 16/21] qom-devices: add a Pin class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 17/21] qom: add CharDriver class,
Anthony Liguori <=
- [Qemu-devel] [PATCH 12/21] qom: add plug_list_props QMP command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 15/21] qom: add Device class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 21/21] qom-chrdrv: add UnixServer, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 19/21] qom-chrdrv: add Socket base class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 18/21] qom-chrdrv: add memory character driver, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 20/21] qom-chrdrv: add TCPServer class, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 14/21] qom: add example qsh command, Anthony Liguori, 2011/07/24
- [Qemu-devel] [PATCH 09/21] qom: add plug_list QMP command, Anthony Liguori, 2011/07/24