[Spice-commits] 23 commits - Makefile audio/audio.c hmp-commands.hx hmp.c hmp.h hw/pc_q35.c hw/ppc405_boards.c hw/spapr.c hw/spapr_vio.c hw/tmp105.c hw/tmp105.h hw/tmp105_regs.h hw/usb include/char qapi-schema.json qemu-char.c qemu-options.hx qmp-commands.hx tests/Makefile tests/libi2c-omap.c tests/libi2c.c tests/libi2c.h tests/tmp105-test.c ui/keymaps.c vl.c

Gerd Hoffmann kraxel at kemper.freedesktop.org
Thu Jan 17 08:21:52 PST 2013


 Makefile             |    1 
 audio/audio.c        |    5 
 hmp-commands.hx      |   32 +++
 hmp.c                |   23 ++
 hmp.h                |    2 
 hw/pc_q35.c          |    1 
 hw/ppc405_boards.c   |    1 
 hw/spapr.c           |    7 
 hw/spapr_vio.c       |   29 ---
 hw/tmp105.c          |   77 +++++---
 hw/tmp105.h          |   64 ++-----
 hw/tmp105_regs.h     |   50 +++++
 hw/usb/dev-storage.c |    2 
 include/char/char.h  |    4 
 qapi-schema.json     |  104 +++++++++++
 qemu-char.c          |  463 +++++++++++++++++++++++++++++++++++++++------------
 qemu-options.hx      |   14 -
 qmp-commands.hx      |   61 ++++++
 tests/Makefile       |    4 
 tests/libi2c-omap.c  |  166 ++++++++++++++++++
 tests/libi2c.c       |   22 ++
 tests/libi2c.h       |   30 +++
 tests/tmp105-test.c  |   76 ++++++++
 ui/keymaps.c         |   16 -
 vl.c                 |    9 
 25 files changed, 1040 insertions(+), 223 deletions(-)

New commits:
commit 47f4dac3fde809e3da4e60d9eb699f1d4b378249
Merge: af381eb 0a1a7fa
Author: Anthony Liguori <aliguori at us.ibm.com>
Date:   Wed Jan 16 15:20:05 2013 -0600

    Merge remote-tracking branch 'kraxel/chardev.1' into staging
    
    # By Gerd Hoffmann
    # Via Gerd Hoffmann
    * kraxel/chardev.1:
      chardev: add pty chardev support to chardev-add (qmp)
      chardev: add socket chardev support to chardev-add (qmp)
      chardev: add parallel chardev support to chardev-add (qmp)
      chardev: add serial chardev support to chardev-add (qmp)
      chardev: add file chardev support to chardev-add (qmp)
      chardev: add hmp hotplug commands
      chardev: add qmp hotplug commands, with null chardev support
      chardev: reduce chardev ifdef mess a bit
      chardev: fix QemuOpts lifecycle
      chardev: add error reporting for qemu_chr_new_from_opts

commit af381ebeacdefcec0d2b44bdbb9d6e01e35f691f
Author: Paolo Bonzini <pbonzini at redhat.com>
Date:   Tue Jan 15 09:49:36 2013 +0100

    build: fix Win32 clean build
    
    The version.o file did not appear explicitly as a dependency, and
    this caused clean builds to fail.  Force its build by making the
    Makefile depend on version.o.
    
    (We cannot add it to libqemuutil.a, because it doesn't export any
    symbol and thus would not be pulled by the linker).
    
    Cc: Blue Swirl <blauwirbel at gmail.com>
    Cc: Stefan Weil <sw at weilnetz.de>
    Tested-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/Makefile b/Makefile
index 7622a4c..cfa2fa6 100644
--- a/Makefile
+++ b/Makefile
@@ -153,6 +153,7 @@ version.o: $(SRC_PATH)/version.rc config-host.h
 	$(call quiet-command,$(WINDRES) -I. -o $@ $<,"  RC    $(TARGET_DIR)$@")
 
 version-obj-$(CONFIG_WIN32) += version.o
+Makefile: $(version-obj-y)
 
 ######################################################################
 # Build libraries
commit eb60d1c55268f489b32e6b694e84e2017b75a3d3
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Wed Jan 16 01:57:59 2013 +0100

    tmp105: Add temperature QOM property
    
    This obsoletes tmp105_set() and allows for better error handling.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/tmp105.c b/hw/tmp105.c
index a16f538..3ad2d2f 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -21,6 +21,7 @@
 #include "hw.h"
 #include "i2c.h"
 #include "tmp105.h"
+#include "qapi/visitor.h"
 
 static void tmp105_interrupt_update(TMP105State *s)
 {
@@ -51,15 +52,30 @@ static void tmp105_alarm_update(TMP105State *s)
     tmp105_interrupt_update(s);
 }
 
+static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque,
+                                   const char *name, Error **errp)
+{
+    TMP105State *s = TMP105(obj);
+    int64_t value = s->temperature;
+
+    visit_type_int(v, &value, name, errp);
+}
+
 /* Units are 0.001 centigrades relative to 0 C.  */
-void tmp105_set(I2CSlave *i2c, int temp)
+static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
+                                   const char *name, Error **errp)
 {
-    TMP105State *s = TMP105(i2c);
+    TMP105State *s = TMP105(obj);
+    int64_t temp;
 
+    visit_type_int(v, &temp, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
     if (temp >= 128000 || temp < -128000) {
-        fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
-                        __FUNCTION__, temp / 1000, temp % 1000);
-        exit(-1);
+        error_setg(errp, "value %" PRId64 ".%03" PRIu64 " °C is out of range",
+                   temp / 1000, temp % 1000);
+        return;
     }
 
     s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
@@ -218,6 +234,13 @@ static int tmp105_init(I2CSlave *i2c)
     return 0;
 }
 
+static void tmp105_initfn(Object *obj)
+{
+    object_property_add(obj, "temperature", "int",
+                        tmp105_get_temperature,
+                        tmp105_set_temperature, NULL, NULL, NULL);
+}
+
 static void tmp105_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -234,6 +257,7 @@ static const TypeInfo tmp105_info = {
     .name          = TYPE_TMP105,
     .parent        = TYPE_I2C_SLAVE,
     .instance_size = sizeof(TMP105State),
+    .instance_init = tmp105_initfn,
     .class_init    = tmp105_class_init,
 };
 
diff --git a/hw/tmp105.h b/hw/tmp105.h
index c21396f..d218919 100644
--- a/hw/tmp105.h
+++ b/hw/tmp105.h
@@ -44,19 +44,4 @@ typedef struct TMP105State {
     uint8_t alarm;
 } TMP105State;
 
-/**
- * tmp105_set:
- * @i2c: dispatcher to TMP105 hardware model
- * @temp: temperature with 0.001 centigrades units in the range -40 C to +125 C
- *
- * Sets the temperature of the TMP105 hardware model.
- *
- * Bits 5 and 6 (value 32 and 64) in the register indexed by TMP105_REG_CONFIG
- * determine the precision of the temperature. See Table 8 in the data sheet.
- *
- * @see_also: I2C_SLAVE macro
- * @see_also: http://www.ti.com/lit/gpn/tmp105
- */
-void tmp105_set(I2CSlave *i2c, int temp);
-
 #endif
commit 2aad80eeb788c7c3f71c57e78352f0fdadf8fe28
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Wed Jan 16 01:57:58 2013 +0100

    tmp105: QOM'ify
    
    Introduce TYPE_ constant and cast macro.
    Move the state struct to the new header to allow for future embedding.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/tmp105.c b/hw/tmp105.c
index 10d94c9..a16f538 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -22,20 +22,6 @@
 #include "i2c.h"
 #include "tmp105.h"
 
-typedef struct {
-    I2CSlave i2c;
-    uint8_t len;
-    uint8_t buf[2];
-    qemu_irq pin;
-
-    uint8_t pointer;
-    uint8_t config;
-    int16_t temperature;
-    int16_t limit[2];
-    int faults;
-    uint8_t alarm;
-} TMP105State;
-
 static void tmp105_interrupt_update(TMP105State *s)
 {
     qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1));	/* POL */
