diff options
51 files changed, 1339 insertions, 408 deletions
@@ -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 @@ -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); +} @@ -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) @@ -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 @@ -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); @@ -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; @@ -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 @@ -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); @@ -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; } |