diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/device-hotplug.c | 5 | ||||
-rw-r--r-- | hw/ecc.c | 27 | ||||
-rw-r--r-- | hw/escc.c | 8 | ||||
-rw-r--r-- | hw/etraxfs_timer.c | 4 | ||||
-rw-r--r-- | hw/flash.h | 3 | ||||
-rw-r--r-- | hw/grlib.h | 126 | ||||
-rw-r--r-- | hw/grlib_apbuart.c | 187 | ||||
-rw-r--r-- | hw/grlib_gptimer.c | 395 | ||||
-rw-r--r-- | hw/grlib_irqmp.c | 376 | ||||
-rw-r--r-- | hw/gumstix.c | 4 | ||||
-rw-r--r-- | hw/hw.h | 10 | ||||
-rw-r--r-- | hw/ide.h | 2 | ||||
-rw-r--r-- | hw/ide/ahci.c | 11 | ||||
-rw-r--r-- | hw/ide/core.c | 119 | ||||
-rw-r--r-- | hw/ide/internal.h | 4 | ||||
-rw-r--r-- | hw/ide/pci.c | 13 | ||||
-rw-r--r-- | hw/leon3.c | 217 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 15 | ||||
-rw-r--r-- | hw/mips_fulong2e.c | 4 | ||||
-rw-r--r-- | hw/mips_jazz.c | 24 | ||||
-rw-r--r-- | hw/mips_malta.c | 23 | ||||
-rw-r--r-- | hw/onenand.c | 1 | ||||
-rw-r--r-- | hw/pc.c | 17 | ||||
-rw-r--r-- | hw/pc.h | 3 | ||||
-rw-r--r-- | hw/pc_piix.c | 3 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 3 | ||||
-rw-r--r-- | hw/pci.c | 4 | ||||
-rw-r--r-- | hw/pl181.c | 7 | ||||
-rw-r--r-- | hw/ppc_prep.c | 5 | ||||
-rw-r--r-- | hw/pxa.h | 10 | ||||
-rw-r--r-- | hw/pxa2xx.c | 4 | ||||
-rw-r--r-- | hw/pxa2xx_gpio.c | 150 | ||||
-rw-r--r-- | hw/qdev.c | 15 | ||||
-rw-r--r-- | hw/qdev.h | 2 | ||||
-rw-r--r-- | hw/scsi-bus.c | 8 | ||||
-rw-r--r-- | hw/scsi-disk.c | 3 | ||||
-rw-r--r-- | hw/scsi.h | 6 | ||||
-rw-r--r-- | hw/sd.c | 7 | ||||
-rw-r--r-- | hw/sh7750.c | 20 | ||||
-rw-r--r-- | hw/sharpsl.h | 7 | ||||
-rw-r--r-- | hw/slavio_intctl.c | 7 | ||||
-rw-r--r-- | hw/spitz.c | 349 | ||||
-rw-r--r-- | hw/ssi-sd.c | 7 | ||||
-rw-r--r-- | hw/tosa.c | 35 | ||||
-rw-r--r-- | hw/usb-bus.c | 28 | ||||
-rw-r--r-- | hw/usb-hid.c | 317 | ||||
-rw-r--r-- | hw/usb-hub.c | 24 | ||||
-rw-r--r-- | hw/usb-msd.c | 7 | ||||
-rw-r--r-- | hw/usb.h | 10 | ||||
-rw-r--r-- | hw/virtio-blk.c | 50 | ||||
-rw-r--r-- | hw/virtio-console.c | 38 | ||||
-rw-r--r-- | hw/virtio-net.c | 13 | ||||
-rw-r--r-- | hw/virtio-serial-bus.c | 123 | ||||
-rw-r--r-- | hw/virtio-serial.h | 24 | ||||
-rw-r--r-- | hw/zaurus.c | 111 |
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; @@ -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(), + }, +}; @@ -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 = { @@ -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))) @@ -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" @@ -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; @@ -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; } @@ -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]); @@ -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); @@ -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; @@ -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(), }, }; @@ -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); @@ -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; } @@ -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(), }, }; @@ -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. */ |