@@ -68,7 +54,7 @@ static void tmp105_alarm_update(TMP105State *s)
 /* Units are 0.001 centigrades relative to 0 C.  */
 void tmp105_set(I2CSlave *i2c, int temp)
 {
-    TMP105State *s = (TMP105State *) i2c;
+    TMP105State *s = TMP105(i2c);
 
     if (temp >= 128000 || temp < -128000) {
         fprintf(stderr, "%s: values is out of range (%i.%03i C)\n",
@@ -141,17 +127,18 @@ static void tmp105_write(TMP105State *s)
 
 static int tmp105_rx(I2CSlave *i2c)
 {
-    TMP105State *s = (TMP105State *) i2c;
+    TMP105State *s = TMP105(i2c);
 
-    if (s->len < 2)
+    if (s->len < 2) {
         return s->buf[s->len ++];
-    else
+    } else {
         return 0xff;
+    }
 }
 
 static int tmp105_tx(I2CSlave *i2c, uint8_t data)
 {
-    TMP105State *s = (TMP105State *) i2c;
+    TMP105State *s = TMP105(i2c);
 
     if (s->len == 0) {
         s->pointer = data;
@@ -169,10 +156,11 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
 
 static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
 {
-    TMP105State *s = (TMP105State *) i2c;
+    TMP105State *s = TMP105(i2c);
 
-    if (event == I2C_START_RECV)
+    if (event == I2C_START_RECV) {
         tmp105_read(s);
+    }
 
     s->len = 0;
 }
@@ -208,7 +196,7 @@ static const VMStateDescription vmstate_tmp105 = {
 
 static void tmp105_reset(I2CSlave *i2c)
 {
-    TMP105State *s = (TMP105State *) i2c;
+    TMP105State *s = TMP105(i2c);
 
     s->temperature = 0;
     s->pointer = 0;
@@ -221,7 +209,7 @@ static void tmp105_reset(I2CSlave *i2c)
 
 static int tmp105_init(I2CSlave *i2c)
 {
-    TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c);
+    TMP105State *s = TMP105(i2c);
 
     qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
 
@@ -243,7 +231,7 @@ static void tmp105_class_init(ObjectClass *klass, void *data)
 }
 
 static const TypeInfo tmp105_info = {
-    .name          = "tmp105",
+    .name          = TYPE_TMP105,
     .parent        = TYPE_I2C_SLAVE,
     .instance_size = sizeof(TMP105State),
     .class_init    = tmp105_class_init,
diff --git a/hw/tmp105.h b/hw/tmp105.h
index 982d1c9..c21396f 100644
--- a/hw/tmp105.h
+++ b/hw/tmp105.h
@@ -17,6 +17,33 @@
 #include "i2c.h"
 #include "tmp105_regs.h"
 
+#define TYPE_TMP105 "tmp105"
+#define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105)
+
+/**
+ * TMP105State:
+ * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the
+ * temperature. See Table 8 in the data sheet.
+ *
+ * @see_also: http://www.ti.com/lit/gpn/tmp105
+ */
+typedef struct TMP105State {
+    /*< private >*/
+    I2CSlave i2c;
+    /*< public >*/
+
+    uint8_t len;
+    uint8_t buf[2];
+    qemu_irq pin;
+
+    uint8_t pointer;
+    uint8_t config;
+    int16_t temperature;
+    int16_t limit[2];
+    int faults;
+    uint8_t alarm;
+} TMP105State;
+
 /**
  * tmp105_set:
  * @i2c: dispatcher to TMP105 hardware model
commit 6e9989034b176a8e4cfdccd85892abfa73977ba7
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Wed Jan 16 01:57:57 2013 +0100

    tests: Add tmp105 qtest test case
    
    Exercise all four commands of the TMP105, testing for an issue in the
    I2C TX path.
    
    The test case uses the N800's OMAP I2C and is the first for ARM.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/tests/Makefile b/tests/Makefile
index 53c5873..d86e95a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -60,6 +60,8 @@ gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c
 check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
 check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
 gcov-files-sparc-y += hw/m48t59.c
+check-qtest-arm-y = tests/tmp105-test$(EXESUF)
+qcov-files-arm-y += hw/tmp105.c
 
 GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
 
@@ -108,6 +110,7 @@ tests/rtc-test$(EXESUF): tests/rtc-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/fdc-test$(EXESUF): tests/fdc-test.o
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
+tests/tmp105-test$(EXESUF): tests/tmp105-test.o
 
 # QTest rules
 
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
new file mode 100644
index 0000000..a6ad213
--- /dev/null
+++ b/tests/tmp105-test.c
@@ -0,0 +1,76 @@
+/*
+ * QTest testcase for the TMP105 temperature sensor
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "libqtest.h"
+#include "libi2c.h"
+#include "hw/tmp105_regs.h"
+
+#include <glib.h>
+
+#define OMAP2_I2C_1_BASE 0x48070000
+
+#define N8X0_ADDR 0x48
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+
+static void send_and_receive(void)
+{
+    uint8_t cmd[3];
+    uint8_t resp[2];
+
+    cmd[0] = TMP105_REG_TEMPERATURE;
+    i2c_send(i2c, addr, cmd, 1);
+    i2c_recv(i2c, addr, resp, 2);
+    g_assert_cmpuint(((uint16_t)resp[0] << 8) | resp[1], ==, 0);
+
+    cmd[0] = TMP105_REG_CONFIG;
+    cmd[1] = 0x0; /* matches the reset value */
+    i2c_send(i2c, addr, cmd, 2);
+    i2c_recv(i2c, addr, resp, 1);
+    g_assert_cmphex(resp[0], ==, cmd[1]);
+
+    cmd[0] = TMP105_REG_T_LOW;
+    cmd[1] = 0x12;
+    cmd[2] = 0x34;
+    i2c_send(i2c, addr, cmd, 3);
+    i2c_recv(i2c, addr, resp, 2);
+    g_assert_cmphex(resp[0], ==, cmd[1]);
+    g_assert_cmphex(resp[1], ==, cmd[2]);
+
+    cmd[0] = TMP105_REG_T_HIGH;
+    cmd[1] = 0x42;
+    cmd[2] = 0x31;
+    i2c_send(i2c, addr, cmd, 3);
+    i2c_recv(i2c, addr, resp, 2);
+    g_assert_cmphex(resp[0], ==, cmd[1]);
+    g_assert_cmphex(resp[1], ==, cmd[2]);
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    s = qtest_start("-display none -machine n800");
+    i2c = omap_i2c_create(OMAP2_I2C_1_BASE);
+    addr = N8X0_ADDR;
+
+    qtest_add_func("/tmp105/tx-rx", send_and_receive);
+
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+    g_free(i2c);
+
+    return ret;
+}
commit cb5ef3fa1871522a0886627033459e94bd537fb7
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Wed Jan 16 01:57:56 2013 +0100

    tmp105: Fix I2C protocol bug
    
    An early length postincrement in the TMP105's I2C TX path led to
    transfers of more than one byte to place the second byte in the third
    byte's place within the buffer and the third byte to get discarded.
    
    Fix this by explictly incrementing the length after the checks but
    before the callback is called, which again checks the length.
    
    Adjust the Coding Style while at it.
    
    Signed-off-by: Alex Horn <alex.horn at cs.ox.ac.uk>
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/tmp105.c b/hw/tmp105.c
index 0ade4eb..10d94c9 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -153,11 +153,14 @@ static int tmp105_tx(I2CSlave *i2c, uint8_t data)
 {
     TMP105State *s = (TMP105State *) i2c;
 
-    if (!s->len ++)
+    if (s->len == 0) {
         s->pointer = data;
-    else {
-        if (s->len <= 2)
+        s->len++;
+    } else {
+        if (s->len <= 2) {
             s->buf[s->len - 1] = data;
+        }
+        s->len++;
         tmp105_write(s);
     }
 
commit 6d0b430176e3571af0e1596276078f05bfe1c5a5
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Wed Jan 16 01:57:55 2013 +0100

    tmp105: Split out I2C message constants from header
    
    Allows value sharing with qtest.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/tmp105.h b/hw/tmp105.h
index 51eff4b..982d1c9 100644
--- a/hw/tmp105.h
+++ b/hw/tmp105.h
@@ -15,39 +15,7 @@
 #define QEMU_TMP105_H
 
 #include "i2c.h"
-
-/**
- * TMP105Reg:
- * @TMP105_REG_TEMPERATURE: Temperature register
- * @TMP105_REG_CONFIG: Configuration register
- * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst)
- * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS)
- *
- * The following temperature sensors are
- * compatible with the TMP105 registers:
- * - adt75
- * - ds1775
- * - ds75
- * - lm75
- * - lm75a
- * - max6625
- * - max6626
- * - mcp980x
- * - stds75
- * - tcn75
- * - tmp100
- * - tmp101
- * - tmp105
- * - tmp175
- * - tmp275
- * - tmp75
- **/
-typedef enum TMP105Reg {
-    TMP105_REG_TEMPERATURE = 0,
-    TMP105_REG_CONFIG,
-    TMP105_REG_T_LOW,
-    TMP105_REG_T_HIGH,
-} TMP105Reg;
+#include "tmp105_regs.h"
 
 /**
  * tmp105_set:
diff --git a/hw/tmp105_regs.h b/hw/tmp105_regs.h
new file mode 100644
index 0000000..9b55aba
--- /dev/null
+++ b/hw/tmp105_regs.h
@@ -0,0 +1,50 @@
+/*
+ * Texas Instruments TMP105 Temperature Sensor I2C messages
+ *
+ * Browse the data sheet:
+ *
+ *    http://www.ti.com/lit/gpn/tmp105
+ *
+ * Copyright (C) 2012 Alex Horn <alex.horn at cs.ox.ac.uk>
+ * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg at gmail.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_TMP105_MSGS_H
+#define QEMU_TMP105_MSGS_H
+
+/**
+ * TMP105Reg:
+ * @TMP105_REG_TEMPERATURE: Temperature register
+ * @TMP105_REG_CONFIG: Configuration register
+ * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst)
+ * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS)
+ *
+ * The following temperature sensors are
+ * compatible with the TMP105 registers:
+ * - adt75
+ * - ds1775
+ * - ds75
+ * - lm75
+ * - lm75a
+ * - max6625
+ * - max6626
+ * - mcp980x
+ * - stds75
+ * - tcn75
+ * - tmp100
+ * - tmp101
+ * - tmp105
+ * - tmp175
+ * - tmp275
+ * - tmp75
+ **/
+typedef enum TMP105Reg {
+    TMP105_REG_TEMPERATURE = 0,
+    TMP105_REG_CONFIG,
+    TMP105_REG_T_LOW,
+    TMP105_REG_T_HIGH,
+} TMP105Reg;
+
+#endif
commit 2bf7b4572b39a494403190636b4e7d44967504c0
Author: Andreas Färber <andreas.faerber at web.de>
Date:   Wed Jan 16 01:57:54 2013 +0100

    libqtest: Prepare I2C libqos
    
    This adds a simple I2C API and a driver implementation for omap_i2c.
    
    Signed-off-by: Andreas Färber <andreas.faerber at web.de>
    Reviewed-by: Anthony Liguori <aliguori at us.ibm.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/tests/Makefile b/tests/Makefile
index d97a571..53c5873 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -116,6 +116,7 @@ QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TA
 check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
 
 qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
+qtest-obj-y += tests/libi2c.o tests/libi2c-omap.o
 $(check-qtest-y): $(qtest-obj-y)
 
 .PHONY: check-help
diff --git a/tests/libi2c-omap.c b/tests/libi2c-omap.c
new file mode 100644
index 0000000..9be57e9
--- /dev/null
+++ b/tests/libi2c-omap.c
@@ -0,0 +1,166 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "libi2c.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+enum OMAPI2CRegisters {
+    OMAP_I2C_REV  = 0x00,
+    OMAP_I2C_STAT = 0x08,
+    OMAP_I2C_CNT  = 0x18,
+    OMAP_I2C_DATA = 0x1c,
+    OMAP_I2C_CON  = 0x24,
+    OMAP_I2C_SA   = 0x2c,
+};
+
+enum OMAPI2CSTATBits {
+    OMAP_I2C_STAT_NACK = 1 << 1,
+    OMAP_I2C_STAT_ARDY = 1 << 2,
+    OMAP_I2C_STAT_RRDY = 1 << 3,
+    OMAP_I2C_STAT_XRDY = 1 << 4,
+    OMAP_I2C_STAT_ROVR = 1 << 11,
+    OMAP_I2C_STAT_SBD  = 1 << 15,
+};
+
+enum OMAPI2CCONBits {
+    OMAP_I2C_CON_STT    = 1 << 0,
+    OMAP_I2C_CON_STP    = 1 << 1,
+    OMAP_I2C_CON_TRX    = 1 << 9,
+    OMAP_I2C_CON_MST    = 1 << 10,
+    OMAP_I2C_CON_BE     = 1 << 14,
+    OMAP_I2C_CON_I2C_EN = 1 << 15,
+};
+
+typedef struct OMAPI2C {
+    I2CAdapter parent;
+
+    uint64_t addr;
+} OMAPI2C;
+
+
+static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr)
+{
+    uint16_t data = addr;
+
+    memwrite(s->addr + OMAP_I2C_SA, &data, 2);
+    memread(s->addr + OMAP_I2C_SA, &data, 2);
+    g_assert_cmphex(data, ==, addr);
+}
+
+static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr,
+                          const uint8_t *buf, uint16_t len)
+{
+    OMAPI2C *s = (OMAPI2C *)i2c;
+    uint16_t data;
+
+    omap_i2c_set_slave_addr(s, addr);
+
+    data = len;
+    memwrite(s->addr + OMAP_I2C_CNT, &data, 2);
+
+    data = OMAP_I2C_CON_I2C_EN |
+           OMAP_I2C_CON_TRX |
+           OMAP_I2C_CON_MST |
+           OMAP_I2C_CON_STT |
+           OMAP_I2C_CON_STP;
+    memwrite(s->addr + OMAP_I2C_CON, &data, 2);
+    memread(s->addr + OMAP_I2C_CON, &data, 2);
+    g_assert((data & OMAP_I2C_CON_STP) != 0);
+
+    memread(s->addr + OMAP_I2C_STAT, &data, 2);
+    g_assert((data & OMAP_I2C_STAT_NACK) == 0);
+
+    while (len > 1) {
+        memread(s->addr + OMAP_I2C_STAT, &data, 2);
+        g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
+
+        memwrite(s->addr + OMAP_I2C_DATA, buf, 2);
+        buf = (uint8_t *)buf + 2;
+        len -= 2;
+    }
+    if (len == 1) {
+        memread(s->addr + OMAP_I2C_STAT, &data, 2);
+        g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
+
+        memwrite(s->addr + OMAP_I2C_DATA, buf, 1);
+    }
+
+    memread(s->addr + OMAP_I2C_CON, &data, 2);
+    g_assert((data & OMAP_I2C_CON_STP) == 0);
+}
+
+static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+                          uint8_t *buf, uint16_t len)
+{
+    OMAPI2C *s = (OMAPI2C *)i2c;
+    uint16_t data, stat;
+
+    omap_i2c_set_slave_addr(s, addr);
+
+    data = len;
+    memwrite(s->addr + OMAP_I2C_CNT, &data, 2);
+
+    data = OMAP_I2C_CON_I2C_EN |
+           OMAP_I2C_CON_MST |
+           OMAP_I2C_CON_STT |
+           OMAP_I2C_CON_STP;
+    memwrite(s->addr + OMAP_I2C_CON, &data, 2);
+    memread(s->addr + OMAP_I2C_CON, &data, 2);
+    g_assert((data & OMAP_I2C_CON_STP) == 0);
+
+    memread(s->addr + OMAP_I2C_STAT, &data, 2);
+    g_assert((data & OMAP_I2C_STAT_NACK) == 0);
+
+    memread(s->addr + OMAP_I2C_CNT, &data, 2);
+    g_assert_cmpuint(data, ==, len);
+
+    while (len > 0) {
+        memread(s->addr + OMAP_I2C_STAT, &data, 2);
+        g_assert((data & OMAP_I2C_STAT_RRDY) != 0);
+        g_assert((data & OMAP_I2C_STAT_ROVR) == 0);
+
+        memread(s->addr + OMAP_I2C_DATA, &data, 2);
+
+        memread(s->addr + OMAP_I2C_STAT, &stat, 2);
+        if (unlikely(len == 1)) {
+            *buf = data & 0xf;
+            buf++;
+            len--;
+        } else {
+            memcpy(buf, &data, 2);
+            buf += 2;
+            len -= 2;
+        }
+    }
+
+    memread(s->addr + OMAP_I2C_CON, &data, 2);
+    g_assert((data & OMAP_I2C_CON_STP) == 0);
+}
+
+I2CAdapter *omap_i2c_create(uint64_t addr)
+{
+    OMAPI2C *s = g_malloc0(sizeof(*s));
+    I2CAdapter *i2c = (I2CAdapter *)s;
+    uint16_t data;
+
+    s->addr = addr;
+
+    i2c->send = omap_i2c_send;
+    i2c->recv = omap_i2c_recv;
+
+    /* verify the mmio address by looking for a known signature */
+    memread(addr + OMAP_I2C_REV, &data, 2);
+    g_assert_cmphex(data, ==, 0x34);
+
+    return i2c;
+}
diff --git a/tests/libi2c.c b/tests/libi2c.c
new file mode 100644
index 0000000..13ec85c
--- /dev/null
+++ b/tests/libi2c.c
@@ -0,0 +1,22 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "libi2c.h"
+#include "libqtest.h"
+
+void i2c_send(I2CAdapter *i2c, uint8_t addr,
+              const uint8_t *buf, uint16_t len)
+{
+    i2c->send(i2c, addr, buf, len);
+}
+
+void i2c_recv(I2CAdapter *i2c, uint8_t addr,
+              uint8_t *buf, uint16_t len)
+{
+    i2c->recv(i2c, addr, buf, len);
+}
diff --git a/tests/libi2c.h b/tests/libi2c.h
new file mode 100644
index 0000000..1ce9af4
--- /dev/null
+++ b/tests/libi2c.h
@@ -0,0 +1,30 @@
+/*
+ * I2C libqos
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef LIBQOS_I2C_H
+#define LIBQOS_I2C_H
+
+#include <stdint.h>
+
+typedef struct I2CAdapter I2CAdapter;
+struct I2CAdapter {
+    void (*send)(I2CAdapter *adapter, uint8_t addr,
+                 const uint8_t *buf, uint16_t len);
+    void (*recv)(I2CAdapter *adapter, uint8_t addr,
+                 uint8_t *buf, uint16_t len);
+};
+
+void i2c_send(I2CAdapter *i2c, uint8_t addr,
+              const uint8_t *buf, uint16_t len);
+void i2c_recv(I2CAdapter *i2c, uint8_t addr,
+              uint8_t *buf, uint16_t len);
+
+/* libi2c-omap.c */
+I2CAdapter *omap_i2c_create(uint64_t addr);
+
+#endif
commit 457b65432700281b061086a2a8527bf1f59163a9
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Jan 16 18:17:33 2013 +0100

    audio: Replace non-portable asprintf in debug code by g_strdup_printf
    
    sw->name already uses the correct g_free to free the allocated memory.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/audio/audio.c b/audio/audio.c
index 1510b59..02bb886 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -828,8 +828,9 @@ static int audio_attach_capture (HWVoiceOut *hw)
         QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
         QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
 #ifdef DEBUG_CAPTURE
-        asprintf (&sw->name, "for %p %d,%d,%d",
-                  hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
+        sw->name = g_strdup_printf ("for %p %d,%d,%d",
+                                    hw, sw->info.freq, sw->info.bits,
+                                    sw->info.nchannels);
         dolog ("Added %s active = %d\n", sw->name, sw->active);
 #endif
         if (sw->active) {
commit a1cbfd554e11bb8af38c2f3e1f1574bf4c563cd2
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jan 16 18:20:25 2013 +0100

    usb-storage: Drop useless null test in usb_msd_handle_data()
    
    scsi_req_new() never returns null, and scsi_req_enqueue() dereferences
    the pointer, so checking for null is useless.
    
    Spotted by Coverity.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 1b87352..b839798 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -427,7 +427,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
             scsi_req_print(s->req);
 #endif
             scsi_req_enqueue(s->req);
-            if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) {
+            if (s->req->cmd.xfer != SCSI_XFER_NONE) {
                 scsi_req_continue(s->req);
             }
             break;
commit 955d7b26779d6654f6ba2c456bac9fd49fa0cd8a
Author: Markus Armbruster <armbru at redhat.com>
Date:   Wed Jan 16 18:20:57 2013 +0100

    ui: Drop useless null tests in parse_keyboard_layout()
    
    Spotted by Coverity.
    
    Signed-off-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/ui/keymaps.c b/ui/keymaps.c
index 9625d82..f373cc5 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -127,25 +127,27 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
                     //		    fprintf(stderr, "Warning: unknown keysym %s\n", line);
 		} else {
 		    const char *rest = end_of_keysym + 1;
-		    char *rest2;
-		    int keycode = strtol(rest, &rest2, 0);
+                    int keycode = strtol(rest, NULL, 0);
 
-		    if (rest && strstr(rest, "numlock")) {
+                    if (strstr(rest, "numlock")) {
 			add_to_key_range(&k->keypad_range, keycode);
 			add_to_key_range(&k->numlock_range, keysym);
 			//fprintf(stderr, "keypad keysym %04x keycode %d\n", keysym, keycode);
 		    }
 
-		    if (rest && strstr(rest, "shift"))
+                    if (strstr(rest, "shift")) {
 			keycode |= SCANCODE_SHIFT;
-		    if (rest && strstr(rest, "altgr"))
+                    }
+                    if (strstr(rest, "altgr")) {
 			keycode |= SCANCODE_ALTGR;
-		    if (rest && strstr(rest, "ctrl"))
+                    }
+                    if (strstr(rest, "ctrl")) {
 			keycode |= SCANCODE_CTRL;
+                    }
 
 		    add_keysym(line, keysym, keycode, k);
 
-		    if (rest && strstr(rest, "addupper")) {
+                    if (strstr(rest, "addupper")) {
 			char *c;
 			for (c = line; *c; c++)
 			    *c = qemu_toupper(*c);
commit 4ecf8aa5a06a830b05c035a5d6184bf991931d20
Author: Stefan Weil <sw at weilnetz.de>
Date:   Wed Jan 16 18:22:29 2013 +0100

    pseries: Replace non-portable asprintf by g_strdup_printf
    
    g_strdup_printf already handles OOM errors, so some error handling in
    QEMU code can be removed.
    
    Signed-off-by: Stefan Weil <sw at weilnetz.de>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/spapr.c b/hw/spapr.c
index 21c261b..d80b792 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -328,14 +328,11 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
             continue;
         }
 
-        if (asprintf(&nodename, "%s@%x", modelname, index) < 0) {
-            fprintf(stderr, "Allocation failure\n");
-            exit(1);
-        }
+        nodename = g_strdup_printf("%s@%x", modelname, index);
 
         _FDT((fdt_begin_node(fdt, nodename)));
 
-        free(nodename);
+        g_free(nodename);
 
         _FDT((fdt_property_cell(fdt, "reg", index)));
         _FDT((fdt_property_string(fdt, "device_type", "cpu")));
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 3a1a486..2054219 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -80,9 +80,7 @@ static char *vio_format_dev_name(VIOsPAPRDevice *dev)
     char *name;
 
     /* Device tree style name device at reg */
-    if (asprintf(&name, "%s@%x", pc->dt_name, dev->reg) < 0) {
-        return NULL;
-    }
+    name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
 
     return name;
 }
@@ -101,12 +99,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
     }
 
     dt_name = vio_format_dev_name(dev);
-    if (!dt_name) {
-        return -ENOMEM;
-    }
-
     node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
-    free(dt_name);
+    g_free(dt_name);
     if (node_off < 0) {
         return node_off;
     }
@@ -444,9 +438,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
     /* Don't overwrite ids assigned on the command line */
     if (!dev->qdev.id) {
         id = vio_format_dev_name(dev);
-        if (!id) {
-            return -1;
-        }
         dev->qdev.id = id;
     }
 
@@ -646,20 +637,12 @@ int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
     }
 
     name = vio_format_dev_name(dev);
-    if (!name) {
-        return -ENOMEM;
-    }
-
-    if (asprintf(&path, "/vdevice/%s", name) < 0) {
-        path = NULL;
-        ret = -ENOMEM;
-        goto out;
-    }
+    path = g_strdup_printf("/vdevice/%s", name);
 
     ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
-out:
-    free(name);
-    free(path);
+
+    g_free(name);
+    g_free(path);
 
     return ret;
 }
commit b8e76b35d47d03f6f9bb3a7455316aaed8b25795
Author: Knut Omang <knuto at ifi.uio.no>
Date:   Wed Jan 16 16:34:34 2013 +0100

    Add new DEFAULT_MACHINE_OPTIONS to q35 and ppc405
    
    Without this default q35/ppc405 based machines would no longer boot
    after commit e4ada29e909787f629626660b1561f6a680187d3
    
    Signed-off-by: Knut Omang <knut.omang at oracle.com>
    Reviewed-by: Markus Armbruster <armbru at redhat.com>
    Signed-off-by: Anthony Liguori <aliguori at us.ibm.com>

diff --git a/hw/pc_q35.c b/hw/pc_q35.c
index 52d9976..d82353e 100644
--- a/hw/pc_q35.c
+++ b/hw/pc_q35.c
@@ -214,6 +214,7 @@ static QEMUMachine pc_q35_machine = {
     .desc = "Standard PC (Q35 + ICH9, 2009)",
     .init = pc_q35_init,
     .max_cpus = 255,
+    DEFAULT_MACHINE_OPTIONS,
 };
 
 static void pc_q35_machine_init(void)
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 45ed376..cf371db 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -362,6 +362,7 @@ static QEMUMachine ref405ep_machine = {
     .name = "ref405ep",
     .desc = "ref405ep",
     .init = ref405ep_init,
+    DEFAULT_MACHINE_OPTIONS,
 };
 
 /*****************************************************************************/
commit 0a1a7fabda7f0fa05ef09051be29e92e81f929ad
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Dec 20 14:39:13 2012 +0100

    chardev: add pty chardev support to chardev-add (qmp)
    
    The ptsname is returned directly, so there is no need to
    use query-chardev to figure the pty device path.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 5c3e3eb..6d7252b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3081,6 +3081,7 @@
 { 'union': 'ChardevBackend', 'data': { 'file'   : 'ChardevFile',
                                        'port'   : 'ChardevPort',
                                        'socket' : 'ChardevSocket',
+                                       'pty'    : 'ChardevDummy',
                                        'null'   : 'ChardevDummy' } }
 
 ##
@@ -3090,7 +3091,7 @@
 #
 # Since: 1.4
 ##
-{ 'type' : 'ChardevReturn', 'data': { } }
+{ 'type' : 'ChardevReturn', 'data': { '*pty' : 'str' } }
 
 ##
 # @chardev-add:
diff --git a/qemu-char.c b/qemu-char.c
index 36d7e29..9ba0573 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3204,6 +3204,19 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     case CHARDEV_BACKEND_KIND_SOCKET:
         chr = qmp_chardev_open_socket(backend->socket, errp);
         break;
+#ifdef HAVE_CHARDEV_TTY
+    case CHARDEV_BACKEND_KIND_PTY:
+    {
+        /* qemu_chr_open_pty sets "path" in opts */
+        QemuOpts *opts;
+        opts = qemu_opts_create_nofail(qemu_find_opts("chardev"));
+        chr = qemu_chr_open_pty(opts);
+        ret->pty = g_strdup(qemu_opt_get(opts, "path"));
+        ret->has_pty = true;
+        qemu_opts_del(opts);
+        break;
+    }
+#endif
     case CHARDEV_BACKEND_KIND_NULL:
         chr = qemu_chr_open_null(NULL);
         break;
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4d382f4..cbf1280 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2685,6 +2685,11 @@ Examples:
                                    "data" : { "out" : "/tmp/bar.log" } } } }
 <- { "return": {} }
 
+-> { "execute" : "chardev-add",
+     "arguments" : { "id" : "baz",
+                     "backend" : { "type" : "pty", "data" : {} } } }
+<- { "return": { "pty" : "/dev/pty/42" } }
+
 EQMP
 
     {
commit f6bd5d6ec514939c421fcd411d1a39bc7dad0948
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Dec 20 13:53:12 2012 +0100

    chardev: add socket chardev support to chardev-add (qmp)
    
    qemu_chr_open_socket is split into two functions.  All initialization
    after creating the socket file handler is split away into the new
    qemu_chr_open_socket_fd function.
    
    chr->filename doesn't get filled from QemuOpts any more.  Qemu gathers
    the information using getsockname and getnameinfo instead.  This way it
    will also work correctly for file handles passed via file descriptor
    passing.
    
    Finally qmp_chardev_open_socket() is the actual qmp hotplug
    implementation which basically just calls socket_listen or
    socket_connect and the new qemu_chr_open_socket_fd function.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 320fa6b..5c3e3eb 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3049,6 +3049,27 @@
                                    'type'   : 'ChardevPortKind'} }
 
 ##
