aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--audio/audio.c5
-rw-r--r--hmp-commands.hx35
-rw-r--r--hmp.c59
-rw-r--r--hmp.h38
-rw-r--r--hw/i8259.c4
-rw-r--r--hw/lm32_pic.c4
-rw-r--r--hw/lm32_pic.h4
-rw-r--r--hw/loader.c2
-rw-r--r--hw/loader.h3
-rw-r--r--hw/pc.h4
-rw-r--r--hw/pc_q35.c1
-rw-r--r--hw/pcmcia.h2
-rw-r--r--hw/ppc405_boards.c1
-rw-r--r--hw/qdev-core.h14
-rw-r--r--hw/qdev-monitor.c4
-rw-r--r--hw/qdev-monitor.h4
-rw-r--r--hw/spapr.c7
-rw-r--r--hw/spapr_vio.c29
-rw-r--r--hw/sun4m.c4
-rw-r--r--hw/sun4m.h4
-rw-r--r--hw/tmp105.c77
-rw-r--r--hw/tmp105.h64
-rw-r--r--hw/tmp105_regs.h50
-rw-r--r--hw/usb.h2
-rw-r--r--hw/usb/bus.c2
-rw-r--r--hw/usb/dev-storage.c2
-rw-r--r--hw/usb/host-bsd.c2
-rw-r--r--hw/usb/host-linux.c2
-rw-r--r--hw/virtio-pci.c6
-rw-r--r--include/char/char.h4
-rw-r--r--include/net/net.h2
-rw-r--r--include/net/slirp.h2
-rw-r--r--include/qemu/bswap.h20
-rw-r--r--include/qom/object.h104
-rw-r--r--include/sysemu/sysemu.h4
-rw-r--r--monitor.c200
-rw-r--r--net/net.c2
-rw-r--r--net/slirp.c2
-rw-r--r--qapi-schema.json104
-rw-r--r--qemu-char.c463
-rw-r--r--qemu-options.hx14
-rw-r--r--qmp-commands.hx61
-rw-r--r--savevm.c2
-rw-r--r--tests/Makefile4
-rw-r--r--tests/libi2c-omap.c166
-rw-r--r--tests/libi2c.c22
-rw-r--r--tests/libi2c.h30
-rw-r--r--tests/tmp105-test.c76
-rw-r--r--ui/keymaps.c16
-rw-r--r--vl.c11
51 files changed, 1339 insertions, 408 deletions
diff --git a/Makefile b/Makefile
index 7622a4cfa4..73adf429d7 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
@@ -226,7 +227,7 @@ clean:
rm -rf qapi-generated
rm -rf qga/qapi-generated
$(MAKE) -C tests/tcg clean
- for d in $(ALL_SUBDIRS) libcacard; do \
+ for d in $(ALL_SUBDIRS); do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
done
diff --git a/audio/audio.c b/audio/audio.c
index 1510b598a6..02bb8861f8 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) {
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 010b8c9ba5..0934b9b915 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1485,11 +1485,44 @@ 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
+@item chardev_add args
+@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
+@item chardev_remove id
+@findex chardev_remove
+
+Removes the chardev @var{id}.
+
+ETEXI
+
+ {
.name = "info",
.args_type = "item:s?",
.params = "[subcommand]",
.help = "show various information about the system state",
- .mhandler.cmd = do_info,
+ .mhandler.cmd = do_info_help,
+ .sub_table = info_cmds,
},
STEXI
diff --git a/hmp.c b/hmp.c
index 9e9e62450e..c7b6ba02fc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -31,7 +31,7 @@ static void hmp_handle_error(Monitor *mon, Error **errp)
}
}
-void hmp_info_name(Monitor *mon)
+void hmp_info_name(Monitor *mon, const QDict *qdict)
{
NameInfo *info;
@@ -42,7 +42,7 @@ void hmp_info_name(Monitor *mon)
qapi_free_NameInfo(info);
}
-void hmp_info_version(Monitor *mon)
+void hmp_info_version(Monitor *mon, const QDict *qdict)
{
VersionInfo *info;
@@ -55,7 +55,7 @@ void hmp_info_version(Monitor *mon)
qapi_free_VersionInfo(info);
}
-void hmp_info_kvm(Monitor *mon)
+void hmp_info_kvm(Monitor *mon, const QDict *qdict)
{
KvmInfo *info;
@@ -70,7 +70,7 @@ void hmp_info_kvm(Monitor *mon)
qapi_free_KvmInfo(info);
}
-void hmp_info_status(Monitor *mon)
+void hmp_info_status(Monitor *mon, const QDict *qdict)
{
StatusInfo *info;
@@ -89,7 +89,7 @@ void hmp_info_status(Monitor *mon)
qapi_free_StatusInfo(info);
}
-void hmp_info_uuid(Monitor *mon)
+void hmp_info_uuid(Monitor *mon, const QDict *qdict)
{
UuidInfo *info;
@@ -98,7 +98,7 @@ void hmp_info_uuid(Monitor *mon)
qapi_free_UuidInfo(info);
}
-void hmp_info_chardev(Monitor *mon)
+void hmp_info_chardev(Monitor *mon, const QDict *qdict)
{
ChardevInfoList *char_info, *info;
@@ -111,7 +111,7 @@ void hmp_info_chardev(Monitor *mon)
qapi_free_ChardevInfoList(char_info);
}
-void hmp_info_mice(Monitor *mon)
+void hmp_info_mice(Monitor *mon, const QDict *qdict)
{
MouseInfoList *mice_list, *mouse;
@@ -131,7 +131,7 @@ void hmp_info_mice(Monitor *mon)
qapi_free_MouseInfoList(mice_list);
}
-void hmp_info_migrate(Monitor *mon)
+void hmp_info_migrate(Monitor *mon, const QDict *qdict)
{
MigrationInfo *info;
MigrationCapabilityStatusList *caps, *cap;
@@ -209,7 +209,7 @@ void hmp_info_migrate(Monitor *mon)
qapi_free_MigrationCapabilityStatusList(caps);
}
-void hmp_info_migrate_capabilities(Monitor *mon)
+void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict)
{
MigrationCapabilityStatusList *caps, *cap;
@@ -228,13 +228,13 @@ void hmp_info_migrate_capabilities(Monitor *mon)
qapi_free_MigrationCapabilityStatusList(caps);
}
-void hmp_info_migrate_cache_size(Monitor *mon)
+void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "xbzrel cache size: %" PRId64 " kbytes\n",
qmp_query_migrate_cache_size(NULL) >> 10);
}
-void hmp_info_cpus(Monitor *mon)
+void hmp_info_cpus(Monitor *mon, const QDict *qdict)
{
CpuInfoList *cpu_list, *cpu;
@@ -272,7 +272,7 @@ void hmp_info_cpus(Monitor *mon)
qapi_free_CpuInfoList(cpu_list);
}
-void hmp_info_block(Monitor *mon)
+void hmp_info_block(Monitor *mon, const QDict *qdict)
{
BlockInfoList *block_list, *info;
@@ -326,7 +326,7 @@ void hmp_info_block(Monitor *mon)
qapi_free_BlockInfoList(block_list);
}
-void hmp_info_blockstats(Monitor *mon)
+void hmp_info_blockstats(Monitor *mon, const QDict *qdict)
{
BlockStatsList *stats_list, *stats;
@@ -360,7 +360,7 @@ void hmp_info_blockstats(Monitor *mon)
qapi_free_BlockStatsList(stats_list);
}
-void hmp_info_vnc(Monitor *mon)
+void hmp_info_vnc(Monitor *mon, const QDict *qdict)
{
VncInfo *info;
Error *err = NULL;
@@ -406,7 +406,7 @@ out:
qapi_free_VncInfo(info);
}
-void hmp_info_spice(Monitor *mon)
+void hmp_info_spice(Monitor *mon, const QDict *qdict)
{
SpiceChannelList *chan;
SpiceInfo *info;
@@ -453,7 +453,7 @@ out:
qapi_free_SpiceInfo(info);
}
-void hmp_info_balloon(Monitor *mon)
+void hmp_info_balloon(Monitor *mon, const QDict *qdict)
{
BalloonInfo *info;
Error *err = NULL;
@@ -570,7 +570,7 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)
}
}
-void hmp_info_pci(Monitor *mon)
+void hmp_info_pci(Monitor *mon, const QDict *qdict)
{
PciInfoList *info_list, *info;
Error *err = NULL;
@@ -593,7 +593,7 @@ void hmp_info_pci(Monitor *mon)
qapi_free_PciInfoList(info_list);
}
-void hmp_info_block_jobs(Monitor *mon)
+void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
{
BlockJobInfoList *list;
Error *err = NULL;
@@ -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 21f3e05d09..44be683fcc 100644
--- a/hmp.h
+++ b/hmp.h
@@ -18,24 +18,24 @@
#include "qapi-types.h"
#include "qapi/qmp/qdict.h"
-void hmp_info_name(Monitor *mon);
-void hmp_info_version(Monitor *mon);
-void hmp_info_kvm(Monitor *mon);
-void hmp_info_status(Monitor *mon);
-void hmp_info_uuid(Monitor *mon);
-void hmp_info_chardev(Monitor *mon);
-void hmp_info_mice(Monitor *mon);
-void hmp_info_migrate(Monitor *mon);
-void hmp_info_migrate_capabilities(Monitor *mon);
-void hmp_info_migrate_cache_size(Monitor *mon);
-void hmp_info_cpus(Monitor *mon);
-void hmp_info_block(Monitor *mon);
-void hmp_info_blockstats(Monitor *mon);
-void hmp_info_vnc(Monitor *mon);
-void hmp_info_spice(Monitor *mon);
-void hmp_info_balloon(Monitor *mon);
-void hmp_info_pci(Monitor *mon);
-void hmp_info_block_jobs(Monitor *mon);
+void hmp_info_name(Monitor *mon, const QDict *qdict);
+void hmp_info_version(Monitor *mon, const QDict *qdict);
+void hmp_info_kvm(Monitor *mon, const QDict *qdict);
+void hmp_info_status(Monitor *mon, const QDict *qdict);
+void hmp_info_uuid(Monitor *mon, const QDict *qdict);
+void hmp_info_chardev(Monitor *mon, const QDict *qdict);
+void hmp_info_mice(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
+void hmp_info_migrate_cache_size(Monitor *mon, const QDict *qdict);
+void hmp_info_cpus(Monitor *mon, const QDict *qdict);
+void hmp_info_block(Monitor *mon, const QDict *qdict);
+void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
+void hmp_info_vnc(Monitor *mon, const QDict *qdict);
+void hmp_info_spice(Monitor *mon, const QDict *qdict);
+void hmp_info_balloon(Monitor *mon, const QDict *qdict);
+void hmp_info_pci(Monitor *mon, const QDict *qdict);
+void hmp_info_block_jobs(Monitor *mon, const QDict *qdict);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
@@ -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
diff --git a/hw/i8259.c b/hw/i8259.c
index 264879e097..54fe14447b 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -407,7 +407,7 @@ static void pic_init(PICCommonState *s)
qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8);
}
-void pic_info(Monitor *mon)
+void pic_info(Monitor *mon, const QDict *qdict)
{
int i;
PICCommonState *s;
@@ -425,7 +425,7 @@ void pic_info(Monitor *mon)
}
}
-void irq_info(Monitor *mon)
+void irq_info(Monitor *mon, const QDict *qdict)
{
#ifndef DEBUG_IRQ_COUNT
monitor_printf(mon, "irq statistic code not compiled.\n");
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 8f13355821..42f298ad51 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -39,7 +39,7 @@ struct LM32PicState {
typedef struct LM32PicState LM32PicState;
static LM32PicState *pic;
-void lm32_do_pic_info(Monitor *mon)
+void lm32_do_pic_info(Monitor *mon, const QDict *qdict)
{
if (pic == NULL) {
return;
@@ -49,7 +49,7 @@ void lm32_do_pic_info(Monitor *mon)
pic->im, pic->ip, pic->irq_state);
}
-void lm32_irq_info(Monitor *mon)
+void lm32_irq_info(Monitor *mon, const QDict *qdict)
{
int i;
uint32_t count;
diff --git a/hw/lm32_pic.h b/hw/lm32_pic.h
index 14456f37cb..555680304e 100644
--- a/hw/lm32_pic.h
+++ b/hw/lm32_pic.h
@@ -8,7 +8,7 @@ uint32_t lm32_pic_get_im(DeviceState *d);
void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
void lm32_pic_set_im(DeviceState *d, uint32_t im);
-void lm32_do_pic_info(Monitor *mon);
-void lm32_irq_info(Monitor *mon);
+void lm32_do_pic_info(Monitor *mon, const QDict *qdict);
+void lm32_irq_info(Monitor *mon, const QDict *qdict);
#endif /* QEMU_HW_LM32_PIC_H */
diff --git a/hw/loader.c b/hw/loader.c
index 3f59fcd14a..995edc3f98 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -778,7 +778,7 @@ void *rom_ptr(hwaddr addr)
return rom->data + (addr - rom->addr);
}
-void do_info_roms(Monitor *mon)
+void do_info_roms(Monitor *mon, const QDict *qdict)
{
Rom *rom;
diff --git a/hw/loader.h b/hw/loader.h
index 26480ad8dd..5e61c95b84 100644
--- a/hw/loader.h
+++ b/hw/loader.h
@@ -1,5 +1,6 @@
#ifndef LOADER_H
#define LOADER_H
+#include "qapi/qmp/qdict.h"
/* loader.c */
int get_image_size(const char *filename);
@@ -30,7 +31,7 @@ int rom_load_all(void);
void rom_set_fw(void *f);
int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
void *rom_ptr(hwaddr addr);
-void do_info_roms(Monitor *mon);
+void do_info_roms(Monitor *mon, const QDict *qdict);
#define rom_add_file_fixed(_f, _a, _i) \
rom_add_file(_f, NULL, _a, _i)
diff --git a/hw/pc.h b/hw/pc.h
index 4134aa94e5..fbcf43d717 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -40,8 +40,8 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
qemu_irq *kvm_i8259_init(ISABus *bus);
int pic_read_irq(DeviceState *d);
int pic_get_output(DeviceState *d);
-void pic_info(Monitor *mon);
-void irq_info(Monitor *mon);
+void pic_info(Monitor *mon, const QDict *qdict);
+void irq_info(Monitor *mon, const QDict *qdict);
/* Global System Interrupts */
diff --git a/hw/pc_q35.c b/hw/pc_q35.c
index 52d997613f..d82353e84f 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/pcmcia.h b/hw/pcmcia.h
index aac1d77cc7..f91669305e 100644
--- a/hw/pcmcia.h
+++ b/hw/pcmcia.h
@@ -14,7 +14,7 @@ typedef struct {
void pcmcia_socket_register(PCMCIASocket *socket);
void pcmcia_socket_unregister(PCMCIASocket *socket);
-void pcmcia_info(Monitor *mon);
+void pcmcia_info(Monitor *mon, const QDict *qdict);
struct PCMCIACardState {
void *state;
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 45ed3769a3..cf371db053 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,
};
/*****************************************************************************/
diff --git a/hw/qdev-core.h b/hw/qdev-core.h
index 3d75ae2e3a..731aadd677 100644
--- a/hw/qdev-core.h
+++ b/hw/qdev-core.h
@@ -60,14 +60,20 @@ struct VMStateDescription;
* The @init callback is considered private to a particular bus implementation
* (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
* "init" callback on their parent class instead.
+ *
* Any type may override the @realize and/or @unrealize callbacks but needs
- * to call (and thus save) the parent type's implementation if so desired.
- * Usually this means storing the previous value of, e.g., @realized inside
- * the type's class structure and overwriting it with a function that first
- * invokes the stored callback, then performs any additional steps.
+ * to call the parent type's implementation if keeping their functionality
+ * is desired. Refer to QOM documentation for further discussion and examples.
+ *
+ * <note>
+ * <para>
* If a type derived directly from TYPE_DEVICE implements @realize, it does
* not need to implement @init and therefore does not need to store and call
* #DeviceClass' default @realize callback.
+ * For other types consult the documentation and implementation of the
+ * respective parent types.
+ * </para>
+ * </note>
*/
typedef struct DeviceClass {
/*< private >*/
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 93283ee57a..1db5ee0f18 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -564,13 +564,13 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
}
#undef qdev_printf
-void do_info_qtree(Monitor *mon)
+void do_info_qtree(Monitor *mon, const QDict *qdict)
{
if (sysbus_get_default())
qbus_print(mon, sysbus_get_default(), 0);
}
-void do_info_qdm(Monitor *mon)
+void do_info_qdm(Monitor *mon, const QDict *qdict)
{
object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
}
diff --git a/hw/qdev-monitor.h b/hw/qdev-monitor.h
index fae1b1ec84..9ec485028e 100644
--- a/hw/qdev-monitor.h
+++ b/hw/qdev-monitor.h
@@ -6,8 +6,8 @@
/*** monitor commands ***/
-void do_info_qtree(Monitor *mon);
-void do_info_qdm(Monitor *mon);
+void do_info_qtree(Monitor *mon, const QDict *qdict);
+void do_info_qdm(Monitor *mon, const QDict *qdict);
int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int qdev_device_help(QemuOpts *opts);
diff --git a/hw/spapr.c b/hw/spapr.c
index 21c261be4a..d80b792b37 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 3a1a4864e6..2054219c95 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@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;
}
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 6f5de44a89..95c505821b 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -216,13 +216,13 @@ static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
static DeviceState *slavio_intctl;
-void sun4m_pic_info(Monitor *mon)
+void sun4m_pic_info(Monitor *mon, const QDict *qdict)
{
if (slavio_intctl)
slavio_pic_info(mon, slavio_intctl);
}
-void sun4m_irq_info(Monitor *mon)
+void sun4m_irq_info(Monitor *mon, const QDict *qdict)
{
if (slavio_intctl)
slavio_irq_info(mon, slavio_intctl);
diff --git a/hw/sun4m.h b/hw/sun4m.h
index 47eb945f07..0361eeed41 100644
--- a/hw/sun4m.h
+++ b/hw/sun4m.h
@@ -27,8 +27,8 @@ void slavio_pic_info(Monitor *mon, DeviceState *dev);
void slavio_irq_info(Monitor *mon, DeviceState *dev);
/* sun4m.c */
-void sun4m_pic_info(Monitor *mon);
-void sun4m_irq_info(Monitor *mon);
+void sun4m_pic_info(Monitor *mon, const QDict *qdict);
+void sun4m_irq_info(Monitor *mon, const QDict *qdict);
/* sparc32_dma.c */
#include "sparc32_dma.h"
diff --git a/hw/tmp105.c b/hw/tmp105.c
index 0ade4eb6bd..3ad2d2f04c 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -21,20 +21,7 @@
#include "hw.h"
#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;
+#include "qapi/visitor.h"
static void tmp105_interrupt_update(TMP105State *s)
{
@@ -65,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 = (TMP105State *) 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;
@@ -141,23 +143,27 @@ 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 ++)
+ 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);
}
@@ -166,10 +172,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;
}
@@ -205,7 +212,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;
@@ -218,7 +225,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);
@@ -227,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);
@@ -240,9 +254,10 @@ 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),
+ .instance_init = tmp105_initfn,
.class_init = tmp105_class_init,
};
diff --git a/hw/tmp105.h b/hw/tmp105.h
index 51eff4be1c..d2189191e2 100644
--- a/hw/tmp105.h
+++ b/hw/tmp105.h
@@ -15,53 +15,33 @@
#define QEMU_TMP105_H
#include "i2c.h"
+#include "tmp105_regs.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;
+#define TYPE_TMP105 "tmp105"
+#define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105)
/**
- * 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.
+ * TMP105State:
+ * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the
+ * temperature. See Table 8 in the data sheet.
*
- * 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);
+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;
#endif
diff --git a/hw/tmp105_regs.h b/hw/tmp105_regs.h
new file mode 100644
index 0000000000..9b55abaf90
--- /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@cs.ox.ac.uk>
+ * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@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
diff --git a/hw/usb.h b/hw/usb.h
index 50c297f341..bc42639b16 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -435,7 +435,7 @@ int set_usb_string(uint8_t *buf, const char *str);
/* usb-linux.c */
USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
int usb_host_device_close(const char *devname);
-void usb_host_info(Monitor *mon);
+void usb_host_info(Monitor *mon, const QDict *qdict);
/* usb-bt.c */
USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci);
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 2dc76756a0..e58cd9ade2 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -542,7 +542,7 @@ static char *usb_get_fw_dev_path(DeviceState *qdev)
return fw_path;
}
-void usb_info(Monitor *mon)
+void usb_info(Monitor *mon, const QDict *qdict)
{
USBBus *bus;
USBDevice *dev;
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 1b87352db0..b839798eaf 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;
diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c
index 172aecbffd..07f0e01cc0 100644
--- a/hw/usb/host-bsd.c
+++ b/hw/usb/host-bsd.c
@@ -633,7 +633,7 @@ static int usb_host_info_device(void *opaque,
return 0;
}
-void usb_host_info(Monitor *mon)
+void usb_host_info(Monitor *mon, const QDict *qdict)
{
usb_host_scan(mon, usb_host_info_device);
}
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index ad75ce0702..a2cff8a74d 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1998,7 +1998,7 @@ static void hex2str(int val, char *str, size_t size)
}
}
-void usb_host_info(Monitor *mon)
+void usb_host_info(Monitor *mon, const QDict *qdict)
{
struct USBAutoFilter *f;
struct USBHostDevice *s;
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 09342463ad..212acd8418 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -576,7 +576,7 @@ undo:
continue;
}
if (proxy->vdev->guest_notifier_mask) {
- kvm_virtio_pci_irqfd_release(proxy, vector, queue_no);
+ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
}
kvm_virtio_pci_vq_vector_release(proxy, vector);
}
@@ -602,7 +602,7 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
* Otherwise, it was cleaned when masked in the frontend.
*/
if (proxy->vdev->guest_notifier_mask) {
- kvm_virtio_pci_irqfd_release(proxy, vector, queue_no);
+ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
}
kvm_virtio_pci_vq_vector_release(proxy, vector);
}
@@ -651,7 +651,7 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
if (proxy->vdev->guest_notifier_mask) {
proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true);
} else {
- kvm_virtio_pci_irqfd_release(proxy, vector, queue_no);
+ kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
}
}
diff --git a/include/char/char.h b/include/char/char.h
index baa5d035fd..c91ce3c98a 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;
};
@@ -89,7 +90,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/include/net/net.h b/include/net/net.h
index de42dd76da..4a92b6c3d2 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -112,7 +112,7 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender,
void *opaque);
void print_net_client(Monitor *mon, NetClientState *nc);
-void do_info_network(Monitor *mon);
+void do_info_network(Monitor *mon, const QDict *qdict);
/* NIC info */
diff --git a/include/net/slirp.h b/include/net/slirp.h
index 54b655c272..0502389c68 100644
--- a/include/net/slirp.h
+++ b/include/net/slirp.h
@@ -40,7 +40,7 @@ int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret
int net_slirp_smb(const char *exported_dir);
-void do_info_usernet(Monitor *mon);
+void do_info_usernet(Monitor *mon, const QDict *qdict);
#endif
diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h
index be9b035353..e6d4798142 100644
--- a/include/qemu/bswap.h
+++ b/include/qemu/bswap.h
@@ -72,45 +72,45 @@ static inline void bswap64s(uint64_t *s)
#if defined(HOST_WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
-#define le_bswap(v, size) bswap ## size(v)
+#define le_bswap(v, size) glue(bswap, size)(v)
#define be_bswaps(v, size)
-#define le_bswaps(p, size) *p = bswap ## size(*p);
+#define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
#else
#define le_bswap(v, size) (v)
-#define be_bswap(v, size) bswap ## size(v)
+#define be_bswap(v, size) glue(bswap, size)(v)
#define le_bswaps(v, size)
-#define be_bswaps(p, size) *p = bswap ## size(*p);
+#define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
#endif
#define CPU_CONVERT(endian, size, type)\
static inline type endian ## size ## _to_cpu(type v)\
{\
- return endian ## _bswap(v, size);\
+ return glue(endian, _bswap)(v, size);\
}\
\
static inline type cpu_to_ ## endian ## size(type v)\
{\
- return endian ## _bswap(v, size);\
+ return glue(endian, _bswap)(v, size);\
}\
\
static inline void endian ## size ## _to_cpus(type *p)\
{\
- endian ## _bswaps(p, size)\
+ glue(endian, _bswaps)(p, size);\
}\
\
static inline void cpu_to_ ## endian ## size ## s(type *p)\
{\
- endian ## _bswaps(p, size)\
+ glue(endian, _bswaps)(p, size);\
}\
\
static inline type endian ## size ## _to_cpup(const type *p)\
{\
- return endian ## size ## _to_cpu(*p);\
+ return glue(glue(endian, size), _to_cpu)(*p);\
}\
\
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
{\
- *p = cpu_to_ ## endian ## size(v);\
+ *p = glue(glue(cpu_to_, endian), size)(v);\
}
CPU_CONVERT(be, 16, uint16_t)
diff --git a/include/qom/object.h b/include/qom/object.h
index 1ef2f0edd4..8e16ea8a44 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -147,9 +147,9 @@ typedef struct InterfaceInfo InterfaceInfo;
* </programlisting>
* </example>
*
- * Introducing new virtual functions requires a class to define its own
- * struct and to add a .class_size member to the TypeInfo. Each function
- * will also have a wrapper to call it easily:
+ * Introducing new virtual methods requires a class to define its own
+ * struct and to add a .class_size member to the #TypeInfo. Each method
+ * will also have a wrapper function to call it easily:
*
* <example>
* <title>Defining an abstract class</title>
@@ -186,6 +186,104 @@ typedef struct InterfaceInfo InterfaceInfo;
* similar to normal types except for the fact that are only defined by
* their classes and never carry any state. You can dynamically cast an object
* to one of its #Interface types and vice versa.
+ *
+ * # Methods #
+ *
+ * A <emphasis>method</emphasis> is a function within the namespace scope of
+ * a class. It usually operates on the object instance by passing it as a
+ * strongly-typed first argument.
+ * If it does not operate on an object instance, it is dubbed
+ * <emphasis>class method</emphasis>.
+ *
+ * Methods cannot be overloaded. That is, the #ObjectClass and method name
+ * uniquely identity the function to be called; the signature does not vary
+ * except for trailing varargs.
+ *
+ * Methods are always <emphasis>virtual</emphasis>. Overriding a method in
+ * #TypeInfo.class_init of a subclass leads to any user of the class obtained
+ * via OBJECT_GET_CLASS() accessing the overridden function.
+ * The original function is not automatically invoked. It is the responsability
+ * of the overriding class to determine whether and when to invoke the method
+ * being overridden.
+ *
+ * To invoke the method being overridden, the preferred solution is to store
+ * the original value in the overriding class before overriding the method.
+ * This corresponds to |[ {super,base}.method(...) ]| in Java and C#
+ * respectively; this frees the overriding class from hardcoding its parent
+ * class, which someone might choose to change at some point.
+ *
+ * <example>
+ * <title>Overriding a virtual method</title>
+ * <programlisting>
+ * typedef struct MyState MyState;
+ *
+ * typedef void (*MyDoSomething)(MyState *obj);
+ *
+ * typedef struct MyClass {
+ * ObjectClass parent_class;
+ *
+ * MyDoSomething do_something;
+ * } MyClass;
+ *
+ * static void my_do_something(MyState *obj)
+ * {
+ * // do something
+ * }
+ *
+ * static void my_class_init(ObjectClass *oc, void *data)
+ * {
+ * MyClass *mc = MY_CLASS(oc);
+ *
+ * mc->do_something = my_do_something;
+ * }
+ *
+ * static const TypeInfo my_type_info = {
+ * .name = TYPE_MY,
+ * .parent = TYPE_OBJECT,
+ * .instance_size = sizeof(MyState),
+ * .class_size = sizeof(MyClass),
+ * .class_init = my_class_init,
+ * };
+ *
+ * typedef struct DerivedClass {
+ * MyClass parent_class;
+ *
+ * MyDoSomething parent_do_something;
+ * } MyClass;
+ *
+ * static void derived_do_something(MyState *obj)
+ * {
+ * DerivedClass *dc = DERIVED_GET_CLASS(obj);
+ *
+ * // do something here
+ * dc->parent_do_something(obj);
+ * // do something else here
+ * }
+ *
+ * static void derived_class_init(ObjectClass *oc, void *data)
+ * {
+ * MyClass *mc = MY_CLASS(oc);
+ * DerivedClass *dc = DERIVED_CLASS(oc);
+ *
+ * dc->parent_do_something = mc->do_something;
+ * mc->do_something = derived_do_something;
+ * }
+ *
+ * static const TypeInfo derived_type_info = {
+ * .name = TYPE_DERIVED,
+ * .parent = TYPE_MY,
+ * .class_size = sizeof(DerivedClass),
+ * .class_init = my_class_init,
+ * };
+ * </programlisting>
+ * </example>
+ *
+ * Alternatively, object_class_by_name() can be used to obtain the class and
+ * its non-overridden methods for a specific type. This would correspond to
+ * |[ MyClass::method(...) ]| in C++.
+ *
+ * The first example of such a QOM method was #CPUClass.reset,
+ * another example is #DeviceClass.realize.
*/
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index c07d4ee458..cd12f0931b 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -68,7 +68,7 @@ void qemu_add_machine_init_done_notifier(Notifier *notify);
void do_savevm(Monitor *mon, const QDict *qdict);
int load_vmstate(const char *name);
void do_delvm(Monitor *mon, const QDict *qdict);
-void do_info_snapshots(Monitor *mon);
+void do_info_snapshots(Monitor *mon, const QDict *qdict);
void qemu_announce_self(void);
@@ -171,7 +171,7 @@ extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
void do_usb_add(Monitor *mon, const QDict *qdict);
void do_usb_del(Monitor *mon, const QDict *qdict);
-void usb_info(Monitor *mon);
+void usb_info(Monitor *mon, const QDict *qdict);
void rtc_change_mon_event(struct tm *tm);
diff --git a/monitor.c b/monitor.c
index 77ac451a23..20bd19b05f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -123,13 +123,17 @@ typedef struct mon_cmd_t {
const char *help;
void (*user_print)(Monitor *mon, const QObject *data);
union {
- void (*info)(Monitor *mon);
void (*cmd)(Monitor *mon, const QDict *qdict);
int (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
int (*cmd_async)(Monitor *mon, const QDict *params,
MonitorCompletion *cb, void *opaque);
} mhandler;
int flags;
+ /* @sub_table is a list of 2nd level of commands. If it do not exist,
+ * mhandler should be used. If it exist, sub_table[?].mhandler should be
+ * used, and mhandler of 1st level plays the role of help function.
+ */
+ struct mon_cmd_t *sub_table;
} mon_cmd_t;
/* file descriptors passed via SCM_RIGHTS */
@@ -807,28 +811,8 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
}
}
-static void do_info(Monitor *mon, const QDict *qdict)
+static void do_info_help(Monitor *mon, const QDict *qdict)
{
- const mon_cmd_t *cmd;
- const char *item = qdict_get_try_str(qdict, "item");
-
- if (!item) {
- goto help;
- }
-
- for (cmd = info_cmds; cmd->name != NULL; cmd++) {
- if (compare_cmd(item, cmd->name))
- break;
- }
-
- if (cmd->name == NULL) {
- goto help;
- }
-
- cmd->mhandler.info(mon);
- return;
-
-help:
help_cmd(mon, "info");
}
@@ -899,19 +883,19 @@ int monitor_get_cpu_index(void)
return cpu->cpu_index;
}
-static void do_info_registers(Monitor *mon)
+static void do_info_registers(Monitor *mon, const QDict *qdict)
{
CPUArchState *env;
env = mon_get_cpu();
cpu_dump_state(env, (FILE *)mon, monitor_fprintf, CPU_DUMP_FPU);
}
-static void do_info_jit(Monitor *mon)
+static void do_info_jit(Monitor *mon, const QDict *qdict)
{
dump_exec_info((FILE *)mon, monitor_fprintf);
}
-static void do_info_history(Monitor *mon)
+static void do_info_history(Monitor *mon, const QDict *qdict)
{
int i;
const char *str;
@@ -930,7 +914,7 @@ static void do_info_history(Monitor *mon)
#if defined(TARGET_PPC)
/* XXX: not implemented in other targets */
-static void do_info_cpu_stats(Monitor *mon)
+static void do_info_cpu_stats(Monitor *mon, const QDict *qdict)
{
CPUArchState *env;
@@ -939,7 +923,7 @@ static void do_info_cpu_stats(Monitor *mon)
}
#endif
-static void do_trace_print_events(Monitor *mon)
+static void do_trace_print_events(Monitor *mon, const QDict *qdict)
{
trace_print_events((FILE *)mon, &monitor_fprintf);
}
@@ -1491,7 +1475,7 @@ static void tlb_info_64(Monitor *mon, CPUArchState *env)
}
#endif
-static void tlb_info(Monitor *mon)
+static void tlb_info(Monitor *mon, const QDict *qdict)
{
CPUArchState *env;
@@ -1714,7 +1698,7 @@ static void mem_info_64(Monitor *mon, CPUArchState *env)
}
#endif
-static void mem_info(Monitor *mon)
+static void mem_info(Monitor *mon, const QDict *qdict)
{
CPUArchState *env;
@@ -1753,7 +1737,7 @@ static void print_tlb(Monitor *mon, int idx, tlb_t *tlb)
tlb->d, tlb->wt);
}
-static void tlb_info(Monitor *mon)
+static void tlb_info(Monitor *mon, const QDict *qdict)
{
CPUArchState *env = mon_get_cpu();
int i;
@@ -1769,7 +1753,7 @@ static void tlb_info(Monitor *mon)
#endif
#if defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_XTENSA)
-static void tlb_info(Monitor *mon)
+static void tlb_info(Monitor *mon, const QDict *qdict)
{
CPUArchState *env1 = mon_get_cpu();
@@ -1777,12 +1761,12 @@ static void tlb_info(Monitor *mon)
}
#endif
-static void do_info_mtree(Monitor *mon)
+static void do_info_mtree(Monitor *mon, const QDict *qdict)
{
mtree_info((fprintf_function)monitor_printf, mon);
}
-static void do_info_numa(Monitor *mon)
+static void do_info_numa(Monitor *mon, const QDict *qdict)
{
int i;
CPUArchState *env;
@@ -1808,7 +1792,7 @@ static void do_info_numa(Monitor *mon)
int64_t qemu_time;
int64_t dev_time;
-static void do_info_profile(Monitor *mon)
+static void do_info_profile(Monitor *mon, const QDict *qdict)
{
int64_t total;
total = qemu_time;
@@ -1822,7 +1806,7 @@ static void do_info_profile(Monitor *mon)
dev_time = 0;
}
#else
-static void do_info_profile(Monitor *mon)
+static void do_info_profile(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "Internal profiler not compiled\n");
}
@@ -1831,7 +1815,7 @@ static void do_info_profile(Monitor *mon)
/* Capture support */
static QLIST_HEAD (capture_list_head, CaptureState) capture_head;
-static void do_info_capture(Monitor *mon)
+static void do_info_capture(Monitor *mon, const QDict *qdict)
{
int i;
CaptureState *s;
@@ -2429,12 +2413,6 @@ int monitor_handle_fd_param(Monitor *mon, const char *fdname)
return fd;
}
-/* mon_cmds and info_cmds would be sorted at runtime */
-static mon_cmd_t mon_cmds[] = {
-#include "hmp-commands.h"
- { NULL, NULL, },
-};
-
/* Please update hmp-commands.hx when adding or changing commands */
static mon_cmd_t info_cmds[] = {
{
@@ -2442,63 +2420,63 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the version of QEMU",
- .mhandler.info = hmp_info_version,
+ .mhandler.cmd = hmp_info_version,
},
{
.name = "network",
.args_type = "",
.params = "",
.help = "show the network state",
- .mhandler.info = do_info_network,
+ .mhandler.cmd = do_info_network,
},
{
.name = "chardev",
.args_type = "",
.params = "",
.help = "show the character devices",
- .mhandler.info = hmp_info_chardev,
+ .mhandler.cmd = hmp_info_chardev,
},
{
.name = "block",
.args_type = "",
.params = "",
.help = "show the block devices",
- .mhandler.info = hmp_info_block,
+ .mhandler.cmd = hmp_info_block,
},
{
.name = "blockstats",
.args_type = "",
.params = "",
.help = "show block device statistics",
- .mhandler.info = hmp_info_blockstats,
+ .mhandler.cmd = hmp_info_blockstats,
},
{
.name = "block-jobs",
.args_type = "",
.params = "",
.help = "show progress of ongoing block device operations",
- .mhandler.info = hmp_info_block_jobs,
+ .mhandler.cmd = hmp_info_block_jobs,
},
{
.name = "registers",
.args_type = "",
.params = "",
.help = "show the cpu registers",
- .mhandler.info = do_info_registers,
+ .mhandler.cmd = do_info_registers,
},
{
.name = "cpus",
.args_type = "",
.params = "",
.help = "show infos for each CPU",
- .mhandler.info = hmp_info_cpus,
+ .mhandler.cmd = hmp_info_cpus,
},
{
.name = "history",
.args_type = "",
.params = "",
.help = "show the command line history",
- .mhandler.info = do_info_history,
+ .mhandler.cmd = do_info_history,
},
#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_MIPS) || \
defined(TARGET_LM32) || (defined(TARGET_SPARC) && !defined(TARGET_SPARC64))
@@ -2508,11 +2486,11 @@ static mon_cmd_t info_cmds[] = {
.params = "",
.help = "show the interrupts statistics (if available)",
#ifdef TARGET_SPARC
- .mhandler.info = sun4m_irq_info,
+ .mhandler.cmd = sun4m_irq_info,
#elif defined(TARGET_LM32)
- .mhandler.info = lm32_irq_info,
+ .mhandler.cmd = lm32_irq_info,
#else
- .mhandler.info = irq_info,
+ .mhandler.cmd = irq_info,
#endif
},
{
@@ -2521,11 +2499,11 @@ static mon_cmd_t info_cmds[] = {
.params = "",
.help = "show i8259 (PIC) state",
#ifdef TARGET_SPARC
- .mhandler.info = sun4m_pic_info,
+ .mhandler.cmd = sun4m_pic_info,
#elif defined(TARGET_LM32)
- .mhandler.info = lm32_do_pic_info,
+ .mhandler.cmd = lm32_do_pic_info,
#else
- .mhandler.info = pic_info,
+ .mhandler.cmd = pic_info,
#endif
},
#endif
@@ -2534,7 +2512,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show PCI info",
- .mhandler.info = hmp_info_pci,
+ .mhandler.cmd = hmp_info_pci,
},
#if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
defined(TARGET_PPC) || defined(TARGET_XTENSA)
@@ -2543,7 +2521,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show virtual to physical memory mappings",
- .mhandler.info = tlb_info,
+ .mhandler.cmd = tlb_info,
},
#endif
#if defined(TARGET_I386)
@@ -2552,7 +2530,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the active virtual memory mappings",
- .mhandler.info = mem_info,
+ .mhandler.cmd = mem_info,
},
#endif
{
@@ -2560,91 +2538,91 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show memory tree",
- .mhandler.info = do_info_mtree,
+ .mhandler.cmd = do_info_mtree,
},
{
.name = "jit",
.args_type = "",
.params = "",
.help = "show dynamic compiler info",
- .mhandler.info = do_info_jit,
+ .mhandler.cmd = do_info_jit,
},
{
.name = "kvm",
.args_type = "",
.params = "",
.help = "show KVM information",
- .mhandler.info = hmp_info_kvm,
+ .mhandler.cmd = hmp_info_kvm,
},
{
.name = "numa",
.args_type = "",
.params = "",
.help = "show NUMA information",
- .mhandler.info = do_info_numa,
+ .mhandler.cmd = do_info_numa,
},
{
.name = "usb",
.args_type = "",
.params = "",
.help = "show guest USB devices",
- .mhandler.info = usb_info,
+ .mhandler.cmd = usb_info,
},
{
.name = "usbhost",
.args_type = "",
.params = "",
.help = "show host USB devices",
- .mhandler.info = usb_host_info,
+ .mhandler.cmd = usb_host_info,
},
{
.name = "profile",
.args_type = "",
.params = "",
.help = "show profiling information",
- .mhandler.info = do_info_profile,
+ .mhandler.cmd = do_info_profile,
},
{
.name = "capture",
.args_type = "",
.params = "",
.help = "show capture information",
- .mhandler.info = do_info_capture,
+ .mhandler.cmd = do_info_capture,
},
{
.name = "snapshots",
.args_type = "",
.params = "",
.help = "show the currently saved VM snapshots",
- .mhandler.info = do_info_snapshots,
+ .mhandler.cmd = do_info_snapshots,
},
{
.name = "status",
.args_type = "",
.params = "",
.help = "show the current VM status (running|paused)",
- .mhandler.info = hmp_info_status,
+ .mhandler.cmd = hmp_info_status,
},
{
.name = "pcmcia",
.args_type = "",
.params = "",
.help = "show guest PCMCIA status",
- .mhandler.info = pcmcia_info,
+ .mhandler.cmd = pcmcia_info,
},
{
.name = "mice",
.args_type = "",
.params = "",
.help = "show which guest mouse is receiving events",
- .mhandler.info = hmp_info_mice,
+ .mhandler.cmd = hmp_info_mice,
},
{
.name = "vnc",
.args_type = "",
.params = "",
.help = "show the vnc server status",
- .mhandler.info = hmp_info_vnc,
+ .mhandler.cmd = hmp_info_vnc,
},
#if defined(CONFIG_SPICE)
{
@@ -2652,7 +2630,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the spice server status",
- .mhandler.info = hmp_info_spice,
+ .mhandler.cmd = hmp_info_spice,
},
#endif
{
@@ -2660,14 +2638,14 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show the current VM name",
- .mhandler.info = hmp_info_name,
+ .mhandler.cmd = hmp_info_name,
},
{
.name = "uuid",
.args_type = "",
.params = "",
.help = "show the current VM UUID",
- .mhandler.info = hmp_info_uuid,
+ .mhandler.cmd = hmp_info_uuid,
},
#if defined(TARGET_PPC)
{
@@ -2675,7 +2653,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show CPU statistics",
- .mhandler.info = do_info_cpu_stats,
+ .mhandler.cmd = do_info_cpu_stats,
},
#endif
#if defined(CONFIG_SLIRP)
@@ -2684,7 +2662,7 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show user network stack connection states",
- .mhandler.info = do_info_usernet,
+ .mhandler.cmd = do_info_usernet,
},
#endif
{
@@ -2692,62 +2670,68 @@ static mon_cmd_t info_cmds[] = {
.args_type = "",
.params = "",
.help = "show migration status",
- .mhandler.info = hmp_info_migrate,
+ .mhandler.cmd = hmp_info_migrate,
},
{
.name = "migrate_capabilities",
.args_type = "",
.params = "",
.help = "show current migration capabilities",
- .mhandler.info = hmp_info_migrate_capabilities,
+ .mhandler.cmd = hmp_info_migrate_capabilities,
},
{
.name = "migrate_cache_size",
.args_type = "",
.params = "",
.help = "show current migration xbzrle cache size",
- .mhandler.info = hmp_info_migrate_cache_size,
+ .mhandler.cmd = hmp_info_migrate_cache_size,
},
{
.name = "balloon",
.args_type = "",
.params = "",
.help = "show balloon information",
- .mhandler.info = hmp_info_balloon,
+ .mhandler.cmd = hmp_info_balloon,
},
{
.name = "qtree",
.args_type = "",
.params = "",
.help = "show device tree",
- .mhandler.info = do_info_qtree,
+ .mhandler.cmd = do_info_qtree,
},
{
.name = "qdm",
.args_type = "",
.params = "",
.help = "show qdev device model list",
- .mhandler.info = do_info_qdm,
+ .mhandler.cmd = do_info_qdm,
},
{
.name = "roms",
.args_type = "",
.params = "",
.help = "show roms",
- .mhandler.info = do_info_roms,
+ .mhandler.cmd = do_info_roms,
},
{
.name = "trace-events",
.args_type = "",
.params = "",
.help = "show available trace-events & their state",
- .mhandler.info = do_trace_print_events,
+ .mhandler.cmd = do_trace_print_events,
},
{
.name = NULL,
},
};
+/* mon_cmds and info_cmds would be sorted at runtime */
+static mon_cmd_t mon_cmds[] = {
+#include "hmp-commands.h"
+ { NULL, NULL, },
+};
+
static const mon_cmd_t qmp_cmds[] = {
#include "qmp-commands-old.h"
{ /* NULL */ },
@@ -3542,18 +3526,27 @@ static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
return NULL;
}
-static const mon_cmd_t *monitor_find_command(const char *cmdname)
-{
- return search_dispatch_table(mon_cmds, cmdname);
-}
-
static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
{
return search_dispatch_table(qmp_cmds, cmdname);
}
+/*
+ * Parse @cmdline according to command table @table.
+ * If @cmdline is blank, return NULL.
+ * If it can't be parsed, report to @mon, and return NULL.
+ * Else, insert command arguments into @qdict, and return the command.
+ * If sub-command table exist, and if @cmdline contains addtional string for
+ * sub-command, this function will try search sub-command table. if no
+ * addtional string for sub-command exist, this function will return the found
+ * one in @table.
+ * Do not assume the returned command points into @table! It doesn't
+ * when the command is a sub-command.
+ */
static const mon_cmd_t *monitor_parse_command(Monitor *mon,
const char *cmdline,
+ int start,
+ mon_cmd_t *table,
QDict *qdict)
{
const char *p, *typestr;
@@ -3564,20 +3557,35 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
char *key;
#ifdef DEBUG
- monitor_printf(mon, "command='%s'\n", cmdline);
+ monitor_printf(mon, "command='%s', start='%d'\n", cmdline, start);
#endif
/* extract the command name */
- p = get_command_name(cmdline, cmdname, sizeof(cmdname));
+ p = get_command_name(cmdline + start, cmdname, sizeof(cmdname));
if (!p)
return NULL;
- cmd = monitor_find_command(cmdname);
+ cmd = search_dispatch_table(table, cmdname);
if (!cmd) {
- monitor_printf(mon, "unknown command: '%s'\n", cmdname);
+ monitor_printf(mon, "unknown command: '%.*s'\n",
+ (int)(p - cmdline), cmdline);
return NULL;
}
+ /* filter out following useless space */
+ while (qemu_isspace(*p)) {
+ p++;
+ }
+ /* search sub command */
+ if (cmd->sub_table != NULL) {
+ /* check if user set additional command */
+ if (*p == '\0') {
+ return cmd;
+ }
+ return monitor_parse_command(mon, cmdline, p - cmdline,
+ cmd->sub_table, qdict);
+ }
+
/* parse the parameters */
typestr = cmd->args_type;
for(;;) {
@@ -3933,7 +3941,7 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
qdict = qdict_new();
- cmd = monitor_parse_command(mon, cmdline, qdict);
+ cmd = monitor_parse_command(mon, cmdline, 0, mon_cmds, qdict);
if (!cmd)
goto out;
diff --git a/net/net.c b/net/net.c
index 02b5458a1b..cdd9b04989 100644
--- a/net/net.c
+++ b/net/net.c
@@ -852,7 +852,7 @@ void print_net_client(Monitor *mon, NetClientState *nc)
NetClientOptionsKind_lookup[nc->info->type], nc->info_str);
}
-void do_info_network(Monitor *mon)
+void do_info_network(Monitor *mon, const QDict *qdict)
{
NetClientState *nc, *peer;
NetClientOptionsKind type;
diff --git a/net/slirp.c b/net/slirp.c
index c14259f004..4df550faf6 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -670,7 +670,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
return -1;
}
-void do_info_usernet(Monitor *mon)
+void do_info_usernet(Monitor *mon, const QDict *qdict)
{
SlirpState *s;
diff --git a/qapi-schema.json b/qapi-schema.json
index 5dfa052391..6d7252b9e8 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3017,3 +3017,107 @@
# Since: 1.3.0
##
{ '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' } }
+
+##
+# @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',
+ 'parallel' ] }
+
+{ 'type': 'ChardevPort', 'data': { 'device' : 'str',
+ '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.
+#
+# Since: 1.4
+##
+{ 'type': 'ChardevDummy', 'data': { } }
+
+{ 'union': 'ChardevBackend', 'data': { 'file' : 'ChardevFile',
+ 'port' : 'ChardevPort',
+ 'socket' : 'ChardevSocket',
+ 'pty' : 'ChardevDummy',
+ 'null' : 'ChardevDummy' } }
+
+##
+# @ChardevReturn:
+#
+# Return info about the chardev backend just created.
+#
+# Since: 1.4
+##
+{ 'type' : 'ChardevReturn', 'data': { '*pty' : 'str' } }
+
+##
+# @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 3be4970423..9ba0573c6a 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;
@@ -1228,30 +1230,34 @@ static void qemu_chr_close_tty(CharDriverState *chr)
}
}
-static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
+static CharDriverState *qemu_chr_open_tty_fd(int fd)
{
- 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;
}
-#else /* ! __linux__ && ! __sun__ */
-static CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
+
+static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
{
- return NULL;
+ const char *filename = qemu_opt_get(opts, "path");
+ int fd;
+
+ TFR(fd = qemu_open(filename, O_RDWR | O_NONBLOCK));
+ if (fd < 0) {
+ return NULL;
+ }
+ return qemu_chr_open_tty_fd(fd);
}
#endif /* __linux__ || __sun__ */
#if defined(__linux__)
+
+#define HAVE_CHARDEV_PARPORT 1
+
typedef struct {
int fd;
int mode;
@@ -1361,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);
@@ -1395,6 +1394,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;
@@ -1432,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;
@@ -1663,9 +1658,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;
@@ -1684,6 +1678,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;
@@ -2439,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;
@@ -2459,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);
@@ -2482,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);
@@ -2540,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;
}
@@ -2737,6 +2771,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);
@@ -2755,19 +2805,18 @@ 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 = "serial", .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 = "parallel", .open = qemu_chr_open_pp },
{ .name = "parport", .open = qemu_chr_open_pp },
#endif
#ifdef CONFIG_SPICE
@@ -2779,36 +2828,37 @@ 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");
- return NULL;
+ error_setg(errp, "chardev: no id specified\n");
+ goto err;
}
if (qemu_opt_get(opts, "backend") == NULL) {
- fprintf(stderr, "chardev: \"%s\" missing backend\n",
- qemu_opts_id(opts));
- return NULL;
+ error_setg(errp, "chardev: \"%s\" missing backend\n",
+ qemu_opts_id(opts));
+ goto err;
}
for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
break;
}
if (i == ARRAY_SIZE(backend_table)) {
- fprintf(stderr, "chardev: backend \"%s\" not found\n",
- qemu_opt_get(opts, "backend"));
- return NULL;
+ error_setg(errp, "chardev: backend \"%s\" not found\n",
+ qemu_opt_get(opts, "backend"));
+ goto err;
}
chr = backend_table[i].open(opts);
if (!chr) {
- fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
- qemu_opt_get(opts, "backend"));
- return NULL;
+ error_setg(errp, "chardev: opening backend \"%s\" failed\n",
+ qemu_opt_get(opts, "backend"));
+ goto err;
}
if (!chr->filename)
@@ -2829,7 +2879,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))
@@ -2837,6 +2892,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,11 +2902,14 @@ 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);
}
- qemu_opts_del(opts);
return chr;
}
@@ -2878,10 +2937,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);
}
@@ -2996,3 +3059,199 @@ QemuOptsList qemu_chardev_opts = {
{ /* end of list */ }
},
};
+
+#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);
+}
+
+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,
+ 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);
+}
+
+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
+#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;
+ }
+}
+
+#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)
+{
+ 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_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_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;
+ 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/qemu-options.hx b/qemu-options.hx
index 9df0cde64c..40cd68399d 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1742,9 +1742,11 @@ 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__)
+ "-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)
@@ -1775,6 +1777,7 @@ Backend is one of:
@option{stdio},
@option{braille},
@option{tty},
+@option{parallel},
@option{parport},
@option{spicevmc}.
@option{spiceport}.
@@ -1910,8 +1913,8 @@ take any options.
Send traffic from the guest to a serial device on the host.
-@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,16 +1940,15 @@ 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.
+@item -chardev parallel ,id=@var{id} ,path=@var{path}
@item -chardev parport ,id=@var{id} ,path=@var{path}
-@option{parport} is only available on Linux, FreeBSD and DragonFlyBSD hosts.
+@option{parallel} is only available on Linux, FreeBSD and DragonFlyBSD hosts.
Connect to a local parallel port.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 5c692d0cb5..cbf12804be 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2654,3 +2654,64 @@ 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
+
+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": {} }
+
+-> { "execute" : "chardev-add",
+ "arguments" : { "id" : "baz",
+ "backend" : { "type" : "pty", "data" : {} } } }
+<- { "return": { "pty" : "/dev/pty/42" } }
+
+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
diff --git a/savevm.c b/savevm.c
index 4e970ca0db..d9ff1d9b72 100644
--- a/savevm.c
+++ b/savevm.c
@@ -2307,7 +2307,7 @@ void do_delvm(Monitor *mon, const QDict *qdict)
}
}
-void do_info_snapshots(Monitor *mon)
+void do_info_snapshots(Monitor *mon, const QDict *qdict)
{
BlockDriverState *bs, *bs1;
QEMUSnapshotInfo *sn_tab, *sn, s, *sn_info = &s;
diff --git a/tests/Makefile b/tests/Makefile
index d97a571c8b..d86e95a400 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
@@ -116,6 +119,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 0000000000..9be57e92c4
--- /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 0000000000..13ec85c0cb
--- /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 0000000000..1ce9af4053
--- /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
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
new file mode 100644
index 0000000000..a6ad213de8
--- /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;
+}
diff --git a/ui/keymaps.c b/ui/keymaps.c
index 9625d82fa1..f373cc53d9 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);
diff --git a/vl.c b/vl.c
index 15e0280daa..f4cf7e8a85 100644
--- a/vl.c
+++ b/vl.c
@@ -1449,7 +1449,7 @@ void pcmcia_socket_unregister(PCMCIASocket *socket)
}
}
-void pcmcia_info(Monitor *mon)
+void pcmcia_info(Monitor *mon, const QDict *qdict)
{
struct pcmcia_socket_entry_s *iter;
@@ -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;
}