summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/device-hotplug.c5
-rw-r--r--hw/ecc.c27
-rw-r--r--hw/escc.c8
-rw-r--r--hw/etraxfs_timer.c4
-rw-r--r--hw/flash.h3
-rw-r--r--hw/grlib.h126
-rw-r--r--hw/grlib_apbuart.c187
-rw-r--r--hw/grlib_gptimer.c395
-rw-r--r--hw/grlib_irqmp.c376
-rw-r--r--hw/gumstix.c4
-rw-r--r--hw/hw.h10
-rw-r--r--hw/ide.h2
-rw-r--r--hw/ide/ahci.c11
-rw-r--r--hw/ide/core.c119
-rw-r--r--hw/ide/internal.h4
-rw-r--r--hw/ide/pci.c13
-rw-r--r--hw/leon3.c217
-rw-r--r--hw/mc146818rtc.c15
-rw-r--r--hw/mips_fulong2e.c4
-rw-r--r--hw/mips_jazz.c24
-rw-r--r--hw/mips_malta.c23
-rw-r--r--hw/onenand.c1
-rw-r--r--hw/pc.c17
-rw-r--r--hw/pc.h3
-rw-r--r--hw/pc_piix.c3
-rw-r--r--hw/pci-hotplug.c3
-rw-r--r--hw/pci.c4
-rw-r--r--hw/pl181.c7
-rw-r--r--hw/ppc_prep.c5
-rw-r--r--hw/pxa.h10
-rw-r--r--hw/pxa2xx.c4
-rw-r--r--hw/pxa2xx_gpio.c150
-rw-r--r--hw/qdev.c15
-rw-r--r--hw/qdev.h2
-rw-r--r--hw/scsi-bus.c8
-rw-r--r--hw/scsi-disk.c3
-rw-r--r--hw/scsi.h6
-rw-r--r--hw/sd.c7
-rw-r--r--hw/sh7750.c20
-rw-r--r--hw/sharpsl.h7
-rw-r--r--hw/slavio_intctl.c7
-rw-r--r--hw/spitz.c349
-rw-r--r--hw/ssi-sd.c7
-rw-r--r--hw/tosa.c35
-rw-r--r--hw/usb-bus.c28
-rw-r--r--hw/usb-hid.c317
-rw-r--r--hw/usb-hub.c24
-rw-r--r--hw/usb-msd.c7
-rw-r--r--hw/usb.h10
-rw-r--r--hw/virtio-blk.c50
-rw-r--r--hw/virtio-console.c38
-rw-r--r--hw/virtio-net.c13
-rw-r--r--hw/virtio-serial-bus.c123
-rw-r--r--hw/virtio-serial.h24
-rw-r--r--hw/zaurus.c111
55 files changed, 2243 insertions, 752 deletions
diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c
index 9704e2feb2..8b2ed7a492 100644
--- a/hw/device-hotplug.c
+++ b/hw/device-hotplug.c
@@ -29,15 +29,14 @@
DriveInfo *add_init_drive(const char *optstr)
{
- int fatal_error;
DriveInfo *dinfo;
QemuOpts *opts;
- opts = drive_add(NULL, "%s", optstr);
+ opts = drive_def(optstr);
if (!opts)
return NULL;
- dinfo = drive_init(opts, current_machine->use_scsi, &fatal_error);
+ dinfo = drive_init(opts, current_machine->use_scsi);
if (!dinfo) {
qemu_opts_del(opts);
return NULL;
diff --git a/hw/ecc.c b/hw/ecc.c
index 2fbf167943..a75408b9ae 100644
--- a/hw/ecc.c
+++ b/hw/ecc.c
@@ -74,18 +74,15 @@ void ecc_reset(ECCState *s)
}
/* Save/restore */
-void ecc_put(QEMUFile *f, ECCState *s)
-{
- qemu_put_8s(f, &s->cp);
- qemu_put_be16s(f, &s->lp[0]);
- qemu_put_be16s(f, &s->lp[1]);
- qemu_put_be16s(f, &s->count);
-}
-
-void ecc_get(QEMUFile *f, ECCState *s)
-{
- qemu_get_8s(f, &s->cp);
- qemu_get_be16s(f, &s->lp[0]);
- qemu_get_be16s(f, &s->lp[1]);
- qemu_get_be16s(f, &s->count);
-}
+VMStateDescription vmstate_ecc_state = {
+ .name = "ecc-state",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(cp, ECCState),
+ VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
+ VMSTATE_UINT16(count, ECCState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
diff --git a/hw/escc.c b/hw/escc.c
index ba6063608d..f6fd9192ea 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -369,14 +369,18 @@ static inline void set_txint(ChannelState *s)
if (!s->rxint_under_svc) {
s->txint_under_svc = 1;
if (s->chn == chn_a) {
- s->rregs[R_INTR] |= INTR_TXINTA;
+ if (s->wregs[W_INTR] & INTR_TXINT) {
+ s->rregs[R_INTR] |= INTR_TXINTA;
+ }
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
else
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
} else {
s->rregs[R_IVEC] = IVEC_TXINTB;
- s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+ if (s->wregs[W_INTR] & INTR_TXINT) {
+ s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+ }
}
escc_update_irq(s);
}
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index ba1adbe3c0..133741b4f5 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -100,7 +100,6 @@ static uint32_t timer_readl (void *opaque, target_phys_addr_t addr)
return r;
}
-#define TIMER_SLOWDOWN 1
static void update_ctrl(struct etrax_timer *t, int tnum)
{
unsigned int op;
@@ -142,9 +141,6 @@ static void update_ctrl(struct etrax_timer *t, int tnum)
}
D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
- div = div * TIMER_SLOWDOWN;
- div /= 1000;
- freq_hz /= 1000;
ptimer_set_freq(timer, freq_hz);
ptimer_set_limit(timer, div, 0);
diff --git a/hw/flash.h b/hw/flash.h
index a80205c4e0..d7d103e66f 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -51,5 +51,4 @@ typedef struct {
uint8_t ecc_digest(ECCState *s, uint8_t sample);
void ecc_reset(ECCState *s);
-void ecc_put(QEMUFile *f, ECCState *s);
-void ecc_get(QEMUFile *f, ECCState *s);
+extern VMStateDescription vmstate_ecc_state;
diff --git a/hw/grlib.h b/hw/grlib.h
new file mode 100644
index 0000000000..fdf4b1190a
--- /dev/null
+++ b/hw/grlib.h
@@ -0,0 +1,126 @@
+/*
+ * QEMU GRLIB Components
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _GRLIB_H_
+#define _GRLIB_H_
+
+#include "qdev.h"
+#include "sysbus.h"
+
+/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ */
+
+/* IRQMP */
+
+typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level);
+
+void grlib_irqmp_ack(DeviceState *dev, int intno);
+
+static inline
+DeviceState *grlib_irqmp_create(target_phys_addr_t base,
+ CPUState *env,
+ qemu_irq **cpu_irqs,
+ uint32_t nr_irqs,
+ set_pil_in_fn set_pil_in)
+{
+ DeviceState *dev;
+
+ assert(cpu_irqs != NULL);
+
+ dev = qdev_create(NULL, "grlib,irqmp");
+ qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in);
+ qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ env->irq_manager = dev;
+
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+ *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
+ dev,
+ nr_irqs);
+
+ return dev;
+}
+
+/* GPTimer */
+
+static inline
+DeviceState *grlib_gptimer_create(target_phys_addr_t base,
+ uint32_t nr_timers,
+ uint32_t freq,
+ qemu_irq *cpu_irqs,
+ int base_irq)
+{
+ DeviceState *dev;
+ int i;
+
+ dev = qdev_create(NULL, "grlib,gptimer");
+ qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
+ qdev_prop_set_uint32(dev, "frequency", freq);
+ qdev_prop_set_uint32(dev, "irq-line", base_irq);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+ for (i = 0; i < nr_timers; i++) {
+ sysbus_connect_irq(sysbus_from_qdev(dev), i, cpu_irqs[base_irq + i]);
+ }
+
+ return dev;
+}
+
+/* APB UART */
+
+static inline
+DeviceState *grlib_apbuart_create(target_phys_addr_t base,
+ CharDriverState *serial,
+ qemu_irq irq)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "grlib,apbuart");
+ qdev_prop_set_chr(dev, "chrdev", serial);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
+
+ return dev;
+}
+
+#endif /* ! _GRLIB_H_ */
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
new file mode 100644
index 0000000000..101b150aa5
--- /dev/null
+++ b/hw/grlib_apbuart.c
@@ -0,0 +1,187 @@
+/*
+ * QEMU GRLIB APB UART Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+
+#include "trace.h"
+
+#define UART_REG_SIZE 20 /* Size of memory mapped registers */
+
+/* UART status register fields */
+#define UART_DATA_READY (1 << 0)
+#define UART_TRANSMIT_SHIFT_EMPTY (1 << 1)
+#define UART_TRANSMIT_FIFO_EMPTY (1 << 2)
+#define UART_BREAK_RECEIVED (1 << 3)
+#define UART_OVERRUN (1 << 4)
+#define UART_PARITY_ERROR (1 << 5)
+#define UART_FRAMING_ERROR (1 << 6)
+#define UART_TRANSMIT_FIFO_HALF (1 << 7)
+#define UART_RECEIVE_FIFO_HALF (1 << 8)
+#define UART_TRANSMIT_FIFO_FULL (1 << 9)
+#define UART_RECEIVE_FIFO_FULL (1 << 10)
+
+/* UART control register fields */
+#define UART_RECEIVE_ENABLE (1 << 0)
+#define UART_TRANSMIT_ENABLE (1 << 1)
+#define UART_RECEIVE_INTERRUPT (1 << 2)
+#define UART_TRANSMIT_INTERRUPT (1 << 3)
+#define UART_PARITY_SELECT (1 << 4)
+#define UART_PARITY_ENABLE (1 << 5)
+#define UART_FLOW_CONTROL (1 << 6)
+#define UART_LOOPBACK (1 << 7)
+#define UART_EXTERNAL_CLOCK (1 << 8)
+#define UART_RECEIVE_FIFO_INTERRUPT (1 << 9)
+#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
+#define UART_FIFO_DEBUG_MODE (1 << 11)
+#define UART_OUTPUT_ENABLE (1 << 12)
+#define UART_FIFO_AVAILABLE (1 << 31)
+
+/* Memory mapped register offsets */
+#define DATA_OFFSET 0x00
+#define STATUS_OFFSET 0x04
+#define CONTROL_OFFSET 0x08
+#define SCALER_OFFSET 0x0C /* not supported */
+#define FIFO_DEBUG_OFFSET 0x10 /* not supported */
+
+typedef struct UART {
+ SysBusDevice busdev;
+
+ qemu_irq irq;
+
+ CharDriverState *chr;
+
+ /* registers */
+ uint32_t receive;
+ uint32_t status;
+ uint32_t control;
+} UART;
+
+static int grlib_apbuart_can_receive(void *opaque)
+{
+ UART *uart = opaque;
+
+ return !!(uart->status & UART_DATA_READY);
+}
+
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ UART *uart = opaque;
+
+ uart->receive = *buf;
+ uart->status |= UART_DATA_READY;
+
+ if (uart->control & UART_RECEIVE_INTERRUPT) {
+ qemu_irq_pulse(uart->irq);
+ }
+}
+
+static void grlib_apbuart_event(void *opaque, int event)
+{
+ trace_grlib_apbuart_event(event);
+}
+
+static void
+grlib_apbuart_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ UART *uart = opaque;
+ unsigned char c = 0;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case DATA_OFFSET:
+ c = value & 0xFF;
+ qemu_chr_write(uart->chr, &c, 1);
+ return;
+
+ case STATUS_OFFSET:
+ /* Read Only */
+ return;
+
+ case CONTROL_OFFSET:
+ /* Not supported */
+ return;
+
+ case SCALER_OFFSET:
+ /* Not supported */
+ return;
+
+ default:
+ break;
+ }
+
+ trace_grlib_apbuart_unknown_register("write", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_apbuart_read[] = {
+ NULL, NULL, NULL,
+};
+
+static CPUWriteMemoryFunc * const grlib_apbuart_write[] = {
+ NULL, NULL, grlib_apbuart_writel,
+};
+
+static int grlib_apbuart_init(SysBusDevice *dev)
+{
+ UART *uart = FROM_SYSBUS(typeof(*uart), dev);
+ int uart_regs = 0;
+
+ qemu_chr_add_handlers(uart->chr,
+ grlib_apbuart_can_receive,
+ grlib_apbuart_receive,
+ grlib_apbuart_event,
+ uart);
+
+ sysbus_init_irq(dev, &uart->irq);
+
+ uart_regs = cpu_register_io_memory(grlib_apbuart_read,
+ grlib_apbuart_write,
+ uart, DEVICE_NATIVE_ENDIAN);
+ if (uart_regs < 0) {
+ return -1;
+ }
+
+ sysbus_init_mmio(dev, UART_REG_SIZE, uart_regs);
+
+ return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+ .init = grlib_apbuart_init,
+ .qdev.name = "grlib,apbuart",
+ .qdev.size = sizeof(UART),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_CHR("chrdev", UART, chr),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void grlib_gptimer_register(void)
+{
+ sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
new file mode 100644
index 0000000000..596a9000a1
--- /dev/null
+++ b/hw/grlib_gptimer.c
@@ -0,0 +1,395 @@
+/*
+ * QEMU GRLIB GPTimer Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+#include "trace.h"
+
+#define UNIT_REG_SIZE 16 /* Size of memory mapped regs for the unit */
+#define GPTIMER_REG_SIZE 16 /* Size of memory mapped regs for a GPTimer */
+
+#define GPTIMER_MAX_TIMERS 8
+
+/* GPTimer Config register fields */
+#define GPTIMER_ENABLE (1 << 0)
+#define GPTIMER_RESTART (1 << 1)
+#define GPTIMER_LOAD (1 << 2)
+#define GPTIMER_INT_ENABLE (1 << 3)
+#define GPTIMER_INT_PENDING (1 << 4)
+#define GPTIMER_CHAIN (1 << 5) /* Not supported */
+#define GPTIMER_DEBUG_HALT (1 << 6) /* Not supported */
+
+/* Memory mapped register offsets */
+#define SCALER_OFFSET 0x00
+#define SCALER_RELOAD_OFFSET 0x04
+#define CONFIG_OFFSET 0x08
+#define COUNTER_OFFSET 0x00
+#define COUNTER_RELOAD_OFFSET 0x04
+#define TIMER_BASE 0x10
+
+typedef struct GPTimer GPTimer;
+typedef struct GPTimerUnit GPTimerUnit;
+
+struct GPTimer {
+ QEMUBH *bh;
+ struct ptimer_state *ptimer;
+
+ qemu_irq irq;
+ int id;
+ GPTimerUnit *unit;
+
+ /* registers */
+ uint32_t counter;
+ uint32_t reload;
+ uint32_t config;
+};
+
+struct GPTimerUnit {
+ SysBusDevice busdev;
+
+ uint32_t nr_timers; /* Number of timers available */
+ uint32_t freq_hz; /* System frequency */
+ uint32_t irq_line; /* Base irq line */
+
+ GPTimer *timers;
+
+ /* registers */
+ uint32_t scaler;
+ uint32_t reload;
+ uint32_t config;
+};
+
+static void grlib_gptimer_enable(GPTimer *timer)
+{
+ assert(timer != NULL);
+
+
+ ptimer_stop(timer->ptimer);
+
+ if (!(timer->config & GPTIMER_ENABLE)) {
+ /* Timer disabled */
+ trace_grlib_gptimer_disabled(timer->id, timer->config);
+ return;
+ }
+
+ /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
+ underflow. Set count + 1 to simulate the GPTimer behavior. */
+
+ trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
+
+ ptimer_set_count(timer->ptimer, timer->counter + 1);
+ ptimer_run(timer->ptimer, 1);
+}
+
+static void grlib_gptimer_restart(GPTimer *timer)
+{
+ assert(timer != NULL);
+
+ trace_grlib_gptimer_restart(timer->id, timer->reload);
+
+ timer->counter = timer->reload;
+ grlib_gptimer_enable(timer);
+}
+
+static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
+{
+ int i = 0;
+ uint32_t value = 0;
+
+ assert(unit != NULL);
+
+ if (scaler > 0) {
+ value = unit->freq_hz / (scaler + 1);
+ } else {
+ value = unit->freq_hz;
+ }
+
+ trace_grlib_gptimer_set_scaler(scaler, value);
+
+ for (i = 0; i < unit->nr_timers; i++) {
+ ptimer_set_freq(unit->timers[i].ptimer, value);
+ }
+}
+
+static void grlib_gptimer_hit(void *opaque)
+{
+ GPTimer *timer = opaque;
+ assert(timer != NULL);
+
+ trace_grlib_gptimer_hit(timer->id);
+
+ /* Timer expired */
+
+ if (timer->config & GPTIMER_INT_ENABLE) {
+ /* Set the pending bit (only unset by write in the config register) */
+ timer->config |= GPTIMER_INT_PENDING;
+ qemu_irq_pulse(timer->irq);
+ }
+
+ if (timer->config & GPTIMER_RESTART) {
+ grlib_gptimer_restart(timer);
+ }
+}
+
+static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
+{
+ GPTimerUnit *unit = opaque;
+ target_phys_addr_t timer_addr;
+ int id;
+ uint32_t value = 0;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case SCALER_OFFSET:
+ trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler);
+ return unit->scaler;
+
+ case SCALER_RELOAD_OFFSET:
+ trace_grlib_gptimer_readl(-1, "reload:", unit->reload);
+ return unit->reload;
+
+ case CONFIG_OFFSET:
+ trace_grlib_gptimer_readl(-1, "config:", unit->config);
+ return unit->config;
+
+ default:
+ break;
+ }
+
+ timer_addr = (addr % TIMER_BASE);
+ id = (addr - TIMER_BASE) / TIMER_BASE;
+
+ if (id >= 0 && id < unit->nr_timers) {
+
+ /* GPTimer registers */
+ switch (timer_addr) {
+ case COUNTER_OFFSET:
+ value = ptimer_get_count(unit->timers[id].ptimer);
+ trace_grlib_gptimer_readl(id, "counter value:", value);
+ return value;
+
+ case COUNTER_RELOAD_OFFSET:
+ value = unit->timers[id].reload;
+ trace_grlib_gptimer_readl(id, "reload value:", value);
+ return value;
+
+ case CONFIG_OFFSET:
+ trace_grlib_gptimer_readl(id, "scaler value:",
+ unit->timers[id].config);
+ return unit->timers[id].config;
+
+ default:
+ break;
+ }
+
+ }
+
+ trace_grlib_gptimer_unknown_register("read", addr);
+ return 0;
+}
+
+static void
+grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ GPTimerUnit *unit = opaque;
+ target_phys_addr_t timer_addr;
+ int id;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case SCALER_OFFSET:
+ value &= 0xFFFF; /* clean up the value */
+ unit->scaler = value;
+ trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler);
+ return;
+
+ case SCALER_RELOAD_OFFSET:
+ value &= 0xFFFF; /* clean up the value */
+ unit->reload = value;
+ trace_grlib_gptimer_writel(-1, "reload:", unit->reload);
+ grlib_gptimer_set_scaler(unit, value);
+ return;
+
+ case CONFIG_OFFSET:
+ /* Read Only (disable timer freeze not supported) */
+ trace_grlib_gptimer_writel(-1, "config (Read Only):", 0);
+ return;
+
+ default:
+ break;
+ }
+
+ timer_addr = (addr % TIMER_BASE);
+ id = (addr - TIMER_BASE) / TIMER_BASE;
+
+ if (id >= 0 && id < unit->nr_timers) {
+
+ /* GPTimer registers */
+ switch (timer_addr) {
+ case COUNTER_OFFSET:
+ trace_grlib_gptimer_writel(id, "counter:", value);
+ unit->timers[id].counter = value;
+ grlib_gptimer_enable(&unit->timers[id]);
+ return;
+
+ case COUNTER_RELOAD_OFFSET:
+ trace_grlib_gptimer_writel(id, "reload:", value);
+ unit->timers[id].reload = value;
+ return;
+
+ case CONFIG_OFFSET:
+ trace_grlib_gptimer_writel(id, "config:", value);
+
+ if (value & GPTIMER_INT_PENDING) {
+ /* clear pending bit */
+ value &= ~GPTIMER_INT_PENDING;
+ } else {
+ /* keep pending bit */
+ value |= unit->timers[id].config & GPTIMER_INT_PENDING;
+ }
+
+ unit->timers[id].config = value;
+
+ /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
+ bits are present, we just have to call restart. */
+
+ if (value & GPTIMER_LOAD) {
+ grlib_gptimer_restart(&unit->timers[id]);
+ } else if (value & GPTIMER_ENABLE) {
+ grlib_gptimer_enable(&unit->timers[id]);
+ }
+
+ /* These fields must always be read as 0 */
+ value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
+
+ unit->timers[id].config = value;
+ return;
+
+ default:
+ break;
+ }
+
+ }
+
+ trace_grlib_gptimer_unknown_register("write", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
+ NULL, NULL, grlib_gptimer_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
+ NULL, NULL, grlib_gptimer_writel,
+};
+
+static void grlib_gptimer_reset(DeviceState *d)
+{
+ GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
+ int i = 0;
+
+ assert(unit != NULL);
+
+ unit->scaler = 0;
+ unit->reload = 0;
+ unit->config = 0;
+
+ unit->config = unit->nr_timers;
+ unit->config |= unit->irq_line << 3;
+ unit->config |= 1 << 8; /* separate interrupt */
+ unit->config |= 1 << 9; /* Disable timer freeze */
+
+
+ for (i = 0; i < unit->nr_timers; i++) {
+ GPTimer *timer = &unit->timers[i];
+
+ timer->counter = 0;
+ timer->reload = 0;
+ timer->config = 0;
+ ptimer_stop(timer->ptimer);
+ ptimer_set_count(timer->ptimer, 0);
+ ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ }
+}
+
+static int grlib_gptimer_init(SysBusDevice *dev)
+{
+ GPTimerUnit *unit = FROM_SYSBUS(typeof(*unit), dev);
+ unsigned int i;
+ int timer_regs;
+
+ assert(unit->nr_timers > 0);
+ assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
+
+ unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
+
+ for (i = 0; i < unit->nr_timers; i++) {
+ GPTimer *timer = &unit->timers[i];
+
+ timer->unit = unit;
+ timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
+ timer->ptimer = ptimer_init(timer->bh);
+ timer->id = i;
+
+ /* One IRQ line for each timer */
+ sysbus_init_irq(dev, &timer->irq);
+
+ ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ }
+
+ timer_regs = cpu_register_io_memory(grlib_gptimer_read,
+ grlib_gptimer_write,
+ unit, DEVICE_NATIVE_ENDIAN);
+ if (timer_regs < 0) {
+ return -1;
+ }
+
+ sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
+ timer_regs);
+ return 0;
+}
+
+static SysBusDeviceInfo grlib_gptimer_info = {
+ .init = grlib_gptimer_init,
+ .qdev.name = "grlib,gptimer",
+ .qdev.reset = grlib_gptimer_reset,
+ .qdev.size = sizeof(GPTimerUnit),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
+ DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
+ DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void grlib_gptimer_register(void)
+{
+ sysbus_register_withprop(&grlib_gptimer_info);
+}
+
+device_init(grlib_gptimer_register)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
new file mode 100644
index 0000000000..f47c491a48
--- /dev/null
+++ b/hw/grlib_irqmp.c
@@ -0,0 +1,376 @@
+/*
+ * QEMU GRLIB IRQMP Emulator
+ *
+ * (Multiprocessor and extended interrupt not supported)
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "cpu.h"
+
+#include "grlib.h"
+
+#include "trace.h"
+
+#define IRQMP_MAX_CPU 16
+#define IRQMP_REG_SIZE 256 /* Size of memory mapped registers */
+
+/* Memory mapped register offsets */
+#define LEVEL_OFFSET 0x00
+#define PENDING_OFFSET 0x04
+#define FORCE0_OFFSET 0x08
+#define CLEAR_OFFSET 0x0C
+#define MP_STATUS_OFFSET 0x10
+#define BROADCAST_OFFSET 0x14
+#define MASK_OFFSET 0x40
+#define FORCE_OFFSET 0x80
+#define EXTENDED_OFFSET 0xC0
+
+typedef struct IRQMPState IRQMPState;
+
+typedef struct IRQMP {
+ SysBusDevice busdev;
+
+ void *set_pil_in;
+ void *set_pil_in_opaque;
+
+ IRQMPState *state;
+} IRQMP;
+
+struct IRQMPState {
+ uint32_t level;
+ uint32_t pending;
+ uint32_t clear;
+ uint32_t broadcast;
+
+ uint32_t mask[IRQMP_MAX_CPU];
+ uint32_t force[IRQMP_MAX_CPU];
+ uint32_t extended[IRQMP_MAX_CPU];
+
+ IRQMP *parent;
+};
+
+static void grlib_irqmp_check_irqs(IRQMPState *state)
+{
+ uint32_t pend = 0;
+ uint32_t level0 = 0;
+ uint32_t level1 = 0;
+ set_pil_in_fn set_pil_in;
+
+ assert(state != NULL);
+ assert(state->parent != NULL);
+
+ /* IRQ for CPU 0 (no SMP support) */
+ pend = (state->pending | state->force[0])
+ & state->mask[0];
+
+ level0 = pend & ~state->level;
+ level1 = pend & state->level;
+
+ trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
+ state->mask[0], level1, level0);
+
+ set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
+
+ /* Trigger level1 interrupt first and level0 if there is no level1 */
+ if (level1 != 0) {
+ set_pil_in(state->parent->set_pil_in_opaque, level1);
+ } else {
+ set_pil_in(state->parent->set_pil_in_opaque, level0);
+ }
+}
+
+void grlib_irqmp_ack(DeviceState *dev, int intno)
+{
+ SysBusDevice *sdev;
+ IRQMP *irqmp;
+ IRQMPState *state;
+ uint32_t mask;
+
+ assert(dev != NULL);
+
+ sdev = sysbus_from_qdev(dev);
+ assert(sdev != NULL);
+
+ irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
+ assert(irqmp != NULL);
+
+ state = irqmp->state;
+ assert(state != NULL);
+
+ intno &= 15;
+ mask = 1 << intno;
+
+ trace_grlib_irqmp_ack(intno);
+
+ /* Clear registers */
+ state->pending &= ~mask;
+ state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+ grlib_irqmp_check_irqs(state);
+}
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level)
+{
+ IRQMP *irqmp;
+ IRQMPState *s;
+ int i = 0;
+
+ assert(opaque != NULL);
+
+ irqmp = FROM_SYSBUS(typeof(*irqmp), sysbus_from_qdev(opaque));
+ assert(irqmp != NULL);
+
+ s = irqmp->state;
+ assert(s != NULL);
+ assert(s->parent != NULL);
+
+
+ if (level) {
+ trace_grlib_irqmp_set_irq(irq);
+
+ if (s->broadcast & 1 << irq) {
+ /* Broadcasted IRQ */
+ for (i = 0; i < IRQMP_MAX_CPU; i++) {
+ s->force[i] |= 1 << irq;
+ }
+ } else {
+ s->pending |= 1 << irq;
+ }
+ grlib_irqmp_check_irqs(s);
+
+ }
+}
+
+static uint32_t grlib_irqmp_readl(void *opaque, target_phys_addr_t addr)
+{
+ IRQMP *irqmp = opaque;
+ IRQMPState *state;
+
+ assert(irqmp != NULL);
+ state = irqmp->state;
+ assert(state != NULL);
+
+ addr &= 0xff;
+
+ /* global registers */
+ switch (addr) {
+ case LEVEL_OFFSET:
+ return state->level;
+
+ case PENDING_OFFSET:
+ return state->pending;
+
+ case FORCE0_OFFSET:
+ /* This register is an "alias" for the force register of CPU 0 */
+ return state->force[0];
+
+ case CLEAR_OFFSET:
+ case MP_STATUS_OFFSET:
+ /* Always read as 0 */
+ return 0;
+
+ case BROADCAST_OFFSET:
+ return state->broadcast;
+
+ default:
+ break;
+ }
+
+ /* mask registers */
+ if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+ int cpu = (addr - MASK_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ return state->mask[cpu];
+ }
+
+ /* force registers */
+ if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+ int cpu = (addr - FORCE_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ return state->force[cpu];
+ }
+
+ /* extended (not supported) */
+ if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+ int cpu = (addr - EXTENDED_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ return state->extended[cpu];
+ }
+
+ trace_grlib_irqmp_unknown_register("read", addr);
+ return 0;
+}
+
+static void
+grlib_irqmp_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ IRQMP *irqmp = opaque;
+ IRQMPState *state;
+
+ assert(irqmp != NULL);
+ state = irqmp->state;
+ assert(state != NULL);
+
+ addr &= 0xff;
+
+ /* global registers */
+ switch (addr) {
+ case LEVEL_OFFSET:
+ value &= 0xFFFF << 1; /* clean up the value */
+ state->level = value;
+ return;
+
+ case PENDING_OFFSET:
+ /* Read Only */
+ return;
+
+ case FORCE0_OFFSET:
+ /* This register is an "alias" for the force register of CPU 0 */
+
+ value &= 0xFFFE; /* clean up the value */
+ state->force[0] = value;
+ grlib_irqmp_check_irqs(irqmp->state);
+ return;
+
+ case CLEAR_OFFSET:
+ value &= ~1; /* clean up the value */
+ state->pending &= ~value;
+ return;
+
+ case MP_STATUS_OFFSET:
+ /* Read Only (no SMP support) */
+ return;
+
+ case BROADCAST_OFFSET:
+ value &= 0xFFFE; /* clean up the value */
+ state->broadcast = value;
+ return;
+
+ default:
+ break;
+ }
+
+ /* mask registers */
+ if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+ int cpu = (addr - MASK_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ value &= ~1; /* clean up the value */
+ state->mask[cpu] = value;
+ grlib_irqmp_check_irqs(irqmp->state);
+ return;
+ }
+
+ /* force registers */
+ if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+ int cpu = (addr - FORCE_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ uint32_t force = value & 0xFFFE;
+ uint32_t clear = (value >> 16) & 0xFFFE;
+ uint32_t old = state->force[cpu];
+
+ state->force[cpu] = (old | force) & ~clear;
+ grlib_irqmp_check_irqs(irqmp->state);
+ return;
+ }
+
+ /* extended (not supported) */
+ if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+ int cpu = (addr - EXTENDED_OFFSET) / 4;
+ assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+ value &= 0xF; /* clean up the value */
+ state->extended[cpu] = value;
+ return;
+ }
+
+ trace_grlib_irqmp_unknown_register("write", addr);
+}
+
+static CPUReadMemoryFunc * const grlib_irqmp_read[] = {
+ NULL, NULL, &grlib_irqmp_readl,
+};
+
+static CPUWriteMemoryFunc * const grlib_irqmp_write[] = {
+ NULL, NULL, &grlib_irqmp_writel,
+};
+
+static void grlib_irqmp_reset(DeviceState *d)
+{
+ IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
+ assert(irqmp != NULL);
+ assert(irqmp->state != NULL);
+
+ memset(irqmp->state, 0, sizeof *irqmp->state);
+ irqmp->state->parent = irqmp;
+}
+
+static int grlib_irqmp_init(SysBusDevice *dev)
+{
+ IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
+ int irqmp_regs;
+
+ assert(irqmp != NULL);
+
+ /* Check parameters */
+ if (irqmp->set_pil_in == NULL) {
+ return -1;
+ }
+
+ irqmp_regs = cpu_register_io_memory(grlib_irqmp_read,
+ grlib_irqmp_write,
+ irqmp, DEVICE_NATIVE_ENDIAN);
+
+ irqmp->state = qemu_mallocz(sizeof *irqmp->state);
+
+ if (irqmp_regs < 0) {
+ return -1;
+ }
+
+ sysbus_init_mmio(dev, IRQMP_REG_SIZE, irqmp_regs);
+
+ return 0;
+}
+
+static SysBusDeviceInfo grlib_irqmp_info = {
+ .init = grlib_irqmp_init,
+ .qdev.name = "grlib,irqmp",
+ .qdev.reset = grlib_irqmp_reset,
+ .qdev.size = sizeof(IRQMP),
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+ DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void grlib_irqmp_register(void)
+{
+ sysbus_register_withprop(&grlib_irqmp_info);
+}
+
+device_init(grlib_irqmp_register)
diff --git a/hw/gumstix.c b/hw/gumstix.c
index af8b464b88..ee63f634cc 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -78,7 +78,7 @@ static void connex_init(ram_addr_t ram_size,
/* Interrupt line of NIC is connected to GPIO line 36 */
smc91c111_init(&nd_table[0], 0x04000300,
- pxa2xx_gpio_in_get(cpu->gpio)[36]);
+ qdev_get_gpio_in(cpu->gpio, 36));
}
static void verdex_init(ram_addr_t ram_size,
@@ -117,7 +117,7 @@ static void verdex_init(ram_addr_t ram_size,
/* Interrupt line of NIC is connected to GPIO line 99 */
smc91c111_init(&nd_table[0], 0x04000300,
- pxa2xx_gpio_in_get(cpu->gpio)[99]);
+ qdev_get_gpio_in(cpu->gpio, 99));
}
static QEMUMachine connex_machine = {
diff --git a/hw/hw.h b/hw/hw.h
index dd993de10c..5e24329589 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -587,6 +587,16 @@ extern const VMStateDescription vmstate_i2c_slave;
.offset = vmstate_offset_value(_state, _field, i2c_slave), \
}
+extern const VMStateDescription vmstate_usb_device;
+
+#define VMSTATE_USB_DEVICE(_field, _state) { \
+ .name = (stringify(_field)), \
+ .size = sizeof(USBDevice), \
+ .vmsd = &vmstate_usb_device, \
+ .flags = VMS_STRUCT, \
+ .offset = vmstate_offset_value(_state, _field, USBDevice), \
+}
+
#define vmstate_offset_macaddr(_state, _field) \
vmstate_offset_array(_state, _field.a, uint8_t, \
sizeof(typeof_field(_state, _field)))
diff --git a/hw/ide.h b/hw/ide.h
index 2b5ae7c39e..73fb550574 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -4,6 +4,8 @@
#include "isa.h"
#include "pci.h"
+#define MAX_IDE_DEVS 2
+
/* ide-isa.c */
ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
DriveInfo *hd0, DriveInfo *hd1);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 968fdcecaf..671b4df7f6 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -70,7 +70,6 @@
#include "monitor.h"
#include "dma.h"
#include "cpu-common.h"
-#include "blockdev.h"
#include "internal.h"
#include <hw/ide/pci.h>
@@ -513,12 +512,12 @@ static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
target_phys_addr_t len = wanted;
if (*ptr) {
- cpu_physical_memory_unmap(*ptr, 1, len, len);
+ cpu_physical_memory_unmap(*ptr, len, 1, len);
}
*ptr = cpu_physical_memory_map(addr, &len, 1);
if (len < wanted) {
- cpu_physical_memory_unmap(*ptr, 1, len, len);
+ cpu_physical_memory_unmap(*ptr, len, 1, len);
*ptr = NULL;
}
}
@@ -956,7 +955,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
if (cmd_mapped) {
- cpu_physical_memory_unmap(cmd_fis, 0, cmd_len, cmd_len);
+ cpu_physical_memory_unmap(cmd_fis, cmd_len, 0, cmd_len);
}
}
@@ -1002,7 +1001,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
}
out:
- cpu_physical_memory_unmap(prdt, 0, prdt_len, prdt_len);
+ cpu_physical_memory_unmap(prdt, prdt_len, 0, prdt_len);
return r;
}
@@ -1228,7 +1227,7 @@ static int handle_cmd(AHCIState *s, int port, int slot)
}
out:
- cpu_physical_memory_unmap(cmd_fis, 1, cmd_len, cmd_len);
+ cpu_physical_memory_unmap(cmd_fis, cmd_len, 1, cmd_len);
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
/* async command, complete later */
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9496e990b9..dd63664c0d 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -321,14 +321,6 @@ static inline void ide_abort_command(IDEState *s)
s->error = ABRT_ERR;
}
-static inline void ide_dma_submit_check(IDEState *s,
- BlockDriverCompletionFunc *dma_cb)
-{
- if (s->bus->dma->aiocb)
- return;
- dma_cb(s, -1);
-}
-
/* prepare data transfer and tell what to do after */
static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func)
@@ -487,16 +479,19 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
return 1;
}
-void ide_read_dma_cb(void *opaque, int ret)
+void ide_dma_cb(void *opaque, int ret)
{
IDEState *s = opaque;
int n;
int64_t sector_num;
+handle_rw_error:
if (ret < 0) {
- if (ide_handle_rw_error(s, -ret,
- BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ))
- {
+ int op = BM_STATUS_DMA_RETRY;
+
+ if (s->is_read)
+ op |= BM_STATUS_RETRY_READ;
+ if (ide_handle_rw_error(s, -ret, op)) {
return;
}
}
@@ -504,7 +499,7 @@ void ide_read_dma_cb(void *opaque, int ret)
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
- dma_buf_commit(s, 1);
+ dma_buf_commit(s, s->is_read);
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -514,32 +509,47 @@ void ide_read_dma_cb(void *opaque, int ret)
if (s->nsector == 0) {
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s->bus);
- eot:
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
- ide_set_inactive(s);
- return;
+ goto eot;
}
/* launch next transfer */
n = s->nsector;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, 1) == 0)
+ if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0)
goto eot;
+
#ifdef DEBUG_AIO
- printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n);
+ printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n",
+ sector_num, n, s->is_read);
#endif
- s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, ide_read_dma_cb, s);
- ide_dma_submit_check(s, ide_read_dma_cb);
+
+ if (s->is_read) {
+ s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
+ ide_dma_cb, s);
+ } else {
+ s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
+ ide_dma_cb, s);
+ }
+
+ if (!s->bus->dma->aiocb) {
+ ret = -1;
+ goto handle_rw_error;
+ }
+ return;
+
+eot:
+ s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
+ ide_set_inactive(s);
}
-static void ide_sector_read_dma(IDEState *s)
+static void ide_sector_start_dma(IDEState *s, int is_read)
{
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
s->io_buffer_index = 0;
s->io_buffer_size = 0;
- s->is_read = 1;
- s->bus->dma->ops->start_dma(s->bus->dma, s, ide_read_dma_cb);
+ s->is_read = is_read;
+ s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
}
static void ide_sector_write_timer_cb(void *opaque)
@@ -594,57 +604,6 @@ void ide_sector_write(IDEState *s)
}
}
-void ide_write_dma_cb(void *opaque, int ret)
-{
- IDEState *s = opaque;
- int n;
- int64_t sector_num;
-
- if (ret < 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_DMA_RETRY))
- return;
- }
-
- n = s->io_buffer_size >> 9;
- sector_num = ide_get_sector(s);
- if (n > 0) {
- dma_buf_commit(s, 0);
- sector_num += n;
- ide_set_sector(s, sector_num);
- s->nsector -= n;
- }
-
- /* end of transfer ? */
- if (s->nsector == 0) {
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s->bus);
- eot:
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
- ide_set_inactive(s);
- return;
- }
-
- n = s->nsector;
- s->io_buffer_size = n * 512;
- /* launch next transfer */
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, 0) == 0)
- goto eot;
-#ifdef DEBUG_AIO
- printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n);
-#endif
- s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, ide_write_dma_cb, s);
- ide_dma_submit_check(s, ide_write_dma_cb);
-}
-
-static void ide_sector_write_dma(IDEState *s)
-{
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
- s->io_buffer_index = 0;
- s->io_buffer_size = 0;
- s->is_read = 0;
- s->bus->dma->ops->start_dma(s->bus->dma, s, ide_write_dma_cb);
-}
-
void ide_atapi_cmd_ok(IDEState *s)
{
s->error = 0;
@@ -1625,11 +1584,15 @@ static void ide_cfata_metadata_write(IDEState *s)
}
/* called when the inserted state of the media has changed */
-static void cdrom_change_cb(void *opaque)
+static void cdrom_change_cb(void *opaque, int reason)
{
IDEState *s = opaque;
uint64_t nb_sectors;
+ if (!(reason & CHANGE_MEDIA)) {
+ return;
+ }
+
bdrv_get_geometry(s->bs, &nb_sectors);
s->nb_sectors = nb_sectors;
@@ -1858,7 +1821,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_read_dma(s);
+ ide_sector_start_dma(s, 1);
break;
case WIN_WRITEDMA_EXT:
lba48 = 1;
@@ -1867,7 +1830,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_write_dma(s);
+ ide_sector_start_dma(s, 0);
s->media_changed = 1;
break;
case WIN_READ_NATIVE_MAX_EXT:
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 697c3b4dc1..d533fb63b3 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -439,7 +439,6 @@ struct IDEState {
uint32_t mdata_size;
uint8_t *mdata_storage;
int media_changed;
- /* for pmac */
int is_read;
/* SMART */
uint8_t smart_enabled;
@@ -560,8 +559,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
void ide_exec_cmd(IDEBus *bus, uint32_t val);
-void ide_read_dma_cb(void *opaque, int ret);
-void ide_write_dma_cb(void *opaque, int ret);
+void ide_dma_cb(void *opaque, int ret);
void ide_sector_write(IDEState *s);
void ide_sector_read(IDEState *s);
void ide_flush_cache(IDEState *s);
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 510b2de597..35168cb469 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -178,14 +178,9 @@ static void bmdma_restart_dma(BMDMAState *bm, int is_read)
s->io_buffer_index = 0;
s->io_buffer_size = 0;
s->nsector = bm->nsector;
+ s->is_read = is_read;
bm->cur_addr = bm->addr;
-
- if (is_read) {
- bm->dma_cb = ide_read_dma_cb;
- } else {
- bm->dma_cb = ide_write_dma_cb;
- }
-
+ bm->dma_cb = ide_dma_cb;
bmdma_start_dma(&bm->dma, s, bm->dma_cb);
}
@@ -272,9 +267,7 @@ static void bmdma_irq(void *opaque, int n, int level)
return;
}
- if (bm) {
- bm->status |= BM_STATUS_INT;
- }
+ bm->status |= BM_STATUS_INT;
/* trigger the real irq */
qemu_set_irq(bm->irq, level);
diff --git a/hw/leon3.c b/hw/leon3.c
new file mode 100644
index 0000000000..919f49fc1c
--- /dev/null
+++ b/hw/leon3.c
@@ -0,0 +1,217 @@
+/*
+ * QEMU Leon3 System Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "trace.h"
+
+#include "grlib.h"
+
+/* Default system clock. */
+#define CPU_CLK (40 * 1000 * 1000)
+
+#define PROM_FILENAME "u-boot.bin"
+
+#define MAX_PILS 16
+
+typedef struct ResetData {
+ CPUState *env;
+ uint32_t entry; /* save kernel entry in case of reset */
+} ResetData;
+
+static void main_cpu_reset(void *opaque)
+{
+ ResetData *s = (ResetData *)opaque;
+ CPUState *env = s->env;
+
+ cpu_reset(env);
+
+ env->halted = 0;
+ env->pc = s->entry;
+ env->npc = s->entry + 4;
+}
+
+void leon3_irq_ack(void *irq_manager, int intno)
+{
+ grlib_irqmp_ack((DeviceState *)irq_manager, intno);
+}
+
+static void leon3_set_pil_in(void *opaque, uint32_t pil_in)
+{
+ CPUState *env = (CPUState *)opaque;
+
+ assert(env != NULL);
+
+ env->pil_in = pil_in;
+
+ if (env->pil_in && (env->interrupt_index == 0 ||
+ (env->interrupt_index & ~15) == TT_EXTINT)) {
+ unsigned int i;
+
+ for (i = 15; i > 0; i--) {
+ if (env->pil_in & (1 << i)) {
+ int old_interrupt = env->interrupt_index;
+
+ env->interrupt_index = TT_EXTINT | i;
+ if (old_interrupt != env->interrupt_index) {
+ trace_leon3_set_irq(i);
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ break;
+ }
+ }
+ } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+ trace_leon3_reset_irq(env->interrupt_index & 15);
+ env->interrupt_index = 0;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void leon3_generic_hw_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ CPUState *env;
+ ram_addr_t ram_offset, prom_offset;
+ int ret;
+ char *filename;
+ qemu_irq *cpu_irqs = NULL;
+ int bios_size;
+ int prom_size;
+ ResetData *reset_info;
+
+ /* Init CPU */
+ if (!cpu_model) {
+ cpu_model = "LEON3";
+ }
+
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "qemu: Unable to find Sparc CPU definition\n");
+ exit(1);
+ }
+
+ cpu_sparc_set_id(env, 0);
+
+ /* Reset data */
+ reset_info = qemu_mallocz(sizeof(ResetData));
+ reset_info->env = env;
+ qemu_register_reset(main_cpu_reset, reset_info);
+
+ /* Allocate IRQ manager */
+ grlib_irqmp_create(0x80000200, env, &cpu_irqs, MAX_PILS, &leon3_set_pil_in);
+
+ env->qemu_irq_ack = leon3_irq_manager;
+
+ /* Allocate RAM */
+ if ((uint64_t)ram_size > (1UL << 30)) {
+ fprintf(stderr,
+ "qemu: Too much memory for this machine: %d, maximum 1G\n",
+ (unsigned int)(ram_size / (1024 * 1024)));
+ exit(1);
+ }
+
+ ram_offset = qemu_ram_alloc(NULL, "leon3.ram", ram_size);
+ cpu_register_physical_memory(0x40000000, ram_size, ram_offset | IO_MEM_RAM);
+
+ /* Allocate BIOS */
+ prom_size = 8 * 1024 * 1024; /* 8Mb */
+ prom_offset = qemu_ram_alloc(NULL, "Leon3.bios", prom_size);
+ cpu_register_physical_memory(0x00000000, prom_size,
+ prom_offset | IO_MEM_ROM);
+
+ /* Load boot prom */
+ if (bios_name == NULL) {
+ bios_name = PROM_FILENAME;
+ }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+ bios_size = get_image_size(filename);
+
+ if (bios_size > prom_size) {
+ fprintf(stderr, "qemu: could not load prom '%s': file too big\n",
+ filename);
+ exit(1);
+ }
+
+ if (bios_size > 0) {
+ ret = load_image_targphys(filename, 0x00000000, bios_size);
+ if (ret < 0 || ret > prom_size) {
+ fprintf(stderr, "qemu: could not load prom '%s'\n", filename);
+ exit(1);
+ }
+ } else if (kernel_filename == NULL) {
+ fprintf(stderr, "Can't read bios image %s\n", filename);
+ exit(1);
+ }
+
+ /* Can directly load an application. */
+ if (kernel_filename != NULL) {
+ long kernel_size;
+ uint64_t entry;
+
+ kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+ 1 /* big endian */, ELF_MACHINE, 0);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ if (bios_size <= 0) {
+ /* If there is no bios/monitor, start the application. */
+ env->pc = entry;
+ env->npc = entry + 4;
+ reset_info->entry = entry;
+ }
+ }
+
+ /* Allocate timers */
+ grlib_gptimer_create(0x80000300, 2, CPU_CLK, cpu_irqs, 6);
+
+ /* Allocate uart */
+ if (serial_hds[0]) {
+ grlib_apbuart_create(0x80000100, serial_hds[0], cpu_irqs[3]);
+ }
+}
+
+QEMUMachine leon3_generic_machine = {
+ .name = "leon3_generic",
+ .desc = "Leon-3 generic",
+ .init = leon3_generic_hw_init,
+ .use_scsi = 0,
+};
+
+static void leon3_machine_init(void)
+{
+ qemu_register_machine(&leon3_generic_machine);
+}
+
+machine_init(leon3_machine_init);
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 6466aff316..a1b0e31ee5 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -72,6 +72,7 @@
#define REG_B_UIE 0x10
#define REG_B_SQWE 0x08
#define REG_B_DM 0x04
+#define REG_B_24H 0x02
#define REG_C_UF 0x10
#define REG_C_IRQF 0x80
@@ -246,7 +247,15 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
rtc_set_time(s);
}
}
- s->cmos_data[RTC_REG_B] = data;
+ if (((s->cmos_data[RTC_REG_B] ^ data) & (REG_B_DM | REG_B_24H)) &&
+ !(data & REG_B_SET)) {
+ /* If the time format has changed and not in set mode,
+ update the registers immediately. */
+ s->cmos_data[RTC_REG_B] = data;
+ rtc_copy_date(s);
+ } else {
+ s->cmos_data[RTC_REG_B] = data;
+ }
rtc_timer_update(s, qemu_get_clock(rtc_clock));
break;
case RTC_REG_C:
@@ -285,7 +294,7 @@ static void rtc_set_time(RTCState *s)
tm->tm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
tm->tm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
tm->tm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
- if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
+ if (!(s->cmos_data[RTC_REG_B] & REG_B_24H) &&
(s->cmos_data[RTC_HOURS] & 0x80)) {
tm->tm_hour += 12;
}
@@ -304,7 +313,7 @@ static void rtc_copy_date(RTCState *s)
s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
- if (s->cmos_data[RTC_REG_B] & 0x02) {
+ if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
} else {
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index 07eb9eeba1..2783ed5837 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -218,13 +218,11 @@ uint8_t eeprom_spd[0x80] = {
};
/* Audio support */
-#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
{
vt82c686b_ac97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 5));
vt82c686b_mc97_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 6));
}
-#endif
/* Network support */
static void network_init (void)
@@ -391,9 +389,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
}
/* Sound card */
-#ifdef HAS_AUDIO
audio_init(pci_bus);
-#endif
/* Network card */
network_init();
}
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index a7caa3f171..85eba5a69a 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -29,7 +29,7 @@
#include "isa.h"
#include "fdc.h"
#include "sysemu.h"
-#include "audio/audio.h"
+#include "arch_init.h"
#include "boards.h"
#include "net.h"
#include "esp.h"
@@ -90,26 +90,6 @@ static CPUWriteMemoryFunc * const dma_dummy_write[3] = {
dma_dummy_writeb,
};
-static void audio_init(qemu_irq *pic)
-{
- struct soundhw *c;
- int audio_enabled = 0;
-
- for (c = soundhw; !audio_enabled && c->name; ++c) {
- audio_enabled = c->enabled;
- }
-
- if (audio_enabled) {
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- if (c->isa) {
- c->init.init_isa(pic);
- }
- }
- }
- }
-}
-
#define MAGNUM_BIOS_SIZE_MAX 0x7e000
#define MAGNUM_BIOS_SIZE (BIOS_SIZE < MAGNUM_BIOS_SIZE_MAX ? BIOS_SIZE : MAGNUM_BIOS_SIZE_MAX)
@@ -284,7 +264,7 @@ void mips_jazz_init (ram_addr_t ram_size,
/* Sound card */
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
- audio_init(i8259);
+ audio_init(i8259, NULL);
/* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */
ds1225y_init(0x80009000, "nvram");
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 87554169c5..2d3f242cc8 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -37,7 +37,7 @@
#include "vmware_vga.h"
#include "qemu-char.h"
#include "sysemu.h"
-#include "audio/audio.h"
+#include "arch_init.h"
#include "boards.h"
#include "qemu-log.h"
#include "mips-bios.h"
@@ -457,25 +457,6 @@ static MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, qemu_irq uart_ir
return s;
}
-/* Audio support */
-static void audio_init (PCIBus *pci_bus)
-{
- struct soundhw *c;
- int audio_enabled = 0;
-
- for (c = soundhw; !audio_enabled && c->name; ++c) {
- audio_enabled = c->enabled;
- }
-
- if (audio_enabled) {
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- c->init.init_pci(pci_bus);
- }
- }
- }
-}
-
/* Network support */
static void network_init(void)
{
@@ -967,7 +948,7 @@ void mips_malta_init (ram_addr_t ram_size,
fdctrl_init_isa(fd);
/* Sound card */
- audio_init(pci_bus);
+ audio_init(NULL, pci_bus);
/* Network card */
network_init();
diff --git a/hw/onenand.c b/hw/onenand.c
index d9cdcf2944..71c1ab40b4 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -19,6 +19,7 @@
*/
#include "qemu-common.h"
+#include "hw.h"
#include "flash.h"
#include "irq.h"
#include "blockdev.h"
diff --git a/hw/pc.c b/hw/pc.c
index fface7dec9..4dfdc0be53 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -829,23 +829,6 @@ static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
-void pc_audio_init (PCIBus *pci_bus, qemu_irq *pic)
-{
- struct soundhw *c;
-
- for (c = soundhw; c->name; ++c) {
- if (c->enabled) {
- if (c->isa) {
- c->init.init_isa(pic);
- } else {
- if (pci_bus) {
- c->init.init_pci(pci_bus);
- }
- }
- }
- }
-}
-
void pc_init_ne2k_isa(NICInfo *nd)
{
static int nb_ne2k = 0;
diff --git a/hw/pc.h b/hw/pc.h
index 68527902a5..a048768d21 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -100,9 +100,6 @@ void pc_basic_device_init(qemu_irq *isa_irq,
FDCtrl **floppy_controller,
ISADevice **rtc_state);
void pc_init_ne2k_isa(NICInfo *nd);
-#ifdef HAS_AUDIO
-void pc_audio_init (PCIBus *pci_bus, qemu_irq *pic);
-#endif
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
const char *boot_device,
BusState *ide0, BusState *ide1,
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index f82508d92f..7b744730f7 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,6 +34,7 @@
#include "kvm.h"
#include "sysemu.h"
#include "sysbus.h"
+#include "arch_init.h"
#include "blockdev.h"
#define MAX_IDE_BUS 2
@@ -148,7 +149,7 @@ static void pc_init1(ram_addr_t ram_size,
}
}
- pc_audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
+ audio_init(isa_irq, pci_enabled ? pci_bus : NULL);
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
idebus[0], idebus[1], floppy_controller, rtc_state);
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 716133c376..b6dcbda0ce 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -90,7 +90,8 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
* specified).
*/
dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
- scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit);
+ dinfo->bus = scsibus->busnr;
+ scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit, false);
if (!scsidev) {
return -1;
}
diff --git a/hw/pci.c b/hw/pci.c
index b8f5385170..d5bbba975b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -641,7 +641,6 @@ static void pci_init_wmask_bridge(PCIDevice *d)
PCI_BRIDGE_CTL_FAST_BACK |
PCI_BRIDGE_CTL_DISCARD |
PCI_BRIDGE_CTL_SEC_DISCARD |
- PCI_BRIDGE_CTL_DISCARD_STATUS |
PCI_BRIDGE_CTL_DISCARD_SERR);
/* Below does not do anything as we never set this bit, put here for
* completeness. */
@@ -833,6 +832,7 @@ static int pci_unregister_device(DeviceState *dev)
pci_unregister_io_regions(pci_dev);
pci_del_option_rom(pci_dev);
+ qemu_free(pci_dev->romfile);
do_pci_unregister_device(pci_dev);
return 0;
}
@@ -2072,7 +2072,7 @@ static char *pcibus_get_dev_path(DeviceState *dev)
for (t = d; t; t = t->bus->parent_dev) {
p -= slot_len;
s = snprintf(slot, sizeof slot, ":%02x.%x",
- PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
+ PCI_SLOT(t->devfn), PCI_FUNC(t->devfn));
assert(s == slot_len);
memcpy(p, slot, slot_len);
}
diff --git a/hw/pl181.c b/hw/pl181.c
index 3e5f92f0e7..36d9d02d6a 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -7,6 +7,7 @@
* This code is licenced under the GPL.
*/
+#include "blockdev.h"
#include "sysbus.h"
#include "sd.h"
@@ -449,15 +450,15 @@ static int pl181_init(SysBusDevice *dev)
{
int iomemtype;
pl181_state *s = FROM_SYSBUS(pl181_state, dev);
- BlockDriverState *bd;
+ DriveInfo *dinfo;
iomemtype = cpu_register_io_memory(pl181_readfn, pl181_writefn, s,
DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio(dev, 0x1000, iomemtype);
sysbus_init_irq(dev, &s->irq[0]);
sysbus_init_irq(dev, &s->irq[1]);
- bd = qdev_init_bdrv(&dev->qdev, IF_SD);
- s->card = sd_init(bd, 0);
+ dinfo = drive_get_next(IF_SD);
+ s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
qemu_register_reset(pl181_reset, s);
pl181_reset(s);
/* ??? Save/restore. */
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 1492266267..6c1499a780 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -600,9 +600,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
if (filename) {
qemu_free(filename);
}
- if (env->nip < 0xFFF80000 && bios_size < 0x00100000) {
- hw_error("PowerPC 601 / 620 / 970 need a 1MB BIOS\n");
- }
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
@@ -693,7 +690,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
}
- for(i = 0; i < MAX_IDE_BUS; i++) {
+ for(i = 0; i < 1/*MAX_IDE_BUS*/; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
hd[2 * i],
hd[2 * i + 1]);
diff --git a/hw/pxa.h b/hw/pxa.h
index 8d6a8c3348..f73d33b1a8 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -70,13 +70,9 @@ void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs);
void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4);
/* pxa2xx_gpio.c */
-typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
-PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base,
+DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
CPUState *env, qemu_irq *pic, int lines);
-qemu_irq *pxa2xx_gpio_in_get(PXA2xxGPIOInfo *s);
-void pxa2xx_gpio_out_set(PXA2xxGPIOInfo *s,
- int line, qemu_irq handler);
-void pxa2xx_gpio_read_notifier(PXA2xxGPIOInfo *s, qemu_irq handler);
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
/* pxa2xx_dma.c */
typedef struct PXA2xxDMAState PXA2xxDMAState;
@@ -132,7 +128,7 @@ typedef struct {
qemu_irq *pic;
qemu_irq reset;
PXA2xxDMAState *dma;
- PXA2xxGPIOInfo *gpio;
+ DeviceState *gpio;
PXA2xxLCDState *lcd;
SSIBus **ssp;
PXA2xxI2CState *i2c[2];
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6e72a5c753..d966846f94 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -2158,7 +2158,7 @@ PXA2xxState *pxa270_init(unsigned int sdram_size, const char *revision)
/* GPIO1 resets the processor */
/* The handler can be overridden by board-specific code */
- pxa2xx_gpio_out_set(s->gpio, 1, s->reset);
+ qdev_connect_gpio_out(s->gpio, 1, s->reset);
return s;
}
@@ -2279,7 +2279,7 @@ PXA2xxState *pxa255_init(unsigned int sdram_size)
/* GPIO1 resets the processor */
/* The handler can be overridden by board-specific code */
- pxa2xx_gpio_out_set(s->gpio, 1, s->reset);
+ qdev_connect_gpio_out(s->gpio, 1, s->reset);
return s;
}
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index 0d034462d2..789965d88b 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -8,15 +8,18 @@
*/
#include "hw.h"
+#include "sysbus.h"
#include "pxa.h"
#define PXA2XX_GPIO_BANKS 4
+typedef struct PXA2xxGPIOInfo PXA2xxGPIOInfo;
struct PXA2xxGPIOInfo {
- qemu_irq *pic;
+ SysBusDevice busdev;
+ qemu_irq irq0, irq1, irqX;
int lines;
+ int ncpu;
CPUState *cpu_env;
- qemu_irq *in;
/* XXX: GNU C vectors are more suitable */
uint32_t ilevel[PXA2XX_GPIO_BANKS];
@@ -66,19 +69,19 @@ static struct {
static void pxa2xx_gpio_irq_update(PXA2xxGPIOInfo *s)
{
if (s->status[0] & (1 << 0))
- qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]);
+ qemu_irq_raise(s->irq0);
else
- qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]);
+ qemu_irq_lower(s->irq0);
if (s->status[0] & (1 << 1))
- qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]);
+ qemu_irq_raise(s->irq1);
else
- qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]);
+ qemu_irq_lower(s->irq1);
if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
- qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]);
+ qemu_irq_raise(s->irqX);
else
- qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]);
+ qemu_irq_lower(s->irqX);
}
/* Bitmap of pins used as standby and sleep wake-up sources. */
@@ -249,96 +252,89 @@ static CPUWriteMemoryFunc * const pxa2xx_gpio_writefn[] = {
pxa2xx_gpio_write
};
-static void pxa2xx_gpio_save(QEMUFile *f, void *opaque)
-{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int i;
-
- qemu_put_be32(f, s->lines);
-
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- qemu_put_be32s(f, &s->ilevel[i]);
- qemu_put_be32s(f, &s->olevel[i]);
- qemu_put_be32s(f, &s->dir[i]);
- qemu_put_be32s(f, &s->rising[i]);
- qemu_put_be32s(f, &s->falling[i]);
- qemu_put_be32s(f, &s->status[i]);
- qemu_put_be32s(f, &s->gafr[i * 2 + 0]);
- qemu_put_be32s(f, &s->gafr[i * 2 + 1]);
-
- qemu_put_be32s(f, &s->prev_level[i]);
- }
-}
-
-static int pxa2xx_gpio_load(QEMUFile *f, void *opaque, int version_id)
+DeviceState *pxa2xx_gpio_init(target_phys_addr_t base,
+ CPUState *env, qemu_irq *pic, int lines)
{
- PXA2xxGPIOInfo *s = (PXA2xxGPIOInfo *) opaque;
- int i;
+ DeviceState *dev;
- if (qemu_get_be32(f) != s->lines)
- return -EINVAL;
+ dev = qdev_create(NULL, "pxa2xx-gpio");
+ qdev_prop_set_int32(dev, "lines", lines);
+ qdev_prop_set_int32(dev, "ncpu", env->cpu_index);
+ qdev_init_nofail(dev);
- for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
- qemu_get_be32s(f, &s->ilevel[i]);
- qemu_get_be32s(f, &s->olevel[i]);
- qemu_get_be32s(f, &s->dir[i]);
- qemu_get_be32s(f, &s->rising[i]);
- qemu_get_be32s(f, &s->falling[i]);
- qemu_get_be32s(f, &s->status[i]);
- qemu_get_be32s(f, &s->gafr[i * 2 + 0]);
- qemu_get_be32s(f, &s->gafr[i * 2 + 1]);
-
- qemu_get_be32s(f, &s->prev_level[i]);
- }
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[PXA2XX_PIC_GPIO_0]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[PXA2XX_PIC_GPIO_1]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[PXA2XX_PIC_GPIO_X]);
- return 0;
+ return dev;
}
-PXA2xxGPIOInfo *pxa2xx_gpio_init(target_phys_addr_t base,
- CPUState *env, qemu_irq *pic, int lines)
+static int pxa2xx_gpio_initfn(SysBusDevice *dev)
{
int iomemtype;
PXA2xxGPIOInfo *s;
- s = (PXA2xxGPIOInfo *)
- qemu_mallocz(sizeof(PXA2xxGPIOInfo));
- memset(s, 0, sizeof(PXA2xxGPIOInfo));
- s->pic = pic;
- s->lines = lines;
- s->cpu_env = env;
- s->in = qemu_allocate_irqs(pxa2xx_gpio_set, s, lines);
+ s = FROM_SYSBUS(PXA2xxGPIOInfo, dev);
- iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn,
- pxa2xx_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
+ s->cpu_env = qemu_get_cpu(s->ncpu);
- register_savevm(NULL, "pxa2xx_gpio", 0, 0,
- pxa2xx_gpio_save, pxa2xx_gpio_load, s);
-
- return s;
-}
+ qdev_init_gpio_in(&dev->qdev, pxa2xx_gpio_set, s->lines);
+ qdev_init_gpio_out(&dev->qdev, s->handler, s->lines);
-qemu_irq *pxa2xx_gpio_in_get(PXA2xxGPIOInfo *s)
-{
- return s->in;
-}
+ iomemtype = cpu_register_io_memory(pxa2xx_gpio_readfn,
+ pxa2xx_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
-void pxa2xx_gpio_out_set(PXA2xxGPIOInfo *s,
- int line, qemu_irq handler)
-{
- if (line >= s->lines) {
- printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
- return;
- }
+ sysbus_init_mmio(dev, 0x1000, iomemtype);
+ sysbus_init_irq(dev, &s->irq0);
+ sysbus_init_irq(dev, &s->irq1);
+ sysbus_init_irq(dev, &s->irqX);
- s->handler[line] = handler;
+ return 0;
}
/*
* Registers a callback to notify on GPLR reads. This normally
* shouldn't be needed but it is used for the hack on Spitz machines.
*/
-void pxa2xx_gpio_read_notifier(PXA2xxGPIOInfo *s, qemu_irq handler)
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler)
{
+ PXA2xxGPIOInfo *s = FROM_SYSBUS(PXA2xxGPIOInfo, sysbus_from_qdev(dev));
s->read_notify = handler;
}
+
+static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
+ .name = "pxa2xx-gpio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(lines, PXA2xxGPIOInfo),
+ VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(dir, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(rising, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(falling, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(status, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
+ VMSTATE_UINT32_ARRAY(gafr, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS * 2),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static SysBusDeviceInfo pxa2xx_gpio_info = {
+ .init = pxa2xx_gpio_initfn,
+ .qdev.name = "pxa2xx-gpio",
+ .qdev.desc = "PXA2xx GPIO controller",
+ .qdev.size = sizeof(PXA2xxGPIOInfo),
+ .qdev.props = (Property []) {
+ DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
+ DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void pxa2xx_gpio_register(void)
+{
+ sysbus_register_withprop(&pxa2xx_gpio_info);
+}
+device_init(pxa2xx_gpio_register);
diff --git a/hw/qdev.c b/hw/qdev.c
index 5b8d3742ec..c7fec44a83 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -29,7 +29,6 @@
#include "qdev.h"
#include "sysemu.h"
#include "monitor.h"
-#include "blockdev.h"
static int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@@ -458,20 +457,6 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
}
}
-static int next_block_unit[IF_COUNT];
-
-/* Get a block device. This should only be used for single-drive devices
- (e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
- appropriate bus. */
-BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
-{
- int unit = next_block_unit[type]++;
- DriveInfo *dinfo;
-
- dinfo = drive_get(type, 0, unit);
- return dinfo ? dinfo->bdrv : NULL;
-}
-
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
{
BusState *bus;
diff --git a/hw/qdev.h b/hw/qdev.h
index e520aaa786..9808f85119 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -137,8 +137,6 @@ bool qdev_machine_modified(void);
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
-BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type);
-
BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
/*** Device API. ***/
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 7febb86e77..ceeb4ecb91 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -87,7 +87,8 @@ void scsi_qdev_register(SCSIDeviceInfo *info)
}
/* handle legacy '-drive if=scsi,...' cmd line args */
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit)
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+ int unit, bool removable)
{
const char *driver;
DeviceState *dev;
@@ -95,6 +96,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int
driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
dev = qdev_create(&bus->qbus, driver);
qdev_prop_set_uint32(dev, "scsi-id", unit);
+ if (qdev_prop_exists(dev, "removable")) {
+ qdev_prop_set_bit(dev, "removable", removable);
+ }
if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
qdev_free(dev);
return NULL;
@@ -117,7 +121,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
continue;
}
qemu_opts_loc_restore(dinfo->opts);
- if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit)) {
+ if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false)) {
res = -1;
break;
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6cb317c8f9..488eedd2cd 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -72,6 +72,7 @@ struct SCSIDiskState
/* The qemu block layer uses a fixed 512 byte sector size.
This is the number of 512 byte blocks in a single scsi sector. */
int cluster_size;
+ uint32_t removable;
uint64_t max_lba;
QEMUBH *bh;
char *version;
@@ -552,6 +553,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memcpy(&outbuf[16], "QEMU CD-ROM ", 16);
} else {
outbuf[0] = 0;
+ outbuf[1] = s->removable ? 0x80 : 0;
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
memcpy(&outbuf[8], "QEMU ", 8);
@@ -1295,6 +1297,7 @@ static SCSIDeviceInfo scsi_disk_info = {
DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),
DEFINE_PROP_STRING("ver", SCSIDiskState, version),
DEFINE_PROP_STRING("serial", SCSIDiskState, serial),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/scsi.h b/hw/scsi.h
index bf02adfbe2..d3b5d56cd6 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,9 +3,10 @@
#include "qdev.h"
#include "block.h"
-#include "blockdev.h"
#include "block_int.h"
+#define MAX_SCSI_DEVS 255
+
#define SCSI_CMD_BUF_SIZE 16
/* scsi-disk.c */
@@ -94,7 +95,8 @@ static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
}
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int unit);
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+ int unit, bool removable);
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
diff --git a/hw/sd.c b/hw/sd.c
index 601545b2d9..789ca84785 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -422,9 +422,14 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
sd->pwd_len = 0;
}
-static void sd_cardchange(void *opaque)
+static void sd_cardchange(void *opaque, int reason)
{
SDState *sd = opaque;
+
+ if (!(reason & CHANGE_MEDIA)) {
+ return;
+ }
+
qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
if (bdrv_is_inserted(sd->bdrv)) {
sd_reset(sd, sd->bdrv);
diff --git a/hw/sh7750.c b/hw/sh7750.c
index 36b702f628..19d5bf8537 100644
--- a/hw/sh7750.c
+++ b/hw/sh7750.c
@@ -625,6 +625,7 @@ static uint32_t invalid_read(void *opaque, target_phys_addr_t addr)
static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr)
{
+ SH7750State *s = opaque;
uint32_t ret = 0;
switch (MM_REGION_TYPE(addr)) {
@@ -633,19 +634,21 @@ static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr)
/* do nothing */
break;
case MM_ITLB_ADDR:
+ ret = cpu_sh4_read_mmaped_itlb_addr(s->cpu, addr);
+ break;
case MM_ITLB_DATA:
- /* XXXXX */
- abort();
- break;
+ ret = cpu_sh4_read_mmaped_itlb_data(s->cpu, addr);
+ break;
case MM_OCACHE_ADDR:
case MM_OCACHE_DATA:
/* do nothing */
break;
case MM_UTLB_ADDR:
+ ret = cpu_sh4_read_mmaped_utlb_addr(s->cpu, addr);
+ break;
case MM_UTLB_DATA:
- /* XXXXX */
- abort();
- break;
+ ret = cpu_sh4_read_mmaped_utlb_data(s->cpu, addr);
+ break;
default:
abort();
}
@@ -673,7 +676,7 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
cpu_sh4_write_mmaped_itlb_addr(s->cpu, addr, mem_value);
break;
case MM_ITLB_DATA:
- /* XXXXX */
+ cpu_sh4_write_mmaped_itlb_data(s->cpu, addr, mem_value);
abort();
break;
case MM_OCACHE_ADDR:
@@ -684,8 +687,7 @@ static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value);
break;
case MM_UTLB_DATA:
- /* XXXXX */
- abort();
+ cpu_sh4_write_mmaped_utlb_data(s->cpu, addr, mem_value);
break;
default:
abort();
diff --git a/hw/sharpsl.h b/hw/sharpsl.h
index c5ccf791f6..0b3a774f2f 100644
--- a/hw/sharpsl.h
+++ b/hw/sharpsl.h
@@ -10,13 +10,6 @@
fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
/* zaurus.c */
-typedef struct ScoopInfo ScoopInfo;
-ScoopInfo *scoop_init(PXA2xxState *cpu,
- int instance, target_phys_addr_t target_base);
-void scoop_gpio_set(void *opaque, int line, int level);
-qemu_irq *scoop_gpio_in_get(ScoopInfo *s);
-void scoop_gpio_out_set(ScoopInfo *s, int line,
- qemu_irq handler);
#define SL_PXA_PARAM_BASE 0xa0000a00
void sl_bootparam_write(target_phys_addr_t ptr);
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index fd69354bb3..a83e5b8272 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -289,7 +289,12 @@ static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
if (set_irqs) {
- for (j = MAX_PILS; j > 0; j--) {
+ /* Since there is not really an interrupt 0 (and pil_pending
+ * and irl_out bit zero are thus always zero) there is no need
+ * to do anything with cpu_irqs[i][0] and it is OK not to do
+ * the j=0 iteration of this loop.
+ */
+ for (j = MAX_PILS-1; j > 0; j--) {
if (pil_pending & (1 << j)) {
if (!(s->slaves[i].irl_out & (1 << j))) {
qemu_irq_raise(s->cpu_irqs[i][j]);
diff --git a/hw/spitz.c b/hw/spitz.c
index 092bb64eac..5b1e42dff3 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -23,6 +23,7 @@
#include "audio/audio.h"
#include "boards.h"
#include "blockdev.h"
+#include "sysbus.h"
#undef REG_FMT
#define REG_FMT "0x%02lx"
@@ -46,8 +47,11 @@
#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
typedef struct {
+ SysBusDevice busdev;
NANDFlashState *nand;
uint8_t ctl;
+ uint8_t manf_id;
+ uint8_t chip_id;
ECCState ecc;
} SLNANDState;
@@ -130,56 +134,53 @@ static void sl_writeb(void *opaque, target_phys_addr_t addr,
}
}
-static void sl_save(QEMUFile *f, void *opaque)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- qemu_put_8s(f, &s->ctl);
- ecc_put(f, &s->ecc);
-}
-
-static int sl_load(QEMUFile *f, void *opaque, int version_id)
-{
- SLNANDState *s = (SLNANDState *) opaque;
-
- qemu_get_8s(f, &s->ctl);
- ecc_get(f, &s->ecc);
-
- return 0;
-}
-
enum {
FLASH_128M,
FLASH_1024M,
};
+static CPUReadMemoryFunc * const sl_readfn[] = {
+ sl_readb,
+ sl_readb,
+ sl_readl,
+};
+static CPUWriteMemoryFunc * const sl_writefn[] = {
+ sl_writeb,
+ sl_writeb,
+ sl_writeb,
+};
+
static void sl_flash_register(PXA2xxState *cpu, int size)
{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "sl-nand");
+
+ qdev_prop_set_uint8(dev, "manf_id", NAND_MFR_SAMSUNG);
+ if (size == FLASH_128M)
+ qdev_prop_set_uint8(dev, "chip_id", 0x73);
+ else if (size == FLASH_1024M)
+ qdev_prop_set_uint8(dev, "chip_id", 0xf1);
+
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, FLASH_BASE);
+}
+
+static int sl_nand_init(SysBusDevice *dev) {
int iomemtype;
SLNANDState *s;
- CPUReadMemoryFunc * const sl_readfn[] = {
- sl_readb,
- sl_readb,
- sl_readl,
- };
- CPUWriteMemoryFunc * const sl_writefn[] = {
- sl_writeb,
- sl_writeb,
- sl_writeb,
- };
-
- s = (SLNANDState *) qemu_mallocz(sizeof(SLNANDState));
+
+ s = FROM_SYSBUS(SLNANDState, dev);
+
s->ctl = 0;
- if (size == FLASH_128M)
- s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73);
- else if (size == FLASH_1024M)
- s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1);
+ s->nand = nand_init(s->manf_id, s->chip_id);
iomemtype = cpu_register_io_memory(sl_readfn,
sl_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(FLASH_BASE, 0x40, iomemtype);
- register_savevm(NULL, "sl_flash", 0, 0, sl_save, sl_load, s);
+ sysbus_init_mmio(dev, 0x40, iomemtype);
+
+ return 0;
}
/* Spitz Keyboard */
@@ -218,11 +219,10 @@ static const int spitz_gpiomap[5] = {
SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
};
-static int spitz_gpio_invert[5] = { 0, 0, 0, 0, 0, };
typedef struct {
+ SysBusDevice busdev;
qemu_irq sense[SPITZ_KEY_SENSE_NUM];
- qemu_irq *strobe;
qemu_irq gpiomap[5];
int keymap[0x80];
uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
@@ -273,8 +273,7 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
/* Handle the additional keys */
if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
- qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80) ^
- spitz_gpio_invert[spitz_keycode & 0xf]);
+ qemu_set_irq(s->gpiomap[spitz_keycode & 0xf], (keycode < 0x80));
return;
}
@@ -292,8 +291,9 @@ static void spitz_keyboard_keydown(SpitzKeyboardState *s, int keycode)
#define QUEUE_KEY(c) s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
-static void spitz_keyboard_handler(SpitzKeyboardState *s, int keycode)
+static void spitz_keyboard_handler(void *opaque, int keycode)
{
+ SpitzKeyboardState *s = opaque;
uint16_t code;
int mapcode;
switch (keycode) {
@@ -439,34 +439,15 @@ static void spitz_keyboard_pre_map(SpitzKeyboardState *s)
s->imodifiers = 0;
s->fifopos = 0;
s->fifolen = 0;
- s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s);
- spitz_keyboard_tick(s);
}
#undef SHIFT
#undef CTRL
#undef FN
-static void spitz_keyboard_save(QEMUFile *f, void *opaque)
-{
- SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
- int i;
-
- qemu_put_be16s(f, &s->sense_state);
- qemu_put_be16s(f, &s->strobe_state);
- for (i = 0; i < 5; i ++)
- qemu_put_byte(f, spitz_gpio_invert[i]);
-}
-
-static int spitz_keyboard_load(QEMUFile *f, void *opaque, int version_id)
+static int spitz_keyboard_post_load(void *opaque, int version_id)
{
SpitzKeyboardState *s = (SpitzKeyboardState *) opaque;
- int i;
-
- qemu_get_be16s(f, &s->sense_state);
- qemu_get_be16s(f, &s->strobe_state);
- for (i = 0; i < 5; i ++)
- spitz_gpio_invert[i] = qemu_get_byte(f);
/* Release all pressed keys */
memset(s->keyrow, 0, sizeof(s->keyrow));
@@ -481,12 +462,40 @@ static int spitz_keyboard_load(QEMUFile *f, void *opaque, int version_id)
static void spitz_keyboard_register(PXA2xxState *cpu)
{
- int i, j;
+ int i;
+ DeviceState *dev;
SpitzKeyboardState *s;
- s = (SpitzKeyboardState *)
- qemu_mallocz(sizeof(SpitzKeyboardState));
- memset(s, 0, sizeof(SpitzKeyboardState));
+ dev = sysbus_create_simple("spitz-keyboard", -1, NULL);
+ s = FROM_SYSBUS(SpitzKeyboardState, sysbus_from_qdev(dev));
+
+ for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
+ qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(cpu->gpio, spitz_gpio_key_sense[i]));
+
+ for (i = 0; i < 5; i ++)
+ s->gpiomap[i] = qdev_get_gpio_in(cpu->gpio, spitz_gpiomap[i]);
+
+ if (!graphic_rotate)
+ s->gpiomap[4] = qemu_irq_invert(s->gpiomap[4]);
+
+ for (i = 0; i < 5; i++)
+ qemu_set_irq(s->gpiomap[i], 0);
+
+ for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
+ qdev_connect_gpio_out(cpu->gpio, spitz_gpio_key_strobe[i],
+ qdev_get_gpio_in(dev, i));
+
+ qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock));
+
+ qemu_add_kbd_event_handler(spitz_keyboard_handler, s);
+}
+
+static int spitz_keyboard_init(SysBusDevice *dev)
+{
+ SpitzKeyboardState *s;
+ int i, j;
+
+ s = FROM_SYSBUS(SpitzKeyboardState, dev);
for (i = 0; i < 0x80; i ++)
s->keymap[i] = -1;
@@ -495,22 +504,13 @@ static void spitz_keyboard_register(PXA2xxState *cpu)
if (spitz_keymap[i][j] != -1)
s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++)
- s->sense[i] = pxa2xx_gpio_in_get(cpu->gpio)[spitz_gpio_key_sense[i]];
-
- for (i = 0; i < 5; i ++)
- s->gpiomap[i] = pxa2xx_gpio_in_get(cpu->gpio)[spitz_gpiomap[i]];
-
- s->strobe = qemu_allocate_irqs(spitz_keyboard_strobe, s,
- SPITZ_KEY_STROBE_NUM);
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
- pxa2xx_gpio_out_set(cpu->gpio, spitz_gpio_key_strobe[i], s->strobe[i]);
-
spitz_keyboard_pre_map(s);
- qemu_add_kbd_event_handler((QEMUPutKBDEvent *) spitz_keyboard_handler, s);
- register_savevm(NULL, "spitz_keyboard", 0, 0,
- spitz_keyboard_save, spitz_keyboard_load, s);
+ s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s);
+ qdev_init_gpio_in(&dev->qdev, spitz_keyboard_strobe, SPITZ_KEY_STROBE_NUM);
+ qdev_init_gpio_out(&dev->qdev, s->sense, SPITZ_KEY_SENSE_NUM);
+
+ return 0;
}
/* LCD backlight controller */
@@ -526,8 +526,8 @@ static void spitz_keyboard_register(PXA2xxState *cpu)
typedef struct {
SSISlave ssidev;
- int bl_intensity;
- int bl_power;
+ uint32_t bl_intensity;
+ uint32_t bl_power;
} SpitzLCDTG;
static void spitz_bl_update(SpitzLCDTG *s)
@@ -591,21 +591,6 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
return 0;
}
-static void spitz_lcdtg_save(QEMUFile *f, void *opaque)
-{
- SpitzLCDTG *s = (SpitzLCDTG *)opaque;
- qemu_put_be32(f, s->bl_intensity);
- qemu_put_be32(f, s->bl_power);
-}
-
-static int spitz_lcdtg_load(QEMUFile *f, void *opaque, int version_id)
-{
- SpitzLCDTG *s = (SpitzLCDTG *)opaque;
- s->bl_intensity = qemu_get_be32(f);
- s->bl_power = qemu_get_be32(f);
- return 0;
-}
-
static int spitz_lcdtg_init(SSISlave *dev)
{
SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
@@ -614,8 +599,6 @@ static int spitz_lcdtg_init(SSISlave *dev)
s->bl_power = 0;
s->bl_intensity = 0x20;
- register_savevm(&dev->qdev, "spitz-lcdtg", -1, 1,
- spitz_lcdtg_save, spitz_lcdtg_load, s);
return 0;
}
@@ -634,7 +617,7 @@ static DeviceState *max1111;
typedef struct {
SSISlave ssidev;
SSIBus *bus[3];
- int enable[3];
+ uint32_t enable[3];
} CorgiSSPState;
static uint32_t corgi_ssp_transfer(SSISlave *dev, uint32_t value)
@@ -676,30 +659,6 @@ static void spitz_adc_temp_on(void *opaque, int line, int level)
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
}
-static void spitz_ssp_save(QEMUFile *f, void *opaque)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- int i;
-
- for (i = 0; i < 3; i++) {
- qemu_put_be32(f, s->enable[i]);
- }
-}
-
-static int spitz_ssp_load(QEMUFile *f, void *opaque, int version_id)
-{
- CorgiSSPState *s = (CorgiSSPState *)opaque;
- int i;
-
- if (version_id != 1) {
- return -EINVAL;
- }
- for (i = 0; i < 3; i++) {
- s->enable[i] = qemu_get_be32(f);
- }
- return 0;
-}
-
static int corgi_ssp_init(SSISlave *dev)
{
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
@@ -709,8 +668,6 @@ static int corgi_ssp_init(SSISlave *dev)
s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
- register_savevm(&dev->qdev, "spitz_ssp", -1, 1,
- spitz_ssp_save, spitz_ssp_load, s);
return 0;
}
@@ -728,7 +685,7 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
bus = qdev_get_child_bus(mux, "ssi1");
dev = ssi_create_slave(bus, "ads7846");
qdev_connect_gpio_out(dev, 0,
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_TP_INT]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_TP_INT));
bus = qdev_get_child_bus(mux, "ssi2");
max1111 = ssi_create_slave(bus, "max1111");
@@ -736,11 +693,11 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
qdev_get_gpio_in(mux, 0));
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
qdev_get_gpio_in(mux, 1));
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
qdev_get_gpio_in(mux, 2));
}
@@ -790,7 +747,7 @@ static void spitz_i2c_setup(PXA2xxState *cpu)
wm = i2c_create_slave(bus, "wm8750", 0);
spitz_wm8750_addr(wm, 0, 0);
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_WM,
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM,
qemu_allocate_irqs(spitz_wm8750_addr, wm, 1)[0]);
/* .. and to the sound interface. */
cpu->i2s->opaque = wm;
@@ -851,21 +808,21 @@ static void spitz_out_switch(void *opaque, int line, int level)
#define SPITZ_SCP2_MIC_BIAS 9
static void spitz_scoop_gpio_setup(PXA2xxState *cpu,
- ScoopInfo *scp0, ScoopInfo *scp1)
+ DeviceState *scp0, DeviceState *scp1)
{
qemu_irq *outsignals = qemu_allocate_irqs(spitz_out_switch, cpu, 8);
- scoop_gpio_out_set(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
- scoop_gpio_out_set(scp0, SPITZ_SCP_JK_B, outsignals[1]);
- scoop_gpio_out_set(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
- scoop_gpio_out_set(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_CHRG_ON, outsignals[0]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_JK_B, outsignals[1]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_GREEN, outsignals[2]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_LED_ORANGE, outsignals[3]);
if (scp1) {
- scoop_gpio_out_set(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
- scoop_gpio_out_set(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
+ qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_CONT, outsignals[4]);
+ qdev_connect_gpio_out(scp1, SPITZ_SCP2_BACKLIGHT_ON, outsignals[5]);
}
- scoop_gpio_out_set(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
+ qdev_connect_gpio_out(scp0, SPITZ_SCP_ADC_TEMP_ON, outsignals[6]);
}
#define SPITZ_GPIO_HSYNC 22
@@ -883,7 +840,7 @@ static int spitz_hsync;
static void spitz_lcd_hsync_handler(void *opaque, int line, int level)
{
PXA2xxState *cpu = (PXA2xxState *) opaque;
- qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_HSYNC], spitz_hsync);
+ qemu_set_irq(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_HSYNC), spitz_hsync);
spitz_hsync ^= 1;
}
@@ -903,36 +860,24 @@ static void spitz_gpio_setup(PXA2xxState *cpu, int slots)
/* MMC/SD host */
pxa2xx_mmci_handlers(cpu->mmc,
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_WP],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SD_DETECT]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_WP),
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_SD_DETECT));
/* Battery lock always closed */
- qemu_irq_raise(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_BAT_COVER]);
+ qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_BAT_COVER));
/* Handle reset */
- pxa2xx_gpio_out_set(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
+ qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_ON_RESET, cpu->reset);
/* PCMCIA signals: card's IRQ and Card-Detect */
if (slots >= 1)
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF1_IRQ],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF1_CD]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_IRQ),
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF1_CD));
if (slots >= 2)
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF2_IRQ],
- pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_CF2_CD]);
-
- /* Initialise the screen rotation related signals */
- spitz_gpio_invert[3] = 0; /* Always open */
- if (graphic_rotate) { /* Tablet mode */
- spitz_gpio_invert[4] = 0;
- } else { /* Portrait mode */
- spitz_gpio_invert[4] = 1;
- }
- qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SWA],
- spitz_gpio_invert[3]);
- qemu_set_irq(pxa2xx_gpio_in_get(cpu->gpio)[SPITZ_GPIO_SWB],
- spitz_gpio_invert[4]);
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_IRQ),
+ qdev_get_gpio_in(cpu->gpio, SPITZ_GPIO_CF2_CD));
}
/* Board init. */
@@ -952,7 +897,7 @@ static void spitz_common_init(ram_addr_t ram_size,
const char *cpu_model, enum spitz_model_e model, int arm_id)
{
PXA2xxState *cpu;
- ScoopInfo *scp0, *scp1 = NULL;
+ DeviceState *scp0, *scp1 = NULL;
if (!cpu_model)
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
@@ -970,9 +915,9 @@ static void spitz_common_init(ram_addr_t ram_size,
spitz_ssp_attach(cpu);
- scp0 = scoop_init(cpu, 0, 0x10800000);
+ scp0 = sysbus_create_simple("scoop", 0x10800000, NULL);
if (model != akita) {
- scp1 = scoop_init(cpu, 1, 0x08800040);
+ scp1 = sysbus_create_simple("scoop", 0x08800040, NULL);
}
spitz_scoop_gpio_setup(cpu, scp0, scp1);
@@ -1069,16 +1014,94 @@ static void spitz_machine_init(void)
machine_init(spitz_machine_init);
+static bool is_version_0(void *opaque, int version_id)
+{
+ return version_id == 0;
+}
+
+static VMStateDescription vmstate_sl_nand_info = {
+ .name = "sl-nand",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(ctl, SLNANDState),
+ VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static SysBusDeviceInfo sl_nand_info = {
+ .init = sl_nand_init,
+ .qdev.name = "sl-nand",
+ .qdev.size = sizeof(SLNANDState),
+ .qdev.vmsd = &vmstate_sl_nand_info,
+ .qdev.props = (Property []) {
+ DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+ DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static VMStateDescription vmstate_spitz_kbd = {
+ .name = "spitz-keyboard",
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .post_load = spitz_keyboard_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT16(sense_state, SpitzKeyboardState),
+ VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
+ VMSTATE_UNUSED_TEST(is_version_0, 5),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static SysBusDeviceInfo spitz_keyboard_info = {
+ .init = spitz_keyboard_init,
+ .qdev.name = "spitz-keyboard",
+ .qdev.size = sizeof(SpitzKeyboardState),
+ .qdev.vmsd = &vmstate_spitz_kbd,
+ .qdev.props = (Property []) {
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static const VMStateDescription vmstate_corgi_ssp_regs = {
+ .name = "corgi-ssp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
static SSISlaveInfo corgi_ssp_info = {
.qdev.name = "corgi-ssp",
.qdev.size = sizeof(CorgiSSPState),
+ .qdev.vmsd = &vmstate_corgi_ssp_regs,
.init = corgi_ssp_init,
.transfer = corgi_ssp_transfer
};
+static const VMStateDescription vmstate_spitz_lcdtg_regs = {
+ .name = "spitz-lcdtg",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
+ VMSTATE_UINT32(bl_power, SpitzLCDTG),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
static SSISlaveInfo spitz_lcdtg_info = {
.qdev.name = "spitz-lcdtg",
.qdev.size = sizeof(SpitzLCDTG),
+ .qdev.vmsd = &vmstate_spitz_lcdtg_regs,
.init = spitz_lcdtg_init,
.transfer = spitz_lcdtg_transfer
};
@@ -1087,6 +1110,8 @@ static void spitz_register_devices(void)
{
ssi_register_slave(&corgi_ssp_info);
ssi_register_slave(&spitz_lcdtg_info);
+ sysbus_register_withprop(&spitz_keyboard_info);
+ sysbus_register_withprop(&sl_nand_info);
}
device_init(spitz_register_devices)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index a1a63b23e2..fb4b649279 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -7,6 +7,7 @@
* This code is licenced under the GNU GPL v2.
*/
+#include "blockdev.h"
#include "ssi.h"
#include "sd.h"
@@ -231,11 +232,11 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
static int ssi_sd_init(SSISlave *dev)
{
ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
- BlockDriverState *bs;
+ DriveInfo *dinfo;
s->mode = SSI_SD_CMD;
- bs = qdev_init_bdrv(&dev->qdev, IF_SD);
- s->sd = sd_init(bs, 1);
+ dinfo = drive_get_next(IF_SD);
+ s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, 1);
register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
return 0;
}
diff --git a/hw/tosa.c b/hw/tosa.c
index cc8ce6d641..0bfab1634a 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -20,6 +20,7 @@
#include "i2c.h"
#include "ssi.h"
#include "blockdev.h"
+#include "sysbus.h"
#define TOSA_RAM 0x04000000
#define TOSA_ROM 0x00800000
@@ -86,34 +87,34 @@ static void tosa_out_switch(void *opaque, int line, int level)
static void tosa_gpio_setup(PXA2xxState *cpu,
- ScoopInfo *scp0,
- ScoopInfo *scp1,
+ DeviceState *scp0,
+ DeviceState *scp1,
TC6393xbState *tmio)
{
qemu_irq *outsignals = qemu_allocate_irqs(tosa_out_switch, cpu, 4);
/* MMC/SD host */
pxa2xx_mmci_handlers(cpu->mmc,
- scoop_gpio_in_get(scp0)[TOSA_GPIO_SD_WP],
- qemu_irq_invert(pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_nSD_DETECT]));
+ qdev_get_gpio_in(scp0, TOSA_GPIO_SD_WP),
+ qemu_irq_invert(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_nSD_DETECT)));
/* Handle reset */
- pxa2xx_gpio_out_set(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
+ qdev_connect_gpio_out(cpu->gpio, TOSA_GPIO_ON_RESET, cpu->reset);
/* PCMCIA signals: card's IRQ and Card-Detect */
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_CF_IRQ],
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_CF_CD]);
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_IRQ),
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_CF_CD));
pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_JC_CF_IRQ],
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_JC_CF_IRQ),
NULL);
- scoop_gpio_out_set(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_BT_LED, outsignals[0]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_NOTE_LED, outsignals[1]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_CHRG_ERR_LED, outsignals[2]);
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]);
- scoop_gpio_out_set(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
+ qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio));
}
static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
@@ -208,7 +209,7 @@ static void tosa_init(ram_addr_t ram_size,
{
PXA2xxState *cpu;
TC6393xbState *tmio;
- ScoopInfo *scp0, *scp1;
+ DeviceState *scp0, *scp1;
if (!cpu_model)
cpu_model = "pxa255";
@@ -219,10 +220,10 @@ static void tosa_init(ram_addr_t ram_size,
qemu_ram_alloc(NULL, "tosa.rom", TOSA_ROM) | IO_MEM_ROM);
tmio = tc6393xb_init(0x10000000,
- pxa2xx_gpio_in_get(cpu->gpio)[TOSA_GPIO_TC6393XB_INT]);
+ qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_TC6393XB_INT));
- scp0 = scoop_init(cpu, 0, 0x08800000);
- scp1 = scoop_init(cpu, 1, 0x14800040);
+ scp0 = sysbus_create_simple("scoop", 0x08800000, NULL);
+ scp1 = sysbus_create_simple("scoop", 0x14800040, NULL);
tosa_gpio_setup(cpu, scp0, scp1, tmio);
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 6e2e5fd17a..abc7e61a59 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -23,6 +23,22 @@ static struct BusInfo usb_bus_info = {
static int next_usb_bus = 0;
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
+const VMStateDescription vmstate_usb_device = {
+ .name = "USBDevice",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(addr, USBDevice),
+ VMSTATE_INT32(state, USBDevice),
+ VMSTATE_INT32(remote_wakeup, USBDevice),
+ VMSTATE_INT32(setup_state, USBDevice),
+ VMSTATE_INT32(setup_len, USBDevice),
+ VMSTATE_INT32(setup_index, USBDevice),
+ VMSTATE_UINT8_ARRAY(setup_buf, USBDevice, 8),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
void usb_bus_new(USBBus *bus, DeviceState *host)
{
qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
@@ -282,20 +298,22 @@ static char *usb_get_fw_dev_path(DeviceState *qdev)
{
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
char *fw_path, *in;
- int pos = 0;
+ ssize_t pos = 0, fw_len;
long nr;
- fw_path = qemu_malloc(32 + strlen(dev->port->path) * 6);
+ fw_len = 32 + strlen(dev->port->path) * 6;
+ fw_path = qemu_malloc(fw_len);
in = dev->port->path;
- while (true) {
+ while (fw_len - pos > 0) {
nr = strtol(in, &in, 10);
if (in[0] == '.') {
/* some hub between root port and device */
- pos += sprintf(fw_path + pos, "hub@%ld/", nr);
+ pos += snprintf(fw_path + pos, fw_len - pos, "hub@%ld/", nr);
in++;
} else {
/* the device itself */
- pos += sprintf(fw_path + pos, "%s@%ld", qdev_fw_name(qdev), nr);
+ pos += snprintf(fw_path + pos, fw_len - pos, "%s@%ld",
+ qdev_fw_name(qdev), nr);
break;
}
}
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 90a2b49e1d..79b20df57e 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -45,18 +45,27 @@
#define USB_TABLET 2
#define USB_KEYBOARD 3
+typedef struct USBPointerEvent {
+ int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+ int32_t dz, buttons_state;
+} USBPointerEvent;
+
+#define QUEUE_LENGTH 16 /* should be enough for a triple-click */
+#define QUEUE_MASK (QUEUE_LENGTH-1u)
+#define QUEUE_INCR(v) ((v)++, (v) &= QUEUE_MASK)
+
typedef struct USBMouseState {
- int dx, dy, dz, buttons_state;
- int x, y;
+ USBPointerEvent queue[QUEUE_LENGTH];
int mouse_grabbed;
QEMUPutMouseEntry *eh_entry;
} USBMouseState;
typedef struct USBKeyboardState {
+ uint32_t keycodes[QUEUE_LENGTH];
uint16_t modifiers;
uint8_t leds;
uint8_t key[16];
- int keys;
+ int32_t keys;
} USBKeyboardState;
typedef struct USBHIDState {
@@ -65,8 +74,10 @@ typedef struct USBHIDState {
USBMouseState ptr;
USBKeyboardState kbd;
};
+ uint32_t head; /* index into circular queue */
+ uint32_t n;
int kind;
- int protocol;
+ int32_t protocol;
uint8_t idle;
int64_t next_idle_clock;
int changed;
@@ -433,40 +444,79 @@ static void usb_hid_changed(USBHIDState *hs)
usb_wakeup(&hs->dev);
}
-static void usb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
+static void usb_pointer_event_clear(USBPointerEvent *e, int buttons) {
+ e->xdx = e->ydy = e->dz = 0;
+ e->buttons_state = buttons;
+}
+
+static void usb_pointer_event_combine(USBPointerEvent *e, int xyrel,
+ int x1, int y1, int z1) {
+ if (xyrel) {
+ e->xdx += x1;
+ e->ydy += y1;
+ } else {
+ e->xdx = x1;
+ e->ydy = y1;
+ }
+ e->dz += z1;
+}
+
+static void usb_pointer_event(void *opaque,
+ int x1, int y1, int z1, int buttons_state)
{
USBHIDState *hs = opaque;
USBMouseState *s = &hs->ptr;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
-
+ unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
+ unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
+
+ /* We combine events where feasible to keep the queue small. We shouldn't
+ * combine anything with the first event of a particular button state, as
+ * that would change the location of the button state change. When the
+ * queue is empty, a second event is needed because we don't know if
+ * the first event changed the button state. */
+ if (hs->n == QUEUE_LENGTH) {
+ /* Queue full. Discard old button state, combine motion normally. */
+ s->queue[use_slot].buttons_state = buttons_state;
+ } else if (hs->n < 2 ||
+ s->queue[use_slot].buttons_state != buttons_state ||
+ s->queue[previous_slot].buttons_state != s->queue[use_slot].buttons_state) {
+ /* Cannot or should not combine, so add an empty item to the queue. */
+ QUEUE_INCR(use_slot);
+ hs->n++;
+ usb_pointer_event_clear(&s->queue[use_slot], buttons_state);
+ }
+ usb_pointer_event_combine(&s->queue[use_slot],
+ hs->kind == USB_MOUSE,
+ x1, y1, z1);
usb_hid_changed(hs);
}
-static void usb_tablet_event(void *opaque,
- int x, int y, int dz, int buttons_state)
+static void usb_keyboard_event(void *opaque, int keycode)
{
USBHIDState *hs = opaque;
- USBMouseState *s = &hs->ptr;
-
- s->x = x;
- s->y = y;
- s->dz += dz;
- s->buttons_state = buttons_state;
+ USBKeyboardState *s = &hs->kbd;
+ int slot;
+ if (hs->n == QUEUE_LENGTH) {
+ fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+ return;
+ }
+ slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+ s->keycodes[slot] = keycode;
usb_hid_changed(hs);
}
-static void usb_keyboard_event(void *opaque, int keycode)
+static void usb_keyboard_process_keycode(USBHIDState *hs)
{
- USBHIDState *hs = opaque;
USBKeyboardState *s = &hs->kbd;
uint8_t hid_code, key;
- int i;
+ int i, keycode, slot;
+
+ if (hs->n == 0) {
+ return;
+ }
+ slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+ keycode = s->keycodes[slot];
key = keycode & 0x7f;
hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
@@ -499,7 +549,6 @@ static void usb_keyboard_event(void *opaque, int keycode)
if (s->key[i] == hid_code) {
s->key[i] = s->key[-- s->keys];
s->key[s->keys] = 0x00;
- usb_hid_changed(hs);
break;
}
if (i < 0)
@@ -514,8 +563,6 @@ static void usb_keyboard_event(void *opaque, int keycode)
} else
return;
}
-
- usb_hid_changed(hs);
}
static inline int int_clamp(int val, int vmin, int vmax)
@@ -528,86 +575,96 @@ static inline int int_clamp(int val, int vmin, int vmax)
return val;
}
-static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
+static int usb_pointer_poll(USBHIDState *hs, uint8_t *buf, int len)
{
int dx, dy, dz, b, l;
+ int index;
USBMouseState *s = &hs->ptr;
+ USBPointerEvent *e;
if (!s->mouse_grabbed) {
qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
+ s->mouse_grabbed = 1;
}
- dx = int_clamp(s->dx, -127, 127);
- dy = int_clamp(s->dy, -127, 127);
- dz = int_clamp(s->dz, -127, 127);
-
- s->dx -= dx;
- s->dy -= dy;
- s->dz -= dz;
+ /* When the buffer is empty, return the last event. Relative
+ movements will all be zero. */
+ index = (hs->n ? hs->head : hs->head - 1);
+ e = &s->queue[index & QUEUE_MASK];
- /* Appears we have to invert the wheel direction */
- dz = 0 - dz;
+ if (hs->kind == USB_MOUSE) {
+ dx = int_clamp(e->xdx, -127, 127);
+ dy = int_clamp(e->ydy, -127, 127);
+ e->xdx -= dx;
+ e->ydy -= dy;
+ } else {
+ dx = e->xdx;
+ dy = e->ydy;
+ }
+ dz = int_clamp(e->dz, -127, 127);
+ e->dz -= dz;
b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+ if (e->buttons_state & MOUSE_EVENT_LBUTTON)
b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+ if (e->buttons_state & MOUSE_EVENT_RBUTTON)
b |= 0x02;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+ if (e->buttons_state & MOUSE_EVENT_MBUTTON)
b |= 0x04;
- l = 0;
- if (len > l)
- buf[l ++] = b;
- if (len > l)
- buf[l ++] = dx;
- if (len > l)
- buf[l ++] = dy;
- if (len > l)
- buf[l ++] = dz;
- return l;
-}
-
-static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
-{
- int dz, b, l;
- USBMouseState *s = &hs->ptr;
-
- if (!s->mouse_grabbed) {
- qemu_activate_mouse_event_handler(s->eh_entry);
- s->mouse_grabbed = 1;
+ if (hs->n &&
+ !e->dz &&
+ (hs->kind == USB_TABLET || (!e->xdx && !e->ydy))) {
+ /* that deals with this event */
+ QUEUE_INCR(hs->head);
+ hs->n--;
}
- dz = int_clamp(s->dz, -127, 127);
- s->dz -= dz;
-
/* Appears we have to invert the wheel direction */
dz = 0 - dz;
- b = 0;
- if (s->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (s->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x02;
- if (s->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x04;
+ l = 0;
+ switch (hs->kind) {
+ case USB_MOUSE:
+ if (len > l)
+ buf[l++] = b;
+ if (len > l)
+ buf[l++] = dx;
+ if (len > l)
+ buf[l++] = dy;
+ if (len > l)
+ buf[l++] = dz;
+ break;
+
+ case USB_TABLET:
+ if (len > l)
+ buf[l++] = b;
+ if (len > l)
+ buf[l++] = dx & 0xff;
+ if (len > l)
+ buf[l++] = dx >> 8;
+ if (len > l)
+ buf[l++] = dy & 0xff;
+ if (len > l)
+ buf[l++] = dy >> 8;
+ if (len > l)
+ buf[l++] = dz;
+ break;
- buf[0] = b;
- buf[1] = s->x & 0xff;
- buf[2] = s->x >> 8;
- buf[3] = s->y & 0xff;
- buf[4] = s->y >> 8;
- buf[5] = dz;
- l = 6;
+ default:
+ abort();
+ }
return l;
}
-static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
+static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
{
+ USBKeyboardState *s = &hs->kbd;
if (len < 2)
return 0;
+ usb_keyboard_process_keycode(hs);
+
buf[0] = s->modifiers & 0xff;
buf[1] = 0;
if (s->keys > 6)
@@ -643,12 +700,9 @@ static void usb_mouse_handle_reset(USBDevice *dev)
{
USBHIDState *s = (USBHIDState *)dev;
- s->ptr.dx = 0;
- s->ptr.dy = 0;
- s->ptr.dz = 0;
- s->ptr.x = 0;
- s->ptr.y = 0;
- s->ptr.buttons_state = 0;
+ memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
+ s->head = 0;
+ s->n = 0;
s->protocol = 1;
}
@@ -657,6 +711,11 @@ static void usb_keyboard_handle_reset(USBDevice *dev)
USBHIDState *s = (USBHIDState *)dev;
qemu_add_kbd_event_handler(usb_keyboard_event, s);
+ memset(s->kbd.keycodes, 0, sizeof (s->kbd.keycodes));
+ s->head = 0;
+ s->n = 0;
+ memset(s->kbd.key, 0, sizeof (s->kbd.key));
+ s->kbd.keys = 0;
s->protocol = 1;
}
@@ -708,12 +767,10 @@ static int usb_hid_handle_control(USBDevice *dev, int request, int value,
}
break;
case GET_REPORT:
- if (s->kind == USB_MOUSE)
- ret = usb_mouse_poll(s, data, length);
- else if (s->kind == USB_TABLET)
- ret = usb_tablet_poll(s, data, length);
+ if (s->kind == USB_MOUSE || s->kind == USB_TABLET)
+ ret = usb_pointer_poll(s, data, length);
else if (s->kind == USB_KEYBOARD)
- ret = usb_keyboard_poll(&s->kbd, data, length);
+ ret = usb_keyboard_poll(s, data, length);
break;
case SET_REPORT:
if (s->kind == USB_KEYBOARD)
@@ -762,13 +819,13 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
return USB_RET_NAK;
usb_hid_set_next_idle(s, curtime);
- s->changed = 0;
- if (s->kind == USB_MOUSE)
- ret = usb_mouse_poll(s, p->data, p->len);
- else if (s->kind == USB_TABLET)
- ret = usb_tablet_poll(s, p->data, p->len);
- else if (s->kind == USB_KEYBOARD)
- ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
+ if (s->kind == USB_MOUSE || s->kind == USB_TABLET) {
+ ret = usb_pointer_poll(s, p->data, p->len);
+ }
+ else if (s->kind == USB_KEYBOARD) {
+ ret = usb_keyboard_poll(s, p->data, p->len);
+ }
+ s->changed = s->n > 0;
} else {
goto fail;
}
@@ -803,13 +860,13 @@ static int usb_hid_initfn(USBDevice *dev, int kind)
s->kind = kind;
if (s->kind == USB_MOUSE) {
- s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s,
+ s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
0, "QEMU USB Mouse");
} else if (s->kind == USB_TABLET) {
- s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s,
+ s->ptr.eh_entry = qemu_add_mouse_event_handler(usb_pointer_event, s,
1, "QEMU USB Tablet");
}
-
+
/* Force poll routine to be run and grab input the first time. */
s->changed = 1;
return 0;
@@ -838,12 +895,72 @@ void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
s->datain = datain;
}
+static int usb_hid_post_load(void *opaque, int version_id)
+{
+ USBHIDState *s = opaque;
+
+ if (s->idle) {
+ usb_hid_set_next_idle(s, qemu_get_clock(vm_clock));
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_usb_ptr_queue = {
+ .name = "usb-ptr-queue",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(xdx, USBPointerEvent),
+ VMSTATE_INT32(ydy, USBPointerEvent),
+ VMSTATE_INT32(dz, USBPointerEvent),
+ VMSTATE_INT32(buttons_state, USBPointerEvent),
+ VMSTATE_END_OF_LIST()
+ }
+};
+static const VMStateDescription vmstate_usb_ptr = {
+ .name = "usb-ptr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = usb_hid_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_USB_DEVICE(dev, USBHIDState),
+ VMSTATE_STRUCT_ARRAY(ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
+ vmstate_usb_ptr_queue, USBPointerEvent),
+ VMSTATE_UINT32(head, USBHIDState),
+ VMSTATE_UINT32(n, USBHIDState),
+ VMSTATE_INT32(protocol, USBHIDState),
+ VMSTATE_UINT8(idle, USBHIDState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_usb_kbd = {
+ .name = "usb-kbd",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = usb_hid_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_USB_DEVICE(dev, USBHIDState),
+ VMSTATE_UINT32_ARRAY(kbd.keycodes, USBHIDState, QUEUE_LENGTH),
+ VMSTATE_UINT32(head, USBHIDState),
+ VMSTATE_UINT32(n, USBHIDState),
+ VMSTATE_UINT16(kbd.modifiers, USBHIDState),
+ VMSTATE_UINT8(kbd.leds, USBHIDState),
+ VMSTATE_UINT8_ARRAY(kbd.key, USBHIDState, 16),
+ VMSTATE_INT32(kbd.keys, USBHIDState),
+ VMSTATE_INT32(protocol, USBHIDState),
+ VMSTATE_UINT8(idle, USBHIDState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static struct USBDeviceInfo hid_info[] = {
{
.product_desc = "QEMU USB Tablet",
.qdev.name = "usb-tablet",
.usbdevice_name = "tablet",
.qdev.size = sizeof(USBHIDState),
+ .qdev.vmsd = &vmstate_usb_ptr,
.usb_desc = &desc_tablet,
.init = usb_tablet_initfn,
.handle_packet = usb_generic_handle_packet,
@@ -856,6 +973,7 @@ static struct USBDeviceInfo hid_info[] = {
.qdev.name = "usb-mouse",
.usbdevice_name = "mouse",
.qdev.size = sizeof(USBHIDState),
+ .qdev.vmsd = &vmstate_usb_ptr,
.usb_desc = &desc_mouse,
.init = usb_mouse_initfn,
.handle_packet = usb_generic_handle_packet,
@@ -868,6 +986,7 @@ static struct USBDeviceInfo hid_info[] = {
.qdev.name = "usb-kbd",
.usbdevice_name = "keyboard",
.qdev.size = sizeof(USBHIDState),
+ .qdev.vmsd = &vmstate_usb_kbd,
.usb_desc = &desc_keyboard,
.init = usb_keyboard_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 78698caf67..3dd31ba31f 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -544,11 +544,35 @@ static int usb_hub_initfn(USBDevice *dev)
return 0;
}
+static const VMStateDescription vmstate_usb_hub_port = {
+ .name = "usb-hub-port",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT16(wPortStatus, USBHubPort),
+ VMSTATE_UINT16(wPortChange, USBHubPort),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_usb_hub = {
+ .name = "usb-hub",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_USB_DEVICE(dev, USBHubState),
+ VMSTATE_STRUCT_ARRAY(ports, USBHubState, NUM_PORTS, 0,
+ vmstate_usb_hub_port, USBHubPort),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static struct USBDeviceInfo hub_info = {
.product_desc = "QEMU USB Hub",
.qdev.name = "usb-hub",
.qdev.fw_name = "hub",
.qdev.size = sizeof(USBHubState),
+ .qdev.vmsd = &vmstate_usb_hub,
.usb_desc = &desc_hub,
.init = usb_hub_initfn,
.handle_packet = usb_hub_handle_packet,
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 729d96ccc3..97d1e4af13 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -51,6 +51,7 @@ typedef struct {
SCSIBus bus;
BlockConf conf;
SCSIDevice *scsi_dev;
+ uint32_t removable;
int result;
/* For async completion. */
USBPacket *packet;
@@ -515,7 +516,7 @@ static int usb_msd_initfn(USBDevice *dev)
usb_desc_init(dev);
scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, usb_msd_command_complete);
- s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0);
+ s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
if (!s->scsi_dev) {
return -1;
}
@@ -541,7 +542,6 @@ static USBDevice *usb_msd_init(const char *filename)
QemuOpts *opts;
DriveInfo *dinfo;
USBDevice *dev;
- int fatal_error;
const char *p1;
char fmt[32];
@@ -571,7 +571,7 @@ static USBDevice *usb_msd_init(const char *filename)
qemu_opt_set(opts, "if", "none");
/* create host drive */
- dinfo = drive_init(opts, 0, &fatal_error);
+ dinfo = drive_init(opts, 0);
if (!dinfo) {
qemu_opts_del(opts);
return NULL;
@@ -607,6 +607,7 @@ static struct USBDeviceInfo msd_info = {
.usbdevice_init = usb_msd_init,
.qdev.props = (Property[]) {
DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+ DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/usb.h b/hw/usb.h
index 5c1da3ed25..d3d755db7b 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -165,13 +165,13 @@ struct USBDevice {
int auto_attach;
int attached;
- int state;
+ int32_t state;
uint8_t setup_buf[8];
uint8_t data_buf[1024];
- int remote_wakeup;
- int setup_state;
- int setup_len;
- int setup_index;
+ int32_t remote_wakeup;
+ int32_t setup_state;
+ int32_t setup_len;
+ int32_t setup_index;
QLIST_HEAD(, USBDescString) strings;
const USBDescDevice *device;
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index f62ccd1fe8..ffac5a4d8f 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -55,7 +55,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
trace_virtio_blk_req_complete(req, status);
- req->in->status = status;
+ stb_p(&req->in->status, status);
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
virtio_notify(&s->vdev, s->vq);
@@ -94,7 +94,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
trace_virtio_blk_rw_complete(req, ret);
if (ret) {
- int is_read = !(req->out->type & VIRTIO_BLK_T_OUT);
+ int is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
if (virtio_blk_handle_rw_error(req, -ret, is_read))
return;
}
@@ -223,10 +223,10 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
status = VIRTIO_BLK_S_OK;
}
- req->scsi->errors = hdr.status;
- req->scsi->residual = hdr.resid;
- req->scsi->sense_len = hdr.sb_len_wr;
- req->scsi->data_len = hdr.dxfer_len;
+ stl_p(&req->scsi->errors, hdr.status);
+ stl_p(&req->scsi->residual, hdr.resid);
+ stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
+ stl_p(&req->scsi->data_len, hdr.dxfer_len);
virtio_blk_req_complete(req, status);
}
@@ -280,10 +280,13 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
BlockRequest *blkreq;
+ uint64_t sector;
- trace_virtio_blk_handle_write(req, req->out->sector, req->qiov.size / 512);
+ sector = ldq_p(&req->out->sector);
- if (req->out->sector & req->dev->sector_mask) {
+ trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
+
+ if (sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
}
@@ -293,7 +296,7 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
}
blkreq = &mrb->blkreq[mrb->num_writes];
- blkreq->sector = req->out->sector;
+ blkreq->sector = sector;
blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
blkreq->qiov = &req->qiov;
blkreq->cb = virtio_blk_rw_complete;
@@ -306,13 +309,16 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
static void virtio_blk_handle_read(VirtIOBlockReq *req)
{
BlockDriverAIOCB *acb;
+ uint64_t sector;
+
+ sector = ldq_p(&req->out->sector);
- if (req->out->sector & req->dev->sector_mask) {
+ if (sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
}
- acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
+ acb = bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
req->qiov.size / BDRV_SECTOR_SIZE,
virtio_blk_rw_complete, req);
if (!acb) {
@@ -323,6 +329,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
static void virtio_blk_handle_request(VirtIOBlockReq *req,
MultiReqBuffer *mrb)
{
+ uint32_t type;
+
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
error_report("virtio-blk missing headers");
exit(1);
@@ -337,17 +345,19 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
req->out = (void *)req->elem.out_sg[0].iov_base;
req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
- if (req->out->type & VIRTIO_BLK_T_FLUSH) {
+ type = ldl_p(&req->out->type);
+
+ if (type & VIRTIO_BLK_T_FLUSH) {
virtio_blk_handle_flush(req, mrb);
- } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
+ } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
virtio_blk_handle_scsi(req);
- } else if (req->out->type & VIRTIO_BLK_T_GET_ID) {
+ } else if (type & VIRTIO_BLK_T_GET_ID) {
VirtIOBlock *s = req->dev;
memcpy(req->elem.in_sg[0].iov_base, s->sn,
MIN(req->elem.in_sg[0].iov_len, sizeof(s->sn)));
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
- } else if (req->out->type & VIRTIO_BLK_T_OUT) {
+ } else if (type & VIRTIO_BLK_T_OUT) {
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
req->elem.out_num - 1);
virtio_blk_handle_write(req, mrb);
@@ -504,6 +514,15 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static void virtio_blk_change_cb(void *opaque, int reason)
+{
+ VirtIOBlock *s = opaque;
+
+ if (reason & CHANGE_SIZE) {
+ virtio_notify_config(&s->vdev);
+ }
+}
+
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
{
VirtIOBlock *s;
@@ -546,6 +565,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
bdrv_set_removable(s->bs, 0);
+ bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s);
s->bs->buffer_alignment = conf->logical_block_size;
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index caea11f3a8..62624ec780 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -20,11 +20,11 @@ typedef struct VirtConsole {
/* Callback function that's called when the guest sends us data */
-static void flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
{
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
- qemu_chr_write(vcon->chr, buf, len);
+ return qemu_chr_write(vcon->chr, buf, len);
}
/* Readiness of the guest to accept data on a port */
@@ -48,34 +48,37 @@ static void chr_event(void *opaque, int event)
VirtConsole *vcon = opaque;
switch (event) {
- case CHR_EVENT_OPENED: {
+ case CHR_EVENT_OPENED:
virtio_serial_open(&vcon->port);
break;
- }
case CHR_EVENT_CLOSED:
virtio_serial_close(&vcon->port);
break;
}
}
-/* Virtio Console Ports */
-static int virtconsole_initfn(VirtIOSerialDevice *dev)
+static int generic_port_init(VirtConsole *vcon, VirtIOSerialDevice *dev)
{
- VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
- VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-
- port->info = dev->info;
-
- port->is_console = true;
+ vcon->port.info = dev->info;
if (vcon->chr) {
qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
vcon);
- port->info->have_data = flush_buf;
+ vcon->port.info->have_data = flush_buf;
}
return 0;
}
+/* Virtio Console Ports */
+static int virtconsole_initfn(VirtIOSerialDevice *dev)
+{
+ VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+ VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+ port->is_console = true;
+ return generic_port_init(vcon, dev);
+}
+
static int virtconsole_exitfn(VirtIOSerialDevice *dev)
{
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
@@ -115,14 +118,7 @@ static int virtserialport_initfn(VirtIOSerialDevice *dev)
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
- port->info = dev->info;
-
- if (vcon->chr) {
- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
- vcon);
- port->info->have_data = flush_buf;
- }
- return 0;
+ return generic_port_init(vcon, dev);
}
static VirtIOSerialPortInfo virtserialport_info = {
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index ccb3e632a4..161f11445f 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -79,7 +79,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
VirtIONet *n = to_virtio_net(vdev);
struct virtio_net_config netcfg;
- netcfg.status = n->status;
+ netcfg.status = lduw_p(&n->status);
memcpy(netcfg.mac, n->mac, ETH_ALEN);
memcpy(config, &netcfg, sizeof(netcfg));
}
@@ -338,7 +338,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
n->mac_table.multi_overflow = 0;
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
- mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
+ mac_data.entries = ldl_p(elem->out_sg[1].iov_base);
if (sizeof(mac_data.entries) +
(mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
@@ -354,7 +354,7 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
n->mac_table.first_multi = n->mac_table.in_use;
- mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
+ mac_data.entries = ldl_p(elem->out_sg[2].iov_base);
if (sizeof(mac_data.entries) +
(mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
@@ -384,7 +384,7 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR;
}
- vid = lduw_le_p(elem->out_sg[1].iov_base);
+ vid = lduw_p(elem->out_sg[1].iov_base);
if (vid >= MAX_VLAN)
return VIRTIO_NET_ERR;
@@ -673,8 +673,9 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
virtqueue_fill(n->rx_vq, &elem, total, i++);
}
- if (mhdr)
- mhdr->num_buffers = i;
+ if (mhdr) {
+ mhdr->num_buffers = lduw_p(&i);
+ }
virtqueue_flush(n->rx_vq, i);
virtio_notify(&n->vdev, n->rx_vq);
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index b728040f3a..09e22aa44a 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -113,39 +113,74 @@ static size_t write_to_port(VirtIOSerialPort *port,
return offset;
}
-static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
- VirtIODevice *vdev, bool discard)
+static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
{
VirtQueueElement elem;
- assert(port || discard);
+ while (virtqueue_pop(vq, &elem)) {
+ virtqueue_push(vq, &elem, 0);
+ }
+ virtio_notify(vdev, vq);
+}
+
+static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
+ VirtIODevice *vdev)
+{
+ assert(port);
assert(virtio_queue_ready(vq));
- while ((discard || !port->throttled) && virtqueue_pop(vq, &elem)) {
- uint8_t *buf;
- size_t ret, buf_size;
+ while (!port->throttled) {
+ unsigned int i;
- if (!discard) {
- buf_size = iov_size(elem.out_sg, elem.out_num);
- buf = qemu_malloc(buf_size);
- ret = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, buf_size);
+ /* Pop an elem only if we haven't left off a previous one mid-way */
+ if (!port->elem.out_num) {
+ if (!virtqueue_pop(vq, &port->elem)) {
+ break;
+ }
+ port->iov_idx = 0;
+ port->iov_offset = 0;
+ }
- port->info->have_data(port, buf, ret);
- qemu_free(buf);
+ for (i = port->iov_idx; i < port->elem.out_num; i++) {
+ size_t buf_size;
+ ssize_t ret;
+
+ buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
+ ret = port->info->have_data(port,
+ port->elem.out_sg[i].iov_base
+ + port->iov_offset,
+ buf_size);
+ if (ret < 0 && ret != -EAGAIN) {
+ /* We don't handle any other type of errors here */
+ abort();
+ }
+ if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) {
+ virtio_serial_throttle_port(port, true);
+ port->iov_idx = i;
+ if (ret > 0) {
+ port->iov_offset += ret;
+ }
+ break;
+ }
+ port->iov_offset = 0;
}
- virtqueue_push(vq, &elem, 0);
+ if (port->throttled) {
+ break;
+ }
+ virtqueue_push(vq, &port->elem, 0);
+ port->elem.out_num = 0;
}
virtio_notify(vdev, vq);
}
-static void flush_queued_data(VirtIOSerialPort *port, bool discard)
+static void flush_queued_data(VirtIOSerialPort *port)
{
assert(port);
if (!virtio_queue_ready(port->ovq)) {
return;
}
- do_flush_queued_data(port, port->ovq, &port->vser->vdev, discard);
+ do_flush_queued_data(port, port->ovq, &port->vser->vdev);
}
static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
@@ -204,7 +239,7 @@ int virtio_serial_close(VirtIOSerialPort *port)
* consume, reset the throttling flag and discard the data.
*/
port->throttled = false;
- flush_queued_data(port, true);
+ discard_vq_data(port->ovq, &port->vser->vdev);
send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
@@ -258,7 +293,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
return;
}
- flush_queued_data(port, false);
+ flush_queued_data(port);
}
/* Guest wants to notify us of some event */
@@ -414,11 +449,15 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
discard = true;
}
- if (!discard && port->throttled) {
+ if (discard) {
+ discard_vq_data(vq, vdev);
+ return;
+ }
+ if (port->throttled) {
return;
}
- do_flush_queued_data(port, vq, vdev, discard);
+ do_flush_queued_data(port, vq, vdev);
}
static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
@@ -488,9 +527,24 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
* Items in struct VirtIOSerialPort.
*/
QTAILQ_FOREACH(port, &s->ports, next) {
+ uint32_t elem_popped;
+
qemu_put_be32s(f, &port->id);
qemu_put_byte(f, port->guest_connected);
qemu_put_byte(f, port->host_connected);
+
+ elem_popped = 0;
+ if (port->elem.out_num) {
+ elem_popped = 1;
+ }
+ qemu_put_be32s(f, &elem_popped);
+ if (elem_popped) {
+ qemu_put_be32s(f, &port->iov_idx);
+ qemu_put_be64s(f, &port->iov_offset);
+
+ qemu_put_buffer(f, (unsigned char *)&port->elem,
+ sizeof(port->elem));
+ }
}
}
@@ -501,7 +555,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
uint32_t max_nr_ports, nr_active_ports, ports_map;
unsigned int i;
- if (version_id > 2) {
+ if (version_id > 3) {
return -EINVAL;
}
@@ -554,6 +608,29 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
port->host_connected);
}
+
+ if (version_id > 2) {
+ uint32_t elem_popped;
+
+ qemu_get_be32s(f, &elem_popped);
+ if (elem_popped) {
+ qemu_get_be32s(f, &port->iov_idx);
+ qemu_get_be64s(f, &port->iov_offset);
+
+ qemu_get_buffer(f, (unsigned char *)&port->elem,
+ sizeof(port->elem));
+ virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
+ port->elem.in_num, 1);
+ virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
+ port->elem.out_num, 1);
+
+ /*
+ * Port was throttled on source machine. Let's
+ * unthrottle it here so data starts flowing again.
+ */
+ virtio_serial_throttle_port(port, false);
+ }
+ }
}
return 0;
}
@@ -634,7 +711,7 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
port = find_port_by_id(vser, port_id);
/* Flush out any unconsumed buffers first */
- flush_queued_data(port, true);
+ discard_vq_data(port->ovq, &port->vser->vdev);
send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
}
@@ -695,6 +772,8 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
port->guest_connected = true;
}
+ port->elem.out_num = 0;
+
QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
port->ivq = port->vser->ivqs[port->id];
port->ovq = port->vser->ovqs[port->id];
@@ -806,7 +885,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
* Register for the savevm section with the virtio-console name
* to preserve backward compat
*/
- register_savevm(dev, "virtio-console", -1, 2, virtio_serial_save,
+ register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
virtio_serial_load, vser);
return vdev;
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index ff08c40681..a308196786 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -102,6 +102,23 @@ struct VirtIOSerialPort {
*/
uint32_t id;
+ /*
+ * This is the elem that we pop from the virtqueue. A slow
+ * backend that consumes guest data (e.g. the file backend for
+ * qemu chardevs) can cause the guest to block till all the output
+ * is flushed. This isn't desired, so we keep a note of the last
+ * element popped and continue consuming it once the backend
+ * becomes writable again.
+ */
+ VirtQueueElement elem;
+
+ /*
+ * The index and the offset into the iov buffer that was popped in
+ * elem above.
+ */
+ uint32_t iov_idx;
+ uint64_t iov_offset;
+
/* Identify if this is a port that binds with hvc in the guest */
uint8_t is_console;
@@ -137,10 +154,11 @@ struct VirtIOSerialPortInfo {
/*
* Guest wrote some data to the port. This data is handed over to
- * the app via this callback. The app is supposed to consume all
- * the data that is presented to it.
+ * the app via this callback. The app can return a size less than
+ * 'len'. In this case, throttling will be enabled for this port.
*/
- void (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, size_t len);
+ ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
+ size_t len);
};
/* Interface to the virtio-serial bus */
diff --git a/hw/zaurus.c b/hw/zaurus.c
index 36be94a179..fca11a5333 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -18,15 +18,17 @@
#include "hw.h"
#include "pxa.h"
#include "sharpsl.h"
+#include "sysbus.h"
#undef REG_FMT
#define REG_FMT "0x%02lx"
/* SCOOP devices */
+typedef struct ScoopInfo ScoopInfo;
struct ScoopInfo {
+ SysBusDevice busdev;
qemu_irq handler[16];
- qemu_irq *in;
uint16_t status;
uint16_t power;
uint32_t gpio_level;
@@ -153,7 +155,7 @@ static CPUWriteMemoryFunc * const scoop_writefn[] = {
scoop_writeb,
};
-void scoop_gpio_set(void *opaque, int line, int level)
+static void scoop_gpio_set(void *opaque, int line, int level)
{
ScoopInfo *s = (ScoopInfo *) opaque;
@@ -163,77 +165,66 @@ void scoop_gpio_set(void *opaque, int line, int level)
s->gpio_level &= ~(1 << line);
}
-qemu_irq *scoop_gpio_in_get(ScoopInfo *s)
+static int scoop_init(SysBusDevice *dev)
{
- return s->in;
-}
+ ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev);
+ int iomemtype;
-void scoop_gpio_out_set(ScoopInfo *s, int line,
- qemu_irq handler) {
- if (line >= 16) {
- fprintf(stderr, "No GPIO pin %i\n", line);
- exit(-1);
- }
+ s->status = 0x02;
+ qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16);
+ qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16);
+ iomemtype = cpu_register_io_memory(scoop_readfn,
+ scoop_writefn, s, DEVICE_NATIVE_ENDIAN);
- s->handler[line] = handler;
-}
+ sysbus_init_mmio(dev, 0x1000, iomemtype);
-static void scoop_save(QEMUFile *f, void *opaque)
-{
- ScoopInfo *s = (ScoopInfo *) opaque;
- qemu_put_be16s(f, &s->status);
- qemu_put_be16s(f, &s->power);
- qemu_put_be32s(f, &s->gpio_level);
- qemu_put_be32s(f, &s->gpio_dir);
- qemu_put_be32s(f, &s->prev_level);
- qemu_put_be16s(f, &s->mcr);
- qemu_put_be16s(f, &s->cdr);
- qemu_put_be16s(f, &s->ccr);
- qemu_put_be16s(f, &s->irr);
- qemu_put_be16s(f, &s->imr);
- qemu_put_be16s(f, &s->isr);
+ return 0;
}
-static int scoop_load(QEMUFile *f, void *opaque, int version_id)
+static bool is_version_0 (void *opaque, int version_id)
{
- uint16_t dummy;
- ScoopInfo *s = (ScoopInfo *) opaque;
- qemu_get_be16s(f, &s->status);
- qemu_get_be16s(f, &s->power);
- qemu_get_be32s(f, &s->gpio_level);
- qemu_get_be32s(f, &s->gpio_dir);
- qemu_get_be32s(f, &s->prev_level);
- qemu_get_be16s(f, &s->mcr);
- qemu_get_be16s(f, &s->cdr);
- qemu_get_be16s(f, &s->ccr);
- qemu_get_be16s(f, &s->irr);
- qemu_get_be16s(f, &s->imr);
- qemu_get_be16s(f, &s->isr);
- if (version_id < 1)
- qemu_get_be16s(f, &dummy);
-
- return 0;
+ return version_id == 0;
}
-ScoopInfo *scoop_init(PXA2xxState *cpu,
- int instance,
- target_phys_addr_t target_base) {
- int iomemtype;
- ScoopInfo *s;
- s = (ScoopInfo *)
- qemu_mallocz(sizeof(ScoopInfo));
- memset(s, 0, sizeof(ScoopInfo));
+static const VMStateDescription vmstate_scoop_regs = {
+ .name = "scoop",
+ .version_id = 1,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT16(status, ScoopInfo),
+ VMSTATE_UINT16(power, ScoopInfo),
+ VMSTATE_UINT32(gpio_level, ScoopInfo),
+ VMSTATE_UINT32(gpio_dir, ScoopInfo),
+ VMSTATE_UINT32(prev_level, ScoopInfo),
+ VMSTATE_UINT16(mcr, ScoopInfo),
+ VMSTATE_UINT16(cdr, ScoopInfo),
+ VMSTATE_UINT16(ccr, ScoopInfo),
+ VMSTATE_UINT16(irr, ScoopInfo),
+ VMSTATE_UINT16(imr, ScoopInfo),
+ VMSTATE_UINT16(isr, ScoopInfo),
+ VMSTATE_UNUSED_TEST(is_version_0, 2),
+ VMSTATE_END_OF_LIST(),
+ },
+};
- s->status = 0x02;
- s->in = qemu_allocate_irqs(scoop_gpio_set, s, 16);
- iomemtype = cpu_register_io_memory(scoop_readfn,
- scoop_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(target_base, 0x1000, iomemtype);
- register_savevm(NULL, "scoop", instance, 1, scoop_save, scoop_load, s);
+static SysBusDeviceInfo scoop_sysbus_info = {
+ .init = scoop_init,
+ .qdev.name = "scoop",
+ .qdev.desc = "Scoop2 Sharp custom ASIC",
+ .qdev.size = sizeof(ScoopInfo),
+ .qdev.vmsd = &vmstate_scoop_regs,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
- return s;
+static void scoop_register(void)
+{
+ sysbus_register_withprop(&scoop_sysbus_info);
}
+device_init(scoop_register);
/* Write the bootloader parameters memory area. */