+# @ChardevSocket:
+#
+# Configuration info for socket chardevs.
+#
+# @addr: socket address to listen on (server=true)
+#        or connect to (server=false)
+# @server: #optional create server socket (default: true)
+# @wait: #optional wait for connect (not used for server
+#        sockets, default: false)
+# @nodelay: #optional set TCP_NODELAY socket option (default: false)
+# @telnet: #optional enable telnet protocol (default: false)
+#
+# Since: 1.4
+##
+{ 'type': 'ChardevSocket', 'data': { 'addr'     : 'SocketAddress',
+                                     '*server'  : 'bool',
+                                     '*wait'    : 'bool',
+                                     '*nodelay' : 'bool',
+                                     '*telnet'  : 'bool' } }
+
+##
 # @ChardevBackend:
 #
 # Configuration info for the new chardev backend.
@@ -3057,9 +3078,10 @@
 ##
 { 'type': 'ChardevDummy', 'data': { } }
 
-{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
-                                       'port' : 'ChardevPort',
-                                       'null' : 'ChardevDummy' } }
+{ 'union': 'ChardevBackend', 'data': { 'file'   : 'ChardevFile',
+                                       'port'   : 'ChardevPort',
+                                       'socket' : 'ChardevSocket',
+                                       'null'   : 'ChardevDummy' } }
 
 ##
 # @ChardevReturn:
diff --git a/qemu-char.c b/qemu-char.c
index 7091e05..36d7e29 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2438,10 +2438,88 @@ static void tcp_chr_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_socket_fd(int fd, bool do_nodelay,
+                                                bool is_listen, bool is_telnet,
+                                                bool is_waitconnect,
+                                                Error **errp)
 {
     CharDriverState *chr = NULL;
     TCPCharDriver *s = NULL;
+    char host[NI_MAXHOST], serv[NI_MAXSERV];
+    const char *left = "", *right = "";
+    struct sockaddr_storage ss;
+    socklen_t ss_len = sizeof(ss);
+
+    memset(&ss, 0, ss_len);
+    if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) != 0) {
+        error_setg(errp, "getsockname: %s", strerror(errno));
+        return NULL;
+    }
+
+    chr = g_malloc0(sizeof(CharDriverState));
+    s = g_malloc0(sizeof(TCPCharDriver));
+
+    s->connected = 0;
+    s->fd = -1;
+    s->listen_fd = -1;
+    s->msgfd = -1;
+
+    chr->filename = g_malloc(256);
+    switch (ss.ss_family) {
+#ifndef _WIN32
+    case AF_UNIX:
+        s->is_unix = 1;
+        snprintf(chr->filename, 256, "unix:%s%s",
+                 ((struct sockaddr_un *)(&ss))->sun_path,
+                 is_listen ? ",server" : "");
+        break;
+#endif
+    case AF_INET6:
+        left  = "[";
+        right = "]";
+        /* fall through */
+    case AF_INET:
+        s->do_nodelay = do_nodelay;
+        getnameinfo((struct sockaddr *) &ss, ss_len, host, sizeof(host),
+                    serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV);
+        snprintf(chr->filename, 256, "%s:%s:%s%s%s%s",
+                 is_telnet ? "telnet" : "tcp",
+                 left, host, right, serv,
+                 is_listen ? ",server" : "");
+        break;
+    }
+
+    chr->opaque = s;
+    chr->chr_write = tcp_chr_write;
+    chr->chr_close = tcp_chr_close;
+    chr->get_msgfd = tcp_get_msgfd;
+    chr->chr_add_client = tcp_chr_add_client;
+
+    if (is_listen) {
+        s->listen_fd = fd;
+        qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
+        if (is_telnet) {
+            s->do_telnetopt = 1;
+        }
+    } else {
+        s->connected = 1;
+        s->fd = fd;
+        socket_set_nodelay(fd);
+        tcp_chr_connect(chr);
+    }
+
+    if (is_listen && is_waitconnect) {
+        printf("QEMU waiting for connection on: %s\n",
+               chr->filename);
+        tcp_chr_accept(chr);
+        socket_set_nonblock(s->listen_fd);
+    }
+    return chr;
+}
+
+static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
+{
+    CharDriverState *chr = NULL;
     Error *local_err = NULL;
     int fd = -1;
     int is_listen;
@@ -2458,9 +2536,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     if (!is_listen)
         is_waitconnect = 0;
 
-    chr = g_malloc0(sizeof(CharDriverState));
-    s = g_malloc0(sizeof(TCPCharDriver));
-
     if (is_unix) {
         if (is_listen) {
             fd = unix_listen_opts(opts, &local_err);
@@ -2481,56 +2556,14 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     if (!is_waitconnect)
         socket_set_nonblock(fd);
 
-    s->connected = 0;
-    s->fd = -1;
-    s->listen_fd = -1;
-    s->msgfd = -1;
-    s->is_unix = is_unix;
-    s->do_nodelay = do_nodelay && !is_unix;
-
-    chr->opaque = s;
-    chr->chr_write = tcp_chr_write;
-    chr->chr_close = tcp_chr_close;
-    chr->get_msgfd = tcp_get_msgfd;
-    chr->chr_add_client = tcp_chr_add_client;
-
-    if (is_listen) {
-        s->listen_fd = fd;
-        qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr);
-        if (is_telnet)
-            s->do_telnetopt = 1;
-
-    } else {
-        s->connected = 1;
-        s->fd = fd;
-        socket_set_nodelay(fd);
-        tcp_chr_connect(chr);
-    }
-
-    /* for "info chardev" monitor command */
-    chr->filename = g_malloc(256);
-    if (is_unix) {
-        snprintf(chr->filename, 256, "unix:%s%s",
-                 qemu_opt_get(opts, "path"),
-                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
-    } else if (is_telnet) {
-        snprintf(chr->filename, 256, "telnet:%s:%s%s",
-                 qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
-                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
-    } else {
-        snprintf(chr->filename, 256, "tcp:%s:%s%s",
-                 qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
-                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
-    }
-
-    if (is_listen && is_waitconnect) {
-        printf("QEMU waiting for connection on: %s\n",
-               chr->filename);
-        tcp_chr_accept(chr);
-        socket_set_nonblock(s->listen_fd);
+    chr = qemu_chr_open_socket_fd(fd, do_nodelay, is_listen, is_telnet,
+                                  is_waitconnect, &local_err);
+    if (error_is_set(&local_err)) {
+        goto fail;
     }
     return chr;
 
+
  fail:
     if (local_err) {
         qerror_report_err(local_err);
@@ -2539,8 +2572,10 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     if (fd >= 0) {
         closesocket(fd);
     }
-    g_free(s);
-    g_free(chr);
+    if (chr) {
+        g_free(chr->opaque);
+        g_free(chr);
+    }
     return NULL;
 }
 
@@ -3124,6 +3159,28 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
 
 #endif /* WIN32 */
 
+static CharDriverState *qmp_chardev_open_socket(ChardevSocket *sock,
+                                                Error **errp)
+{
+    SocketAddress *addr = sock->addr;
+    bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
+    bool is_listen      = sock->has_server  ? sock->server  : true;
+    bool is_telnet      = sock->has_telnet  ? sock->telnet  : false;
+    bool is_waitconnect = sock->has_wait    ? sock->wait    : false;
+    int fd;
+
+    if (is_listen) {
+        fd = socket_listen(addr, errp);
+    } else {
+        fd = socket_connect(addr, errp, NULL, NULL);
+    }
+    if (error_is_set(errp)) {
+        return NULL;
+    }
+    return qemu_chr_open_socket_fd(fd, do_nodelay, is_listen,
+                                   is_telnet, is_waitconnect, errp);
+}
+
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {
@@ -3144,6 +3201,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     case CHARDEV_BACKEND_KIND_PORT:
         chr = qmp_chardev_open_port(backend->port, errp);
         break;
+    case CHARDEV_BACKEND_KIND_SOCKET:
+        chr = qmp_chardev_open_socket(backend->socket, errp);
+        break;
     case CHARDEV_BACKEND_KIND_NULL:
         chr = qemu_chr_open_null(NULL);
         break;
commit 88a946d32dd9e4c6c0ad56e19f2822bd5c8b416e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jan 10 14:20:58 2013 +0100

    chardev: add parallel chardev support to chardev-add (qmp)
    
    Also alias the old parport name to parallel for -chardev.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index bbbbd33..320fa6b 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3042,7 +3042,8 @@
 #
 # Since: 1.4
 ##
-{ 'enum': 'ChardevPortKind', 'data': [ 'serial' ] }
+{ 'enum': 'ChardevPortKind', 'data': [ 'serial',
+                                       'parallel' ] }
 
 { 'type': 'ChardevPort', 'data': { 'device' : 'str',
                                    'type'   : 'ChardevPortKind'} }
diff --git a/qemu-char.c b/qemu-char.c
index 8398398..7091e05 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1367,17 +1367,10 @@ static void pp_close(CharDriverState *chr)
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_pp_fd(int fd)
 {
-    const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     ParallelCharDriver *drv;
-    int fd;
-
-    TFR(fd = qemu_open(filename, O_RDWR));
-    if (fd < 0) {
-        return NULL;
-    }
 
     if (ioctl(fd, PPCLAIM) < 0) {
         close(fd);
@@ -1441,16 +1434,9 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_pp_fd(int fd)
 {
-    const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
-    int fd;
-
-    fd = qemu_open(filename, O_RDWR);
-    if (fd < 0) {
-        return NULL;
-    }
 
     chr = g_malloc0(sizeof(CharDriverState));
     chr->opaque = (void *)(intptr_t)fd;
@@ -2750,6 +2736,22 @@ fail:
     return NULL;
 }
 
+#ifdef HAVE_CHARDEV_PARPORT
+
+static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
+{
+    const char *filename = qemu_opt_get(opts, "path");
+    int fd;
+
+    fd = qemu_open(filename, O_RDWR);
+    if (fd < 0) {
+        return NULL;
+    }
+    return qemu_chr_open_pp_fd(fd);
+}
+
+#endif
+
 static const struct {
     const char *name;
     CharDriverState *(*open)(QemuOpts *opts);
@@ -2779,6 +2781,7 @@ static const struct {
     { .name = "pty",       .open = qemu_chr_open_pty },
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
+    { .name = "parallel",  .open = qemu_chr_open_pp },
     { .name = "parport",   .open = qemu_chr_open_pp },
 #endif
 #ifdef CONFIG_SPICE
@@ -3104,6 +3107,15 @@ static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
         socket_set_nonblock(fd);
         return qemu_chr_open_tty_fd(fd);
 #endif
+#ifdef HAVE_CHARDEV_PARPORT
+    case CHARDEV_PORT_KIND_PARALLEL:
+        flags = O_RDWR;
+        fd = qmp_chardev_open_file_source(port->device, flags, errp);
+        if (error_is_set(errp)) {
+            return NULL;
+        }
+        return qemu_chr_open_pp_fd(fd);
+#endif
     default:
         error_setg(errp, "unknown chardev port (%d)", port->type);
         return NULL;
diff --git a/qemu-options.hx b/qemu-options.hx
index 17cc1ad..40cd683 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1746,6 +1746,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
     "-chardev tty,id=id,path=path[,mux=on|off]\n"
 #endif
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
+    "-chardev parallel,id=id,path=path[,mux=on|off]\n"
     "-chardev parport,id=id,path=path[,mux=on|off]\n"
 #endif
 #if defined(CONFIG_SPICE)
@@ -1776,6 +1777,7 @@ Backend is one of:
 @option{stdio},
 @option{braille},
 @option{tty},
+ at option{parallel},
 @option{parport},
 @option{spicevmc}.
 @option{spiceport}.
@@ -1943,9 +1945,10 @@ DragonFlyBSD hosts.  It is an alias for -serial.
 
 @option{path} specifies the path to the tty. @option{path} is required.
 
+ at item -chardev parallel ,id=@var{id} ,path=@var{path}
 @item -chardev parport ,id=@var{id} ,path=@var{path}
 
- at option{parport} is only available on Linux, FreeBSD and DragonFlyBSD hosts.
+ at option{parallel} is only available on Linux, FreeBSD and DragonFlyBSD hosts.
 
 Connect to a local parallel port.
 
commit d59044ef74d577797d087bc6ffb156cec89ed39a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 19 13:50:29 2012 +0100

    chardev: add serial chardev support to chardev-add (qmp)
    
    Similar to file, except that no separate in/out files are supported
    because it's pointless for direct device access.  Also the special
    tty ioctl hooks (pass through linespeed settings etc) are activated
    on Unix.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index c70c118..bbbbd33 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3032,6 +3032,22 @@
                                    'out' : 'str' } }
 
 ##
+# @ChardevPort:
+#
+# Configuration info for device chardevs.
+#
+# @device: The name of the special file for the device,
+#          i.e. /dev/ttyS0 on Unix or COM1: on Windows
+# @type: What kind of device this is.
+#
+# Since: 1.4
+##
+{ 'enum': 'ChardevPortKind', 'data': [ 'serial' ] }
+
+{ 'type': 'ChardevPort', 'data': { 'device' : 'str',
+                                   'type'   : 'ChardevPortKind'} }
+
+##
 # @ChardevBackend:
 #
 # Configuration info for the new chardev backend.
@@ -3041,6 +3057,7 @@
 { 'type': 'ChardevDummy', 'data': { } }
 
 { 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
+                                       'port' : 'ChardevPort',
                                        'null' : 'ChardevDummy' } }
 
 ##
diff --git a/qemu-char.c b/qemu-char.c
index d447d96..8398398 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1230,21 +1230,27 @@ static void qemu_chr_close_tty(CharDriverState *chr)
     }
 }
 
+static CharDriverState *qemu_chr_open_tty_fd(int fd)
+{
+    CharDriverState *chr;
+
+    tty_serial_init(fd, 115200, 'N', 8, 1);
+    chr = qemu_chr_open_fd(fd, fd);
+    chr->chr_ioctl = tty_serial_ioctl;
+    chr->chr_close = qemu_chr_close_tty;
+    return chr;
+}
+
 static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
 {
     const char *filename = qemu_opt_get(opts, "path");
-    CharDriverState *chr;
     int fd;
 
     TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
     if (fd < 0) {
         return NULL;
     }
-    tty_serial_init(fd, 115200, 'N', 8, 1);
-    chr = qemu_chr_open_fd(fd, fd);
-    chr->chr_ioctl = tty_serial_ioctl;
-    chr->chr_close = qemu_chr_close_tty;
-    return chr;
+    return qemu_chr_open_tty_fd(fd);
 }
 #endif /* __linux__ || __sun__ */
 
@@ -1666,9 +1672,8 @@ static int win_chr_poll(void *opaque)
     return 0;
 }
 
-static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_win_path(const char *filename)
 {
-    const char *filename = qemu_opt_get(opts, "path");
     CharDriverState *chr;
     WinCharState *s;
 
@@ -1687,6 +1692,11 @@ static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
     return chr;
 }
 
+static CharDriverState *qemu_chr_open_win(QemuOpts *opts)
+{
+    return qemu_chr_open_win_path(qemu_opt_get(opts, "path"));
+}
+
 static int win_chr_pipe_poll(void *opaque)
 {
     CharDriverState *chr = opaque;
@@ -2765,6 +2775,7 @@ static const struct {
 #endif
 #ifdef HAVE_CHARDEV_TTY
     { .name = "tty",       .open = qemu_chr_open_tty },
+    { .name = "serial",    .open = qemu_chr_open_tty },
     { .name = "pty",       .open = qemu_chr_open_pty },
 #endif
 #ifdef HAVE_CHARDEV_PARPORT
@@ -3031,6 +3042,17 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
     return qemu_chr_open_win_file(out);
 }
 
+static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
+{
+    switch (port->type) {
+    case CHARDEV_PORT_KIND_SERIAL:
+        return qemu_chr_open_win_path(port->device);
+    default:
+        error_setg(errp, "unknown chardev port (%d)", port->type);
+        return NULL;
+    }
+}
+
 #else /* WIN32 */
 
 static int qmp_chardev_open_file_source(char *src, int flags,
@@ -3067,6 +3089,27 @@ static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
     return qemu_chr_open_fd(in, out);
 }
 
+static CharDriverState *qmp_chardev_open_port(ChardevPort *port, Error **errp)
+{
+    int flags, fd;
+
+    switch (port->type) {
+#ifdef HAVE_CHARDEV_TTY
+    case CHARDEV_PORT_KIND_SERIAL:
+        flags = O_RDWR;
+        fd = qmp_chardev_open_file_source(port->device, flags, errp);
+        if (error_is_set(errp)) {
+            return NULL;
+        }
+        socket_set_nonblock(fd);
+        return qemu_chr_open_tty_fd(fd);
+#endif
+    default:
+        error_setg(errp, "unknown chardev port (%d)", port->type);
+        return NULL;
+    }
+}
+
 #endif /* WIN32 */
 
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
@@ -3086,6 +3129,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     case CHARDEV_BACKEND_KIND_FILE:
         chr = qmp_chardev_open_file(backend->file, errp);
         break;
+    case CHARDEV_BACKEND_KIND_PORT:
+        chr = qmp_chardev_open_port(backend->port, errp);
+        break;
     case CHARDEV_BACKEND_KIND_NULL:
         chr = qemu_chr_open_null(NULL);
         break;
diff --git a/qemu-options.hx b/qemu-options.hx
index 9df0cde..17cc1ad 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1742,6 +1742,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
 #endif
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
         || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    "-chardev serial,id=id,path=path[,mux=on|off]\n"
     "-chardev tty,id=id,path=path[,mux=on|off]\n"
 #endif
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__)
@@ -1910,8 +1911,8 @@ take any options.
 
 Send traffic from the guest to a serial device on the host.
 
- at option{serial} is
-only available on Windows hosts.
+On Unix hosts serial will actually accept any tty device,
+not only serial lines.
 
 @option{path} specifies the name of the serial device to open.
 
@@ -1937,10 +1938,8 @@ Connect to a local BrlAPI server. @option{braille} does not take any options.
 
 @item -chardev tty ,id=@var{id} ,path=@var{path}
 
-Connect to a local tty device.
-
 @option{tty} is only available on Linux, Sun, FreeBSD, NetBSD, OpenBSD and
-DragonFlyBSD hosts.
+DragonFlyBSD hosts.  It is an alias for -serial.
 
 @option{path} specifies the path to the tty. @option{path} is required.
 
commit ffbdbe59acc5f175d6c05a5d90f0b7c865fafd5b
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 19 13:13:57 2012 +0100

    chardev: add file chardev support to chardev-add (qmp)
    
    Add support for file chardevs.  Output file is mandatory,
    input file is optional.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 462511e..c70c118 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3019,6 +3019,19 @@
 { 'command': 'nbd-server-stop' }
 
 ##
+# @ChardevFile:
+#
+# Configuration info for file chardevs.
+#
+# @in:  #optional The name of the input file
+# @out: The name of the output file
+#
+# Since: 1.4
+##
+{ 'type': 'ChardevFile', 'data': { '*in' : 'str',
+                                   'out' : 'str' } }
+
+##
 # @ChardevBackend:
 #
 # Configuration info for the new chardev backend.
@@ -3027,7 +3040,8 @@
 ##
 { 'type': 'ChardevDummy', 'data': { } }
 
-{ 'union': 'ChardevBackend', 'data': { 'null' : 'ChardevDummy' } }
+{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
+                                       'null' : 'ChardevDummy' } }
 
 ##
 # @ChardevReturn:
diff --git a/qemu-char.c b/qemu-char.c
index 73a5e37..d447d96 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3011,6 +3011,64 @@ QemuOptsList qemu_chardev_opts = {
     },
 };
 
+#ifdef _WIN32
+
+static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
+{
+    HANDLE out;
+
+    if (file->in) {
+        error_setg(errp, "input file not supported");
+        return NULL;
+    }
+
+    out = CreateFile(file->out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
+                     OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (out == INVALID_HANDLE_VALUE) {
+        error_setg(errp, "open %s failed", file->out);
+        return NULL;
+    }
+    return qemu_chr_open_win_file(out);
+}
+
+#else /* WIN32 */
+
+static int qmp_chardev_open_file_source(char *src, int flags,
+                                        Error **errp)
+{
+    int fd = -1;
+
+    TFR(fd = qemu_open(src, flags, 0666));
+    if (fd == -1) {
+        error_setg(errp, "open %s: %s", src, strerror(errno));
+    }
+    return fd;
+}
+
+static CharDriverState *qmp_chardev_open_file(ChardevFile *file, Error **errp)
+{
+    int flags, in = -1, out = -1;
+
+    flags = O_WRONLY | O_TRUNC | O_CREAT | O_BINARY;
+    out = qmp_chardev_open_file_source(file->out, flags, errp);
+    if (error_is_set(errp)) {
+        return NULL;
+    }
+
+    if (file->in) {
+        flags = O_RDONLY;
+        in = qmp_chardev_open_file_source(file->in, flags, errp);
+        if (error_is_set(errp)) {
+            qemu_close(out);
+            return NULL;
+        }
+    }
+
+    return qemu_chr_open_fd(in, out);
+}
+
+#endif /* WIN32 */
+
 ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
                                Error **errp)
 {
@@ -3025,6 +3083,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
     }
 
     switch (backend->kind) {
+    case CHARDEV_BACKEND_KIND_FILE:
+        chr = qmp_chardev_open_file(backend->file, errp);
+        break;
     case CHARDEV_BACKEND_KIND_NULL:
         chr = qemu_chr_open_null(NULL);
         break;
diff --git a/qmp-commands.hx b/qmp-commands.hx
index c9ab37c..4d382f4 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2672,13 +2672,19 @@ Arguments:
 - "id": the chardev's ID, must be unique (json-string)
 - "backend": chardev backend type + parameters
 
-Example:
+Examples:
 
 -> { "execute" : "chardev-add",
      "arguments" : { "id" : "foo",
                      "backend" : { "type" : "null", "data" : {} } } }
 <- { "return": {} }
 
+-> { "execute" : "chardev-add",
+     "arguments" : { "id" : "bar",
+                     "backend" : { "type" : "file",
+                                   "data" : { "out" : "/tmp/bar.log" } } } }
+<- { "return": {} }
+
 EQMP
 
     {
commit f10889089153edf032476b45229477866a9ca0b1
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 19 10:33:40 2012 +0100

    chardev: add hmp hotplug commands
    
    Add chardev-add and chardev-remove commands to the human monitor.
    chardev-add accepts the same syntax as -chardev, chardev-remove
    expects a chardev id.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 010b8c9..67569ef 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1485,6 +1485,38 @@ passed since 1970, i.e. unix epoch.
 ETEXI
 
     {
+        .name       = "chardev-add",
+        .args_type  = "args:s",
+        .params     = "args",
+        .help       = "add chardev",
+        .mhandler.cmd = hmp_chardev_add,
+    },
+
+STEXI
+ at item chardev_add args
+ at findex chardev_add
+
+chardev_add accepts the same parameters as the -chardev command line switch.
+
+ETEXI
+
+    {
+        .name       = "chardev-remove",
+        .args_type  = "id:s",
+        .params     = "id",
+        .help       = "remove chardev",
+        .mhandler.cmd = hmp_chardev_remove,
+    },
+
+STEXI
+ at item chardev_remove id
+ at findex chardev_remove
+
+Removes the chardev @var{id}.
+
+ETEXI
+
+    {
         .name       = "info",
         .args_type  = "item:s?",
         .params     = "[subcommand]",
diff --git a/hmp.c b/hmp.c
index 9e9e624..68929b4 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1336,3 +1336,26 @@ void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict)
     qmp_nbd_server_stop(&errp);
     hmp_handle_error(mon, &errp);
 }
+
+void hmp_chardev_add(Monitor *mon, const QDict *qdict)
+{
+    const char *args = qdict_get_str(qdict, "args");
+    Error *err = NULL;
+    QemuOpts *opts;
+
+    opts = qemu_opts_parse(qemu_find_opts("chardev"), args, 1);
+    if (opts == NULL) {
+        error_setg(&err, "Parsing chardev args failed\n");
+    } else {
+        qemu_chr_new_from_opts(opts, NULL, &err);
+    }
+    hmp_handle_error(mon, &err);
+}
+
+void hmp_chardev_remove(Monitor *mon, const QDict *qdict)
+{
+    Error *local_err = NULL;
+
+    qmp_chardev_remove(qdict_get_str(qdict, "id"), &local_err);
+    hmp_handle_error(mon, &local_err);
+}
diff --git a/hmp.h b/hmp.h
index 21f3e05..700fbdc 100644
--- a/hmp.h
+++ b/hmp.h
@@ -80,5 +80,7 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_add(Monitor *mon, const QDict *qdict);
 void hmp_nbd_server_stop(Monitor *mon, const QDict *qdict);
+void hmp_chardev_add(Monitor *mon, const QDict *qdict);
+void hmp_chardev_remove(Monitor *mon, const QDict *qdict);
 
 #endif
commit f1a1a35638bf045a2b158c0cb23d92ef39c06792
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 19 10:33:56 2012 +0100

    chardev: add qmp hotplug commands, with null chardev support
    
    Add chardev-add and chardev-remove qmp commands.  Hotplugging
    a null chardev is supported for now, more will be added later.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qapi-schema.json b/qapi-schema.json
index 5dfa052..462511e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3017,3 +3017,52 @@
 # Since: 1.3.0
 ##
 { 'command': 'nbd-server-stop' }
+
+##
+# @ChardevBackend:
+#
+# Configuration info for the new chardev backend.
+#
+# Since: 1.4
+##
+{ 'type': 'ChardevDummy', 'data': { } }
+
+{ 'union': 'ChardevBackend', 'data': { 'null' : 'ChardevDummy' } }
+
+##
+# @ChardevReturn:
+#
+# Return info about the chardev backend just created.
+#
+# Since: 1.4
+##
+{ 'type' : 'ChardevReturn', 'data': { } }
+
+##
+# @chardev-add:
+#
+# Add a file chardev
+#
+# @id: the chardev's ID, must be unique
+# @backend: backend type and parameters
+#
+# Returns: chardev info.
+#
+# Since: 1.4
+##
+{ 'command': 'chardev-add', 'data': {'id'      : 'str',
+                                     'backend' : 'ChardevBackend' },
+  'returns': 'ChardevReturn' }
+
+##
+# @chardev-remove:
+#
+# Remove a chardev
+#
+# @id: the chardev's ID, must exist and not be in use
+#
+# Returns: Nothing on success
+#
+# Since: 1.4
+##
+{ 'command': 'chardev-remove', 'data': {'id': 'str'} }
diff --git a/qemu-char.c b/qemu-char.c
index ea15d35..73a5e37 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -3010,3 +3010,56 @@ QemuOptsList qemu_chardev_opts = {
         { /* end of list */ }
     },
 };
+
+ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
+                               Error **errp)
+{
+    ChardevReturn *ret = g_new0(ChardevReturn, 1);
+    CharDriverState *chr = NULL;
+
+    chr = qemu_chr_find(id);
+    if (chr) {
+        error_setg(errp, "Chardev '%s' already exists", id);
+        g_free(ret);
+        return NULL;
+    }
+
+    switch (backend->kind) {
+    case CHARDEV_BACKEND_KIND_NULL:
+        chr = qemu_chr_open_null(NULL);
+        break;
+    default:
+        error_setg(errp, "unknown chardev backend (%d)", backend->kind);
+        break;
+    }
+
+    if (chr == NULL && !error_is_set(errp)) {
+        error_setg(errp, "Failed to create chardev");
+    }
+    if (chr) {
+        chr->label = g_strdup(id);
+        chr->avail_connections = 1;
+        QTAILQ_INSERT_TAIL(&chardevs, chr, next);
+        return ret;
+    } else {
+        g_free(ret);
+        return NULL;
+    }
+}
+
+void qmp_chardev_remove(const char *id, Error **errp)
+{
+    CharDriverState *chr;
+
+    chr = qemu_chr_find(id);
+    if (NULL == chr) {
+        error_setg(errp, "Chardev '%s' not found", id);
+        return;
+    }
+    if (chr->chr_can_read || chr->chr_read ||
+        chr->chr_event || chr->handler_opaque) {
+        error_setg(errp, "Chardev '%s' is busy", id);
+        return;
+    }
+    qemu_chr_delete(chr);
+}
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5c692d0..c9ab37c 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2654,3 +2654,53 @@ EQMP
         .args_type  = "",
         .mhandler.cmd_new = qmp_marshal_input_query_target,
     },
+
+    {
+        .name       = "chardev-add",
+        .args_type  = "id:s,backend:q",
+        .mhandler.cmd_new = qmp_marshal_input_chardev_add,
+    },
+
+SQMP
+chardev-add
+----------------
+
+Add a chardev.
+
+Arguments:
+
+- "id": the chardev's ID, must be unique (json-string)
+- "backend": chardev backend type + parameters
+
+Example:
+
+-> { "execute" : "chardev-add",
+     "arguments" : { "id" : "foo",
+                     "backend" : { "type" : "null", "data" : {} } } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "chardev-remove",
+        .args_type  = "id:s",
+        .mhandler.cmd_new = qmp_marshal_input_chardev_remove,
+    },
+
+
+SQMP
+chardev-remove
+--------------
+
+Remove a chardev.
+
+Arguments:
+
+- "id": the chardev's ID, must exist and not be in use (json-string)
+
+Example:
+
+-> { "execute": "chardev-remove", "arguments": { "id" : "foo" } }
+<- { "return": {} }
+
+EQMP
commit e551498e7283fc7f12a0f9cd5645517bfe9008f6
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Wed Dec 19 16:35:42 2012 +0100

    chardev: reduce chardev ifdef mess a bit
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/qemu-char.c b/qemu-char.c
index 16b33ac..ea15d35 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -856,6 +856,8 @@ static void cfmakeraw (struct termios *termios_p)
     || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
     || defined(__GLIBC__)
 
+#define HAVE_CHARDEV_TTY 1
+
 typedef struct {
     int fd;
     int connected;
@@ -1244,14 +1246,12 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
     chr->chr_close = qemu_chr_close_tty;
     return chr;
 }
-#else  /* ! __linux__ && ! __sun__ */
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
-{
-    return NULL;
-}
 #endif /* __linux__ || __sun__ */
 
 #if defined(__linux__)
+
+#define HAVE_CHARDEV_PARPORT 1
+
 typedef struct {
     int fd;
     int mode;
@@ -1395,6 +1395,9 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
 #endif /* __linux__ */
 
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+
+#define HAVE_CHARDEV_PARPORT 1
+
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
     int fd = (int)(intptr_t)chr->opaque;
@@ -2755,19 +2758,16 @@ static const struct {
 #else
     { .name = "file",      .open = qemu_chr_open_file_out },
     { .name = "pipe",      .open = qemu_chr_open_pipe },
-    { .name = "pty",       .open = qemu_chr_open_pty },
     { .name = "stdio",     .open = qemu_chr_open_stdio },
 #endif
 #ifdef CONFIG_BRLAPI
     { .name = "braille",   .open = chr_baum_init },
 #endif
-#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
-    || defined(__FreeBSD_kernel__)
+#ifdef HAVE_CHARDEV_TTY
     { .name = "tty",       .open = qemu_chr_open_tty },
+    { .name = "pty",       .open = qemu_chr_open_pty },
 #endif
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \
-    || defined(__FreeBSD_kernel__)
+#ifdef HAVE_CHARDEV_PARPORT
     { .name = "parport",   .open = qemu_chr_open_pp },
 #endif
 #ifdef CONFIG_SPICE
commit 2274ae9d1a841c9d214b7c877d28e2f037a9b26e
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Oct 15 09:30:59 2012 +0200

    chardev: fix QemuOpts lifecycle
    
    qemu_chr_new_from_opts handles QemuOpts release now, so callers don't
    have to worry.  It will either be saved in CharDriverState, then
    released in qemu_chr_delete, or in the error case released instantly.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/include/char/char.h b/include/char/char.h
index 1952a10..c91ce3c 100644
--- a/include/char/char.h
+++ b/include/char/char.h
@@ -75,6 +75,7 @@ struct CharDriverState {
     char *filename;
     int opened;
     int avail_connections;
+    QemuOpts *opts;
     QTAILQ_ENTRY(CharDriverState) next;
 };
 
diff --git a/qemu-char.c b/qemu-char.c
index b3ff470..16b33ac 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2787,13 +2787,13 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
 
     if (qemu_opts_id(opts) == NULL) {
         error_setg(errp, "chardev: no id specified\n");
-        return NULL;
+        goto err;
     }
 
     if (qemu_opt_get(opts, "backend") == NULL) {
         error_setg(errp, "chardev: \"%s\" missing backend\n",
                    qemu_opts_id(opts));
-        return NULL;
+        goto err;
     }
     for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
         if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
@@ -2802,14 +2802,14 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
     if (i == ARRAY_SIZE(backend_table)) {
         error_setg(errp, "chardev: backend \"%s\" not found\n",
                    qemu_opt_get(opts, "backend"));
-        return NULL;
+        goto err;
     }
 
     chr = backend_table[i].open(opts);
     if (!chr) {
         error_setg(errp, "chardev: opening backend \"%s\" failed\n",
                    qemu_opt_get(opts, "backend"));
-        return NULL;
+        goto err;
     }
 
     if (!chr->filename)
@@ -2830,7 +2830,12 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
         chr->avail_connections = 1;
     }
     chr->label = g_strdup(qemu_opts_id(opts));
+    chr->opts = opts;
     return chr;
+
+err:
+    qemu_opts_del(opts);
+    return NULL;
 }
 
 CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
@@ -2856,7 +2861,6 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
         monitor_init(chr, MONITOR_USE_READLINE);
     }
-    qemu_opts_del(opts);
     return chr;
 }
 
@@ -2884,10 +2888,14 @@ void qemu_chr_fe_close(struct CharDriverState *chr)
 void qemu_chr_delete(CharDriverState *chr)
 {
     QTAILQ_REMOVE(&chardevs, chr, next);
-    if (chr->chr_close)
+    if (chr->chr_close) {
         chr->chr_close(chr);
+    }
     g_free(chr->filename);
     g_free(chr->label);
+    if (chr->opts) {
+        qemu_opts_del(chr->opts);
+    }
     g_free(chr);
 }
 
commit bd2d80b2b75b36955d536564ceb593f5bdae2f12
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Mon Oct 15 09:28:05 2012 +0200

    chardev: add error reporting for qemu_chr_new_from_opts
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/include/char/char.h b/include/char/char.h
index baa5d03..1952a10 100644
--- a/include/char/char.h
+++ b/include/char/char.h
@@ -89,7 +89,8 @@ struct CharDriverState {
  * Returns: a new character backend
  */
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
-                                    void (*init)(struct CharDriverState *s));
+                                    void (*init)(struct CharDriverState *s),
+                                    Error **errp);
 
 /**
  * @qemu_chr_new:
diff --git a/qemu-char.c b/qemu-char.c
index 3be4970..b3ff470 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2779,19 +2779,20 @@ static const struct {
 };
 
 CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
-                                    void (*init)(struct CharDriverState *s))
+                                    void (*init)(struct CharDriverState *s),
+                                    Error **errp)
 {
     CharDriverState *chr;
     int i;
 
     if (qemu_opts_id(opts) == NULL) {
-        fprintf(stderr, "chardev: no id specified\n");
+        error_setg(errp, "chardev: no id specified\n");
         return NULL;
     }
 
     if (qemu_opt_get(opts, "backend") == NULL) {
-        fprintf(stderr, "chardev: \"%s\" missing backend\n",
-                qemu_opts_id(opts));
+        error_setg(errp, "chardev: \"%s\" missing backend\n",
+                   qemu_opts_id(opts));
         return NULL;
     }
     for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
@@ -2799,15 +2800,15 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
             break;
     }
     if (i == ARRAY_SIZE(backend_table)) {
-        fprintf(stderr, "chardev: backend \"%s\" not found\n",
-                qemu_opt_get(opts, "backend"));
+        error_setg(errp, "chardev: backend \"%s\" not found\n",
+                   qemu_opt_get(opts, "backend"));
         return NULL;
     }
 
     chr = backend_table[i].open(opts);
     if (!chr) {
-        fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
-                qemu_opt_get(opts, "backend"));
+        error_setg(errp, "chardev: opening backend \"%s\" failed\n",
+                   qemu_opt_get(opts, "backend"));
         return NULL;
     }
 
@@ -2837,6 +2838,7 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in
     const char *p;
     CharDriverState *chr;
     QemuOpts *opts;
+    Error *err = NULL;
 
     if (strstart(filename, "chardev:", &p)) {
         return qemu_chr_find(p);
@@ -2846,7 +2848,11 @@ CharDriverState *qemu_chr_new(const char *label, const char *filename, void (*in
     if (!opts)
         return NULL;
 
-    chr = qemu_chr_new_from_opts(opts, init);
+    chr = qemu_chr_new_from_opts(opts, init, &err);
+    if (error_is_set(&err)) {
+        fprintf(stderr, "%s\n", error_get_pretty(err));
+        error_free(err);
+    }
     if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
         monitor_init(chr, MONITOR_USE_READLINE);
     }
diff --git a/vl.c b/vl.c
index 15e0280..8ce2b10 100644
--- a/vl.c
+++ b/vl.c
@@ -2238,11 +2238,14 @@ static int device_init_func(QemuOpts *opts, void *opaque)
 
 static int chardev_init_func(QemuOpts *opts, void *opaque)
 {
-    CharDriverState *chr;
+    Error *local_err = NULL;
 
-    chr = qemu_chr_new_from_opts(opts, NULL);
-    if (!chr)
+    qemu_chr_new_from_opts(opts, NULL, &local_err);
+    if (error_is_set(&local_err)) {
+        fprintf(stderr, "%s\n", error_get_pretty(local_err));
+        error_free(local_err);
         return -1;
+    }
     return 0;
 }
 


More information about the Spice-commits mailing list