aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/a9mpcore.c2
-rw-r--r--hw/acpi.c298
-rw-r--r--hw/acpi_piix4.c22
-rw-r--r--hw/an5206.c2
-rw-r--r--hw/apb_pci.c2
-rw-r--r--hw/arm-misc.h2
-rw-r--r--hw/arm11mpcore.c2
-rw-r--r--hw/arm_boot.c2
-rw-r--r--hw/arm_gic.c2
-rw-r--r--hw/arm_pic.c2
-rw-r--r--hw/arm_sysctl.c2
-rw-r--r--hw/arm_timer.c2
-rw-r--r--hw/armv7m_nvic.c2
-rw-r--r--hw/axis_dev88.c8
-rw-r--r--hw/baum.c7
-rw-r--r--hw/baum.h2
-rw-r--r--hw/bitbang_i2c.c2
-rw-r--r--hw/bonito.c4
-rw-r--r--hw/bt-hid.c62
-rw-r--r--hw/ccid-card-emulated.c2
-rw-r--r--hw/ccid.h3
-rw-r--r--hw/dp8393x.c2
-rw-r--r--hw/ds1225y.c152
-rw-r--r--hw/ds1338.c2
-rw-r--r--hw/dummy_m68k.c2
-rw-r--r--hw/esp.c2
-rw-r--r--hw/etraxfs_eth.c2
-rw-r--r--hw/flash.h17
-rw-r--r--hw/fw_cfg.c142
-rw-r--r--hw/grackle_pci.c5
-rw-r--r--hw/gt64xxx.c4
-rw-r--r--hw/hid.c403
-rw-r--r--hw/hid.h58
-rw-r--r--hw/hw.h1
-rw-r--r--hw/i2c.c2
-rw-r--r--hw/i2c.h2
-rw-r--r--hw/ide.h1
-rw-r--r--hw/ide/ich.c6
-rw-r--r--hw/ide/piix.c44
-rw-r--r--hw/ide/qdev.c5
-rw-r--r--hw/integratorcp.c2
-rw-r--r--hw/lan9118.c2
-rw-r--r--hw/lm832x.c4
-rw-r--r--hw/lsi53c895a.c24
-rw-r--r--hw/marvell_88w8618_audio.c2
-rw-r--r--hw/mc146818rtc.c20
-rw-r--r--hw/mcf5206.c2
-rw-r--r--hw/mcf5208.c2
-rw-r--r--hw/mcf_fec.c4
-rw-r--r--hw/mcf_intc.c2
-rw-r--r--hw/mcf_uart.c2
-rw-r--r--hw/milkymist-softusb.c23
-rw-r--r--hw/mips.h4
-rw-r--r--hw/mips_jazz.c10
-rw-r--r--hw/mipsnet.c2
-rw-r--r--hw/mpcore.c2
-rw-r--r--hw/msmouse.c5
-rw-r--r--hw/msmouse.h2
-rw-r--r--hw/multiboot.c32
-rw-r--r--hw/musicpal.c2
-rw-r--r--hw/nand.c351
-rw-r--r--hw/nseries.c59
-rw-r--r--hw/omap.h22
-rw-r--r--hw/omap1.c10
-rw-r--r--hw/omap2.c34
-rw-r--r--hw/omap_clk.c6
-rw-r--r--hw/omap_gpio.c258
-rw-r--r--hw/omap_l4.c6
-rw-r--r--hw/onenand.c172
-rw-r--r--hw/palm.c26
-rw-r--r--hw/pc.c62
-rw-r--r--hw/pc.h9
-rw-r--r--hw/pc_piix.c26
-rw-r--r--hw/pci.c63
-rw-r--r--hw/pci.h15
-rw-r--r--hw/pci_host.h1
-rw-r--r--hw/pci_ids.h8
-rw-r--r--hw/pci_internals.h1
-rw-r--r--hw/piix_pci.c13
-rw-r--r--hw/pl011.c2
-rw-r--r--hw/pl022.c2
-rw-r--r--hw/pl050.c2
-rw-r--r--hw/pl061.c2
-rw-r--r--hw/pl080.c2
-rw-r--r--hw/pl110.c2
-rw-r--r--hw/pl110_template.h2
-rw-r--r--hw/pl181.c2
-rw-r--r--hw/pl190.c2
-rw-r--r--hw/ppc4xx_pci.c5
-rw-r--r--hw/ppc_mac.h9
-rw-r--r--hw/ppc_newworld.c5
-rw-r--r--hw/ppc_oldworld.c3
-rw-r--r--hw/ppc_prep.c3
-rw-r--r--hw/ppce500_pci.c6
-rw-r--r--hw/prep_pci.c5
-rw-r--r--hw/prep_pci.h3
-rw-r--r--hw/ptimer.c2
-rw-r--r--hw/pxa.h2
-rw-r--r--hw/pxa2xx.c2
-rw-r--r--hw/pxa2xx_dma.c2
-rw-r--r--hw/pxa2xx_pic.c2
-rw-r--r--hw/pxa2xx_timer.c2
-rw-r--r--hw/qdev.c5
-rw-r--r--hw/qxl-logger.c4
-rw-r--r--hw/qxl-render.c4
-rw-r--r--hw/qxl.c486
-rw-r--r--hw/qxl.h34
-rw-r--r--hw/realview.c2
-rw-r--r--hw/realview_gic.c2
-rw-r--r--hw/scsi-bus.c83
-rw-r--r--hw/scsi-defs.h62
-rw-r--r--hw/scsi-disk.c102
-rw-r--r--hw/scsi-generic.c9
-rw-r--r--hw/scsi.h10
-rw-r--r--hw/sd.c23
-rw-r--r--hw/sh_intc.c2
-rw-r--r--hw/sh_pci.c4
-rw-r--r--hw/sh_timer.c2
-rw-r--r--hw/smbus.c2
-rw-r--r--hw/smc91c111.c2
-rw-r--r--hw/spapr_hcall.c2
-rw-r--r--hw/spapr_vscsi.c28
-rw-r--r--hw/spitz.c6
-rw-r--r--hw/ssd0303.c2
-rw-r--r--hw/ssd0323.c2
-rw-r--r--hw/ssi-sd.c2
-rw-r--r--hw/ssi.c2
-rw-r--r--hw/stellaris.c4
-rw-r--r--hw/stellaris_enet.c2
-rw-r--r--hw/stellaris_input.c2
-rw-r--r--hw/sysbus.c27
-rw-r--r--hw/sysbus.h3
-rw-r--r--hw/tc6393xb.c7
-rw-r--r--hw/unin_pci.c10
-rw-r--r--hw/usb-bt.c61
-rw-r--r--hw/usb-bus.c46
-rw-r--r--hw/usb-ccid.c57
-rw-r--r--hw/usb-ehci.c439
-rw-r--r--hw/usb-hid.c517
-rw-r--r--hw/usb-hub.c98
-rw-r--r--hw/usb-libhw.c63
-rw-r--r--hw/usb-msd.c132
-rw-r--r--hw/usb-musb.c46
-rw-r--r--hw/usb-net.c71
-rw-r--r--hw/usb-ohci.c154
-rw-r--r--hw/usb-serial.c35
-rw-r--r--hw/usb-uhci.c152
-rw-r--r--hw/usb-wacom.c12
-rw-r--r--hw/usb.c99
-rw-r--r--hw/usb.h33
-rw-r--r--hw/versatile_pci.c4
-rw-r--r--hw/versatilepb.c2
-rw-r--r--hw/vga_int.h10
-rw-r--r--hw/virtio-balloon.c76
-rw-r--r--hw/virtio-console.c29
-rw-r--r--hw/virtio-net.c2
-rw-r--r--hw/virtio-pci.c14
-rw-r--r--hw/virtio-serial-bus.c29
-rw-r--r--hw/virtio.h1
-rw-r--r--hw/xen.h12
-rw-r--r--hw/xen_common.h12
-rw-r--r--hw/xen_console.c25
-rw-r--r--hw/xen_devconfig.c4
-rw-r--r--hw/xen_disk.c37
-rw-r--r--hw/xen_platform.c43
-rw-r--r--hw/xenfb.c19
-rw-r--r--hw/z2.c358
167 files changed, 4133 insertions, 2139 deletions
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index b5e5328395..6f108f4ce2 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
/* 64 external IRQ lines. */
diff --git a/hw/acpi.c b/hw/acpi.c
index ad40fb4c3c..79ec66c147 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -20,19 +20,30 @@
#include "pc.h"
#include "acpi.h"
-struct acpi_table_header
-{
- char signature [4]; /* ACPI signature (4 ASCII characters) */
+struct acpi_table_header {
+ uint16_t _length; /* our length, not actual part of the hdr */
+ /* XXX why we have 2 length fields here? */
+ char sig[4]; /* ACPI signature (4 ASCII characters) */
uint32_t length; /* Length of table, in bytes, including header */
uint8_t revision; /* ACPI Specification minor version # */
uint8_t checksum; /* To make sum of entire table == 0 */
- char oem_id [6]; /* OEM identification */
- char oem_table_id [8]; /* OEM table identification */
+ char oem_id[6]; /* OEM identification */
+ char oem_table_id[8]; /* OEM table identification */
uint32_t oem_revision; /* OEM revision number */
- char asl_compiler_id [4]; /* ASL compiler vendor ID */
+ char asl_compiler_id[4]; /* ASL compiler vendor ID */
uint32_t asl_compiler_revision; /* ASL compiler revision number */
} __attribute__((packed));
+#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
+#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t) /* size of the extra prefix */
+
+static const char dfl_hdr[ACPI_TABLE_HDR_SIZE] =
+ "\0\0" /* fake _length (2) */
+ "QEMU\0\0\0\0\1\0" /* sig (4), len(4), revno (1), csum (1) */
+ "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
+ "QEMU\1\0\0\0" /* ASL compiler ID (4), version (4) */
+ ;
+
char *acpi_tables;
size_t acpi_tables_len;
@@ -40,163 +51,198 @@ static int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;
sum = 0;
- for(i = 0; i < len; i++)
+ for (i = 0; i < len; i++) {
sum += data[i];
+ }
return (-sum) & 0xff;
}
+/* like strncpy() but zero-fills the tail of destination */
+static void strzcpy(char *dst, const char *src, size_t size)
+{
+ size_t len = strlen(src);
+ if (len >= size) {
+ len = size;
+ } else {
+ memset(dst + len, 0, size - len);
+ }
+ memcpy(dst, src, len);
+}
+
+/* XXX fixme: this function uses obsolete argument parsing interface */
int acpi_table_add(const char *t)
{
- static const char *dfl_id = "QEMUQEMU";
char buf[1024], *p, *f;
- struct acpi_table_header acpi_hdr;
unsigned long val;
- uint32_t length;
- struct acpi_table_header *acpi_hdr_p;
- size_t off;
+ size_t len, start, allen;
+ bool has_header;
+ int changed;
+ int r;
+ struct acpi_table_header hdr;
+
+ r = 0;
+ r |= get_param_value(buf, sizeof(buf), "data", t) ? 1 : 0;
+ r |= get_param_value(buf, sizeof(buf), "file", t) ? 2 : 0;
+ switch (r) {
+ case 0:
+ buf[0] = '\0';
+ /* fallthrough for default behavior */
+ case 1:
+ has_header = false;
+ break;
+ case 2:
+ has_header = true;
+ break;
+ default:
+ fprintf(stderr, "acpitable: both data and file are specified\n");
+ return -1;
+ }
- memset(&acpi_hdr, 0, sizeof(acpi_hdr));
-
- if (get_param_value(buf, sizeof(buf), "sig", t)) {
- strncpy(acpi_hdr.signature, buf, 4);
+ if (!acpi_tables) {
+ allen = sizeof(uint16_t);
+ acpi_tables = qemu_mallocz(allen);
} else {
- strncpy(acpi_hdr.signature, dfl_id, 4);
+ allen = acpi_tables_len;
}
+
+ start = allen;
+ acpi_tables = qemu_realloc(acpi_tables, start + ACPI_TABLE_HDR_SIZE);
+ allen += has_header ? ACPI_TABLE_PFX_SIZE : ACPI_TABLE_HDR_SIZE;
+
+ /* now read in the data files, reallocating buffer as needed */
+
+ for (f = strtok(buf, ":"); f; f = strtok(NULL, ":")) {
+ int fd = open(f, O_RDONLY);
+
+ if (fd < 0) {
+ fprintf(stderr, "can't open file %s: %s\n", f, strerror(errno));
+ return -1;
+ }
+
+ for (;;) {
+ char data[8192];
+ r = read(fd, data, sizeof(data));
+ if (r == 0) {
+ break;
+ } else if (r > 0) {
+ acpi_tables = qemu_realloc(acpi_tables, allen + r);
+ memcpy(acpi_tables + allen, data, r);
+ allen += r;
+ } else if (errno != EINTR) {
+ fprintf(stderr, "can't read file %s: %s\n",
+ f, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
+
+ close(fd);
+ }
+
+ /* now fill in the header fields */
+
+ f = acpi_tables + start; /* start of the table */
+ changed = 0;
+
+ /* copy the header to temp place to align the fields */
+ memcpy(&hdr, has_header ? f : dfl_hdr, ACPI_TABLE_HDR_SIZE);
+
+ /* length of the table minus our prefix */
+ len = allen - start - ACPI_TABLE_PFX_SIZE;
+
+ hdr._length = cpu_to_le16(len);
+
+ if (get_param_value(buf, sizeof(buf), "sig", t)) {
+ strzcpy(hdr.sig, buf, sizeof(hdr.sig));
+ ++changed;
+ }
+
+ /* length of the table including header, in bytes */
+ if (has_header) {
+ /* check if actual length is correct */
+ val = le32_to_cpu(hdr.length);
+ if (val != len) {
+ fprintf(stderr,
+ "warning: acpitable has wrong length,"
+ " header says %lu, actual size %zu bytes\n",
+ val, len);
+ ++changed;
+ }
+ }
+ /* we may avoid putting length here if has_header is true */
+ hdr.length = cpu_to_le32(len);
+
if (get_param_value(buf, sizeof(buf), "rev", t)) {
- val = strtoul(buf, &p, 10);
- if (val > 255 || *p != '\0')
- goto out;
- } else {
- val = 1;
+ val = strtoul(buf, &p, 0);
+ if (val > 255 || *p) {
+ fprintf(stderr, "acpitable: \"rev=%s\" is invalid\n", buf);
+ return -1;
+ }
+ hdr.revision = (uint8_t)val;
+ ++changed;
}
- acpi_hdr.revision = (int8_t)val;
if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
- strncpy(acpi_hdr.oem_id, buf, 6);
- } else {
- strncpy(acpi_hdr.oem_id, dfl_id, 6);
+ strzcpy(hdr.oem_id, buf, sizeof(hdr.oem_id));
+ ++changed;
}
if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
- strncpy(acpi_hdr.oem_table_id, buf, 8);
- } else {
- strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
+ strzcpy(hdr.oem_table_id, buf, sizeof(hdr.oem_table_id));
+ ++changed;
}
if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
- val = strtol(buf, &p, 10);
- if(*p != '\0')
- goto out;
- } else {
- val = 1;
+ val = strtol(buf, &p, 0);
+ if (*p) {
+ fprintf(stderr, "acpitable: \"oem_rev=%s\" is invalid\n", buf);
+ return -1;
+ }
+ hdr.oem_revision = cpu_to_le32(val);
+ ++changed;
}
- acpi_hdr.oem_revision = cpu_to_le32(val);
if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
- strncpy(acpi_hdr.asl_compiler_id, buf, 4);
- } else {
- strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
+ strzcpy(hdr.asl_compiler_id, buf, sizeof(hdr.asl_compiler_id));
+ ++changed;
}
if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
- val = strtol(buf, &p, 10);
- if(*p != '\0')
- goto out;
- } else {
- val = 1;
- }
- acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
-
- if (!get_param_value(buf, sizeof(buf), "data", t)) {
- buf[0] = '\0';
- }
-
- length = sizeof(acpi_hdr);
-
- f = buf;
- while (buf[0]) {
- struct stat s;
- char *n = strchr(f, ':');
- if (n)
- *n = '\0';
- if(stat(f, &s) < 0) {
- fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
- goto out;
+ val = strtol(buf, &p, 0);
+ if (*p) {
+ fprintf(stderr, "acpitable: \"%s=%s\" is invalid\n",
+ "asl_compiler_rev", buf);
+ return -1;
}
- length += s.st_size;
- if (!n)
- break;
- *n = ':';
- f = n + 1;
+ hdr.asl_compiler_revision = cpu_to_le32(val);
+ ++changed;
}
- if (!acpi_tables) {
- acpi_tables_len = sizeof(uint16_t);
- acpi_tables = qemu_mallocz(acpi_tables_len);
+ if (!has_header && !changed) {
+ fprintf(stderr, "warning: acpitable: no table headers are specified\n");
}
- acpi_tables = qemu_realloc(acpi_tables,
- acpi_tables_len + sizeof(uint16_t) + length);
- p = acpi_tables + acpi_tables_len;
- acpi_tables_len += sizeof(uint16_t) + length;
-
- *(uint16_t*)p = cpu_to_le32(length);
- p += sizeof(uint16_t);
- memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
- off = sizeof(acpi_hdr);
-
- f = buf;
- while (buf[0]) {
- struct stat s;
- int fd;
- char *n = strchr(f, ':');
- if (n)
- *n = '\0';
- fd = open(f, O_RDONLY);
-
- if(fd < 0)
- goto out;
- if(fstat(fd, &s) < 0) {
- close(fd);
- goto out;
- }
- /* off < length is necessary because file size can be changed
- under our foot */
- while(s.st_size && off < length) {
- int r;
- r = read(fd, p + off, s.st_size);
- if (r > 0) {
- off += r;
- s.st_size -= r;
- } else if ((r < 0 && errno != EINTR) || r == 0) {
- close(fd);
- goto out;
- }
- }
- close(fd);
- if (!n)
- break;
- f = n + 1;
- }
- if (off < length) {
- /* don't pass random value in process to guest */
- memset(p + off, 0, length - off);
+ /* now calculate checksum of the table, complete with the header */
+ /* we may as well leave checksum intact if has_header is true */
+ /* alternatively there may be a way to set cksum to a given value */
+ hdr.checksum = 0; /* for checksum calculation */
+
+ /* put header back */
+ memcpy(f, &hdr, sizeof(hdr));
+
+ if (changed || !has_header || 1) {
+ ((struct acpi_table_header *)f)->checksum =
+ acpi_checksum((uint8_t *)f + ACPI_TABLE_PFX_SIZE, len);
}
- acpi_hdr_p = (struct acpi_table_header*)p;
- acpi_hdr_p->length = cpu_to_le32(length);
- acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length);
/* increase number of tables */
- (*(uint16_t*)acpi_tables) =
- cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
+ (*(uint16_t *)acpi_tables) =
+ cpu_to_le32(le32_to_cpu(*(uint16_t *)acpi_tables) + 1);
+
+ acpi_tables_len = allen;
return 0;
-out:
- if (acpi_tables) {
- qemu_free(acpi_tables);
- acpi_tables = NULL;
- }
- return -1;
+
}
/* ACPI PM1a EVT */
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 350558b859..29f0f76c35 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -23,6 +23,7 @@
#include "acpi.h"
#include "sysemu.h"
#include "range.h"
+#include "ioport.h"
//#define DEBUG
@@ -63,6 +64,7 @@ typedef struct PIIX4PMState {
qemu_irq irq;
qemu_irq smi_irq;
int kvm_enabled;
+ Notifier machine_ready;
/* for pci hotplug */
ACPIGPE gpe;
@@ -311,6 +313,19 @@ static void piix4_powerdown(void *opaque, int irq, int power_failing)
acpi_pm1_evt_power_down(pm1a, tmr);
}
+static void piix4_pm_machine_ready(Notifier *n, void *opaque)
+{
+ PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
+ uint8_t *pci_conf;
+
+ pci_conf = s->dev.config;
+ pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
+ pci_conf[0x63] = 0x60;
+ pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
+ (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
+
+}
+
static int piix4_pm_initfn(PCIDevice *dev)
{
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
@@ -337,11 +352,6 @@ static int piix4_pm_initfn(PCIDevice *dev)
/* XXX: which specification is used ? The i82731AB has different
mappings */
- pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
- pci_conf[0x63] = 0x60;
- pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
- (serial_hds[1] != NULL ? 0x90 : 0);
-
pci_conf[0x90] = s->smb_io_base | 1;
pci_conf[0x91] = s->smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
@@ -354,6 +364,8 @@ static int piix4_pm_initfn(PCIDevice *dev)
qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
pm_smbus_init(&s->dev.qdev, &s->smb);
+ s->machine_ready.notify = piix4_pm_machine_ready;
+ qemu_add_machine_init_done_notifier(&s->machine_ready);
qemu_register_reset(piix4_reset, s);
piix4_acpi_system_hot_add_init(dev->bus, s);
diff --git a/hw/an5206.c b/hw/an5206.c
index 42a0163fbd..04ca420a90 100644
--- a/hw/an5206.c
+++ b/hw/an5206.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 974c87a8ce..8b9939c06a 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -34,6 +34,7 @@
#include "rwhandler.h"
#include "apb_pci.h"
#include "sysemu.h"
+#include "exec-memory.h"
/* debug APB */
//#define DEBUG_APB
@@ -346,6 +347,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
d->bus = pci_register_bus(&d->busdev.qdev, "pci",
pci_apb_set_irq, pci_pbm_map_irq, d,
+ get_system_memory(),
0, 32);
pci_bus_set_mem_base(d->bus, mem_base);
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 9aeeaea759..f8a747289b 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*
*/
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index 3bbd8856cf..b47707f7bb 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index e0215768b1..215d5dec64 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0e934ecd64..fb07314d52 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
/* This file contains implementation code for the RealView EB interrupt
diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index f44568cebb..985148a380 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL
+ * This code is licensed under the LGPL
*/
#include "hw.h"
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 9225b588b8..fd0c8bc3d6 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index dac9e70750..fd9448f055 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -4,7 +4,7 @@
* Copyright (c) 2005-2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index d06eec9b39..1df8d4db45 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*
* The ARMv7M System controller is fairly tightly tied in with the
* NVIC. Much of that is also implemented here.
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 0e2135afd0..e0a8c14c12 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -30,13 +30,14 @@
#include "loader.h"
#include "elf.h"
#include "cris-boot.h"
+#include "blockdev.h"
#define D(x)
#define DNAND(x)
struct nand_state_t
{
- NANDFlashState *nand;
+ DeviceState *nand;
unsigned int rdy:1;
unsigned int ale:1;
unsigned int cle:1;
@@ -251,6 +252,7 @@ void axisdev88_init (ram_addr_t ram_size,
CPUState *env;
DeviceState *dev;
SysBusDevice *s;
+ DriveInfo *nand;
qemu_irq irq[30], nmi[2], *cpu_irq;
void *etraxfs_dmac;
struct etraxfs_dma_client *eth[2] = {NULL, NULL};
@@ -278,7 +280,9 @@ void axisdev88_init (ram_addr_t ram_size,
/* Attach a NAND flash to CS1. */
- nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
+ nand = drive_get(IF_MTD, 0, 0);
+ nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
+ NAND_MFR_STMICRO, 0x39);
nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
diff --git a/hw/baum.c b/hw/baum.c
index 2aaf5ffe9d..33a22a73d9 100644
--- a/hw/baum.c
+++ b/hw/baum.c
@@ -576,7 +576,7 @@ static void baum_close(struct CharDriverState *chr)
qemu_free(baum);
}
-CharDriverState *chr_baum_init(QemuOpts *opts)
+int chr_baum_init(QemuOpts *opts, CharDriverState **_chr)
{
BaumDriverState *baum;
CharDriverState *chr;
@@ -629,7 +629,8 @@ CharDriverState *chr_baum_init(QemuOpts *opts)
qemu_chr_generic_open(chr);
- return chr;
+ *_chr = chr;
+ return 0;
fail:
qemu_free_timer(baum->cellCount_timer);
@@ -638,5 +639,5 @@ fail_handle:
qemu_free(handle);
qemu_free(chr);
qemu_free(baum);
- return NULL;
+ return -EIO;
}
diff --git a/hw/baum.h b/hw/baum.h
index 8af710fa21..3f28cc339a 100644
--- a/hw/baum.h
+++ b/hw/baum.h
@@ -23,4 +23,4 @@
*/
/* char device */
-CharDriverState *chr_baum_init(QemuOpts *opts);
+int chr_baum_init(QemuOpts *opts, CharDriverState **_chr);
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index 2937b5c4a1..53e9c5c4c4 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2008 Jan Kiszka
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "hw.h"
#include "bitbang_i2c.h"
diff --git a/hw/bonito.c b/hw/bonito.c
index e8c57a36ff..5f62dda6e2 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -42,6 +42,7 @@
#include "mips.h"
#include "pci_host.h"
#include "sysemu.h"
+#include "exec-memory.h"
//#define DEBUG_BONITO
@@ -773,7 +774,8 @@ PCIBus *bonito_init(qemu_irq *pic)
dev = qdev_create(NULL, "Bonito-pcihost");
pcihost = FROM_SYSBUS(BonitoState, sysbus_from_qdev(dev));
b = pci_register_bus(&pcihost->busdev.qdev, "pci", pci_bonito_set_irq,
- pci_bonito_map_irq, pic, 0x28, 32);
+ pci_bonito_map_irq, pic, get_system_memory(),
+ 0x28, 32);
pcihost->bus = b;
qdev_init_nofail(dev);
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
index 09120af074..5f1afe3e89 100644
--- a/hw/bt-hid.c
+++ b/hw/bt-hid.c
@@ -19,7 +19,9 @@
*/
#include "qemu-common.h"
-#include "usb.h"
+#include "qemu-timer.h"
+#include "console.h"
+#include "hid.h"
#include "bt.h"
enum hid_transaction_req {
@@ -86,7 +88,7 @@ struct bt_hid_device_s {
struct bt_l2cap_device_s btdev;
struct bt_l2cap_conn_params_s *control;
struct bt_l2cap_conn_params_s *interrupt;
- USBDevice *usbdev;
+ HIDState hid;
int proto;
int connected;
@@ -111,7 +113,7 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
bt_l2cap_device_done(&s->btdev);
bt_l2cap_device_init(&s->btdev, net);
- s->usbdev->info->handle_reset(s->usbdev);
+ hid_reset(&s->hid);
s->proto = BT_HID_PROTO_REPORT;
s->state = bt_state_ready;
s->dataother.len = 0;
@@ -124,23 +126,16 @@ static void bt_hid_reset(struct bt_hid_device_s *s)
static int bt_hid_out(struct bt_hid_device_s *s)
{
- USBPacket p;
-
if (s->data_type == BT_DATA_OUTPUT) {
- p.pid = USB_TOKEN_OUT;
- p.devep = 1;
- p.data = s->dataout.buffer;
- p.len = s->dataout.len;
- s->dataout.len = s->usbdev->info->handle_data(s->usbdev, &p);
-
- return s->dataout.len;
+ /* nothing */
+ ;
}
if (s->data_type == BT_DATA_FEATURE) {
/* XXX:
* does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
* or a SET_REPORT? */
- p.devep = 0;
+ ;
}
return -1;
@@ -148,14 +143,8 @@ static int bt_hid_out(struct bt_hid_device_s *s)
static int bt_hid_in(struct bt_hid_device_s *s)
{
- USBPacket p;
-
- p.pid = USB_TOKEN_IN;
- p.devep = 1;
- p.data = s->datain.buffer;
- p.len = sizeof(s->datain.buffer);
- s->datain.len = s->usbdev->info->handle_data(s->usbdev, &p);
-
+ s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
+ sizeof(s->datain.buffer));
return s->datain.len;
}
@@ -323,8 +312,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
break;
}
s->proto = parameter;
- s->usbdev->info->handle_control(s->usbdev, NULL, SET_PROTOCOL, s->proto, 0, 0,
- NULL);
+ s->hid.protocol = parameter;
ret = BT_HS_SUCCESSFUL;
break;
@@ -333,8 +321,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
ret = BT_HS_ERR_INVALID_PARAMETER;
break;
}
- s->usbdev->info->handle_control(s->usbdev, NULL, GET_IDLE, 0, 0, 1,
- s->control->sdu_out(s->control, 1));
+ *s->control->sdu_out(s->control, 1) = s->hid.idle;
s->control->sdu_submit(s->control);
break;
@@ -344,11 +331,7 @@ static void bt_hid_control_transaction(struct bt_hid_device_s *s,
break;
}
- /* We don't need to know about the Idle Rate here really,
- * so just pass it on to the device. */
- ret = s->usbdev->info->handle_control(s->usbdev, NULL,
- SET_IDLE, data[1], 0, 0, NULL) ?
- BT_HS_SUCCESSFUL : BT_HS_ERR_INVALID_PARAMETER;
+ s->hid.idle = data[1];
/* XXX: Does this generate a handshake? */
break;
@@ -385,9 +368,10 @@ static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
bt_hid_control_transaction(hid, data, len);
}
-static void bt_hid_datain(void *opaque)
+static void bt_hid_datain(HIDState *hs)
{
- struct bt_hid_device_s *hid = opaque;
+ struct bt_hid_device_s *hid =
+ container_of(hs, struct bt_hid_device_s, hid);
/* If suspended, wake-up and send a wake-up event first. We might
* want to also inspect the input report and ignore event like
@@ -450,7 +434,7 @@ static void bt_hid_connected_update(struct bt_hid_device_s *hid)
hid->btdev.device.inquiry_scan = !hid->connected;
if (hid->connected && !prev) {
- hid->usbdev->info->handle_reset(hid->usbdev);
+ hid_reset(&hid->hid);
hid->proto = BT_HID_PROTO_REPORT;
}
@@ -518,7 +502,7 @@ static void bt_hid_destroy(struct bt_device_s *dev)
bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
bt_l2cap_device_done(&hid->btdev);
- hid->usbdev->info->handle_destroy(hid->usbdev);
+ hid_free(&hid->hid);
qemu_free(hid);
}
@@ -531,7 +515,7 @@ enum peripheral_minor_class {
};
static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
- USBDevice *dev, enum peripheral_minor_class minor)
+ enum peripheral_minor_class minor)
{
struct bt_hid_device_s *s = qemu_mallocz(sizeof(*s));
uint32_t class =
@@ -551,9 +535,8 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
BT_HID_MTU, bt_hid_new_interrupt_ch);
- s->usbdev = dev;
- s->btdev.device.lmp_name = s->usbdev->product_desc;
- usb_hid_datain_cb(s->usbdev, s, bt_hid_datain);
+ hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
+ s->btdev.device.lmp_name = "BT Keyboard";
s->btdev.device.handle_destroy = bt_hid_destroy;
@@ -566,6 +549,5 @@ static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
{
- USBDevice *dev = usb_create_simple(NULL /* FIXME */, "usb-kbd");
- return bt_hid_init(net, dev, class_keyboard);
+ return bt_hid_init(net, class_keyboard);
}
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 0b0718426d..4762e85116 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -4,7 +4,7 @@
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
- * This code is licenced under the GNU LGPL, version 2 or later.
+ * This code is licensed under the GNU LGPL, version 2 or later.
*/
/*
diff --git a/hw/ccid.h b/hw/ccid.h
index dbfc13c4f5..9e3abe1b4c 100644
--- a/hw/ccid.h
+++ b/hw/ccid.h
@@ -4,7 +4,7 @@
* Copyright (c) 2011 Red Hat.
* Written by Alon Levy.
*
- * This code is licenced under the GNU LGPL, version 2 or later.
+ * This code is licensed under the GNU LGPL, version 2 or later.
*/
#ifndef CCID_H
@@ -29,7 +29,6 @@ struct CCIDCardState {
*/
struct CCIDCardInfo {
DeviceInfo qdev;
- void (*print)(Monitor *mon, CCIDCardState *card, int indent);
const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
void (*apdu_from_guest)(CCIDCardState *card,
const uint8_t *apdu,
diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index c332dd59d2..1bcd8eeba9 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -898,7 +898,7 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
- memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(s->conf.macaddr));
+ s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
s->conf.peer = nd->netdev;
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index b1c52321fe..662d7b5166 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -22,31 +22,24 @@
* THE SOFTWARE.
*/
-#include "hw.h"
-#include "mips.h"
-#include "nvram.h"
+#include "sysbus.h"
+#include "trace.h"
-//#define DEBUG_NVRAM
-
-typedef struct ds1225y_t
-{
+typedef struct {
+ DeviceState qdev;
uint32_t chip_size;
+ char *filename;
QEMUFile *file;
uint8_t *contents;
- uint8_t protection;
-} ds1225y_t;
-
+} NvRamState;
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
- ds1225y_t *s = opaque;
+ NvRamState *s = opaque;
uint32_t val;
val = s->contents[addr];
-
-#ifdef DEBUG_NVRAM
- printf("nvram: read 0x%x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+ trace_nvram_read(addr, val);
return val;
}
@@ -70,13 +63,12 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
{
- ds1225y_t *s = opaque;
+ NvRamState *s = opaque;
-#ifdef DEBUG_NVRAM
- printf("nvram: write 0x%x at " TARGET_FMT_lx "\n", val, addr);
-#endif
+ val &= 0xff;
+ trace_nvram_write(addr, s->contents[addr], val);
- s->contents[addr] = val & 0xff;
+ s->contents[addr] = val;
if (s->file) {
qemu_fseek(s->file, addr, SEEK_SET);
qemu_put_byte(s->file, (int)val);
@@ -98,34 +90,6 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
nvram_writeb(opaque, addr + 3, (val >> 24) & 0xff);
}
-static void nvram_writeb_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- ds1225y_t *s = opaque;
-
- if (s->protection != 7) {
-#ifdef DEBUG_NVRAM
- printf("nvram: prevent write of 0x%x at " TARGET_FMT_lx "\n", val, addr);
-#endif
- return;
- }
-
- nvram_writeb(opaque, addr, val);
-}
-
-static void nvram_writew_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- nvram_writeb_protected(opaque, addr, val & 0xff);
- nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
-}
-
-static void nvram_writel_protected (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- nvram_writeb_protected(opaque, addr, val & 0xff);
- nvram_writeb_protected(opaque, addr + 1, (val >> 8) & 0xff);
- nvram_writeb_protected(opaque, addr + 2, (val >> 16) & 0xff);
- nvram_writeb_protected(opaque, addr + 3, (val >> 24) & 0xff);
-}
-
static CPUReadMemoryFunc * const nvram_read[] = {
&nvram_readb,
&nvram_readw,
@@ -138,45 +102,83 @@ static CPUWriteMemoryFunc * const nvram_write[] = {
&nvram_writel,
};
-static CPUWriteMemoryFunc * const nvram_write_protected[] = {
- &nvram_writeb_protected,
- &nvram_writew_protected,
- &nvram_writel_protected,
+static int nvram_post_load(void *opaque, int version_id)
+{
+ NvRamState *s = opaque;
+
+ /* Close file, as filename may has changed in load/store process */
+ if (s->file) {
+ qemu_fclose(s->file);
+ }
+
+ /* Write back nvram contents */
+ s->file = qemu_fopen(s->filename, "wb");
+ if (s->file) {
+ /* Write back contents, as 'wb' mode cleaned the file */
+ qemu_put_buffer(s->file, s->contents, s->chip_size);
+ qemu_fflush(s->file);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_nvram = {
+ .name = "nvram",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .post_load = nvram_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
+ vmstate_info_uint8, uint8_t),
+ VMSTATE_END_OF_LIST()
+ }
};
-/* Initialisation routine */
-void *ds1225y_init(target_phys_addr_t mem_base, const char *filename)
+typedef struct {
+ SysBusDevice busdev;
+ NvRamState nvram;
+} SysBusNvRamState;
+
+static int nvram_sysbus_initfn(SysBusDevice *dev)
{
- ds1225y_t *s;
- int mem_indexRW, mem_indexRP;
+ NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
QEMUFile *file;
+ int s_io;
- s = qemu_mallocz(sizeof(ds1225y_t));
- s->chip_size = 0x2000; /* Fixed for ds1225y chip: 8 KiB */
s->contents = qemu_mallocz(s->chip_size);
- s->protection = 7;
+
+ s_io = cpu_register_io_memory(nvram_read, nvram_write, s,
+ DEVICE_NATIVE_ENDIAN);
+ sysbus_init_mmio(dev, s->chip_size, s_io);
/* Read current file */
- file = qemu_fopen(filename, "rb");
+ file = qemu_fopen(s->filename, "rb");
if (file) {
/* Read nvram contents */
qemu_get_buffer(file, s->contents, s->chip_size);
qemu_fclose(file);
}
- s->file = qemu_fopen(filename, "wb");
- if (s->file) {
- /* Write back contents, as 'wb' mode cleaned the file */
- qemu_put_buffer(s->file, s->contents, s->chip_size);
- qemu_fflush(s->file);
- }
+ nvram_post_load(s, 0);
+
+ return 0;
+}
+
+static SysBusDeviceInfo nvram_sysbus_info = {
+ .qdev.name = "ds1225y",
+ .qdev.size = sizeof(SysBusNvRamState),
+ .qdev.vmsd = &vmstate_nvram,
+ .init = nvram_sysbus_initfn,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+ DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
- /* Read/write memory */
- mem_indexRW = cpu_register_io_memory(nvram_read, nvram_write, s,
- DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(mem_base, s->chip_size, mem_indexRW);
- /* Read/write protected memory */
- mem_indexRP = cpu_register_io_memory(nvram_read, nvram_write_protected, s,
- DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(mem_base + s->chip_size, s->chip_size, mem_indexRP);
- return s;
+static void nvram_register(void)
+{
+ sysbus_register_withprop(&nvram_sysbus_info);
}
+
+device_init(nvram_register)
diff --git a/hw/ds1338.c b/hw/ds1338.c
index 6f5ae5e6c1..3522af5b5a 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "i2c.h"
diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c
index cec1cc8e82..eed9e3843c 100644
--- a/hw/dummy_m68k.c
+++ b/hw/dummy_m68k.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
diff --git a/hw/esp.c b/hw/esp.c
index aa50800a56..9ddd6373c8 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -244,7 +244,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
lun = busid & 7;
- s->current_req = scsi_req_new(s->current_dev, 0, lun);
+ s->current_req = scsi_req_new(s->current_dev, 0, lun, NULL);
datalen = scsi_req_enqueue(s->current_req, buf);
s->ti_size = datalen;
if (datalen != 0) {
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 6aa4007203..dff5f55f33 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -602,7 +602,7 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory (base, 0x5c, eth->ethregs);
- memcpy(eth->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
+ eth->conf.macaddr = nd->macaddr;
eth->conf.vlan = nd->vlan;
eth->conf.peer = nd->netdev;
diff --git a/hw/flash.h b/hw/flash.h
index c22e1a922c..140ae39801 100644
--- a/hw/flash.h
+++ b/hw/flash.h
@@ -18,14 +18,13 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
int be);
/* nand.c */
-typedef struct NANDFlashState NANDFlashState;
-NANDFlashState *nand_init(int manf_id, int chip_id);
-void nand_done(NANDFlashState *s);
-void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd);
-void nand_getpins(NANDFlashState *s, int *rb);
-void nand_setio(NANDFlashState *s, uint8_t value);
-uint8_t nand_getio(NANDFlashState *s);
+void nand_getpins(DeviceState *dev, int *rb);
+void nand_setio(DeviceState *dev, uint32_t value);
+uint32_t nand_getio(DeviceState *dev);
+uint32_t nand_getbuswidth(DeviceState *dev);
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
@@ -39,7 +38,9 @@ uint8_t nand_getio(NANDFlashState *s);
/* onenand.c */
void onenand_base_update(void *opaque, target_phys_addr_t new);
void onenand_base_unmap(void *opaque);
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq);
+void *onenand_init(BlockDriverState *bdrv,
+ uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
+ int regshift, qemu_irq irq);
void *onenand_raw_otp(void *opaque);
/* ecc.c */
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index 85c8c3c7bf..a29db9055d 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -26,6 +26,7 @@
#include "isa.h"
#include "fw_cfg.h"
#include "sysbus.h"
+#include "qemu-error.h"
/* debug firmware config */
//#define DEBUG_FW_CFG
@@ -56,6 +57,143 @@ struct FWCfgState {
Notifier machine_ready;
};
+#define JPG_FILE 0
+#define BMP_FILE 1
+
+static FILE *probe_splashfile(char *filename, int *file_sizep, int *file_typep)
+{
+ FILE *fp = NULL;
+ int fop_ret;
+ int file_size;
+ int file_type = -1;
+ unsigned char buf[2] = {0, 0};
+ unsigned int filehead_value = 0;
+ int bmp_bpp;
+
+ fp = fopen(filename, "rb");
+ if (fp == NULL) {
+ error_report("failed to open file '%s'.", filename);
+ return fp;
+ }
+ /* check file size */
+ fseek(fp, 0L, SEEK_END);
+ file_size = ftell(fp);
+ if (file_size < 2) {
+ error_report("file size is less than 2 bytes '%s'.", filename);
+ fclose(fp);
+ fp = NULL;
+ return fp;
+ }
+ /* check magic ID */
+ fseek(fp, 0L, SEEK_SET);
+ fop_ret = fread(buf, 1, 2, fp);
+ filehead_value = (buf[0] + (buf[1] << 8)) & 0xffff;
+ if (filehead_value == 0xd8ff) {
+ file_type = JPG_FILE;
+ } else {
+ if (filehead_value == 0x4d42) {
+ file_type = BMP_FILE;
+ }
+ }
+ if (file_type < 0) {
+ error_report("'%s' not jpg/bmp file,head:0x%x.",
+ filename, filehead_value);
+ fclose(fp);
+ fp = NULL;
+ return fp;
+ }
+ /* check BMP bpp */
+ if (file_type == BMP_FILE) {
+ fseek(fp, 28, SEEK_SET);
+ fop_ret = fread(buf, 1, 2, fp);
+ bmp_bpp = (buf[0] + (buf[1] << 8)) & 0xffff;
+ if (bmp_bpp != 24) {
+ error_report("only 24bpp bmp file is supported.");
+ fclose(fp);
+ fp = NULL;
+ return fp;
+ }
+ }
+ /* return values */
+ *file_sizep = file_size;
+ *file_typep = file_type;
+ return fp;
+}
+
+static void fw_cfg_bootsplash(FWCfgState *s)
+{
+ int boot_splash_time = -1;
+ const char *boot_splash_filename = NULL;
+ char *p;
+ char *filename;
+ FILE *fp;
+ int fop_ret;
+ int file_size;
+ int file_type = -1;
+ const char *temp;
+
+ /* get user configuration */
+ QemuOptsList *plist = qemu_find_opts("boot-opts");
+ QemuOpts *opts = QTAILQ_FIRST(&plist->head);
+ if (opts != NULL) {
+ temp = qemu_opt_get(opts, "splash");
+ if (temp != NULL) {
+ boot_splash_filename = temp;
+ }
+ temp = qemu_opt_get(opts, "splash-time");
+ if (temp != NULL) {
+ p = (char *)temp;
+ boot_splash_time = strtol(p, (char **)&p, 10);
+ }
+ }
+
+ /* insert splash time if user configurated */
+ if (boot_splash_time >= 0) {
+ /* validate the input */
+ if (boot_splash_time > 0xffff) {
+ error_report("splash time is big than 65535, force it to 65535.");
+ boot_splash_time = 0xffff;
+ }
+ /* use little endian format */
+ qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
+ qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
+ fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
+ }
+
+ /* insert splash file if user configurated */
+ if (boot_splash_filename != NULL) {
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
+ if (filename == NULL) {
+ error_report("failed to find file '%s'.", boot_splash_filename);
+ return;
+ }
+ /* probing the file */
+ fp = probe_splashfile(filename, &file_size, &file_type);
+ if (fp == NULL) {
+ qemu_free(filename);
+ return;
+ }
+ /* loading file data */
+ if (boot_splash_filedata != NULL) {
+ qemu_free(boot_splash_filedata);
+ }
+ boot_splash_filedata = qemu_malloc(file_size);
+ boot_splash_filedata_size = file_size;
+ fseek(fp, 0L, SEEK_SET);
+ fop_ret = fread(boot_splash_filedata, 1, file_size, fp);
+ fclose(fp);
+ /* insert data */
+ if (file_type == JPG_FILE) {
+ fw_cfg_add_file(s, "bootsplash.jpg",
+ boot_splash_filedata, boot_splash_filedata_size);
+ } else {
+ fw_cfg_add_file(s, "bootsplash.bmp",
+ boot_splash_filedata, boot_splash_filedata_size);
+ }
+ qemu_free(filename);
+ }
+}
+
static void fw_cfg_write(FWCfgState *s, uint8_t value)
{
int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
@@ -316,7 +454,7 @@ int fw_cfg_add_file(FWCfgState *s, const char *filename, uint8_t *data,
return 1;
}
-static void fw_cfg_machine_ready(struct Notifier* n)
+static void fw_cfg_machine_ready(struct Notifier *n, void *data)
{
uint32_t len;
FWCfgState *s = container_of(n, FWCfgState, machine_ready);
@@ -352,7 +490,7 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
-
+ fw_cfg_bootsplash(s);
s->machine_ready.notify = fw_cfg_machine_ready;
qemu_add_machine_init_done_notifier(&s->machine_ready);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index cee07e06c7..da67cf9b38 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -61,7 +61,8 @@ static void pci_grackle_reset(void *opaque)
{
}
-PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
+ MemoryRegion *address_space)
{
DeviceState *dev;
SysBusDevice *s;
@@ -74,7 +75,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
pci_grackle_set_irq,
pci_grackle_map_irq,
- pic, 0, 4);
+ pic, address_space, 0, 4);
pci_create_simple(d->host_state.bus, 0, "grackle");
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 8e1f6a069d..65e63ddab8 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -27,6 +27,7 @@
#include "pci.h"
#include "pci_host.h"
#include "pc.h"
+#include "exec-memory.h"
//#define DEBUG
@@ -1092,7 +1093,8 @@ PCIBus *gt64120_register(qemu_irq *pic)
d = FROM_SYSBUS(GT64120State, s);
d->pci.bus = pci_register_bus(&d->busdev.qdev, "pci",
gt64120_pci_set_irq, gt64120_pci_map_irq,
- pic, PCI_DEVFN(18, 0), 4);
+ pic, get_system_memory(),
+ PCI_DEVFN(18, 0), 4);
d->ISD_handle = cpu_register_io_memory(gt64120_read, gt64120_write, d,
DEVICE_NATIVE_ENDIAN);
diff --git a/hw/hid.c b/hw/hid.c
new file mode 100644
index 0000000000..7b5ef5fc92
--- /dev/null
+++ b/hw/hid.c
@@ -0,0 +1,403 @@
+/*
+ * QEMU HID devices
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
+ *
+ * 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 "console.h"
+#include "qemu-timer.h"
+#include "hid.h"
+
+#define HID_USAGE_ERROR_ROLLOVER 0x01
+#define HID_USAGE_POSTFAIL 0x02
+#define HID_USAGE_ERROR_UNDEFINED 0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
+static const uint8_t hid_usage_keys[0x100] = {
+ 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+ 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+ 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+ 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+ 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+ 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+ 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+ 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+ 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+ 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+ 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+ 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+ 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+ 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+bool hid_has_events(HIDState *hs)
+{
+ return hs->n > 0;
+}
+
+void hid_set_next_idle(HIDState *hs, int64_t curtime)
+{
+ hs->next_idle_clock = curtime + (get_ticks_per_sec() * hs->idle * 4) / 1000;
+}
+
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
+ e->xdx = e->ydy = e->dz = 0;
+ e->buttons_state = buttons;
+}
+
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
+ int x1, int y1, int z1) {
+ if (xyrel) {
+ e->xdx += x1;
+ e->ydy += y1;
+ } else {
+ e->xdx = x1;
+ e->ydy = y1;
+ /* Windows drivers do not like the 0/0 position and ignore such
+ * events. */
+ if (!(x1 | y1)) {
+ x1 = 1;
+ }
+ }
+ e->dz += z1;
+}
+
+static void hid_pointer_event(void *opaque,
+ int x1, int y1, int z1, int buttons_state)
+{
+ HIDState *hs = opaque;
+ 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. */
+ hs->ptr.queue[use_slot].buttons_state = buttons_state;
+ } else if (hs->n < 2 ||
+ hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+ hs->ptr.queue[previous_slot].buttons_state !=
+ hs->ptr.queue[use_slot].buttons_state) {
+ /* Cannot or should not combine, so add an empty item to the queue. */
+ QUEUE_INCR(use_slot);
+ hs->n++;
+ hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
+ }
+ hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+ hs->kind == HID_MOUSE,
+ x1, y1, z1);
+ hs->event(hs);
+}
+
+static void hid_keyboard_event(void *opaque, int keycode)
+{
+ HIDState *hs = opaque;
+ 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++;
+ hs->kbd.keycodes[slot] = keycode;
+ hs->event(hs);
+}
+
+static void hid_keyboard_process_keycode(HIDState *hs)
+{
+ uint8_t hid_code, key;
+ int i, keycode, slot;
+
+ if (hs->n == 0) {
+ return;
+ }
+ slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+ keycode = hs->kbd.keycodes[slot];
+
+ key = keycode & 0x7f;
+ hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+ hs->kbd.modifiers &= ~(1 << 8);
+
+ switch (hid_code) {
+ case 0x00:
+ return;
+
+ case 0xe0:
+ if (hs->kbd.modifiers & (1 << 9)) {
+ hs->kbd.modifiers ^= 3 << 8;
+ return;
+ }
+ case 0xe1 ... 0xe7:
+ if (keycode & (1 << 7)) {
+ hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
+ return;
+ }
+ case 0xe8 ... 0xef:
+ hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
+ return;
+ }
+
+ if (keycode & (1 << 7)) {
+ for (i = hs->kbd.keys - 1; i >= 0; i--) {
+ if (hs->kbd.key[i] == hid_code) {
+ hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+ hs->kbd.key[hs->kbd.keys] = 0x00;
+ break;
+ }
+ }
+ if (i < 0) {
+ return;
+ }
+ } else {
+ for (i = hs->kbd.keys - 1; i >= 0; i--) {
+ if (hs->kbd.key[i] == hid_code) {
+ break;
+ }
+ }
+ if (i < 0) {
+ if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+ hs->kbd.key[hs->kbd.keys++] = hid_code;
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+ if (val < vmin) {
+ return vmin;
+ } else if (val > vmax) {
+ return vmax;
+ } else {
+ return val;
+ }
+}
+
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
+{
+ int dx, dy, dz, b, l;
+ int index;
+ HIDPointerEvent *e;
+
+ if (!hs->ptr.mouse_grabbed) {
+ qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+ hs->ptr.mouse_grabbed = 1;
+ }
+
+ /* When the buffer is empty, return the last event. Relative
+ movements will all be zero. */
+ index = (hs->n ? hs->head : hs->head - 1);
+ e = &hs->ptr.queue[index & QUEUE_MASK];
+
+ if (hs->kind == HID_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 (e->buttons_state & MOUSE_EVENT_LBUTTON) {
+ b |= 0x01;
+ }
+ if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
+ b |= 0x02;
+ }
+ if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
+ b |= 0x04;
+ }
+
+ if (hs->n &&
+ !e->dz &&
+ (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
+ /* that deals with this event */
+ QUEUE_INCR(hs->head);
+ hs->n--;
+ }
+
+ /* Appears we have to invert the wheel direction */
+ dz = 0 - dz;
+ l = 0;
+ switch (hs->kind) {
+ case HID_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 HID_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;
+
+ default:
+ abort();
+ }
+
+ return l;
+}
+
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
+{
+ if (len < 2) {
+ return 0;
+ }
+
+ hid_keyboard_process_keycode(hs);
+
+ buf[0] = hs->kbd.modifiers & 0xff;
+ buf[1] = 0;
+ if (hs->kbd.keys > 6) {
+ memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+ } else {
+ memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+ }
+
+ return MIN(8, len);
+}
+
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
+{
+ if (len > 0) {
+ int ledstate = 0;
+ /* 0x01: Num Lock LED
+ * 0x02: Caps Lock LED
+ * 0x04: Scroll Lock LED
+ * 0x08: Compose LED
+ * 0x10: Kana LED */
+ hs->kbd.leds = buf[0];
+ if (hs->kbd.leds & 0x04) {
+ ledstate |= QEMU_SCROLL_LOCK_LED;
+ }
+ if (hs->kbd.leds & 0x01) {
+ ledstate |= QEMU_NUM_LOCK_LED;
+ }
+ if (hs->kbd.leds & 0x02) {
+ ledstate |= QEMU_CAPS_LOCK_LED;
+ }
+ kbd_put_ledstate(ledstate);
+ }
+ return 0;
+}
+
+void hid_reset(HIDState *hs)
+{
+ switch (hs->kind) {
+ case HID_KEYBOARD:
+ qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+ memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+ memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+ hs->kbd.keys = 0;
+ break;
+ case HID_MOUSE:
+ case HID_TABLET:
+ memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+ break;
+ }
+ hs->head = 0;
+ hs->n = 0;
+ hs->protocol = 1;
+ hs->idle = 0;
+}
+
+void hid_free(HIDState *hs)
+{
+ switch (hs->kind) {
+ case HID_KEYBOARD:
+ qemu_remove_kbd_event_handler();
+ break;
+ case HID_MOUSE:
+ case HID_TABLET:
+ qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+ break;
+ }
+}
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
+ hs->kind = kind;
+ hs->event = event;
+
+ if (hs->kind == HID_MOUSE) {
+ hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+ 0, "QEMU HID Mouse");
+ } else if (hs->kind == HID_TABLET) {
+ hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+ 1, "QEMU HID Tablet");
+ }
+}
diff --git a/hw/hid.h b/hw/hid.h
new file mode 100644
index 0000000000..4a8fa5b63f
--- /dev/null
+++ b/hw/hid.h
@@ -0,0 +1,58 @@
+#ifndef QEMU_HID_H
+#define QEMU_HID_H
+
+#define HID_MOUSE 1
+#define HID_TABLET 2
+#define HID_KEYBOARD 3
+
+typedef struct HIDPointerEvent {
+ int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+ int32_t dz, buttons_state;
+} HIDPointerEvent;
+
+#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 HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
+typedef struct HIDMouseState {
+ HIDPointerEvent queue[QUEUE_LENGTH];
+ int mouse_grabbed;
+ QEMUPutMouseEntry *eh_entry;
+} HIDMouseState;
+
+typedef struct HIDKeyboardState {
+ uint32_t keycodes[QUEUE_LENGTH];
+ uint16_t modifiers;
+ uint8_t leds;
+ uint8_t key[16];
+ int32_t keys;
+} HIDKeyboardState;
+
+struct HIDState {
+ union {
+ HIDMouseState ptr;
+ HIDKeyboardState kbd;
+ };
+ uint32_t head; /* index into circular queue */
+ uint32_t n;
+ int kind;
+ int32_t protocol;
+ uint8_t idle;
+ int64_t next_idle_clock;
+ HIDEventFunc event;
+};
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event);
+void hid_reset(HIDState *hs);
+void hid_free(HIDState *hs);
+
+bool hid_has_events(HIDState *hs);
+void hid_set_next_idle(HIDState *hs, int64_t curtime);
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len);
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len);
+
+#endif /* QEMU_HID_H */
diff --git a/hw/hw.h b/hw/hw.h
index 9dd7096fc2..df6ca65058 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -324,6 +324,7 @@ typedef struct VMStateSubsection {
struct VMStateDescription {
const char *name;
+ int unmigratable;
int version_id;
int minimum_version_id;
int minimum_version_id_old;
diff --git a/hw/i2c.c b/hw/i2c.c
index f80d12db4f..49b9ecb8b6 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*/
#include "i2c.h"
diff --git a/hw/i2c.h b/hw/i2c.h
index 5514402029..9381d01589 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -72,6 +72,6 @@ void wm8750_set_bclk_in(void *opaque, int new_hz);
void tmp105_set(i2c_slave *i2c, int temp);
/* lm832x.c */
-void lm832x_key_event(i2c_slave *i2c, int key, int state);
+void lm832x_key_event(DeviceState *dev, int key, int state);
#endif
diff --git a/hw/ide.h b/hw/ide.h
index 34d9394bcc..a490cbb6c5 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -13,6 +13,7 @@ ISADevice *isa_ide_init(int iobase, int iobase2, int isairq,
/* ide-pci.c */
void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
int secondary_ide_enabled);
+PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 054e0734e4..d241ea8005 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -72,6 +72,11 @@
#include <hw/ide/pci.h>
#include <hw/ide/ahci.h>
+static const VMStateDescription vmstate_ahci = {
+ .name = "ahci",
+ .unmigratable = 1,
+};
+
static int pci_ich9_ahci_init(PCIDevice *dev)
{
struct AHCIPCIState *d;
@@ -123,6 +128,7 @@ static PCIDeviceInfo ich_ahci_info[] = {
.qdev.name = "ich9-ahci",
.qdev.alias = "ahci",
.qdev.size = sizeof(AHCIPCIState),
+ .qdev.vmsd = &vmstate_ahci,
.init = pci_ich9_ahci_init,
.exit = pci_ich9_uninit,
.config_write = pci_ich9_write_config,
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 84f72b0a66..f527dbd57e 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -149,6 +149,42 @@ static int pci_piix_ide_initfn(PCIDevice *dev)
return 0;
}
+static int pci_piix3_xen_ide_unplug(DeviceState *dev)
+{
+ PCIDevice *pci_dev;
+ PCIIDEState *pci_ide;
+ DriveInfo *di;
+ int i = 0;
+
+ pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
+ pci_ide = DO_UPCAST(PCIIDEState, dev, pci_dev);
+
+ for (; i < 3; i++) {
+ di = drive_get_by_index(IF_IDE, i);
+ if (di != NULL && di->bdrv != NULL && !di->bdrv->removable) {
+ DeviceState *ds = bdrv_get_attached(di->bdrv);
+ if (ds) {
+ bdrv_detach(di->bdrv, ds);
+ }
+ bdrv_close(di->bdrv);
+ pci_ide->bus[di->bus].ifs[di->unit].bs = NULL;
+ drive_put_ref(di);
+ }
+ }
+ qdev_reset_all(&(pci_ide->dev.qdev));
+ return 0;
+}
+
+PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
+{
+ PCIDevice *dev;
+
+ dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
+ dev->qdev.info->unplug = pci_piix3_xen_ide_unplug;
+ pci_ide_create_devs(dev, hd_table);
+ return dev;
+}
+
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
@@ -182,6 +218,14 @@ static PCIDeviceInfo piix_ide_info[] = {
.device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
.class_id = PCI_CLASS_STORAGE_IDE,
},{
+ .qdev.name = "piix3-ide-xen",
+ .qdev.size = sizeof(PCIIDEState),
+ .qdev.no_user = 1,
+ .init = pci_piix_ide_initfn,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
+ .class_id = PCI_CLASS_STORAGE_IDE,
+ },{
.qdev.name = "piix4-ide",
.qdev.size = sizeof(PCIIDEState),
.qdev.no_user = 1,
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index d9b8f24bb5..6bd8d20270 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -31,6 +31,10 @@ static struct BusInfo ide_bus_info = {
.name = "IDE",
.size = sizeof(IDEBus),
.get_fw_dev_path = idebus_get_fw_dev_path,
+ .props = (Property[]) {
+ DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
+ DEFINE_PROP_END_OF_LIST(),
+ },
};
void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
@@ -174,7 +178,6 @@ static int ide_drive_initfn(IDEDevice *dev)
}
#define DEFINE_IDE_DEV_PROPERTIES() \
- DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1), \
DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf), \
DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
DEFINE_PROP_STRING("serial", IDEDrive, dev.serial)
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index a6c27be82c..281410899f 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "sysbus.h"
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 3f3c05df4c..73a8661ca3 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery, LLC.
* Written by Paul Brook
*
- * This code is licenced under the GNU GPL v2
+ * This code is licensed under the GNU GPL v2
*/
#include "sysbus.h"
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 590a4ccff9..992ce49729 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -474,9 +474,9 @@ static int lm8323_init(i2c_slave *i2c)
return 0;
}
-void lm832x_key_event(struct i2c_slave *i2c, int key, int state)
+void lm832x_key_event(DeviceState *dev, int key, int state)
{
- LM823KbdState *s = (LM823KbdState *) i2c;
+ LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE_FROM_QDEV(dev));
if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
return;
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 940b43abfd..e9904c49d9 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*/
/* ??? Need to check if the {read,write}[wl] routines work properly on
@@ -661,7 +661,7 @@ static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
static void lsi_request_cancelled(SCSIRequest *req)
{
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
- lsi_request *p;
+ lsi_request *p = req->hba_private;
if (s->current && req == s->current->req) {
scsi_req_unref(req);
@@ -670,7 +670,6 @@ static void lsi_request_cancelled(SCSIRequest *req)
return;
}
- p = lsi_find_by_tag(s, req->tag);
if (p) {
QTAILQ_REMOVE(&s->queue, p, next);
scsi_req_unref(req);
@@ -680,18 +679,12 @@ static void lsi_request_cancelled(SCSIRequest *req)
/* Record that data is available for a queued command. Returns zero if
the device was reselected, nonzero if the IO is deferred. */
-static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t len)
+static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
{
- lsi_request *p;
-
- p = lsi_find_by_tag(s, tag);
- if (!p) {
- BADF("IO with unknown tag %d\n", tag);
- return 1;
- }
+ lsi_request *p = req->hba_private;
if (p->pending) {
- BADF("Multiple IO pending for tag %d\n", tag);
+ BADF("Multiple IO pending for request %p\n", p);
}
p->pending = len;
/* Reselect if waiting for it, or if reselection triggers an IRQ
@@ -743,9 +736,9 @@ static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
int out;
- if (s->waiting == 1 || !s->current || req->tag != s->current->tag ||
+ if (s->waiting == 1 || !s->current || req->hba_private != s->current ||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
- if (lsi_queue_tag(s, req->tag, len)) {
+ if (lsi_queue_req(s, req, len)) {
return;
}
}
@@ -789,7 +782,8 @@ static void lsi_do_command(LSIState *s)
assert(s->current == NULL);
s->current = qemu_mallocz(sizeof(lsi_request));
s->current->tag = s->select_tag;
- s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun);
+ s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun,
+ s->current);
n = scsi_req_enqueue(s->current->req, buf);
if (n) {
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 3eff925b0e..f8c5242867 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 2008 Jan Kiszka
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "sysbus.h"
#include "hw.h"
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 1c9a706b1b..feb3b25acd 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -99,6 +99,7 @@ typedef struct RTCState {
QEMUTimer *coalesced_timer;
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
+ Notifier clock_reset_notifier;
} RTCState;
static void rtc_set_time(RTCState *s);
@@ -572,6 +573,22 @@ static const VMStateDescription vmstate_rtc = {
}
};
+static void rtc_notify_clock_reset(Notifier *notifier, void *data)
+{
+ RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
+ int64_t now = *(int64_t *)data;
+
+ rtc_set_date_from_host(&s->dev);
+ s->next_second_time = now + (get_ticks_per_sec() * 99) / 100;
+ qemu_mod_timer(s->second_timer2, s->next_second_time);
+ rtc_timer_update(s, now);
+#ifdef TARGET_I386
+ if (rtc_td_hack) {
+ rtc_coalesced_timer_update(s);
+ }
+#endif
+}
+
static void rtc_reset(void *opaque)
{
RTCState *s = opaque;
@@ -608,6 +625,9 @@ static int rtc_initfn(ISADevice *dev)
s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
+ s->clock_reset_notifier.notify = rtc_notify_clock_reset;
+ qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
+
s->next_second_time =
qemu_get_clock_ns(rtc_clock) + (get_ticks_per_sec() * 99) / 100;
qemu_mod_timer(s->second_timer2, s->next_second_time);
diff --git a/hw/mcf5206.c b/hw/mcf5206.c
index 2a618d4446..fce282d98b 100644
--- a/hw/mcf5206.c
+++ b/hw/mcf5206.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index 17a692d4a3..78fbc5f232 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
index 21035da345..748eb5906b 100644
--- a/hw/mcf_fec.c
+++ b/hw/mcf_fec.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
#include "net.h"
@@ -471,7 +471,7 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(base, 0x400, s->mmio_index);
- memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
+ s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
s->conf.peer = nd->netdev;
diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c
index ac04295198..6cb0a09b7f 100644
--- a/hw/mcf_intc.c
+++ b/hw/mcf_intc.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
index db57096af2..905e116de6 100644
--- a/hw/mcf_uart.c
+++ b/hw/mcf_uart.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "hw.h"
#include "mcf.h"
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 5ab35c3827..75c85aeb6f 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -234,11 +234,11 @@ static void softusb_usbdev_datain(void *opaque)
USBPacket p;
- p.pid = USB_TOKEN_IN;
- p.devep = 1;
- p.data = s->kbd_usb_buffer;
- p.len = sizeof(s->kbd_usb_buffer);
+ usb_packet_init(&p);
+ usb_packet_setup(&p, USB_TOKEN_IN, 0, 1);
+ usb_packet_addbuf(&p, s->kbd_usb_buffer, sizeof(s->kbd_usb_buffer));
s->usbdev->info->handle_data(s->usbdev, &p);
+ usb_packet_cleanup(&p);
softusb_kbd_changed(s);
}
@@ -247,16 +247,21 @@ static void softusb_attach(USBPort *port)
{
}
-static void softusb_device_destroy(USBBus *bus, USBDevice *dev)
+static void softusb_detach(USBPort *port)
+{
+}
+
+static void softusb_child_detach(USBPort *port, USBDevice *child)
{
}
static USBPortOps softusb_ops = {
.attach = softusb_attach,
+ .detach = softusb_detach,
+ .child_detach = softusb_child_detach,
};
static USBBusOps softusb_bus_ops = {
- .device_destroy = softusb_device_destroy,
};
static void milkymist_softusb_reset(DeviceState *d)
@@ -305,10 +310,12 @@ static int milkymist_softusb_init(SysBusDevice *dev)
usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
/* our two ports */
+ /* FIXME: claim to support full speed devices. qemu mouse and keyboard
+ * report themselves as full speed devices. */
usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
- USB_SPEED_MASK_LOW);
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
- USB_SPEED_MASK_LOW);
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
/* and finally create an usb keyboard */
s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
diff --git a/hw/mips.h b/hw/mips.h
index 73aa8f8b0e..cae5f4c804 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -8,10 +8,6 @@ PCIBus *gt64120_register(qemu_irq *pic);
/* bonito.c */
PCIBus *bonito_init(qemu_irq *pic);
-/* ds1225y.c */
-void *ds1225y_init(target_phys_addr_t mem_base, const char *filename);
-void ds1225y_set_protection(void *opaque, int protection);
-
/* g364fb.c */
int g364fb_mm_init(target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift,
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index a1003945fd..f6ab6dc455 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -37,6 +37,7 @@
#include "loader.h"
#include "mc146818rtc.h"
#include "blockdev.h"
+#include "sysbus.h"
enum jazz_model_e
{
@@ -115,6 +116,8 @@ void mips_jazz_init (ram_addr_t ram_size,
void* rc4030_opaque;
int s_rtc, s_dma_dummy;
NICInfo *nd;
+ DeviceState *dev;
+ SysBusDevice *sysbus;
ISADevice *pit;
DriveInfo *fds[MAX_FD];
qemu_irq esp_reset, dma_enable;
@@ -266,8 +269,11 @@ void mips_jazz_init (ram_addr_t ram_size,
/* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */
audio_init(i8259, NULL);
- /* NVRAM: Unprotected at 0x9000, Protected at 0xa000, Read only at 0xb000 */
- ds1225y_init(0x80009000, "nvram");
+ /* NVRAM */
+ dev = qdev_create(NULL, "ds1225y");
+ qdev_init_nofail(dev);
+ sysbus = sysbus_from_qdev(dev);
+ sysbus_mmio_map(sysbus, 0, 0x80009000);
/* LED indicator */
jazz_led_init(0x8000f000);
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index 26aad51eab..0db3ba7a89 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -258,7 +258,7 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
s->irq = irq;
if (nd) {
- memcpy(s->conf.macaddr.a, nd->macaddr, sizeof(nd->macaddr));
+ s->conf.macaddr = nd->macaddr;
s->conf.vlan = nd->vlan;
s->conf.peer = nd->netdev;
diff --git a/hw/mpcore.c b/hw/mpcore.c
index 379065a3eb..d778507516 100644
--- a/hw/mpcore.c
+++ b/hw/mpcore.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/msmouse.c b/hw/msmouse.c
index 05f893ca93..67c6cd43e0 100644
--- a/hw/msmouse.c
+++ b/hw/msmouse.c
@@ -64,7 +64,7 @@ static void msmouse_chr_close (struct CharDriverState *chr)
qemu_free (chr);
}
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
+int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr)
{
CharDriverState *chr;
@@ -74,5 +74,6 @@ CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts)
qemu_add_mouse_event_handler(msmouse_event, chr, 0, "QEMU Microsoft Mouse");
- return chr;
+ *_chr = chr;
+ return 0;
}
diff --git a/hw/msmouse.h b/hw/msmouse.h
index 456cb21424..8b853b35bf 100644
--- a/hw/msmouse.h
+++ b/hw/msmouse.h
@@ -1,2 +1,2 @@
/* msmouse.c */
-CharDriverState *qemu_chr_open_msmouse(QemuOpts *opts);
+int qemu_chr_open_msmouse(QemuOpts *opts, CharDriverState **_chr);
diff --git a/hw/multiboot.c b/hw/multiboot.c
index 6e6cfb9531..a1d3f41293 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -97,11 +97,11 @@ typedef struct {
static uint32_t mb_add_cmdline(MultibootState *s, const char *cmdline)
{
- int len = strlen(cmdline) + 1;
target_phys_addr_t p = s->offset_cmdlines;
+ char *b = (char *)s->mb_buf + p;
- pstrcpy((char *)s->mb_buf + p, len, cmdline);
- s->offset_cmdlines += len;
+ get_opt_value(b, strlen(cmdline) + 1, cmdline);
+ s->offset_cmdlines += strlen(b) + 1;
return s->mb_buf_phys + p;
}
@@ -198,11 +198,14 @@ int load_multiboot(void *fw_cfg,
} else {
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_ADDR. */
uint32_t mh_header_addr = ldl_p(header+i+12);
+ uint32_t mh_load_end_addr = ldl_p(header+i+20);
+ uint32_t mh_bss_end_addr = ldl_p(header+i+24);
mh_load_addr = ldl_p(header+i+16);
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
+ uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
mh_entry_addr = ldl_p(header+i+28);
- mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
+ mb_kernel_size = mh_bss_end_addr - mh_load_addr;
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
uint32_t mh_mode_type = ldl_p(header+i+32);
@@ -212,17 +215,18 @@ int load_multiboot(void *fw_cfg,
mb_debug("multiboot: mh_header_addr = %#x\n", mh_header_addr);
mb_debug("multiboot: mh_load_addr = %#x\n", mh_load_addr);
- mb_debug("multiboot: mh_load_end_addr = %#x\n", ldl_p(header+i+20));
- mb_debug("multiboot: mh_bss_end_addr = %#x\n", ldl_p(header+i+24));
+ mb_debug("multiboot: mh_load_end_addr = %#x\n", mh_load_end_addr);
+ mb_debug("multiboot: mh_bss_end_addr = %#x\n", mh_bss_end_addr);
mb_debug("qemu: loading multiboot kernel (%#x bytes) at %#x\n",
- mb_kernel_size, mh_load_addr);
+ mb_load_size, mh_load_addr);
mbs.mb_buf = qemu_malloc(mb_kernel_size);
fseek(f, mb_kernel_text_offset, SEEK_SET);
- if (fread(mbs.mb_buf, 1, mb_kernel_size, f) != mb_kernel_size) {
+ if (fread(mbs.mb_buf, 1, mb_load_size, f) != mb_load_size) {
fprintf(stderr, "fread() failed\n");
exit(1);
}
+ memset(mbs.mb_buf + mb_load_size, 0, mb_kernel_size - mb_load_size);
fclose(f);
}
@@ -238,7 +242,7 @@ int load_multiboot(void *fw_cfg,
const char *r = initrd_filename;
mbs.mb_buf_size += strlen(r) + 1;
mbs.mb_mods_avail = 1;
- while ((r = strchr(r, ','))) {
+ while (*(r = get_opt_value(NULL, 0, r))) {
mbs.mb_mods_avail++;
r++;
}
@@ -252,7 +256,7 @@ int load_multiboot(void *fw_cfg,
mbs.offset_cmdlines = mbs.offset_mbinfo + mbs.mb_mods_avail * MB_MOD_SIZE;
if (initrd_filename) {
- char *next_initrd;
+ char *next_initrd, not_last;
mbs.offset_mods = mbs.mb_buf_size;
@@ -261,9 +265,9 @@ int load_multiboot(void *fw_cfg,
int mb_mod_length;
uint32_t offs = mbs.mb_buf_size;
- next_initrd = strchr(initrd_filename, ',');
- if (next_initrd)
- *next_initrd = '\0';
+ next_initrd = (char *)get_opt_value(NULL, 0, initrd_filename);
+ not_last = *next_initrd;
+ *next_initrd = '\0';
/* if a space comes after the module filename, treat everything
after that as parameters */
target_phys_addr_t c = mb_add_cmdline(&mbs, initrd_filename);
@@ -287,7 +291,7 @@ int load_multiboot(void *fw_cfg,
(char *)mbs.mb_buf + offs,
(char *)mbs.mb_buf + offs + mb_mod_length, c);
initrd_filename = next_initrd+1;
- } while (next_initrd);
+ } while (not_last);
}
/* Commandline support */
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 52b2931d15..63dd391176 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2008 Jan Kiszka
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "sysbus.h"
diff --git a/hw/nand.c b/hw/nand.c
index 37e51d7140..28d9f0b60d 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -6,6 +6,10 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * from ST Microelectronics.
+ *
* This code is licensed under the GNU GPL v2.
*/
@@ -14,7 +18,7 @@
# include "hw.h"
# include "flash.h"
# include "blockdev.h"
-/* FIXME: Pass block device as an argument. */
+# include "sysbus.h"
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
@@ -44,8 +48,11 @@
# define MAX_PAGE 0x800
# define MAX_OOB 0x40
+typedef struct NANDFlashState NANDFlashState;
struct NANDFlashState {
+ SysBusDevice busdev;
uint8_t manf_id, chip_id;
+ uint8_t buswidth; /* in BYTES */
int size, pages;
int page_shift, oob_shift, erase_shift, addr_shift;
uint8_t *storage;
@@ -58,18 +65,28 @@ struct NANDFlashState {
uint8_t *ioaddr;
int iolen;
- uint32_t cmd, addr;
+ uint32_t cmd;
+ uint64_t addr;
int addrlen;
int status;
int offset;
void (*blk_write)(NANDFlashState *s);
void (*blk_erase)(NANDFlashState *s);
- void (*blk_load)(NANDFlashState *s, uint32_t addr, int offset);
+ void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
uint32_t ioaddr_vmstate;
};
+static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
+{
+ /* Like memcpy() but we logical-AND the data into the destination */
+ int i;
+ for (i = 0; i < n; i++) {
+ dest[i] &= src[i];
+ }
+}
+
# define NAND_NO_AUTOINCR 0x00000001
# define NAND_BUSWIDTH_16 0x00000002
# define NAND_NO_PADDING 0x00000004
@@ -201,8 +218,9 @@ static const struct {
[0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 },
};
-static void nand_reset(NANDFlashState *s)
+static void nand_reset(DeviceState *dev)
{
+ NANDFlashState *s = FROM_SYSBUS(NANDFlashState, sysbus_from_qdev(dev));
s->cmd = NAND_CMD_READ0;
s->addr = 0;
s->addrlen = 0;
@@ -211,6 +229,14 @@ static void nand_reset(NANDFlashState *s)
s->status &= NAND_IOSTATUS_UNPROTCT;
}
+static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
+{
+ s->ioaddr[s->iolen++] = value;
+ for (value = s->buswidth; --value;) {
+ s->ioaddr[s->iolen++] = 0;
+ }
+}
+
static void nand_command(NANDFlashState *s)
{
unsigned int offset;
@@ -220,15 +246,19 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_READID:
- s->io[0] = s->manf_id;
- s->io[1] = s->chip_id;
- s->io[2] = 'Q'; /* Don't-care byte (often 0xa5) */
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
- s->io[3] = 0x15; /* Page Size, Block Size, Spare Size.. */
- else
- s->io[3] = 0xc0; /* Multi-plane */
s->ioaddr = s->io;
- s->iolen = 4;
+ s->iolen = 0;
+ nand_pushio_byte(s, s->manf_id);
+ nand_pushio_byte(s, s->chip_id);
+ nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
+ if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+ /* Page Size, Block Size, Spare Size; bit 6 indicates
+ * 8 vs 16 bit width NAND.
+ */
+ nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
+ } else {
+ nand_pushio_byte(s, 0xc0); /* Multi-plane */
+ }
break;
case NAND_CMD_RANDOMREAD2:
@@ -244,7 +274,7 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_RESET:
- nand_reset(s);
+ nand_reset(&s->busdev.qdev);
break;
case NAND_CMD_PAGEPROGRAM1:
@@ -273,9 +303,9 @@ static void nand_command(NANDFlashState *s)
break;
case NAND_CMD_READSTATUS:
- s->io[0] = s->status;
s->ioaddr = s->io;
- s->iolen = 1;
+ s->iolen = 0;
+ nand_pushio_byte(s, s->status);
break;
default:
@@ -304,9 +334,9 @@ static int nand_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_nand = {
.name = "nand",
- .version_id = 0,
- .minimum_version_id = 0,
- .minimum_version_id_old = 0,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
.pre_save = nand_pre_save,
.post_load = nand_post_load,
.fields = (VMStateField[]) {
@@ -319,7 +349,7 @@ static const VMStateDescription vmstate_nand = {
VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
VMSTATE_INT32(iolen, NANDFlashState),
VMSTATE_UINT32(cmd, NANDFlashState),
- VMSTATE_UINT32(addr, NANDFlashState),
+ VMSTATE_UINT64(addr, NANDFlashState),
VMSTATE_INT32(addrlen, NANDFlashState),
VMSTATE_INT32(status, NANDFlashState),
VMSTATE_INT32(offset, NANDFlashState),
@@ -328,15 +358,85 @@ static const VMStateDescription vmstate_nand = {
}
};
+static int nand_device_init(SysBusDevice *dev)
+{
+ int pagesize;
+ NANDFlashState *s = FROM_SYSBUS(NANDFlashState, dev);
+
+ s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
+ s->size = nand_flash_ids[s->chip_id].size << 20;
+ if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+ s->page_shift = 11;
+ s->erase_shift = 6;
+ } else {
+ s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+ s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+ }
+
+ switch (1 << s->page_shift) {
+ case 256:
+ nand_init_256(s);
+ break;
+ case 512:
+ nand_init_512(s);
+ break;
+ case 2048:
+ nand_init_2048(s);
+ break;
+ default:
+ hw_error("%s: Unsupported NAND block size.\n", __func__);
+ }
+
+ pagesize = 1 << s->oob_shift;
+ s->mem_oob = 1;
+ if (s->bdrv && bdrv_getlength(s->bdrv) >=
+ (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+ pagesize = 0;
+ s->mem_oob = 0;
+ }
+
+ if (!s->bdrv) {
+ pagesize += 1 << s->page_shift;
+ }
+ if (pagesize) {
+ s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
+ 0xff, s->pages * pagesize);
+ }
+ /* Give s->ioaddr a sane value in case we save state before it is used. */
+ s->ioaddr = s->io;
+
+ return 0;
+}
+
+static SysBusDeviceInfo nand_info = {
+ .init = nand_device_init,
+ .qdev.name = "nand",
+ .qdev.size = sizeof(NANDFlashState),
+ .qdev.reset = nand_reset,
+ .qdev.vmsd = &vmstate_nand,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+ DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+ DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void nand_create_device(void)
+{
+ sysbus_register_withprop(&nand_info);
+}
+
/*
* Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip
* outputs are R/B and eight I/O pins.
*
* CE, WP and R/B are active low.
*/
-void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
uint8_t ce, uint8_t wp, uint8_t gnd)
{
+ NANDFlashState *s = (NANDFlashState *) dev;
s->cle = cle;
s->ale = ale;
s->ce = ce;
@@ -348,13 +448,15 @@ void nand_setpins(NANDFlashState *s, uint8_t cle, uint8_t ale,
s->status &= ~NAND_IOSTATUS_UNPROTCT;
}
-void nand_getpins(NANDFlashState *s, int *rb)
+void nand_getpins(DeviceState *dev, int *rb)
{
*rb = 1;
}
-void nand_setio(NANDFlashState *s, uint8_t value)
+void nand_setio(DeviceState *dev, uint32_t value)
{
+ int i;
+ NANDFlashState *s = (NANDFlashState *) dev;
if (!s->ce && s->cle) {
if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
@@ -400,40 +502,69 @@ void nand_setio(NANDFlashState *s, uint8_t value)
s->addr = (s->addr & mask) | v;
s->addrlen ++;
- if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
- nand_command(s);
-
- if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- s->addrlen == 3 && (
- s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1))
- nand_command(s);
- if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
- s->addrlen == 4 && (
- s->cmd == NAND_CMD_READ0 ||
- s->cmd == NAND_CMD_PAGEPROGRAM1))
- nand_command(s);
+ switch (s->addrlen) {
+ case 1:
+ if (s->cmd == NAND_CMD_READID) {
+ nand_command(s);
+ }
+ break;
+ case 2: /* fix cache address as a byte address */
+ s->addr <<= (s->buswidth - 1);
+ break;
+ case 3:
+ if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+ (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+ nand_command(s);
+ }
+ break;
+ case 4:
+ if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+ nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
+ (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+ nand_command(s);
+ }
+ break;
+ case 5:
+ if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+ nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
+ (s->cmd == NAND_CMD_READ0 ||
+ s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+ nand_command(s);
+ }
+ break;
+ default:
+ break;
+ }
}
if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
- if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
- s->io[s->iolen ++] = value;
+ if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
+ for (i = s->buswidth; i--; value >>= 8) {
+ s->io[s->iolen ++] = (uint8_t) (value & 0xff);
+ }
+ }
} else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
if ((s->addr & ((1 << s->addr_shift) - 1)) <
(1 << s->page_shift) + (1 << s->oob_shift)) {
- s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
- s->addr ++;
+ for (i = s->buswidth; i--; s->addr++, value >>= 8) {
+ s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+ (uint8_t) (value & 0xff);
+ }
}
}
}
-uint8_t nand_getio(NANDFlashState *s)
+uint32_t nand_getio(DeviceState *dev)
{
int offset;
+ uint32_t x = 0;
+ NANDFlashState *s = (NANDFlashState *) dev;
/* Allow sequential reading */
if (!s->iolen && s->cmd == NAND_CMD_READ0) {
- offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+ offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
s->offset = 0;
s->blk_load(s, s->addr, offset);
@@ -446,129 +577,90 @@ uint8_t nand_getio(NANDFlashState *s)
if (s->ce || s->iolen <= 0)
return 0;
- s->iolen --;
- s->addr++;
- return *(s->ioaddr ++);
+ for (offset = s->buswidth; offset--;) {
+ x |= s->ioaddr[offset] << (offset << 3);
+ }
+ /* after receiving READ STATUS command all subsequent reads will
+ * return the status register value until another command is issued
+ */
+ if (s->cmd != NAND_CMD_READSTATUS) {
+ s->addr += s->buswidth;
+ s->ioaddr += s->buswidth;
+ s->iolen -= s->buswidth;
+ }
+ return x;
+}
+
+uint32_t nand_getbuswidth(DeviceState *dev)
+{
+ NANDFlashState *s = (NANDFlashState *) dev;
+ return s->buswidth << 3;
}
-NANDFlashState *nand_init(int manf_id, int chip_id)
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
{
- int pagesize;
- NANDFlashState *s;
- DriveInfo *dinfo;
+ DeviceState *dev;
if (nand_flash_ids[chip_id].size == 0) {
hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
}
-
- s = (NANDFlashState *) qemu_mallocz(sizeof(NANDFlashState));
- dinfo = drive_get(IF_MTD, 0, 0);
- if (dinfo)
- s->bdrv = dinfo->bdrv;
- s->manf_id = manf_id;
- s->chip_id = chip_id;
- s->size = nand_flash_ids[s->chip_id].size << 20;
- if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
- s->page_shift = 11;
- s->erase_shift = 6;
- } else {
- s->page_shift = nand_flash_ids[s->chip_id].page_shift;
- s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+ dev = qdev_create(NULL, "nand");
+ qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
+ qdev_prop_set_uint8(dev, "chip_id", chip_id);
+ if (bdrv) {
+ qdev_prop_set_drive_nofail(dev, "drive", bdrv);
}
- switch (1 << s->page_shift) {
- case 256:
- nand_init_256(s);
- break;
- case 512:
- nand_init_512(s);
- break;
- case 2048:
- nand_init_2048(s);
- break;
- default:
- hw_error("%s: Unsupported NAND block size.\n", __FUNCTION__);
- }
-
- pagesize = 1 << s->oob_shift;
- s->mem_oob = 1;
- if (s->bdrv && bdrv_getlength(s->bdrv) >=
- (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
- pagesize = 0;
- s->mem_oob = 0;
- }
-
- if (!s->bdrv)
- pagesize += 1 << s->page_shift;
- if (pagesize)
- s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
- 0xff, s->pages * pagesize);
- /* Give s->ioaddr a sane value in case we save state before it
- is used. */
- s->ioaddr = s->io;
-
- vmstate_register(NULL, -1, &vmstate_nand, s);
-
- return s;
+ qdev_init_nofail(dev);
+ return dev;
}
-void nand_done(NANDFlashState *s)
-{
- if (s->bdrv) {
- bdrv_close(s->bdrv);
- bdrv_delete(s->bdrv);
- }
-
- if (!s->bdrv || s->mem_oob)
- qemu_free(s->storage);
-
- qemu_free(s);
-}
+device_init(nand_create_device)
#else
/* Program a single page */
static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
{
- uint32_t off, page, sector, soff;
+ uint64_t off, page, sector, soff;
uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
if (PAGE(s->addr) >= s->pages)
return;
if (!s->bdrv) {
- memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+ mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
s->offset, s->io, s->iolen);
} else if (s->mem_oob) {
sector = SECTOR(s->addr);
off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr);
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
- printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
- memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+ mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
if (off + s->iolen > PAGE_SIZE) {
page = PAGE(s->addr);
- memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+ mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
}
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
} else {
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
sector = off >> 9;
soff = off & 0x1ff;
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
- printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
- memcpy(iobuf + soff, s->io, s->iolen);
+ mem_and(iobuf + soff, s->io, s->iolen);
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
s->offset = 0;
}
@@ -576,7 +668,7 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
/* Erase a single block */
static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
{
- uint32_t i, page, addr;
+ uint64_t i, page, addr;
uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
@@ -593,34 +685,35 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
for (; i < page; i ++)
if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, i);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
} else {
addr = PAGE_START(addr);
page = addr >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: read error in sector %i\n", __FUNCTION__, page);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, page);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
memset(iobuf, 0xff, 0x200);
i = (addr & ~0x1ff) + 0x200;
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200)
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+ printf("%s: write error in sector %" PRIu64 "\n",
+ __func__, i >> 9);
page = i >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: read error in sector %i\n", __FUNCTION__, page);
+ printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
- printf("%s: write error in sector %i\n", __FUNCTION__, page);
+ printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
}
static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
- uint32_t addr, int offset)
+ uint64_t addr, int offset)
{
if (PAGE(addr) >= s->pages)
return;
@@ -628,8 +721,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
if (s->bdrv) {
if (s->mem_oob) {
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
- printf("%s: read error in sector %i\n",
- __FUNCTION__, SECTOR(addr));
+ printf("%s: read error in sector %" PRIu64 "\n",
+ __func__, SECTOR(addr));
memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
s->storage + (PAGE(s->addr) << OOB_SHIFT),
OOB_SIZE);
@@ -637,8 +730,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
} else {
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
s->io, (PAGE_SECTORS + 2)) == -1)
- printf("%s: read error in sector %i\n",
- __FUNCTION__, PAGE_START(addr) >> 9);
+ printf("%s: read error in sector %" PRIu64 "\n",
+ __func__, PAGE_START(addr) >> 9);
s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
}
} else {
diff --git a/hw/nseries.c b/hw/nseries.c
index 2f84f5305b..6a5575e78e 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -31,6 +31,7 @@
#include "hw.h"
#include "bt.h"
#include "loader.h"
+#include "blockdev.h"
/* Nokia N8x0 support */
struct n800_s {
@@ -45,7 +46,7 @@ struct n800_s {
i2c_bus *i2c;
int keymap[0x80];
- i2c_slave *kbd;
+ DeviceState *kbd;
TUSBState *usb;
void *retu;
@@ -134,9 +135,9 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level)
static void n8x0_gpio_setup(struct n800_s *s)
{
qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_MMC_CS_GPIO, mmc_cs[0]);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_MMC_CS_GPIO, mmc_cs[0]);
- qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]);
+ qemu_irq_lower(qdev_get_gpio_in(s->cpu->gpio, N800_BAT_COVER_GPIO));
}
#define MAEMO_CAL_HEADER(...) \
@@ -163,13 +164,15 @@ static const uint8_t n8x0_cal_bt_id[] = {
static void n8x0_nand_setup(struct n800_s *s)
{
char *otp_region;
+ DriveInfo *dinfo;
- /* Either ec40xx or ec48xx are OK for the ID */
+ dinfo = drive_get(IF_MTD, 0, 0);
+ /* Either 0x40 or 0x48 are OK for the device ID */
+ s->nand = onenand_init(dinfo ? dinfo->bdrv : 0,
+ NAND_MFR_SAMSUNG, 0x48, 0, 1,
+ qdev_get_gpio_in(s->cpu->gpio, N8X0_ONENAND_GPIO));
omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update,
- onenand_base_unmap,
- (s->nand = onenand_init(0xec4800, 1,
- omap2_gpio_in_get(s->cpu->gpif,
- N8X0_ONENAND_GPIO)[0])));
+ onenand_base_unmap, s->nand);
otp_region = onenand_raw_otp(s->nand);
memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
@@ -180,7 +183,7 @@ static void n8x0_nand_setup(struct n800_s *s)
static void n8x0_i2c_setup(struct n800_s *s)
{
DeviceState *dev;
- qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0];
+ qemu_irq tmp_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TMP105_GPIO);
/* Attach the CPU on one end of our I2C bus. */
s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
@@ -249,8 +252,8 @@ static void n800_tsc_kbd_setup(struct n800_s *s)
/* XXX: are the three pins inverted inside the chip between the
* tsc and the cpu (N4111)? */
qemu_irq penirq = NULL; /* NC */
- qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0];
- qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0];
+ qemu_irq kbirq = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_KP_IRQ_GPIO);
+ qemu_irq dav = qdev_get_gpio_in(s->cpu->gpio, N800_TSC_TS_GPIO);
s->ts.chip = tsc2301_init(penirq, kbirq, dav);
s->ts.opaque = s->ts.chip->opaque;
@@ -269,7 +272,7 @@ static void n800_tsc_kbd_setup(struct n800_s *s)
static void n810_tsc_setup(struct n800_s *s)
{
- qemu_irq pintdav = omap2_gpio_in_get(s->cpu->gpif, N810_TSC_TS_GPIO)[0];
+ qemu_irq pintdav = qdev_get_gpio_in(s->cpu->gpio, N810_TSC_TS_GPIO);
s->ts.opaque = tsc2005_init(pintdav);
s->ts.txrx = tsc2005_txrx;
@@ -361,8 +364,7 @@ static int n810_keys[0x80] = {
static void n810_kbd_setup(struct n800_s *s)
{
- qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0];
- DeviceState *dev;
+ qemu_irq kbd_irq = qdev_get_gpio_in(s->cpu->gpio, N810_KEYBOARD_GPIO);
int i;
for (i = 0; i < 0x80; i ++)
@@ -375,8 +377,8 @@ static void n810_kbd_setup(struct n800_s *s)
/* Attach the LM8322 keyboard to the I2C bus,
* should happen in n8x0_i2c_setup and s->kbd be initialised here. */
- dev = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
- qdev_connect_gpio_out(dev, 0, kbd_irq);
+ s->kbd = i2c_create_slave(s->i2c, "lm8323", N810_LM8323_ADDR);
+ qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
}
/* LCD MIPI DBI-C controller (URAL) */
@@ -726,15 +728,15 @@ static void n8x0_dss_setup(struct n800_s *s)
static void n8x0_cbus_setup(struct n800_s *s)
{
- qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0];
- qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0];
- qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0];
+ qemu_irq dat_out = qdev_get_gpio_in(s->cpu->gpio, N8X0_CBUS_DAT_GPIO);
+ qemu_irq retu_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_RETU_GPIO);
+ qemu_irq tahvo_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TAHVO_GPIO);
CBus *cbus = cbus_init(dat_out);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
@@ -743,12 +745,11 @@ static void n8x0_cbus_setup(struct n800_s *s)
static void n8x0_uart_setup(struct n800_s *s)
{
CharDriverState *radio = uart_hci_init(
- omap2_gpio_in_get(s->cpu->gpif,
- N8X0_BT_HOST_WKUP_GPIO)[0]);
+ qdev_get_gpio_in(s->cpu->gpio, N8X0_BT_HOST_WKUP_GPIO));
- omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_RESET_GPIO,
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_RESET_GPIO,
csrhci_pins_get(radio)[csrhci_pin_reset]);
- omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_WKUP_GPIO,
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_BT_WKUP_GPIO,
csrhci_pins_get(radio)[csrhci_pin_wakeup]);
omap_uart_attach(s->cpu->uart[BT_UART], radio);
@@ -763,7 +764,7 @@ static void n8x0_usb_power_cb(void *opaque, int line, int level)
static void n8x0_usb_setup(struct n800_s *s)
{
- qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0];
+ qemu_irq tusb_irq = qdev_get_gpio_in(s->cpu->gpio, N8X0_TUSB_INT_GPIO);
qemu_irq tusb_pwr = qemu_allocate_irqs(n8x0_usb_power_cb, s, 1)[0];
TUSBState *tusb = tusb6010_init(tusb_irq);
@@ -774,7 +775,7 @@ static void n8x0_usb_setup(struct n800_s *s)
tusb6010_sync_io(tusb), NULL, NULL, tusb);
s->usb = tusb;
- omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
+ qdev_connect_gpio_out(s->cpu->gpio, N8X0_TUSB_ENABLE_GPIO, tusb_pwr);
}
/* Setup done before the main bootloader starts by some early setup code
@@ -1020,7 +1021,7 @@ static void n8x0_boot_init(void *opaque)
/* If the machine has a slided keyboard, open it */
if (s->kbd)
- qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N810_SLIDE_GPIO)[0]);
+ qemu_irq_raise(qdev_get_gpio_in(s->cpu->gpio, N810_SLIDE_GPIO));
}
#define OMAP_TAG_NOKIA_BT 0x4e01
diff --git a/hw/omap.h b/hw/omap.h
index c227a82b2c..a064353aba 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -93,6 +93,8 @@ struct omap_target_agent_s *omap_l4ta_get(
int cs);
target_phys_addr_t omap_l4_attach(struct omap_target_agent_s *ta, int region,
int iotype);
+target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
+ int region);
int l4_register_io_memory(CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write, void *opaque);
@@ -681,22 +683,6 @@ qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
-/* omap1 gpio module interface */
-struct omap_gpio_s;
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk clk);
-void omap_gpio_reset(struct omap_gpio_s *s);
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s);
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler);
-
-/* omap2 gpio interface */
-struct omap_gpif_s;
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
- qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules);
-void omap_gpif_reset(struct omap_gpif_s *s);
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start);
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler);
-
struct uWireSlave {
uint16_t (*receive)(void *opaque);
void (*send)(void *opaque, uint16_t data);
@@ -850,7 +836,7 @@ struct omap_mpu_state_s {
/* MPUI-TIPB peripherals */
struct omap_uart_s *uart[3];
- struct omap_gpio_s *gpio;
+ DeviceState *gpio;
struct omap_mcbsp_s *mcbsp1;
struct omap_mcbsp_s *mcbsp3;
@@ -948,8 +934,6 @@ struct omap_mpu_state_s {
struct omap_gpmc_s *gpmc;
struct omap_sysctl_s *sysc;
- struct omap_gpif_s *gpif;
-
struct omap_mcspi_s *mcspi[2];
struct omap_dss_s *dss;
diff --git a/hw/omap1.c b/hw/omap1.c
index 364c26f877..400de475d9 100644
--- a/hw/omap1.c
+++ b/hw/omap1.c
@@ -27,6 +27,7 @@
#include "pc.h"
#include "blockdev.h"
#include "range.h"
+#include "sysbus.h"
/* Should signal the TCMI/GPMC */
uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr)
@@ -3585,7 +3586,6 @@ static void omap1_mpu_reset(void *opaque)
omap_uart_reset(mpu->uart[2]);
omap_mmc_reset(mpu->mmc);
omap_mpuio_reset(mpu->mpuio);
- omap_gpio_reset(mpu->gpio);
omap_uwire_reset(mpu->microwire);
omap_pwl_reset(mpu);
omap_pwt_reset(mpu);
@@ -3845,8 +3845,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO],
s->wakeup, omap_findclk(s, "clk32-kHz"));
- s->gpio = omap_gpio_init(0xfffce000, s->irq[0][OMAP_INT_GPIO_BANK1],
- omap_findclk(s, "arm_gpio_ck"));
+ s->gpio = qdev_create(NULL, "omap-gpio");
+ qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+ qdev_init_nofail(s->gpio);
+ sysbus_connect_irq(sysbus_from_qdev(s->gpio), 0,
+ s->irq[0][OMAP_INT_GPIO_BANK1]);
+ sysbus_mmio_map(sysbus_from_qdev(s->gpio), 0, 0xfffce000);
s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX],
s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
diff --git a/hw/omap2.c b/hw/omap2.c
index 0f13272c7b..c9b35405ed 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -27,6 +27,7 @@
#include "qemu-char.h"
#include "flash.h"
#include "soc_dma.h"
+#include "sysbus.h"
#include "audio/audio.h"
/* Enhanced Audio Controller (CODEC only) */
@@ -2203,7 +2204,6 @@ static void omap2_mpu_reset(void *opaque)
omap_uart_reset(mpu->uart[1]);
omap_uart_reset(mpu->uart[2]);
omap_mmc_reset(mpu->mmc);
- omap_gpif_reset(mpu->gpif);
omap_mcspi_reset(mpu->mcspi[0]);
omap_mcspi_reset(mpu->mcspi[1]);
omap_i2c_reset(mpu->i2c[0]);
@@ -2232,9 +2232,10 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
ram_addr_t sram_base, q2_base;
qemu_irq *cpu_irq;
qemu_irq dma_irqs[4];
- omap_clk gpio_clks[4];
DriveInfo *dinfo;
int i;
+ SysBusDevice *busdev;
+ struct omap_target_agent_s *ta;
/* Core */
s->mpu_model = omap2420;
@@ -2377,13 +2378,28 @@ struct omap_mpu_state_s *omap2420_mpu_init(unsigned long sdram_size,
omap_findclk(s, "i2c2.fclk"),
omap_findclk(s, "i2c2.iclk"));
- gpio_clks[0] = omap_findclk(s, "gpio1_dbclk");
- gpio_clks[1] = omap_findclk(s, "gpio2_dbclk");
- gpio_clks[2] = omap_findclk(s, "gpio3_dbclk");
- gpio_clks[3] = omap_findclk(s, "gpio4_dbclk");
- s->gpif = omap2_gpio_init(omap_l4ta(s->l4, 3),
- &s->irq[0][OMAP_INT_24XX_GPIO_BANK1],
- gpio_clks, omap_findclk(s, "gpio_iclk"), 4);
+ s->gpio = qdev_create(NULL, "omap2-gpio");
+ qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
+ qdev_prop_set_ptr(s->gpio, "iclk", omap_findclk(s, "gpio_iclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk0", omap_findclk(s, "gpio1_dbclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk1", omap_findclk(s, "gpio2_dbclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk2", omap_findclk(s, "gpio3_dbclk"));
+ qdev_prop_set_ptr(s->gpio, "fclk3", omap_findclk(s, "gpio4_dbclk"));
+ if (s->mpu_model == omap2430) {
+ qdev_prop_set_ptr(s->gpio, "fclk4", omap_findclk(s, "gpio5_dbclk"));
+ }
+ qdev_init_nofail(s->gpio);
+ busdev = sysbus_from_qdev(s->gpio);
+ sysbus_connect_irq(busdev, 0, s->irq[0][OMAP_INT_24XX_GPIO_BANK1]);
+ sysbus_connect_irq(busdev, 3, s->irq[0][OMAP_INT_24XX_GPIO_BANK2]);
+ sysbus_connect_irq(busdev, 6, s->irq[0][OMAP_INT_24XX_GPIO_BANK3]);
+ sysbus_connect_irq(busdev, 9, s->irq[0][OMAP_INT_24XX_GPIO_BANK4]);
+ ta = omap_l4ta(s->l4, 3);
+ sysbus_mmio_map(busdev, 0, omap_l4_region_base(ta, 1));
+ sysbus_mmio_map(busdev, 1, omap_l4_region_base(ta, 0));
+ sysbus_mmio_map(busdev, 2, omap_l4_region_base(ta, 2));
+ sysbus_mmio_map(busdev, 3, omap_l4_region_base(ta, 4));
+ sysbus_mmio_map(busdev, 4, omap_l4_region_base(ta, 5));
s->sdrc = omap_sdrc_init(0x68009000);
s->gpmc = omap_gpmc_init(0x6800a000, s->irq[0][OMAP_INT_24XX_GPMC_IRQ]);
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
index 6bcabef8ac..577b326ae9 100644
--- a/hw/omap_clk.c
+++ b/hw/omap_clk.c
@@ -836,7 +836,7 @@ static struct clk i2c2_iclk = {
.parent = &core_l4_iclk,
};
-static struct clk gpio_dbclk[4] = {
+static struct clk gpio_dbclk[5] = {
{
.name = "gpio1_dbclk",
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
@@ -853,6 +853,10 @@ static struct clk gpio_dbclk[4] = {
.name = "gpio4_dbclk",
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.parent = &wu_32k_clk,
+ }, {
+ .name = "gpio5_dbclk",
+ .flags = CLOCK_IN_OMAP243X,
+ .parent = &wu_32k_clk,
},
};
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 478f7d9825..c23964c66d 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -20,10 +20,10 @@
#include "hw.h"
#include "omap.h"
-/* General-Purpose I/O */
+#include "sysbus.h"
+
struct omap_gpio_s {
qemu_irq irq;
- qemu_irq *in;
qemu_irq handler[16];
uint16_t inputs;
@@ -35,9 +35,17 @@ struct omap_gpio_s {
uint16_t pins;
};
+struct omap_gpif_s {
+ SysBusDevice busdev;
+ int mpu_model;
+ void *clk;
+ struct omap_gpio_s omap1;
+};
+
+/* General-Purpose I/O of OMAP1 */
static void omap_gpio_set(void *opaque, int line, int level)
{
- struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+ struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1;
uint16_t prev = s->inputs;
if (level)
@@ -160,7 +168,7 @@ static CPUWriteMemoryFunc * const omap_gpio_writefn[] = {
omap_badwidth_write16,
};
-void omap_gpio_reset(struct omap_gpio_s *s)
+static void omap_gpio_reset(struct omap_gpio_s *s)
{
s->inputs = 0;
s->outputs = ~0;
@@ -171,43 +179,12 @@ void omap_gpio_reset(struct omap_gpio_s *s)
s->pins = ~0;
}
-struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base,
- qemu_irq irq, omap_clk clk)
-{
- int iomemtype;
- struct omap_gpio_s *s = (struct omap_gpio_s *)
- qemu_mallocz(sizeof(struct omap_gpio_s));
-
- s->irq = irq;
- s->in = qemu_allocate_irqs(omap_gpio_set, s, 16);
- omap_gpio_reset(s);
-
- iomemtype = cpu_register_io_memory(omap_gpio_readfn,
- omap_gpio_writefn, s, DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(base, 0x1000, iomemtype);
-
- return s;
-}
-
-qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s)
-{
- return s->in;
-}
-
-void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler)
-{
- if (line >= 16 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->handler[line] = handler;
-}
-
-/* General-Purpose Interface of OMAP2 */
struct omap2_gpio_s {
qemu_irq irq[2];
qemu_irq wkup;
- qemu_irq *in;
- qemu_irq handler[32];
+ qemu_irq *handler;
+ uint8_t revision;
uint8_t config[2];
uint32_t inputs;
uint32_t outputs;
@@ -221,8 +198,21 @@ struct omap2_gpio_s {
uint8_t delay;
};
+struct omap2_gpif_s {
+ SysBusDevice busdev;
+ int mpu_model;
+ void *iclk;
+ void *fclk[6];
+ int modulecount;
+ struct omap2_gpio_s *modules;
+ qemu_irq *handler;
+ int autoidle;
+ int gpo;
+};
+
+/* General-Purpose Interface of OMAP2/3 */
static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
- int line)
+ int line)
{
qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
}
@@ -269,10 +259,12 @@ static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
omap2_gpio_module_wake(s, line);
}
-static void omap2_gpio_module_set(void *opaque, int line, int level)
+static void omap2_gpio_set(void *opaque, int line, int level)
{
- struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+ struct omap2_gpif_s *p = opaque;
+ struct omap2_gpio_s *s = &p->modules[line >> 5];
+ line &= 31;
if (level) {
if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
omap2_gpio_module_int(s, line);
@@ -308,7 +300,7 @@ static uint32_t omap2_gpio_module_read(void *opaque, target_phys_addr_t addr)
switch (addr) {
case 0x00: /* GPIO_REVISION */
- return 0x18;
+ return s->revision;
case 0x10: /* GPIO_SYSCONFIG */
return s->config[0];
@@ -583,45 +575,28 @@ static CPUWriteMemoryFunc * const omap2_gpio_module_writefn[] = {
omap2_gpio_module_write,
};
-static void omap2_gpio_module_init(struct omap2_gpio_s *s,
- struct omap_target_agent_s *ta, int region,
- qemu_irq mpu, qemu_irq dsp, qemu_irq wkup,
- omap_clk fclk, omap_clk iclk)
+static void omap_gpif_reset(DeviceState *dev)
{
- int iomemtype;
-
- s->irq[0] = mpu;
- s->irq[1] = dsp;
- s->wkup = wkup;
- s->in = qemu_allocate_irqs(omap2_gpio_module_set, s, 32);
-
- iomemtype = l4_register_io_memory(omap2_gpio_module_readfn,
- omap2_gpio_module_writefn, s);
- omap_l4_attach(ta, region, iomemtype);
+ struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s,
+ sysbus_from_qdev(dev));
+ omap_gpio_reset(&s->omap1);
}
-struct omap_gpif_s {
- struct omap2_gpio_s module[5];
- int modules;
-
- int autoidle;
- int gpo;
-};
-
-void omap_gpif_reset(struct omap_gpif_s *s)
+static void omap2_gpif_reset(DeviceState *dev)
{
int i;
-
- for (i = 0; i < s->modules; i ++)
- omap2_gpio_module_reset(s->module + i);
-
+ struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s,
+ sysbus_from_qdev(dev));
+ for (i = 0; i < s->modulecount; i++) {
+ omap2_gpio_module_reset(&s->modules[i]);
+ }
s->autoidle = 0;
s->gpo = 0;
}
-static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
+static uint32_t omap2_gpif_top_read(void *opaque, target_phys_addr_t addr)
{
- struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+ struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
switch (addr) {
case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -647,10 +622,10 @@ static uint32_t omap_gpif_top_read(void *opaque, target_phys_addr_t addr)
return 0;
}
-static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
+static void omap2_gpif_top_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- struct omap_gpif_s *s = (struct omap_gpif_s *) opaque;
+ struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
switch (addr) {
case 0x00: /* IPGENERICOCPSPL_REVISION */
@@ -662,7 +637,7 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
if (value & (1 << 1)) /* SOFTRESET */
- omap_gpif_reset(s);
+ omap2_gpif_reset(&s->busdev.qdev);
s->autoidle = value & 1;
break;
@@ -676,50 +651,119 @@ static void omap_gpif_top_write(void *opaque, target_phys_addr_t addr,
}
}
-static CPUReadMemoryFunc * const omap_gpif_top_readfn[] = {
- omap_gpif_top_read,
- omap_gpif_top_read,
- omap_gpif_top_read,
+static CPUReadMemoryFunc * const omap2_gpif_top_readfn[] = {
+ omap2_gpif_top_read,
+ omap2_gpif_top_read,
+ omap2_gpif_top_read,
};
-static CPUWriteMemoryFunc * const omap_gpif_top_writefn[] = {
- omap_gpif_top_write,
- omap_gpif_top_write,
- omap_gpif_top_write,
+static CPUWriteMemoryFunc * const omap2_gpif_top_writefn[] = {
+ omap2_gpif_top_write,
+ omap2_gpif_top_write,
+ omap2_gpif_top_write,
};
-struct omap_gpif_s *omap2_gpio_init(struct omap_target_agent_s *ta,
- qemu_irq *irq, omap_clk *fclk, omap_clk iclk, int modules)
+static int omap_gpio_init(SysBusDevice *dev)
{
- int iomemtype, i;
- struct omap_gpif_s *s = (struct omap_gpif_s *)
- qemu_mallocz(sizeof(struct omap_gpif_s));
- int region[4] = { 0, 2, 4, 5 };
+ struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev);
+ if (!s->clk) {
+ hw_error("omap-gpio: clk not connected\n");
+ }
+ qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
+ qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
+ sysbus_init_irq(dev, &s->omap1.irq);
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap_gpio_readfn,
+ omap_gpio_writefn,
+ &s->omap1,
+ DEVICE_NATIVE_ENDIAN));
+ return 0;
+}
- s->modules = modules;
- for (i = 0; i < modules; i ++)
- omap2_gpio_module_init(s->module + i, ta, region[i],
- irq[i], NULL, NULL, fclk[i], iclk);
+static int omap2_gpio_init(SysBusDevice *dev)
+{
+ int i;
+ struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev);
+ if (!s->iclk) {
+ hw_error("omap2-gpio: iclk not connected\n");
+ }
+ if (s->mpu_model < omap3430) {
+ s->modulecount = (s->mpu_model < omap2430) ? 4 : 5;
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap2_gpif_top_readfn,
+ omap2_gpif_top_writefn, s,
+ DEVICE_NATIVE_ENDIAN));
+ } else {
+ s->modulecount = 6;
+ }
+ s->modules = qemu_mallocz(s->modulecount * sizeof(struct omap2_gpio_s));
+ s->handler = qemu_mallocz(s->modulecount * 32 * sizeof(qemu_irq));
+ qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
+ qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
+ for (i = 0; i < s->modulecount; i++) {
+ struct omap2_gpio_s *m = &s->modules[i];
+ if (!s->fclk[i]) {
+ hw_error("omap2-gpio: fclk%d not connected\n", i);
+ }
+ m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
+ m->handler = &s->handler[i * 32];
+ sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */
+ sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */
+ sysbus_init_irq(dev, &m->wkup);
+ sysbus_init_mmio(dev, 0x1000,
+ cpu_register_io_memory(omap2_gpio_module_readfn,
+ omap2_gpio_module_writefn,
+ m, DEVICE_NATIVE_ENDIAN));
+ }
+ return 0;
+}
- omap_gpif_reset(s);
+/* Using qdev pointer properties for the clocks is not ideal.
+ * qdev should support a generic means of defining a 'port' with
+ * an arbitrary interface for connecting two devices. Then we
+ * could reframe the omap clock API in terms of clock ports,
+ * and get some type safety. For now the best qdev provides is
+ * passing an arbitrary pointer.
+ * (It's not possible to pass in the string which is the clock
+ * name, because this device does not have the necessary information
+ * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
+ * translation.)
+ */
- iomemtype = l4_register_io_memory(omap_gpif_top_readfn,
- omap_gpif_top_writefn, s);
- omap_l4_attach(ta, 1, iomemtype);
+static SysBusDeviceInfo omap_gpio_info = {
+ .init = omap_gpio_init,
+ .qdev.name = "omap-gpio",
+ .qdev.size = sizeof(struct omap_gpif_s),
+ .qdev.reset = omap_gpif_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
- return s;
-}
+static SysBusDeviceInfo omap2_gpio_info = {
+ .init = omap2_gpio_init,
+ .qdev.name = "omap2-gpio",
+ .qdev.size = sizeof(struct omap2_gpif_s),
+ .qdev.reset = omap2_gpif_reset,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+ DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+ DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+ DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+ DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+ DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+ DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
-qemu_irq *omap2_gpio_in_get(struct omap_gpif_s *s, int start)
+static void omap_gpio_register_device(void)
{
- if (start >= s->modules * 32 || start < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, start);
- return s->module[start >> 5].in + (start & 31);
+ sysbus_register_withprop(&omap_gpio_info);
+ sysbus_register_withprop(&omap2_gpio_info);
}
-void omap2_gpio_out_set(struct omap_gpif_s *s, int line, qemu_irq handler)
-{
- if (line >= s->modules * 32 || line < 0)
- hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
- s->module[line >> 5].handler[line & 31] = handler;
-}
+device_init(omap_gpio_register_device)
diff --git a/hw/omap_l4.c b/hw/omap_l4.c
index 4af0ca8ea6..59c84b19a2 100644
--- a/hw/omap_l4.c
+++ b/hw/omap_l4.c
@@ -146,6 +146,12 @@ struct omap_l4_s *omap_l4_init(target_phys_addr_t base, int ta_num)
return bus;
}
+target_phys_addr_t omap_l4_region_base(struct omap_target_agent_s *ta,
+ int region)
+{
+ return ta->bus->base + ta->start[region].offset;
+}
+
static uint32_t omap_l4ta_read(void *opaque, target_phys_addr_t addr)
{
struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
diff --git a/hw/onenand.c b/hw/onenand.c
index 71c1ab40b4..b0cbebc178 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -31,7 +31,11 @@
#define BLOCK_SHIFT (PAGE_SHIFT + 6)
typedef struct {
- uint32_t id;
+ struct {
+ uint16_t man;
+ uint16_t dev;
+ uint16_t ver;
+ } id;
int shift;
target_phys_addr_t base;
qemu_irq intr;
@@ -175,14 +179,39 @@ static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
void *src)
{
- if (s->bdrv_cur)
- return bdrv_write(s->bdrv_cur, sec, src, secn) < 0;
- else if (sec + secn > s->secs_cur)
- return 1;
-
- memcpy(s->current + (sec << 9), src, secn << 9);
+ int result = 0;
+
+ if (secn > 0) {
+ uint32_t size = (uint32_t) secn * 512;
+ const uint8_t *sp = (const uint8_t *) src;
+ uint8_t *dp = 0;
+ if (s->bdrv_cur) {
+ dp = qemu_malloc(size);
+ if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+ result = 1;
+ }
+ } else {
+ if (sec + secn > s->secs_cur) {
+ result = 1;
+ } else {
+ dp = (uint8_t *) s->current + (sec << 9);
+ }
+ }
+ if (!result) {
+ uint32_t i;
+ for (i = 0; i < size; i++) {
+ dp[i] &= sp[i];
+ }
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+ }
+ }
+ if (dp && s->bdrv_cur) {
+ qemu_free(dp);
+ }
+ }
- return 0;
+ return result;
}
static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
@@ -205,35 +234,87 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
void *src)
{
- uint8_t buf[512];
-
- if (s->bdrv_cur) {
- if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
- return 1;
- memcpy(buf + ((sec & 31) << 4), src, secn << 4);
- return bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0;
- } else if (sec + secn > s->secs_cur)
- return 1;
-
- memcpy(s->current + (s->secs_cur << 9) + (sec << 4), src, secn << 4);
-
- return 0;
+ int result = 0;
+ if (secn > 0) {
+ const uint8_t *sp = (const uint8_t *) src;
+ uint8_t *dp = 0, *dpp = 0;
+ if (s->bdrv_cur) {
+ dp = qemu_malloc(512);
+ if (!dp || bdrv_read(s->bdrv_cur,
+ s->secs_cur + (sec >> 5),
+ dp, 1) < 0) {
+ result = 1;
+ } else {
+ dpp = dp + ((sec & 31) << 4);
+ }
+ } else {
+ if (sec + secn > s->secs_cur) {
+ result = 1;
+ } else {
+ dpp = s->current + (s->secs_cur << 9) + (sec << 4);
+ }
+ }
+ if (!result) {
+ uint32_t i;
+ for (i = 0; i < (secn << 4); i++) {
+ dpp[i] &= sp[i];
+ }
+ if (s->bdrv_cur) {
+ result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
+ dp, 1) < 0;
+ }
+ }
+ if (dp) {
+ qemu_free(dp);
+ }
+ }
+ return result;
}
static inline int onenand_erase(OneNANDState *s, int sec, int num)
{
- /* TODO: optimise */
- uint8_t buf[512];
-
- memset(buf, 0xff, sizeof(buf));
- for (; num > 0; num --, sec ++) {
- if (onenand_prog_main(s, sec, 1, buf))
- return 1;
- if (onenand_prog_spare(s, sec, 1, buf))
- return 1;
+ uint8_t *blankbuf, *tmpbuf;
+ blankbuf = qemu_malloc(512);
+ if (!blankbuf) {
+ return 1;
+ }
+ tmpbuf = qemu_malloc(512);
+ if (!tmpbuf) {
+ qemu_free(blankbuf);
+ return 1;
+ }
+ memset(blankbuf, 0xff, 512);
+ for (; num > 0; num--, sec++) {
+ if (s->bdrv_cur) {
+ int erasesec = s->secs_cur + (sec >> 5);
+ if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1)) {
+ goto fail;
+ }
+ if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+ goto fail;
+ }
+ memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
+ if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+ goto fail;
+ }
+ } else {
+ if (sec + 1 > s->secs_cur) {
+ goto fail;
+ }
+ memcpy(s->current + (sec << 9), blankbuf, 512);
+ memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
+ blankbuf, 1 << 4);
+ }
}
+ qemu_free(tmpbuf);
+ qemu_free(blankbuf);
return 0;
+
+fail:
+ qemu_free(tmpbuf);
+ qemu_free(blankbuf);
+ return 1;
}
static void onenand_command(OneNANDState *s, int cmd)
@@ -453,12 +534,12 @@ static uint32_t onenand_read(void *opaque, target_phys_addr_t addr)
return lduw_le_p(s->boot[0] + addr);
case 0xf000: /* Manufacturer ID */
- return (s->id >> 16) & 0xff;
+ return s->id.man;
case 0xf001: /* Device ID */
- return (s->id >> 8) & 0xff;
- /* TODO: get the following values from a real chip! */
+ return s->id.dev;
case 0xf002: /* Version ID */
- return (s->id >> 0) & 0xff;
+ return s->id.ver;
+ /* TODO: get the following values from a real chip! */
case 0xf003: /* Data Buffer size */
return 1 << PAGE_SHIFT;
case 0xf004: /* Boot Buffer size */
@@ -541,8 +622,8 @@ static void onenand_write(void *opaque, target_phys_addr_t addr,
case 0x0090: /* Read Identification Data */
memset(s->boot[0], 0, 3 << s->shift);
- s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff;
- s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff;
+ s->boot[0][0 << s->shift] = s->id.man & 0xff;
+ s->boot[0][1 << s->shift] = s->id.dev & 0xff;
s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
break;
@@ -615,28 +696,31 @@ static CPUWriteMemoryFunc * const onenand_writefn[] = {
onenand_write,
};
-void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
+void *onenand_init(BlockDriverState *bdrv,
+ uint16_t man_id, uint16_t dev_id, uint16_t ver_id,
+ int regshift, qemu_irq irq)
{
OneNANDState *s = (OneNANDState *) qemu_mallocz(sizeof(*s));
- DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
- uint32_t size = 1 << (24 + ((id >> 12) & 7));
+ uint32_t size = 1 << (24 + ((dev_id >> 4) & 7));
void *ram;
s->shift = regshift;
s->intr = irq;
s->rdy = NULL;
- s->id = id;
+ s->id.man = man_id;
+ s->id.dev = dev_id;
+ s->id.ver = ver_id;
s->blocks = size >> BLOCK_SHIFT;
s->secs = size >> 9;
s->blockwp = qemu_malloc(s->blocks);
- s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0;
+ s->density_mask = (dev_id & 0x08) ? (1 << (6 + ((dev_id >> 4) & 7))) : 0;
s->iomemtype = cpu_register_io_memory(onenand_readfn,
onenand_writefn, s, DEVICE_NATIVE_ENDIAN);
- if (!dinfo)
+ s->bdrv = bdrv;
+ if (!s->bdrv) {
s->image = memset(qemu_malloc(size + (size >> 5)),
0xff, size + (size >> 5));
- else
- s->bdrv = dinfo->bdrv;
+ }
s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
0xff, (64 + 2) << PAGE_SHIFT);
s->ram = qemu_ram_alloc(NULL, "onenand.ram", 0xc000 << s->shift);
diff --git a/hw/palm.c b/hw/palm.c
index f22d7775ee..4c67e75c83 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -94,7 +94,7 @@ static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
{
uWireSlave *tsc;
- tsc = tsc2102_init(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]);
+ tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
omap_uwire_attach(cpu->microwire, tsc, 0);
omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
@@ -163,24 +163,24 @@ static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
qemu_irq *misc_gpio;
omap_mmc_handlers(cpu->mmc,
- omap_gpio_in_get(cpu->gpio)[PALMTE_MMC_WP_GPIO],
+ qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
[PALMTE_MMC_SWITCH_GPIO]));
misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
- omap_gpio_out_set(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]);
- omap_gpio_out_set(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]);
- omap_gpio_out_set(cpu->gpio, 11, misc_gpio[2]);
- omap_gpio_out_set(cpu->gpio, 12, misc_gpio[3]);
- omap_gpio_out_set(cpu->gpio, 13, misc_gpio[4]);
- omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]);
- omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]);
+ qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO, misc_gpio[0]);
+ qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO, misc_gpio[1]);
+ qdev_connect_gpio_out(cpu->gpio, 11, misc_gpio[2]);
+ qdev_connect_gpio_out(cpu->gpio, 12, misc_gpio[3]);
+ qdev_connect_gpio_out(cpu->gpio, 13, misc_gpio[4]);
+ omap_mpuio_out_set(cpu->mpuio, 1, misc_gpio[5]);
+ omap_mpuio_out_set(cpu->mpuio, 3, misc_gpio[6]);
/* Reset some inputs to initial state. */
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USBDETECT_GPIO]);
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_USB_OR_DC_GPIO]);
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[4]);
- qemu_irq_lower(omap_gpio_in_get(cpu->gpio)[PALMTE_HEADPHONES_GPIO]);
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
+ qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
diff --git a/hw/pc.c b/hw/pc.c
index a3e8539dc6..1c9d89a4b8 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -41,6 +41,7 @@
#include "sysemu.h"
#include "blockdev.h"
#include "ui/qemu-spice.h"
+#include "memory.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -957,7 +958,8 @@ void pc_cpus_init(const char *cpu_model)
}
}
-void pc_memory_init(const char *kernel_filename,
+void pc_memory_init(MemoryRegion *system_memory,
+ const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
ram_addr_t below_4g_mem_size,
@@ -965,22 +967,30 @@ void pc_memory_init(const char *kernel_filename,
{
char *filename;
int ret, linux_boot, i;
- ram_addr_t ram_addr, bios_offset, option_rom_offset;
+ MemoryRegion *ram, *bios, *isa_bios, *option_rom_mr;
+ MemoryRegion *ram_below_4g, *ram_above_4g;
int bios_size, isa_bios_size;
void *fw_cfg;
linux_boot = (kernel_filename != NULL);
- /* allocate RAM */
- ram_addr = qemu_ram_alloc(NULL, "pc.ram",
- below_4g_mem_size + above_4g_mem_size);
- cpu_register_physical_memory(0, 0xa0000, ram_addr);
- cpu_register_physical_memory(0x100000,
- below_4g_mem_size - 0x100000,
- ram_addr + 0x100000);
+ /* Allocate RAM. We allocate it as a single memory region and use
+ * aliases to address portions of it, mostly for backwards compatiblity
+ * with older qemus that used qemu_ram_alloc().
+ */
+ ram = qemu_malloc(sizeof(*ram));
+ memory_region_init_ram(ram, NULL, "pc.ram",
+ below_4g_mem_size + above_4g_mem_size);
+ ram_below_4g = qemu_malloc(sizeof(*ram_below_4g));
+ memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
+ 0, below_4g_mem_size);
+ memory_region_add_subregion(system_memory, 0, ram_below_4g);
if (above_4g_mem_size > 0) {
- cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
- ram_addr + below_4g_mem_size);
+ ram_above_4g = qemu_malloc(sizeof(*ram_above_4g));
+ memory_region_init_alias(ram_above_4g, "ram-above-4g", ram,
+ below_4g_mem_size, above_4g_mem_size);
+ memory_region_add_subregion(system_memory, 0x100000000ULL,
+ ram_above_4g);
}
/* BIOS load */
@@ -996,7 +1006,9 @@ void pc_memory_init(const char *kernel_filename,
(bios_size % 65536) != 0) {
goto bios_error;
}
- bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
+ bios = qemu_malloc(sizeof(*bios));
+ memory_region_init_ram(bios, NULL, "pc.bios", bios_size);
+ memory_region_set_readonly(bios, true);
ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
if (ret != 0) {
bios_error:
@@ -1010,16 +1022,26 @@ void pc_memory_init(const char *kernel_filename,
isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024))
isa_bios_size = 128 * 1024;
- cpu_register_physical_memory(0x100000 - isa_bios_size,
- isa_bios_size,
- (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
-
- option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
- cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
+ isa_bios = qemu_malloc(sizeof(*isa_bios));
+ memory_region_init_alias(isa_bios, "isa-bios", bios,
+ bios_size - isa_bios_size, isa_bios_size);
+ memory_region_add_subregion_overlap(system_memory,
+ 0x100000 - isa_bios_size,
+ isa_bios,
+ 1);
+ memory_region_set_readonly(isa_bios, true);
+
+ option_rom_mr = qemu_malloc(sizeof(*option_rom_mr));
+ memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE);
+ memory_region_add_subregion_overlap(system_memory,
+ PC_ROM_MIN_VGA,
+ option_rom_mr,
+ 1);
/* map all the bios at the top of memory */
- cpu_register_physical_memory((uint32_t)(-bios_size),
- bios_size, bios_offset | IO_MEM_ROM);
+ memory_region_add_subregion(system_memory,
+ (uint32_t)(-bios_size),
+ bios);
fw_cfg = bochs_bios_init();
rom_set_fw(fw_cfg);
diff --git a/hw/pc.h b/hw/pc.h
index 6d5730b26b..a2de0fecfa 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -2,10 +2,12 @@
#define HW_PC_H
#include "qemu-common.h"
+#include "memory.h"
#include "ioport.h"
#include "isa.h"
#include "fdc.h"
#include "net.h"
+#include "memory.h"
/* PC-style peripherals (also used by other machines). */
@@ -129,7 +131,8 @@ void pc_cmos_set_s3_resume(void *opaque, int irq, int level);
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
void pc_cpus_init(const char *cpu_model);
-void pc_memory_init(const char *kernel_filename,
+void pc_memory_init(MemoryRegion *system_memory,
+ const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
ram_addr_t below_4g_mem_size,
@@ -175,7 +178,9 @@ int pcspk_audio_init(qemu_irq *pic);
struct PCII440FXState;
typedef struct PCII440FXState PCII440FXState;
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, ram_addr_t ram_size);
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
+ qemu_irq *pic, MemoryRegion *address_space,
+ ram_addr_t ram_size);
void i440fx_init_memory_mappings(PCII440FXState *d);
/* piix4.c */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index c5c16b4571..c0a2abe4bc 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -39,6 +39,8 @@
#include "blockdev.h"
#include "smbus.h"
#include "xen.h"
+#include "memory.h"
+#include "exec-memory.h"
#ifdef CONFIG_XEN
# include <xen/hvm/hvm_info_table.h>
#endif
@@ -66,7 +68,8 @@ static void ioapic_init(IsaIrqState *isa_irq_state)
}
/* PC hardware initialisation */
-static void pc_init1(ram_addr_t ram_size,
+static void pc_init1(MemoryRegion *system_memory,
+ ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename,
const char *kernel_cmdline,
@@ -106,7 +109,8 @@ static void pc_init1(ram_addr_t ram_size,
/* allocate ram and load rom/bios */
if (!xen_enabled()) {
- pc_memory_init(kernel_filename, kernel_cmdline, initrd_filename,
+ pc_memory_init(system_memory,
+ kernel_filename, kernel_cmdline, initrd_filename,
below_4g_mem_size, above_4g_mem_size);
}
@@ -124,7 +128,8 @@ static void pc_init1(ram_addr_t ram_size,
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+ pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq,
+ system_memory, ram_size);
} else {
pci_bus = NULL;
i440fx_state = NULL;
@@ -155,7 +160,11 @@ static void pc_init1(ram_addr_t ram_size,
ide_drive_get(hd, MAX_IDE_BUS);
if (pci_enabled) {
PCIDevice *dev;
- dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+ if (xen_enabled()) {
+ dev = pci_piix3_xen_ide_init(pci_bus, hd, piix3_devfn + 1);
+ } else {
+ dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+ }
idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1");
} else {
@@ -208,7 +217,8 @@ static void pc_init_pci(ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model)
{
- pc_init1(ram_size, boot_device,
+ pc_init1(get_system_memory(),
+ ram_size, boot_device,
kernel_filename, kernel_cmdline,
initrd_filename, cpu_model, 1, 1);
}
@@ -220,7 +230,8 @@ static void pc_init_pci_no_kvmclock(ram_addr_t ram_size,
const char *initrd_filename,
const char *cpu_model)
{
- pc_init1(ram_size, boot_device,
+ pc_init1(get_system_memory(),
+ ram_size, boot_device,
kernel_filename, kernel_cmdline,
initrd_filename, cpu_model, 1, 0);
}
@@ -234,7 +245,8 @@ static void pc_init_isa(ram_addr_t ram_size,
{
if (cpu_model == NULL)
cpu_model = "486";
- pc_init1(ram_size, boot_device,
+ pc_init1(get_system_memory(),
+ ram_size, boot_device,
kernel_filename, kernel_cmdline,
initrd_filename, cpu_model, 0, 1);
}
diff --git a/hw/pci.c b/hw/pci.c
index ef94739718..8621d3d2b1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -263,11 +263,14 @@ int pci_find_domain(const PCIBus *bus)
}
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
- const char *name, uint8_t devfn_min)
+ const char *name,
+ MemoryRegion *address_space,
+ uint8_t devfn_min)
{
qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
assert(PCI_FUNC(devfn_min) == 0);
bus->devfn_min = devfn_min;
+ bus->address_space = address_space;
/* host bridge */
QLIST_INIT(&bus->child);
@@ -276,13 +279,14 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
vmstate_register(NULL, -1, &vmstate_pcibus, bus);
}
-PCIBus *pci_bus_new(DeviceState *parent, const char *name, uint8_t devfn_min)
+PCIBus *pci_bus_new(DeviceState *parent, const char *name,
+ MemoryRegion *address_space, uint8_t devfn_min)
{
PCIBus *bus;
bus = qemu_mallocz(sizeof(*bus));
bus->qbus.qdev_allocated = 1;
- pci_bus_new_inplace(bus, parent, name, devfn_min);
+ pci_bus_new_inplace(bus, parent, name, address_space, devfn_min);
return bus;
}
@@ -310,11 +314,13 @@ void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *irq_opaque, uint8_t devfn_min, int nirq)
+ void *irq_opaque,
+ MemoryRegion *address_space,
+ uint8_t devfn_min, int nirq)
{
PCIBus *bus;
- bus = pci_bus_new(parent, name, devfn_min);
+ bus = pci_bus_new(parent, name, address_space, devfn_min);
pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
return bus;
}
@@ -838,10 +844,15 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
isa_unassign_ioport(r->addr, r->filtered_size);
} else {
- cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
- r->addr),
- r->filtered_size,
- IO_MEM_UNASSIGNED);
+ if (r->memory) {
+ memory_region_del_subregion(pci_dev->bus->address_space,
+ r->memory);
+ } else {
+ cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
+ r->addr),
+ r->filtered_size,
+ IO_MEM_UNASSIGNED);
+ }
}
}
}
@@ -887,6 +898,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
r->type = type;
r->map_func = map_func;
r->ram_addr = IO_MEM_UNASSIGNED;
+ r->memory = NULL;
wmask = ~(size - 1);
addr = pci_bar(pci_dev, region_num);
@@ -912,6 +924,16 @@ static void pci_simple_bar_mapfunc(PCIDevice *pci_dev, int region_num,
pci_dev->io_regions[region_num].ram_addr);
}
+static void pci_simple_bar_mapfunc_region(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size,
+ int type)
+{
+ memory_region_add_subregion_overlap(pci_dev->bus->address_space,
+ addr,
+ pci_dev->io_regions[region_num].memory,
+ 1);
+}
+
void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
pcibus_t size, uint8_t attr, ram_addr_t ram_addr)
{
@@ -921,6 +943,15 @@ void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
pci_dev->io_regions[region_num].ram_addr = ram_addr;
}
+void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
+ uint8_t attr, MemoryRegion *memory)
+{
+ pci_register_bar(pci_dev, region_num, memory_region_size(memory),
+ PCI_BASE_ADDRESS_SPACE_MEMORY | attr,
+ pci_simple_bar_mapfunc_region);
+ pci_dev->io_regions[region_num].memory = memory;
+}
+
static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
uint8_t type)
{
@@ -1059,10 +1090,16 @@ static void pci_update_mappings(PCIDevice *d)
isa_unassign_ioport(r->addr, r->filtered_size);
}
} else {
- cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
- r->filtered_size,
- IO_MEM_UNASSIGNED);
- qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
+ if (r->memory) {
+ memory_region_del_subregion(d->bus->address_space,
+ r->memory);
+ } else {
+ cpu_register_physical_memory(pci_to_cpu_addr(d->bus,
+ r->addr),
+ r->filtered_size,
+ IO_MEM_UNASSIGNED);
+ qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
+ }
}
}
r->addr = new_addr;
diff --git a/hw/pci.h b/hw/pci.h
index c220745c98..c51156d21c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -5,6 +5,7 @@
#include "qobject.h"
#include "qdev.h"
+#include "memory.h"
/* PCI includes legacy ISA access. */
#include "isa.h"
@@ -93,6 +94,7 @@ typedef struct PCIIORegion {
uint8_t type;
PCIMapIORegionFunc *map_func;
ram_addr_t ram_addr;
+ MemoryRegion *memory;
} PCIIORegion;
#define PCI_ROM_SLOT 6
@@ -203,6 +205,8 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
PCIMapIORegionFunc *map_func);
void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
+void pci_register_bar_region(PCIDevice *pci_dev, int region_num,
+ uint8_t attr, MemoryRegion *memory);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
uint8_t offset, uint8_t size);
@@ -233,15 +237,20 @@ typedef enum {
typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
PCIHotplugState state);
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
- const char *name, uint8_t devfn_min);
-PCIBus *pci_bus_new(DeviceState *parent, const char *name, uint8_t devfn_min);
+ const char *name,
+ MemoryRegion *address_space,
+ uint8_t devfn_min);
+PCIBus *pci_bus_new(DeviceState *parent, const char *name,
+ MemoryRegion *address_space, uint8_t devfn_min);
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *irq_opaque, uint8_t devfn_min, int nirq);
+ void *irq_opaque,
+ MemoryRegion *address_space,
+ uint8_t devfn_min, int nirq);
void pci_device_reset(PCIDevice *dev);
void pci_bus_reset(PCIBus *bus);
diff --git a/hw/pci_host.h b/hw/pci_host.h
index c8390eec56..7f551143bb 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -35,6 +35,7 @@ struct PCIHostState {
SysBusDevice busdev;
ReadWriteHandler conf_handler;
ReadWriteHandler data_handler;
+ MemoryRegion *address_space;
uint32_t config_reg;
PCIBus *bus;
};
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index b49c602844..83f38934ec 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -109,6 +109,14 @@
#define PCI_DEVICE_ID_INTEL_82371AB 0x7111
#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112
#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
#define PCI_VENDOR_ID_XEN 0x5853
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index fbe1866808..c3a463a703 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -25,6 +25,7 @@ struct PCIBus {
PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
PCIDevice *parent_dev;
target_phys_addr_t mem_base;
+ MemoryRegion *address_space;
QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index d08b31a266..80d6665350 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -241,7 +241,9 @@ static int i440fx_initfn(PCIDevice *dev)
static PCIBus *i440fx_common_init(const char *device_name,
PCII440FXState **pi440fx_state,
int *piix3_devfn,
- qemu_irq *pic, ram_addr_t ram_size)
+ qemu_irq *pic,
+ MemoryRegion *address_space,
+ ram_addr_t ram_size)
{
DeviceState *dev;
PCIBus *b;
@@ -251,7 +253,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
dev = qdev_create(NULL, "i440FX-pcihost");
s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
- b = pci_bus_new(&s->busdev.qdev, NULL, 0);
+ s->address_space = address_space;
+ b = pci_bus_new(&s->busdev.qdev, NULL, s->address_space, 0);
s->bus = b;
qdev_init_nofail(dev);
@@ -288,11 +291,13 @@ static PCIBus *i440fx_common_init(const char *device_name,
}
PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
- qemu_irq *pic, ram_addr_t ram_size)
+ qemu_irq *pic, MemoryRegion *address_space,
+ ram_addr_t ram_size)
{
PCIBus *b;
- b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic, ram_size);
+ b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic,
+ address_space, ram_size);
return b;
}
diff --git a/hw/pl011.c b/hw/pl011.c
index 3b94b14cb9..997ce848f8 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/pl022.c b/hw/pl022.c
index 00e494a0de..9a1cb710f3 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/pl050.c b/hw/pl050.c
index b155cc07b6..f7fa2e253c 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/pl061.c b/hw/pl061.c
index 372dfc2da2..79e5c53e89 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -5,7 +5,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/pl080.c b/hw/pl080.c
index dd8139ba96..5ba3b0859b 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/pl110.c b/hw/pl110.c
index 06d2dfada6..62aba17ad4 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -4,7 +4,7 @@
* Copyright (c) 2005-2009 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GNU LGPL
+ * This code is licensed under the GNU LGPL
*/
#include "sysbus.h"
diff --git a/hw/pl110_template.h b/hw/pl110_template.h
index b3c9077dcc..d303336786 100644
--- a/hw/pl110_template.h
+++ b/hw/pl110_template.h
@@ -4,7 +4,7 @@
* Copyright (c) 2005 CodeSourcery, LLC.
* Written by Paul Brook
*
- * This code is licenced under the GNU LGPL
+ * This code is licensed under the GNU LGPL
*
* Framebuffer format conversion routines.
*/
diff --git a/hw/pl181.c b/hw/pl181.c
index 6bc79f5f7a..0943c09eca 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "blockdev.h"
diff --git a/hw/pl190.c b/hw/pl190.c
index 75f2ba1966..8dc7e42861 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 299473c4b5..15c24f6e7a 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -24,6 +24,7 @@
#include "ppc4xx.h"
#include "pci.h"
#include "pci_host.h"
+#include "exec-memory.h"
#undef DEBUG
#ifdef DEBUG
@@ -345,7 +346,9 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
controller->pci_state.bus = pci_register_bus(NULL, "pci",
ppc4xx_pci_set_irq,
ppc4xx_pci_map_irq,
- pci_irqs, 0, 4);
+ pci_irqs,
+ get_system_memory(),
+ 0, 4);
controller->pci_dev = pci_register_device(controller->pci_state.bus,
"host bridge", sizeof(PCIDevice),
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index 68dade7e40..6fad20a745 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -25,6 +25,8 @@
#if !defined(__PPC_MAC_H__)
#define __PPC_MAC_H__
+#include "memory.h"
+
/* SMP is not enabled, for now */
#define MAX_CPUS 1
@@ -52,11 +54,12 @@ qemu_irq *heathrow_pic_init(int *pmem_index,
int nb_cpus, qemu_irq **irqs);
/* Grackle PCI */
-PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
+ MemoryRegion *address_space);
/* UniNorth PCI */
-PCIBus *pci_pmac_init(qemu_irq *pic);
-PCIBus *pci_pmac_u3_init(qemu_irq *pic);
+PCIBus *pci_pmac_init(qemu_irq *pic, MemoryRegion *address_space);
+PCIBus *pci_pmac_u3_init(qemu_irq *pic, MemoryRegion *address_space);
/* Mac NVRAM */
typedef struct MacIONVRAMState MacIONVRAMState;
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 5bce709bab..2c0fae8ef3 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -67,6 +67,7 @@
#include "kvm_ppc.h"
#include "hw/usb.h"
#include "blockdev.h"
+#include "exec-memory.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
@@ -317,10 +318,10 @@ static void ppc_core99_init (ram_addr_t ram_size,
pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
/* 970 gets a U3 bus */
- pci_bus = pci_pmac_u3_init(pic);
+ pci_bus = pci_pmac_u3_init(pic, get_system_memory());
machine_arch = ARCH_MAC99_U3;
} else {
- pci_bus = pci_pmac_init(pic);
+ pci_bus = pci_pmac_init(pic, get_system_memory());
machine_arch = ARCH_MAC99;
}
/* init basic PC hardware */
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 20cd8e1a8d..585afd6c4b 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -43,6 +43,7 @@
#include "kvm.h"
#include "kvm_ppc.h"
#include "blockdev.h"
+#include "exec-memory.h"
#define MAX_IDE_BUS 2
#define CFG_ADDR 0xf0000510
@@ -233,7 +234,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
hw_error("Only 6xx bus is supported on heathrow machine\n");
}
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
- pci_bus = pci_grackle_init(0xfec00000, pic);
+ pci_bus = pci_grackle_init(0xfec00000, pic, get_system_memory());
pci_vga_init(pci_bus);
escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 0e9cfc24cd..91ebe07dcd 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -38,6 +38,7 @@
#include "loader.h"
#include "mc146818rtc.h"
#include "blockdev.h"
+#include "exec-memory.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
@@ -648,7 +649,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
hw_error("Only 6xx bus is supported on PREP machine\n");
}
i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
- pci_bus = pci_prep_init(i8259);
+ pci_bus = pci_prep_init(i8259, get_system_memory());
/* Hmm, prep has no pci-isa bridge ??? */
isa_bus_new(NULL);
isa_bus_irqs(i8259);
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index fc11af4374..134453965b 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -274,12 +274,15 @@ static void e500_pci_map(SysBusDevice *dev, target_phys_addr_t base)
s->reg);
}
+#include "exec-memory.h"
+
static int e500_pcihost_initfn(SysBusDevice *dev)
{
PCIHostState *h;
PPCE500PCIState *s;
PCIBus *b;
int i;
+ MemoryRegion *address_space = get_system_memory();
h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
s = DO_UPCAST(PPCE500PCIState, pci_state, h);
@@ -289,7 +292,8 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
}
b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, mpc85xx_pci_set_irq,
- mpc85xx_pci_map_irq, s->irq, PCI_DEVFN(0x11, 0), 4);
+ mpc85xx_pci_map_irq, s->irq, address_space,
+ PCI_DEVFN(0x11, 0), 4);
s->pci_state.bus = b;
pci_create_simple(b, 0, "e500-host-bridge");
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index f88b8254c2..da02f0ea8e 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -110,7 +110,7 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
}
-PCIBus *pci_prep_init(qemu_irq *pic)
+PCIBus *pci_prep_init(qemu_irq *pic, MemoryRegion *address_space)
{
PREPPCIState *s;
PCIDevice *d;
@@ -118,7 +118,8 @@ PCIBus *pci_prep_init(qemu_irq *pic)
s = qemu_mallocz(sizeof(PREPPCIState));
s->bus = pci_register_bus(NULL, "pci",
- prep_set_irq, prep_map_irq, pic, 0, 4);
+ prep_set_irq, prep_map_irq, pic,
+ address_space, 0, 4);
pci_host_conf_register_ioport(0xcf8, s);
diff --git a/hw/prep_pci.h b/hw/prep_pci.h
index cd6851288c..a27368b99b 100644
--- a/hw/prep_pci.h
+++ b/hw/prep_pci.h
@@ -2,7 +2,8 @@
#define QEMU_PREP_PCI_H
#include "qemu-common.h"
+#include "memory.h"
-PCIBus *pci_prep_init(qemu_irq *pic);
+PCIBus *pci_prep_init(qemu_irq *pic, MemoryRegion *address_space);
#endif
diff --git a/hw/ptimer.c b/hw/ptimer.c
index 47964a67e1..6f13ce92fc 100644
--- a/hw/ptimer.c
+++ b/hw/ptimer.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2007 CodeSourcery.
*
- * This code is licenced under the GNU LGPL.
+ * This code is licensed under the GNU LGPL.
*/
#include "hw.h"
#include "qemu-timer.h"
diff --git a/hw/pxa.h b/hw/pxa.h
index d982f00c5d..859fc676e4 100644
--- a/hw/pxa.h
+++ b/hw/pxa.h
@@ -4,7 +4,7 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#ifndef PXA_H
# define PXA_H "pxa.h"
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index ac5d95d718..cf9311014d 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index a67498b2bc..599581e266 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -5,7 +5,7 @@
* Copyright (c) 2006 Thorsten Zitterell
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index e9a536102b..bdd82e6bf2 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -5,7 +5,7 @@
* Copyright (c) 2006 Thorsten Zitterell
* Written by Andrzej Zaborowski <balrog@zabor.org>
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index f777a21226..4235e42639 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 Openedhand Ltd.
* Copyright (c) 2006 Thorsten Zitterell
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
diff --git a/hw/qdev.c b/hw/qdev.c
index 292b52f8c5..b4ea8e13d1 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -289,6 +289,9 @@ int qdev_init(DeviceState *dev)
dev->alias_required_for_version);
}
dev->state = DEV_STATE_INITIALIZED;
+ if (dev->hotplugged && dev->info->reset) {
+ dev->info->reset(dev);
+ }
return 0;
}
@@ -459,7 +462,7 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
{
- qdev_prop_set_macaddr(dev, "mac", nd->macaddr);
+ qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
if (nd->vlan)
qdev_prop_set_vlan(dev, "vlan", nd->vlan);
if (nd->netdev)
diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c
index 76f43e646c..74cadba302 100644
--- a/hw/qxl-logger.c
+++ b/hw/qxl-logger.c
@@ -19,6 +19,7 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu-timer.h"
#include "qxl.h"
static const char *qxl_type[] = {
@@ -223,7 +224,8 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
if (!qxl->cmdlog) {
return;
}
- fprintf(stderr, "qxl-%d/%s:", qxl->id, ring);
+ fprintf(stderr, "%ld qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
+ qxl->id, ring);
fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
qxl_name(qxl_type, ext->cmd.type),
compat ? "(compat)" : "");
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 1316066599..643ff2d841 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl)
update.bottom = qxl->guest_primary.surface.height;
memset(dirty, 0, sizeof(dirty));
- qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
- dirty, ARRAY_SIZE(dirty), 1);
+ qxl_spice_update_area(qxl, 0, &update,
+ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
for (i = 0; i < ARRAY_SIZE(dirty); i++) {
if (qemu_spice_rect_is_empty(dirty+i)) {
diff --git a/hw/qxl.c b/hw/qxl.c
index 16316f2bf5..b684608f87 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -120,11 +120,127 @@ static QXLMode qxl_modes[] = {
static PCIQXLDevice *qxl0;
static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
-static void qxl_destroy_primary(PCIQXLDevice *d);
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
static void qxl_reset_memslots(PCIQXLDevice *d);
static void qxl_reset_surfaces(PCIQXLDevice *d);
static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+{
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
+#endif
+ if (qxl->guestdebug) {
+ va_list ap;
+ va_start(ap, msg);
+ fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+ struct QXLRect *area, struct QXLRect *dirty_rects,
+ uint32_t num_dirty_rects,
+ uint32_t clear_dirty_region,
+ qxl_async_io async)
+{
+ if (async == QXL_SYNC) {
+ qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
+ dirty_rects, num_dirty_rects, clear_dirty_region);
+ } else {
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
+ clear_dirty_region, 0);
+#else
+ abort();
+#endif
+ }
+}
+
+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
+ uint32_t id)
+{
+ qemu_mutex_lock(&qxl->track_lock);
+ qxl->guest_surfaces.cmds[id] = 0;
+ qxl->guest_surfaces.count--;
+ qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
+ qxl_async_io async)
+{
+ if (async) {
+#if SPICE_INTERFACE_QXL_MINOR < 1
+ abort();
+#else
+ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
+ (uint64_t)id);
+#endif
+ } else {
+ qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+ qxl_spice_destroy_surface_wait_complete(qxl, id);
+ }
+}
+
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
+{
+ spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0);
+}
+#endif
+
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+ uint32_t count)
+{
+ qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
+}
+
+void qxl_spice_oom(PCIQXLDevice *qxl)
+{
+ qxl->ssd.worker->oom(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+{
+ qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
+}
+
+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
+{
+ qemu_mutex_lock(&qxl->track_lock);
+ memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
+ qxl->guest_surfaces.count = 0;
+ qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
+{
+ if (async) {
+#if SPICE_INTERFACE_QXL_MINOR < 1
+ abort();
+#else
+ spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
+#endif
+ } else {
+ qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+ qxl_spice_destroy_surfaces_complete(qxl);
+ }
+}
+
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+{
+ qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
+{
+ qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+}
+
+
static inline uint32_t msb_mask(uint32_t val)
{
uint32_t mask;
@@ -270,6 +386,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
uint32_t id = le32_to_cpu(cmd->surface_id);
PANIC_ON(id >= NUM_SURFACES);
+ qemu_mutex_lock(&qxl->track_lock);
if (cmd->type == QXL_SURFACE_CMD_CREATE) {
qxl->guest_surfaces.cmds[id] = ext->cmd.data;
qxl->guest_surfaces.count++;
@@ -280,6 +397,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
qxl->guest_surfaces.cmds[id] = 0;
qxl->guest_surfaces.count--;
}
+ qemu_mutex_unlock(&qxl->track_lock);
break;
}
case QXL_CMD_CURSOR:
@@ -336,6 +454,58 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
info->n_surfaces = NUM_SURFACES;
}
+static const char *qxl_mode_to_string(int mode)
+{
+ switch (mode) {
+ case QXL_MODE_COMPAT:
+ return "compat";
+ case QXL_MODE_NATIVE:
+ return "native";
+ case QXL_MODE_UNDEFINED:
+ return "undefined";
+ case QXL_MODE_VGA:
+ return "vga";
+ }
+ return "INVALID";
+}
+
+static const char *io_port_to_string(uint32_t io_port)
+{
+ if (io_port >= QXL_IO_RANGE_SIZE) {
+ return "out of range";
+ }
+ static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
+ [QXL_IO_NOTIFY_CMD] = "QXL_IO_NOTIFY_CMD",
+ [QXL_IO_NOTIFY_CURSOR] = "QXL_IO_NOTIFY_CURSOR",
+ [QXL_IO_UPDATE_AREA] = "QXL_IO_UPDATE_AREA",
+ [QXL_IO_UPDATE_IRQ] = "QXL_IO_UPDATE_IRQ",
+ [QXL_IO_NOTIFY_OOM] = "QXL_IO_NOTIFY_OOM",
+ [QXL_IO_RESET] = "QXL_IO_RESET",
+ [QXL_IO_SET_MODE] = "QXL_IO_SET_MODE",
+ [QXL_IO_LOG] = "QXL_IO_LOG",
+ [QXL_IO_MEMSLOT_ADD] = "QXL_IO_MEMSLOT_ADD",
+ [QXL_IO_MEMSLOT_DEL] = "QXL_IO_MEMSLOT_DEL",
+ [QXL_IO_DETACH_PRIMARY] = "QXL_IO_DETACH_PRIMARY",
+ [QXL_IO_ATTACH_PRIMARY] = "QXL_IO_ATTACH_PRIMARY",
+ [QXL_IO_CREATE_PRIMARY] = "QXL_IO_CREATE_PRIMARY",
+ [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY",
+ [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT",
+ [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES",
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC",
+ [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC",
+ [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC",
+ [QXL_IO_DESTROY_PRIMARY_ASYNC] = "QXL_IO_DESTROY_PRIMARY_ASYNC",
+ [QXL_IO_DESTROY_SURFACE_ASYNC] = "QXL_IO_DESTROY_SURFACE_ASYNC",
+ [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
+ = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
+ [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC",
+ [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE",
+#endif
+ };
+ return io_port_to_string[io_port];
+}
+
/* called from spice server thread context only */
static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
{
@@ -358,18 +528,19 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
}
qemu_mutex_unlock(&qxl->ssd.lock);
if (ret) {
+ dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
qxl_log_command(qxl, "vga", ext);
}
return ret;
case QXL_MODE_COMPAT:
case QXL_MODE_NATIVE:
case QXL_MODE_UNDEFINED:
- dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
- qxl->cmdflags ? "compat" : "native");
+ dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
ring = &qxl->ram->cmd_ring;
if (SPICE_RING_IS_EMPTY(ring)) {
return false;
}
+ dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode));
SPICE_RING_CONS_ITEM(ring, cmd);
ext->cmd = *cmd;
ext->group_id = MEMSLOT_GROUP_GUEST;
@@ -563,6 +734,38 @@ static int interface_flush_resources(QXLInstance *sin)
return ret;
}
+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
+
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+
+/* called from spice server thread context only */
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
+{
+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+ uint32_t current_async;
+
+ qemu_mutex_lock(&qxl->async_lock);
+ current_async = qxl->current_async;
+ qxl->current_async = QXL_UNDEFINED_IO;
+ qemu_mutex_unlock(&qxl->async_lock);
+
+ dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
+ switch (current_async) {
+ case QXL_IO_CREATE_PRIMARY_ASYNC:
+ qxl_create_guest_primary_complete(qxl);
+ break;
+ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+ qxl_spice_destroy_surfaces_complete(qxl);
+ break;
+ case QXL_IO_DESTROY_SURFACE_ASYNC:
+ qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
+ break;
+ }
+ qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
+}
+
+#endif
+
static const QXLInterface qxl_interface = {
.base.type = SPICE_INTERFACE_QXL,
.base.description = "qxl gpu",
@@ -582,6 +785,9 @@ static const QXLInterface qxl_interface = {
.req_cursor_notification = interface_req_cursor_notification,
.notify_update = interface_notify_update,
.flush_resources = interface_flush_resources,
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ .async_complete = interface_async_complete,
+#endif
};
static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -601,7 +807,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
return;
}
dprint(d, 1, "%s\n", __FUNCTION__);
- qxl_destroy_primary(d);
+ qxl_destroy_primary(d, QXL_SYNC);
}
static void qxl_set_irq(PCIQXLDevice *d)
@@ -640,8 +846,8 @@ static void qxl_reset_state(PCIQXLDevice *d)
QXLRam *ram = d->ram;
QXLRom *rom = d->rom;
- assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
- assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+ assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+ assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
d->shadow_rom.update_id = cpu_to_le32(0);
*rom = d->shadow_rom;
qxl_rom_set_dirty(d);
@@ -668,8 +874,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
dprint(d, 1, "%s: start%s\n", __FUNCTION__,
loadvm ? " (loadvm)" : "");
- d->ssd.worker->reset_cursor(d->ssd.worker);
- d->ssd.worker->reset_image_cache(d->ssd.worker);
+ qxl_spice_reset_cursor(d);
+ qxl_spice_reset_image_cache(d);
qxl_reset_surfaces(d);
qxl_reset_memslots(d);
@@ -698,13 +904,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
if (qxl->mode != QXL_MODE_VGA) {
dprint(qxl, 1, "%s\n", __FUNCTION__);
- qxl_destroy_primary(qxl);
+ qxl_destroy_primary(qxl, QXL_SYNC);
qxl_soft_reset(qxl);
}
vga_ioport_write(opaque, addr, val);
}
-static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
+ qxl_async_io async)
{
static const int regions[] = {
QXL_RAM_RANGE_INDEX,
@@ -774,7 +981,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
__FUNCTION__, memslot.slot_id,
memslot.virt_start, memslot.virt_end);
- d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
+ qemu_spice_add_memslot(&d->ssd, &memslot, async);
d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
d->guest_slots[slot_id].delta = delta;
@@ -784,14 +991,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
{
dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
- d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
+ qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
d->guest_slots[slot_id].active = 0;
}
static void qxl_reset_memslots(PCIQXLDevice *d)
{
dprint(d, 1, "%s:\n", __FUNCTION__);
- d->ssd.worker->reset_memslots(d->ssd.worker);
+ qxl_spice_reset_memslots(d);
memset(&d->guest_slots, 0, sizeof(d->guest_slots));
}
@@ -799,8 +1006,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
{
dprint(d, 1, "%s:\n", __FUNCTION__);
d->mode = QXL_MODE_UNDEFINED;
- d->ssd.worker->destroy_surfaces(d->ssd.worker);
- memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+ qxl_spice_destroy_surfaces(d, QXL_SYNC);
}
/* called from spice server thread context only */
@@ -825,7 +1031,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
}
}
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
+{
+ /* for local rendering */
+ qxl_render_resize(qxl);
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
+ qxl_async_io async)
{
QXLDevSurfaceCreate surface;
QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
@@ -853,22 +1066,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
qxl->mode = QXL_MODE_NATIVE;
qxl->cmdflags = 0;
- qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
+ qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
- /* for local rendering */
- qxl_render_resize(qxl);
+ if (async == QXL_SYNC) {
+ qxl_create_guest_primary_complete(qxl);
+ }
}
-static void qxl_destroy_primary(PCIQXLDevice *d)
+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
+ * done (in QXL_SYNC case), 0 otherwise. */
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
{
if (d->mode == QXL_MODE_UNDEFINED) {
- return;
+ return 0;
}
dprint(d, 1, "%s\n", __FUNCTION__);
d->mode = QXL_MODE_UNDEFINED;
- d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
+ qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+ return 1;
}
static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
@@ -898,10 +1115,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
}
d->guest_slots[0].slot = slot;
- qxl_add_memslot(d, 0, devmem);
+ qxl_add_memslot(d, 0, devmem, QXL_SYNC);
d->guest_primary.surface = surface;
- qxl_create_guest_primary(d, 0);
+ qxl_create_guest_primary(d, 0, QXL_SYNC);
d->mode = QXL_MODE_COMPAT;
d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
@@ -919,6 +1136,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PCIQXLDevice *d = opaque;
uint32_t io_port = addr - d->io_base;
+ qxl_async_io async = QXL_SYNC;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ uint32_t orig_io_port = io_port;
+#endif
switch (io_port) {
case QXL_IO_RESET:
@@ -926,27 +1147,83 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
case QXL_IO_MEMSLOT_ADD:
case QXL_IO_MEMSLOT_DEL:
case QXL_IO_CREATE_PRIMARY:
+ case QXL_IO_UPDATE_IRQ:
+ case QXL_IO_LOG:
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ case QXL_IO_MEMSLOT_ADD_ASYNC:
+ case QXL_IO_CREATE_PRIMARY_ASYNC:
+#endif
break;
default:
- if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
+ if (d->mode != QXL_MODE_VGA) {
break;
- dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
+ }
+ dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
+ __func__, io_port, io_port_to_string(io_port));
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ /* be nice to buggy guest drivers */
+ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
+ io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
+ qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+ }
+#endif
return;
}
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ /* we change the io_port to avoid ifdeffery in the main switch */
+ orig_io_port = io_port;
+ switch (io_port) {
+ case QXL_IO_UPDATE_AREA_ASYNC:
+ io_port = QXL_IO_UPDATE_AREA;
+ goto async_common;
+ case QXL_IO_MEMSLOT_ADD_ASYNC:
+ io_port = QXL_IO_MEMSLOT_ADD;
+ goto async_common;
+ case QXL_IO_CREATE_PRIMARY_ASYNC:
+ io_port = QXL_IO_CREATE_PRIMARY;
+ goto async_common;
+ case QXL_IO_DESTROY_PRIMARY_ASYNC:
+ io_port = QXL_IO_DESTROY_PRIMARY;
+ goto async_common;
+ case QXL_IO_DESTROY_SURFACE_ASYNC:
+ io_port = QXL_IO_DESTROY_SURFACE_WAIT;
+ goto async_common;
+ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+ io_port = QXL_IO_DESTROY_ALL_SURFACES;
+ goto async_common;
+ case QXL_IO_FLUSH_SURFACES_ASYNC:
+async_common:
+ async = QXL_ASYNC;
+ qemu_mutex_lock(&d->async_lock);
+ if (d->current_async != QXL_UNDEFINED_IO) {
+ qxl_guest_bug(d, "%d async started before last (%d) complete",
+ io_port, d->current_async);
+ qemu_mutex_unlock(&d->async_lock);
+ return;
+ }
+ d->current_async = orig_io_port;
+ qemu_mutex_unlock(&d->async_lock);
+ dprint(d, 2, "start async %d (%d)\n", io_port, val);
+ break;
+ default:
+ break;
+ }
+#endif
+
switch (io_port) {
case QXL_IO_UPDATE_AREA:
{
QXLRect update = d->ram->update_area;
- d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
- &update, NULL, 0, 0);
+ qxl_spice_update_area(d, d->ram->update_surface,
+ &update, NULL, 0, 0, async);
break;
}
case QXL_IO_NOTIFY_CMD:
- d->ssd.worker->wakeup(d->ssd.worker);
+ qemu_spice_wakeup(&d->ssd);
break;
case QXL_IO_NOTIFY_CURSOR:
- d->ssd.worker->wakeup(d->ssd.worker);
+ qemu_spice_wakeup(&d->ssd);
break;
case QXL_IO_UPDATE_IRQ:
qxl_set_irq(d);
@@ -960,7 +1237,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
break;
}
d->oom_running = 1;
- d->ssd.worker->oom(d->ssd.worker);
+ qxl_spice_oom(d);
d->oom_running = 0;
break;
case QXL_IO_SET_MODE:
@@ -969,7 +1246,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
break;
case QXL_IO_LOG:
if (d->guestdebug) {
- fprintf(stderr, "qxl/guest: %s", d->ram->log_buf);
+ fprintf(stderr, "qxl/guest-%d: %ld: %s", d->id,
+ qemu_get_clock_ns(vm_clock), d->ram->log_buf);
}
break;
case QXL_IO_RESET:
@@ -977,35 +1255,97 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
qxl_hard_reset(d, 0);
break;
case QXL_IO_MEMSLOT_ADD:
- PANIC_ON(val >= NUM_MEMSLOTS);
- PANIC_ON(d->guest_slots[val].active);
+ if (val >= NUM_MEMSLOTS) {
+ qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
+ break;
+ }
+ if (d->guest_slots[val].active) {
+ qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active");
+ break;
+ }
d->guest_slots[val].slot = d->ram->mem_slot;
- qxl_add_memslot(d, val, 0);
+ qxl_add_memslot(d, val, 0, async);
break;
case QXL_IO_MEMSLOT_DEL:
+ if (val >= NUM_MEMSLOTS) {
+ qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
+ break;
+ }
qxl_del_memslot(d, val);
break;
case QXL_IO_CREATE_PRIMARY:
- PANIC_ON(val != 0);
- dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
+ if (val != 0) {
+ qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
+ async);
+ goto cancel_async;
+ }
+ dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async);
d->guest_primary.surface = d->ram->create_surface;
- qxl_create_guest_primary(d, 0);
+ qxl_create_guest_primary(d, 0, async);
break;
case QXL_IO_DESTROY_PRIMARY:
- PANIC_ON(val != 0);
- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY\n");
- qxl_destroy_primary(d);
+ if (val != 0) {
+ qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
+ async);
+ goto cancel_async;
+ }
+ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async,
+ qxl_mode_to_string(d->mode));
+ if (!qxl_destroy_primary(d, async)) {
+ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n",
+ qxl_mode_to_string(d->mode));
+ goto cancel_async;
+ }
break;
case QXL_IO_DESTROY_SURFACE_WAIT:
- d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
+ if (val >= NUM_SURFACES) {
+ qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
+ "%d >= NUM_SURFACES", async, val);
+ goto cancel_async;
+ }
+ qxl_spice_destroy_surface_wait(d, val, async);
+ break;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ case QXL_IO_FLUSH_RELEASE: {
+ QXLReleaseRing *ring = &d->ram->release_ring;
+ if (ring->prod - ring->cons + 1 == ring->num_items) {
+ fprintf(stderr,
+ "ERROR: no flush, full release ring [p%d,%dc]\n",
+ ring->prod, ring->cons);
+ }
+ qxl_push_free_res(d, 1 /* flush */);
+ dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n",
+ qxl_mode_to_string(d->mode), d->guest_surfaces.count,
+ d->num_free_res, d->last_release);
+ break;
+ }
+ case QXL_IO_FLUSH_SURFACES_ASYNC:
+ dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n",
+ val, qxl_mode_to_string(d->mode), d->guest_surfaces.count,
+ d->num_free_res);
+ qxl_spice_flush_surfaces_async(d);
break;
+#endif
case QXL_IO_DESTROY_ALL_SURFACES:
- d->ssd.worker->destroy_surfaces(d->ssd.worker);
+ d->mode = QXL_MODE_UNDEFINED;
+ qxl_spice_destroy_surfaces(d, async);
break;
default:
fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
abort();
}
+ return;
+cancel_async:
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ if (async) {
+ qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+ qemu_mutex_lock(&d->async_lock);
+ d->current_async = QXL_UNDEFINED_IO;
+ qemu_mutex_unlock(&d->async_lock);
+ }
+#else
+ return;
+#endif
}
static uint32_t ioport_read(void *opaque, uint32_t addr)
@@ -1167,11 +1507,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
if (!running && qxl->mode == QXL_MODE_NATIVE) {
- /* dirty all vram (which holds surfaces) to make sure it is saved */
+ /* dirty all vram (which holds surfaces) and devram (primary surface)
+ * to make sure they are saved */
/* FIXME #1: should go out during "live" stage */
/* FIXME #2: we only need to save the areas which are actually used */
- ram_addr_t addr = qxl->vram_offset;
- qxl_set_dirty(addr, addr + qxl->vram_size);
+ ram_addr_t vram_addr = qxl->vram_offset;
+ ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
+ qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size);
+ qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
}
}
@@ -1207,7 +1550,6 @@ static DisplayChangeListener display_listener = {
static int qxl_init_common(PCIQXLDevice *qxl)
{
uint8_t* config = qxl->pci.config;
- uint32_t pci_device_id;
uint32_t pci_device_rev;
uint32_t io_size;
@@ -1215,23 +1557,25 @@ static int qxl_init_common(PCIQXLDevice *qxl)
qxl->generation = 1;
qxl->num_memslots = NUM_MEMSLOTS;
qxl->num_surfaces = NUM_SURFACES;
+ qemu_mutex_init(&qxl->track_lock);
+ qemu_mutex_init(&qxl->async_lock);
+ qxl->current_async = QXL_UNDEFINED_IO;
switch (qxl->revision) {
case 1: /* spice 0.4 -- qxl-1 */
- pci_device_id = QXL_DEVICE_ID_STABLE;
pci_device_rev = QXL_REVISION_STABLE_V04;
break;
case 2: /* spice 0.6 -- qxl-2 */
- pci_device_id = QXL_DEVICE_ID_STABLE;
pci_device_rev = QXL_REVISION_STABLE_V06;
break;
- default: /* experimental */
- pci_device_id = QXL_DEVICE_ID_DEVEL;
- pci_device_rev = 1;
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+ case 3: /* qxl-3 */
+#endif
+ default:
+ pci_device_rev = QXL_DEFAULT_REVISION;
break;
}
- pci_config_set_device_id(config, pci_device_id);
pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
@@ -1300,12 +1644,7 @@ static int qxl_init_primary(PCIDevice *dev)
vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
qxl_hw_screen_dump, qxl_hw_text_update, qxl);
- qxl->ssd.ds = vga->ds;
- qemu_mutex_init(&qxl->ssd.lock);
- qxl->ssd.mouse_x = -1;
- qxl->ssd.mouse_y = -1;
- qxl->ssd.bufsize = (16 * 1024 * 1024);
- qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
+ qemu_spice_display_init_common(&qxl->ssd, vga->ds);
qxl0 = qxl;
register_displaychangelistener(vga->ds, &display_listener);
@@ -1375,7 +1714,8 @@ static int qxl_post_load(void *opaque, int version)
d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
- dprint(d, 1, "%s: restore mode\n", __FUNCTION__);
+ dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__,
+ qxl_mode_to_string(d->mode));
newmode = d->mode;
d->mode = QXL_MODE_UNDEFINED;
switch (newmode) {
@@ -1389,9 +1729,9 @@ static int qxl_post_load(void *opaque, int version)
if (!d->guest_slots[i].active) {
continue;
}
- qxl_add_memslot(d, i, 0);
+ qxl_add_memslot(d, i, 0, QXL_SYNC);
}
- qxl_create_guest_primary(d, 1);
+ qxl_create_guest_primary(d, 1, QXL_SYNC);
/* replay surface-create and cursor-set commands */
cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
@@ -1408,7 +1748,7 @@ static int qxl_post_load(void *opaque, int version)
cmds[out].cmd.type = QXL_CMD_CURSOR;
cmds[out].group_id = MEMSLOT_GROUP_GUEST;
out++;
- d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
+ qxl_spice_loadvm_commands(d, cmds, out);
qemu_free(cmds);
break;
@@ -1492,11 +1832,15 @@ static PCIDeviceInfo qxl_info_primary = {
.config_write = qxl_write_config,
.romfile = "vgabios-qxl.bin",
.vendor_id = REDHAT_PCI_VENDOR_ID,
+ .device_id = QXL_DEVICE_ID_STABLE,
.class_id = PCI_CLASS_DISPLAY_VGA,
.qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+ DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+ 64 * 1024 * 1024),
+ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
+ 64 * 1024 * 1024),
+ DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+ QXL_DEFAULT_REVISION),
DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
@@ -1512,11 +1856,15 @@ static PCIDeviceInfo qxl_info_secondary = {
.qdev.vmsd = &qxl_vmstate,
.init = qxl_init_secondary,
.vendor_id = REDHAT_PCI_VENDOR_ID,
+ .device_id = QXL_DEVICE_ID_STABLE,
.class_id = PCI_CLASS_DISPLAY_OTHER,
.qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+ DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+ 64 * 1024 * 1024),
+ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size,
+ 64 * 1024 * 1024),
+ DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+ QXL_DEFAULT_REVISION),
DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
diff --git a/hw/qxl.h b/hw/qxl.h
index f6c450d32d..4bcf7e1429 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -15,6 +15,8 @@ enum qxl_mode {
QXL_MODE_NATIVE,
};
+#define QXL_UNDEFINED_IO UINT32_MAX
+
typedef struct PCIQXLDevice {
PCIDevice pci;
SimpleSpiceDisplay ssd;
@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice {
int32_t num_memslots;
int32_t num_surfaces;
+ uint32_t current_async;
+ QemuMutex async_lock;
+
struct guest_slots {
QXLMemSlot slot;
void *ptr;
@@ -55,6 +60,8 @@ typedef struct PCIQXLDevice {
} guest_surfaces;
QXLPHYSICAL guest_cursor;
+ QemuMutex track_lock;
+
/* thread signaling */
pthread_t main;
int pipe[2];
@@ -84,7 +91,7 @@ typedef struct PCIQXLDevice {
#define PANIC_ON(x) if ((x)) { \
printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
- exit(-1); \
+ abort(); \
}
#define dprint(_qxl, _level, _fmt, ...) \
@@ -95,8 +102,27 @@ typedef struct PCIQXLDevice {
} \
} while (0)
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10
+#else
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06
+#endif
+
/* qxl.c */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+ struct QXLRect *area, struct QXLRect *dirty_rects,
+ uint32_t num_dirty_rects,
+ uint32_t clear_dirty_region,
+ qxl_async_io async);
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+ uint32_t count);
+void qxl_spice_oom(PCIQXLDevice *qxl);
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
/* qxl-logger.c */
void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
@@ -106,3 +132,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
void qxl_render_resize(PCIQXLDevice *qxl);
void qxl_render_update(PCIQXLDevice *qxl);
void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
+#if SPICE_INTERFACE_QXL_MINOR >= 1
+void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id,
+ struct QXLRect *area,
+ uint32_t clear_dirty_region,
+ int is_vga);
+#endif
diff --git a/hw/realview.c b/hw/realview.c
index 82f3d82d44..94ab900512 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index db908b6439..43a2a0d5ed 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index ad6a730be0..0b0344c1fd 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -131,7 +131,8 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
return res;
}
-SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun)
+SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
+ uint32_t lun, void *hba_private)
{
SCSIRequest *req;
@@ -141,14 +142,16 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
req->dev = d;
req->tag = tag;
req->lun = lun;
+ req->hba_private = hba_private;
req->status = -1;
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
return req;
}
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun)
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+ void *hba_private)
{
- return d->info->alloc_req(d, tag, lun);
+ return d->info->alloc_req(d, tag, lun, hba_private);
}
uint8_t *scsi_req_get_buf(SCSIRequest *req)
@@ -220,7 +223,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
switch(cmd[0]) {
case TEST_UNIT_READY:
- case REZERO_UNIT:
+ case REWIND:
case START_STOP:
case SEEK_6:
case WRITE_FILEMARKS:
@@ -229,24 +232,24 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
case RELEASE:
case ERASE:
case ALLOW_MEDIUM_REMOVAL:
- case VERIFY:
+ case VERIFY_10:
case SEEK_10:
case SYNCHRONIZE_CACHE:
case LOCK_UNLOCK_CACHE:
case LOAD_UNLOAD:
case SET_CD_SPEED:
case SET_LIMITS:
- case WRITE_LONG:
+ case WRITE_LONG_10:
case MOVE_MEDIUM:
case UPDATE_BLOCK:
req->cmd.xfer = 0;
break;
case MODE_SENSE:
break;
- case WRITE_SAME:
+ case WRITE_SAME_10:
req->cmd.xfer = 1;
break;
- case READ_CAPACITY:
+ case READ_CAPACITY_10:
req->cmd.xfer = 8;
break;
case READ_BLOCK_LIMITS:
@@ -262,7 +265,7 @@ static int scsi_req_length(SCSIRequest *req, uint8_t *cmd)
req->cmd.xfer *= 8;
break;
case WRITE_10:
- case WRITE_VERIFY:
+ case WRITE_VERIFY_10:
case WRITE_6:
case WRITE_12:
case WRITE_VERIFY_12:
@@ -322,7 +325,7 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
switch (req->cmd.buf[0]) {
case WRITE_6:
case WRITE_10:
- case WRITE_VERIFY:
+ case WRITE_VERIFY_10:
case WRITE_12:
case WRITE_VERIFY_12:
case WRITE_16:
@@ -342,15 +345,13 @@ static void scsi_req_xfer_mode(SCSIRequest *req)
case SEARCH_HIGH:
case SEARCH_LOW:
case UPDATE_BLOCK:
- case WRITE_LONG:
- case WRITE_SAME:
+ case WRITE_LONG_10:
+ case WRITE_SAME_10:
case SEARCH_HIGH_12:
case SEARCH_EQUAL_12:
case SEARCH_LOW_12:
- case SET_WINDOW:
case MEDIUM_SCAN:
case SEND_VOLUME_TAG:
- case WRITE_LONG_2:
case PERSISTENT_RESERVE_OUT:
case MAINTENANCE_OUT:
req->cmd.mode = SCSI_XFER_TO_DEV;
@@ -514,8 +515,7 @@ static const char *scsi_command_name(uint8_t cmd)
{
static const char *names[] = {
[ TEST_UNIT_READY ] = "TEST_UNIT_READY",
- [ REZERO_UNIT ] = "REZERO_UNIT",
- /* REWIND and REZERO_UNIT use the same operation code */
+ [ REWIND ] = "REWIND",
[ REQUEST_SENSE ] = "REQUEST_SENSE",
[ FORMAT_UNIT ] = "FORMAT_UNIT",
[ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
@@ -540,14 +540,12 @@ static const char *scsi_command_name(uint8_t cmd)
[ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
[ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
[ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
-
- [ SET_WINDOW ] = "SET_WINDOW",
- [ READ_CAPACITY ] = "READ_CAPACITY",
+ [ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
[ READ_10 ] = "READ_10",
[ WRITE_10 ] = "WRITE_10",
[ SEEK_10 ] = "SEEK_10",
- [ WRITE_VERIFY ] = "WRITE_VERIFY",
- [ VERIFY ] = "VERIFY",
+ [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
+ [ VERIFY_10 ] = "VERIFY_10",
[ SEARCH_HIGH ] = "SEARCH_HIGH",
[ SEARCH_EQUAL ] = "SEARCH_EQUAL",
[ SEARCH_LOW ] = "SEARCH_LOW",
@@ -563,11 +561,14 @@ static const char *scsi_command_name(uint8_t cmd)
[ WRITE_BUFFER ] = "WRITE_BUFFER",
[ READ_BUFFER ] = "READ_BUFFER",
[ UPDATE_BLOCK ] = "UPDATE_BLOCK",
- [ READ_LONG ] = "READ_LONG",
- [ WRITE_LONG ] = "WRITE_LONG",
+ [ READ_LONG_10 ] = "READ_LONG_10",
+ [ WRITE_LONG_10 ] = "WRITE_LONG_10",
[ CHANGE_DEFINITION ] = "CHANGE_DEFINITION",
- [ WRITE_SAME ] = "WRITE_SAME",
+ [ WRITE_SAME_10 ] = "WRITE_SAME_10",
+ [ UNMAP ] = "UNMAP",
[ READ_TOC ] = "READ_TOC",
+ [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
+ [ GET_CONFIGURATION ] = "GET_CONFIGURATION",
[ LOG_SELECT ] = "LOG_SELECT",
[ LOG_SENSE ] = "LOG_SENSE",
[ MODE_SELECT_10 ] = "MODE_SELECT_10",
@@ -576,27 +577,39 @@ static const char *scsi_command_name(uint8_t cmd)
[ MODE_SENSE_10 ] = "MODE_SENSE_10",
[ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN",
[ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
+ [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
+ [ EXTENDED_COPY ] = "EXTENDED_COPY",
+ [ ATA_PASSTHROUGH ] = "ATA_PASSTHROUGH",
+ [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
+ [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
+ [ READ_16 ] = "READ_16",
+ [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE",
+ [ WRITE_16 ] = "WRITE_16",
+ [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
+ [ VERIFY_16 ] = "VERIFY_16",
+ [ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16",
+ [ LOCATE_16 ] = "LOCATE_16",
+ [ WRITE_SAME_16 ] = "WRITE_SAME_16",
+ [ ERASE_16 ] = "ERASE_16",
+ [ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN",
+ [ WRITE_LONG_16 ] = "WRITE_LONG_16",
+ [ REPORT_LUNS ] = "REPORT_LUNS",
+ [ BLANK ] = "BLANK",
+ [ MAINTENANCE_IN ] = "MAINTENANCE_IN",
+ [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
[ MOVE_MEDIUM ] = "MOVE_MEDIUM",
+ [ LOAD_UNLOAD ] = "LOAD_UNLOAD",
[ READ_12 ] = "READ_12",
[ WRITE_12 ] = "WRITE_12",
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
+ [ VERIFY_12 ] = "VERIFY_12",
[ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
[ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
[ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
[ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
[ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG",
- [ WRITE_LONG_2 ] = "WRITE_LONG_2",
-
- [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
- [ GET_CONFIGURATION ] = "GET_CONFIGURATION",
- [ READ_16 ] = "READ_16",
- [ WRITE_16 ] = "WRITE_16",
- [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
- [ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN",
- [ REPORT_LUNS ] = "REPORT_LUNS",
- [ LOAD_UNLOAD ] = "LOAD_UNLOAD",
+ [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
[ SET_CD_SPEED ] = "SET_CD_SPEED",
- [ BLANK ] = "BLANK",
};
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 413cce07b5..27010b74c0 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -25,7 +25,7 @@
*/
#define TEST_UNIT_READY 0x00
-#define REZERO_UNIT 0x01
+#define REWIND 0x01
#define REQUEST_SENSE 0x03
#define FORMAT_UNIT 0x04
#define READ_BLOCK_LIMITS 0x05
@@ -48,14 +48,13 @@
#define RECEIVE_DIAGNOSTIC 0x1c
#define SEND_DIAGNOSTIC 0x1d
#define ALLOW_MEDIUM_REMOVAL 0x1e
-
-#define SET_WINDOW 0x24
-#define READ_CAPACITY 0x25
+#define READ_CAPACITY_10 0x25
#define READ_10 0x28
#define WRITE_10 0x2a
#define SEEK_10 0x2b
-#define WRITE_VERIFY 0x2e
-#define VERIFY 0x2f
+#define LOCATE_10 0x2b
+#define WRITE_VERIFY_10 0x2e
+#define VERIFY_10 0x2f
#define SEARCH_HIGH 0x30
#define SEARCH_EQUAL 0x31
#define SEARCH_LOW 0x32
@@ -71,11 +70,14 @@
#define WRITE_BUFFER 0x3b
#define READ_BUFFER 0x3c
#define UPDATE_BLOCK 0x3d
-#define READ_LONG 0x3e
-#define WRITE_LONG 0x3f
+#define READ_LONG_10 0x3e
+#define WRITE_LONG_10 0x3f
#define CHANGE_DEFINITION 0x40
-#define WRITE_SAME 0x41
+#define WRITE_SAME_10 0x41
+#define UNMAP 0x42
#define READ_TOC 0x43
+#define REPORT_DENSITY_SUPPORT 0x44
+#define GET_CONFIGURATION 0x46
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
#define MODE_SELECT_10 0x55
@@ -84,32 +86,40 @@
#define MODE_SENSE_10 0x5a
#define PERSISTENT_RESERVE_IN 0x5e
#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARLENGTH_CDB 0x7f
+#define WRITE_FILEMARKS_16 0x80
+#define EXTENDED_COPY 0x83
+#define ATA_PASSTHROUGH 0x85
+#define ACCESS_CONTROL_IN 0x86
+#define ACCESS_CONTROL_OUT 0x87
+#define READ_16 0x88
+#define COMPARE_AND_WRITE 0x89
+#define WRITE_16 0x8a
+#define WRITE_VERIFY_16 0x8e
+#define VERIFY_16 0x8f
+#define SYNCHRONIZE_CACHE_16 0x91
+#define LOCATE_16 0x92
#define WRITE_SAME_16 0x93
+#define ERASE_16 0x93
+#define SERVICE_ACTION_IN 0x9e
+#define WRITE_LONG_16 0x9f
+#define REPORT_LUNS 0xa0
+#define BLANK 0xa1
#define MAINTENANCE_IN 0xa3
#define MAINTENANCE_OUT 0xa4
#define MOVE_MEDIUM 0xa5
+#define LOAD_UNLOAD 0xa6
#define READ_12 0xa8
#define WRITE_12 0xaa
#define WRITE_VERIFY_12 0xae
+#define VERIFY_12 0xaf
#define SEARCH_HIGH_12 0xb0
#define SEARCH_EQUAL_12 0xb1
#define SEARCH_LOW_12 0xb2
#define READ_ELEMENT_STATUS 0xb8
#define SEND_VOLUME_TAG 0xb6
-#define WRITE_LONG_2 0xea
-
-/* from hw/scsi-generic.c */
-#define REWIND 0x01
-#define REPORT_DENSITY_SUPPORT 0x44
-#define GET_CONFIGURATION 0x46
-#define READ_16 0x88
-#define WRITE_16 0x8a
-#define WRITE_VERIFY_16 0x8e
-#define SERVICE_ACTION_IN 0x9e
-#define REPORT_LUNS 0xa0
-#define LOAD_UNLOAD 0xa6
-#define SET_CD_SPEED 0xbb
-#define BLANK 0xa1
+#define READ_DEFECT_DATA_12 0xb7
+#define SET_CD_SPEED 0xbb
/*
* SAM Status codes
@@ -154,6 +164,7 @@
#define TYPE_DISK 0x00
#define TYPE_TAPE 0x01
+#define TYPE_PRINTER 0x02
#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
#define TYPE_WORM 0x04 /* Treated as ROM by our system */
#define TYPE_ROM 0x05
@@ -161,6 +172,9 @@
#define TYPE_MOD 0x07 /* Magneto-optical disk -
* - treated as TYPE_DISK */
#define TYPE_MEDIUM_CHANGER 0x08
-#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
+#define TYPE_STORAGE_ARRAY 0x0c /* Storage array device */
+#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */
+#define TYPE_RBC 0x0e /* Simplified Direct-Access Device */
+#define TYPE_OSD 0x11 /* Object-storage Device */
#define TYPE_NO_LUN 0x7f
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a8c7372d3e..fa198f928c 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -12,7 +12,7 @@
* 2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
* MODE SENSE response.
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*
* Note that this file only handles the SCSI architecture model and device
* commands. Emulation of interface/link layer protocols is handled by
@@ -59,8 +59,6 @@ typedef struct SCSIDiskReq {
uint32_t status;
} SCSIDiskReq;
-typedef enum { SCSI_HD, SCSI_CD } SCSIDriveKind;
-
struct SCSIDiskState
{
SCSIDevice qdev;
@@ -74,20 +72,19 @@ struct SCSIDiskState
char *version;
char *serial;
SCSISense sense;
- SCSIDriveKind drive_kind;
};
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
- uint32_t lun)
+ uint32_t lun, void *hba_private)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *req;
SCSIDiskReq *r;
- req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
+ req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun, hba_private);
r = DO_UPCAST(SCSIDiskReq, req, req);
r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
return req;
@@ -382,7 +379,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
return -1;
}
- if (s->drive_kind == SCSI_CD) {
+ if (s->qdev.type == TYPE_ROM) {
outbuf[buflen++] = 5;
} else {
outbuf[buflen++] = 0;
@@ -398,9 +395,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
"buffer size %zd\n", req->cmd.xfer);
pages = buflen++;
outbuf[buflen++] = 0x00; // list of supported pages (this page)
- outbuf[buflen++] = 0x80; // unit serial number
+ if (s->serial)
+ outbuf[buflen++] = 0x80; // unit serial number
outbuf[buflen++] = 0x83; // device identification
- if (s->drive_kind == SCSI_HD) {
+ if (s->qdev.type == TYPE_DISK) {
outbuf[buflen++] = 0xb0; // block limits
outbuf[buflen++] = 0xb2; // thin provisioning
}
@@ -409,8 +407,14 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
}
case 0x80: /* Device serial number, optional */
{
- int l = strlen(s->serial);
+ int l;
+ if (!s->serial) {
+ DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
+ return -1;
+ }
+
+ l = strlen(s->serial);
if (l > req->cmd.xfer)
l = req->cmd.xfer;
if (l > 20)
@@ -453,7 +457,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
unsigned int opt_io_size =
s->qdev.conf.opt_io_size / s->qdev.blocksize;
- if (s->drive_kind == SCSI_CD) {
+ if (s->qdev.type == TYPE_ROM) {
DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
page_code);
return -1;
@@ -519,16 +523,15 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memset(outbuf, 0, buflen);
if (req->lun) {
- outbuf[0] = 0x7f; /* LUN not supported */
+ outbuf[0] = 0x7f; /* LUN not supported */
return buflen;
}
- if (s->drive_kind == SCSI_CD) {
- outbuf[0] = 5;
+ outbuf[0] = s->qdev.type & 0x1f;
+ if (s->qdev.type == TYPE_ROM) {
outbuf[1] = 0x80;
memcpy(&outbuf[16], "QEMU CD-ROM ", 16);
} else {
- outbuf[0] = 0;
outbuf[1] = s->removable ? 0x80 : 0;
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
@@ -654,7 +657,7 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
return p[1] + 2;
case 0x2a: /* CD Capabilities and Mechanical Status page. */
- if (s->drive_kind != SCSI_CD)
+ if (s->qdev.type != TYPE_ROM)
return 0;
p[0] = 0x2a;
p[1] = 0x14;
@@ -829,7 +832,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
case TEST_UNIT_READY:
if (!bdrv_is_inserted(s->bs))
goto not_ready;
- break;
+ break;
case REQUEST_SENSE:
if (req->cmd.xfer < 4)
goto illegal_request;
@@ -841,7 +844,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
buflen = scsi_disk_emulate_inquiry(req, outbuf);
if (buflen < 0)
goto illegal_request;
- break;
+ break;
case MODE_SENSE:
case MODE_SENSE_10:
buflen = scsi_disk_emulate_mode_sense(req, outbuf);
@@ -870,18 +873,18 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
goto illegal_request;
break;
case START_STOP:
- if (s->drive_kind == SCSI_CD && (req->cmd.buf[4] & 2)) {
+ if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) {
/* load/eject medium */
bdrv_eject(s->bs, !(req->cmd.buf[4] & 1));
}
- break;
+ break;
case ALLOW_MEDIUM_REMOVAL:
bdrv_set_locked(s->bs, req->cmd.buf[4] & 1);
- break;
- case READ_CAPACITY:
+ break;
+ case READ_CAPACITY_10:
/* The normal LEN field for this command is zero. */
- memset(outbuf, 0, 8);
- bdrv_get_geometry(s->bs, &nb_sectors);
+ memset(outbuf, 0, 8);
+ bdrv_get_geometry(s->bs, &nb_sectors);
if (!nb_sectors)
goto not_ready;
nb_sectors /= s->cluster_size;
@@ -901,7 +904,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
outbuf[6] = s->cluster_size * 2;
outbuf[7] = 0;
buflen = 8;
- break;
+ break;
case SYNCHRONIZE_CACHE:
ret = bdrv_flush(s->bs);
if (ret < 0) {
@@ -963,13 +966,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
outbuf[3] = 8;
buflen = 16;
break;
- case VERIFY:
- break;
- case REZERO_UNIT:
- DPRINTF("Rezero Unit\n");
- if (!bdrv_is_inserted(s->bs)) {
- goto not_ready;
- }
+ case VERIFY_10:
break;
default:
scsi_command_complete(r, CHECK_CONDITION, SENSE_CODE(INVALID_OPCODE));
@@ -1007,7 +1004,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
command = buf[0];
outbuf = (uint8_t *)r->iov.iov_base;
- DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
+ DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", req->lun, req->tag, buf[0]);
if (scsi_req_parse(&r->req, buf) != 0) {
BADF("Unsupported command length, command %x\n", command);
@@ -1045,14 +1042,13 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
case RELEASE_10:
case START_STOP:
case ALLOW_MEDIUM_REMOVAL:
- case READ_CAPACITY:
+ case READ_CAPACITY_10:
case SYNCHRONIZE_CACHE:
case READ_TOC:
case GET_CONFIGURATION:
case SERVICE_ACTION_IN:
case REPORT_LUNS:
- case VERIFY:
- case REZERO_UNIT:
+ case VERIFY_10:
rc = scsi_disk_emulate_command(r, outbuf);
if (rc < 0) {
return 0;
@@ -1075,7 +1071,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
case WRITE_10:
case WRITE_12:
case WRITE_16:
- case WRITE_VERIFY:
+ case WRITE_VERIFY_10:
case WRITE_VERIFY_12:
case WRITE_VERIFY_16:
len = r->req.cmd.xfer / s->qdev.blocksize;
@@ -1183,7 +1179,7 @@ static void scsi_destroy(SCSIDevice *dev)
blockdev_mark_auto_del(s->qdev.conf.bs);
}
-static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
+static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
DriveInfo *dinfo;
@@ -1193,9 +1189,8 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
return -1;
}
s->bs = s->qdev.conf.bs;
- s->drive_kind = kind;
- if (kind == SCSI_HD && !bdrv_is_inserted(s->bs)) {
+ if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->bs)) {
error_report("Device needs media, but drive is empty");
return -1;
}
@@ -1203,7 +1198,9 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(s->bs);
- s->serial = qemu_strdup(*dinfo->serial ? dinfo->serial : "0");
+ if (*dinfo->serial) {
+ s->serial = qemu_strdup(dinfo->serial);
+ }
}
if (!s->version) {
@@ -1215,44 +1212,47 @@ static int scsi_initfn(SCSIDevice *dev, SCSIDriveKind kind)
return -1;
}
- if (kind == SCSI_CD) {
+ if (scsi_type == TYPE_ROM) {
s->qdev.blocksize = 2048;
- } else {
+ } else if (scsi_type == TYPE_DISK) {
s->qdev.blocksize = s->qdev.conf.logical_block_size;
+ } else {
+ error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
+ return -1;
}
s->cluster_size = s->qdev.blocksize / 512;
s->bs->buffer_alignment = s->qdev.blocksize;
- s->qdev.type = TYPE_DISK;
+ s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
- bdrv_set_removable(s->bs, kind == SCSI_CD);
+ bdrv_set_removable(s->bs, scsi_type == TYPE_ROM);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
return 0;
}
static int scsi_hd_initfn(SCSIDevice *dev)
{
- return scsi_initfn(dev, SCSI_HD);
+ return scsi_initfn(dev, TYPE_DISK);
}
static int scsi_cd_initfn(SCSIDevice *dev)
{
- return scsi_initfn(dev, SCSI_CD);
+ return scsi_initfn(dev, TYPE_ROM);
}
static int scsi_disk_initfn(SCSIDevice *dev)
{
- SCSIDriveKind kind;
DriveInfo *dinfo;
+ uint8_t scsi_type;
if (!dev->conf.bs) {
- kind = SCSI_HD; /* will die in scsi_initfn() */
+ scsi_type = TYPE_DISK; /* will die in scsi_initfn() */
} else {
dinfo = drive_get_by_blockdev(dev->conf.bs);
- kind = dinfo->media_cd ? SCSI_CD : SCSI_HD;
+ scsi_type = dinfo->media_cd ? TYPE_ROM : TYPE_DISK;
}
- return scsi_initfn(dev, kind);
+ return scsi_initfn(dev, scsi_type);
}
#define DEFINE_SCSI_DISK_PROPERTIES() \
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 8e59c7ee89..7b0026eb98 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -7,7 +7,7 @@
*
* Written by Laurent Vivier <Laurent.Vivier@bull.net>
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*
*/
@@ -96,11 +96,12 @@ static int scsi_get_sense(SCSIRequest *req, uint8_t *outbuf, int len)
return size;
}
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+ void *hba_private)
{
SCSIRequest *req;
- req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
+ req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun, hba_private);
return req;
}
@@ -405,7 +406,7 @@ static int get_blocksize(BlockDriverState *bdrv)
memset(cmd, 0, sizeof(cmd));
memset(buf, 0, sizeof(buf));
- cmd[0] = READ_CAPACITY;
+ cmd[0] = READ_CAPACITY_10;
memset(&io_header, 0, sizeof(io_header));
io_header.interface_id = 'S';
diff --git a/hw/scsi.h b/hw/scsi.h
index c1dca35b86..6b15bbc2cd 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -43,6 +43,7 @@ struct SCSIRequest {
} cmd;
BlockDriverAIOCB *aiocb;
bool enqueued;
+ void *hba_private;
QTAILQ_ENTRY(SCSIRequest) next;
};
@@ -67,7 +68,8 @@ struct SCSIDeviceInfo {
DeviceInfo qdev;
scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s);
- SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun);
+ SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ void *hba_private);
void (*free_req)(SCSIRequest *req);
int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
void (*read_data)(SCSIRequest *req);
@@ -138,8 +140,10 @@ extern const struct SCSISense sense_code_LUN_FAILURE;
int scsi_build_sense(SCSISense sense, uint8_t *buf, int len, int fixed);
int scsi_sense_valid(SCSISense sense);
-SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun);
+SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag,
+ uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+ void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req, uint8_t *buf);
void scsi_req_free(SCSIRequest *req);
SCSIRequest *scsi_req_ref(SCSIRequest *req);
diff --git a/hw/sd.c b/hw/sd.c
index cedfb20249..c2c80ab7b8 100644
--- a/hw/sd.c
+++ b/hw/sd.c
@@ -393,9 +393,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
} else {
sect = 0;
}
- sect <<= 9;
-
- size = sect + 1;
+ size = sect << 9;
sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
@@ -1450,14 +1448,8 @@ void sd_write_data(SDState *sd, uint8_t value)
break;
case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->blk_written ++;
- sd->data_start += sd->blk_len;
- sd->data_offset = 0;
+ if (sd->data_offset == 0) {
+ /* Start of the block - lets check the address is valid */
if (sd->data_start + sd->blk_len > sd->size) {
sd->card_status |= ADDRESS_ERROR;
break;
@@ -1466,6 +1458,15 @@ void sd_write_data(SDState *sd, uint8_t value)
sd->card_status |= WP_VIOLATION;
break;
}
+ }
+ sd->data[sd->data_offset++] = value;
+ if (sd->data_offset >= sd->blk_len) {
+ /* TODO: Check CRC before committing */
+ sd->state = sd_programming_state;
+ BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+ sd->blk_written++;
+ sd->data_start += sd->blk_len;
+ sd->data_offset = 0;
sd->csd[14] |= 0x40;
/* Bzzzzzzztt .... Operation complete. */
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
index 0734da90f0..c43b99f811 100644
--- a/hw/sh_intc.c
+++ b/hw/sh_intc.c
@@ -5,7 +5,7 @@
* Based on sh_timer.c and arm_timer.c by Paul Brook
* Copyright (c) 2005-2006 CodeSourcery.
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sh_intc.h"
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index a076cf2ff0..0ef93a062e 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -26,6 +26,7 @@
#include "pci.h"
#include "pci_host.h"
#include "bswap.h"
+#include "exec-memory.h"
typedef struct SHPCIState {
SysBusDevice busdev;
@@ -127,7 +128,8 @@ static int sh_pci_init_device(SysBusDevice *dev)
}
s->bus = pci_register_bus(&s->busdev.qdev, "pci",
sh_pci_set_irq, sh_pci_map_irq,
- s->irq, PCI_DEVFN(0, 0), 4);
+ s->irq, get_system_memory(),
+ PCI_DEVFN(0, 0), 4);
s->memconfig = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w,
s, DEVICE_NATIVE_ENDIAN);
sysbus_init_mmio_cb(dev, 0x224, sh_pci_map);
diff --git a/hw/sh_timer.c b/hw/sh_timer.c
index 5eec6b7c14..5df7fb64bc 100644
--- a/hw/sh_timer.c
+++ b/hw/sh_timer.c
@@ -5,7 +5,7 @@
* Based on arm_timer.c by Paul Brook
* Copyright (c) 2005-2006 CodeSourcery.
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
diff --git a/hw/smbus.c b/hw/smbus.c
index e464539150..ff027c814f 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*/
/* TODO: Implement PEC. */
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 701baafe6c..3a8a85c1f1 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -4,7 +4,7 @@
* Copyright (c) 2005 CodeSourcery, LLC.
* Written by Paul Brook
*
- * This code is licenced under the GPL
+ * This code is licensed under the GPL
*/
#include "sysbus.h"
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 5cd8d8f5ae..f7ead04a96 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -1,9 +1,9 @@
#include "sysemu.h"
#include "cpu.h"
+#include "dyngen-exec.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "qemu-char.h"
-#include "exec.h"
#include "helper_regs.h"
#include "hw/spapr.h"
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 1c901ef6eb..646b1e3caf 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -121,7 +121,7 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s)
return NULL;
}
-static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
+static void vscsi_put_req(vscsi_req *req)
{
if (req->sreq != NULL) {
scsi_req_unref(req->sreq);
@@ -130,15 +130,6 @@ static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
req->active = 0;
}
-static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req)
-{
- uint32_t tag = req->tag;
- if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
- return NULL;
- }
- return &s->reqs[tag];
-}
-
static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
{
/* XXX Figure that one out properly ! This is crackpot */
@@ -454,7 +445,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
if (n) {
req->senselen = n;
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
- vscsi_put_req(s, req);
+ vscsi_put_req(req);
return;
}
@@ -483,7 +474,7 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
{
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
- vscsi_req *req = vscsi_find_req(s, sreq);
+ vscsi_req *req = sreq->hba_private;
uint8_t *buf;
int rc = 0;
@@ -531,7 +522,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
{
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
- vscsi_req *req = vscsi_find_req(s, sreq);
+ vscsi_req *req = sreq->hba_private;
int32_t res_in = 0, res_out = 0;
dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
@@ -563,15 +554,14 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status)
}
}
vscsi_send_rsp(s, req, 0, res_in, res_out);
- vscsi_put_req(s, req);
+ vscsi_put_req(req);
}
static void vscsi_request_cancelled(SCSIRequest *sreq)
{
- VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
- vscsi_req *req = vscsi_find_req(s, sreq);
+ vscsi_req *req = sreq->hba_private;
- vscsi_put_req(s, req);
+ vscsi_put_req(req);
}
static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
@@ -659,7 +649,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
}
req->lun = lun;
- req->sreq = scsi_req_new(sdev, req->qtag, lun);
+ req->sreq = scsi_req_new(sdev, req->qtag, lun, req);
n = scsi_req_enqueue(req->sreq, srp->cmd.cdb);
dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
@@ -858,7 +848,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
}
if (done) {
- vscsi_put_req(s, req);
+ vscsi_put_req(req);
}
}
diff --git a/hw/spitz.c b/hw/spitz.c
index 006f7a97e3..c05b5f7d56 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -48,7 +48,7 @@
typedef struct {
SysBusDevice busdev;
- NANDFlashState *nand;
+ DeviceState *nand;
uint8_t ctl;
uint8_t manf_id;
uint8_t chip_id;
@@ -169,11 +169,13 @@ static void sl_flash_register(PXA2xxState *cpu, int size)
static int sl_nand_init(SysBusDevice *dev) {
int iomemtype;
SLNANDState *s;
+ DriveInfo *nand;
s = FROM_SYSBUS(SLNANDState, dev);
s->ctl = 0;
- s->nand = nand_init(s->manf_id, s->chip_id);
+ nand = drive_get(IF_MTD, 0, 0);
+ s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
iomemtype = cpu_register_io_memory(sl_readfn,
sl_writefn, s, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index b39e2596fb..401fdf592a 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
/* The controller can support a variety of different displays, but we only
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 8643961144..1eb3823fed 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
/* The controller can support a variety of different displays, but we only
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index fb4b649279..18dabd64a6 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007-2009 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "blockdev.h"
diff --git a/hw/ssi.c b/hw/ssi.c
index cfe7c072f1..3f4c5f9f06 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -4,7 +4,7 @@
* Copyright (c) 2009 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "ssi.h"
diff --git a/hw/stellaris.c b/hw/stellaris.c
index ac9fcc1f38..a28093043a 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
@@ -1230,7 +1230,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
}
}
- stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr);
+ stellaris_sys_init(0x400fe000, pic[28], board, nd_table[0].macaddr.a);
for (i = 0; i < 7; i++) {
if (board->dc4 & (1 << i)) {
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 6a0583a256..12919317ec 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
#include "net.h"
diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c
index 06c5f9d955..95604ecded 100644
--- a/hw/stellaris_input.c
+++ b/hw/stellaris_input.c
@@ -4,7 +4,7 @@
* Copyright (c) 2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "hw.h"
#include "devices.h"
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e22be7b25..ea442acb50 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -19,6 +19,7 @@
#include "sysbus.h"
#include "monitor.h"
+#include "exec-memory.h"
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
static char *sysbus_get_fw_dev_path(DeviceState *dev);
@@ -49,11 +50,20 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
}
if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
/* Unregister previous mapping. */
- cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
- IO_MEM_UNASSIGNED);
+ if (dev->mmio[n].memory) {
+ memory_region_del_subregion(get_system_memory(),
+ dev->mmio[n].memory);
+ } else {
+ cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
+ IO_MEM_UNASSIGNED);
+ }
}
dev->mmio[n].addr = addr;
- if (dev->mmio[n].cb) {
+ if (dev->mmio[n].memory) {
+ memory_region_add_subregion(get_system_memory(),
+ addr,
+ dev->mmio[n].memory);
+ } else if (dev->mmio[n].cb) {
dev->mmio[n].cb(dev, addr);
} else {
cpu_register_physical_memory(addr, dev->mmio[n].size,
@@ -107,6 +117,17 @@ void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
dev->mmio[n].cb = cb;
}
+void sysbus_init_mmio_region(SysBusDevice *dev, MemoryRegion *memory)
+{
+ int n;
+
+ assert(dev->num_mmio < QDEV_MAX_MMIO);
+ n = dev->num_mmio++;
+ dev->mmio[n].addr = -1;
+ dev->mmio[n].size = memory_region_size(memory);
+ dev->mmio[n].memory = memory;
+}
+
void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
{
pio_addr_t i;
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 4e8cb16d42..5f62e2da31 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -4,6 +4,7 @@
/* Devices attached directly to the main system bus. */
#include "qdev.h"
+#include "memory.h"
#define QDEV_MAX_MMIO 32
#define QDEV_MAX_PIO 32
@@ -23,6 +24,7 @@ struct SysBusDevice {
target_phys_addr_t size;
mmio_mapfunc cb;
ram_addr_t iofunc;
+ MemoryRegion *memory;
} mmio[QDEV_MAX_MMIO];
int num_pio;
pio_addr_t pio[QDEV_MAX_PIO];
@@ -46,6 +48,7 @@ void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size,
ram_addr_t iofunc);
void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
mmio_mapfunc cb);
+void sysbus_init_mmio_region(SysBusDevice *dev, MemoryRegion *memory);
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index ed49e944df..a1c48bf1d9 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -12,6 +12,7 @@
#include "flash.h"
#include "console.h"
#include "pixel_ops.h"
+#include "blockdev.h"
#define IRQ_TC6393_NAND 0
#define IRQ_TC6393_MMC 1
@@ -117,7 +118,7 @@ struct TC6393xbState {
} nand;
int nand_enable;
uint32_t nand_phys;
- NANDFlashState *flash;
+ DeviceState *flash;
ECCState ecc;
DisplayState *ds;
@@ -566,6 +567,7 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
{
int iomemtype;
TC6393xbState *s;
+ DriveInfo *nand;
CPUReadMemoryFunc * const tc6393xb_readfn[] = {
tc6393xb_readb,
tc6393xb_readw,
@@ -586,7 +588,8 @@ TC6393xbState *tc6393xb_init(uint32_t base, qemu_irq irq)
s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
- s->flash = nand_init(NAND_MFR_TOSHIBA, 0x76);
+ nand = drive_get(IF_MTD, 0, 0);
+ s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
iomemtype = cpu_register_io_memory(tc6393xb_readfn,
tc6393xb_writefn, s, DEVICE_NATIVE_ENDIAN);
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index d364daa53a..b499523c93 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -201,7 +201,7 @@ static int pci_unin_internal_init_device(SysBusDevice *dev)
return 0;
}
-PCIBus *pci_pmac_init(qemu_irq *pic)
+PCIBus *pci_pmac_init(qemu_irq *pic, MemoryRegion *address_space)
{
DeviceState *dev;
SysBusDevice *s;
@@ -215,7 +215,8 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
d = FROM_SYSBUS(UNINState, s);
d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
pci_unin_set_irq, pci_unin_map_irq,
- pic, PCI_DEVFN(11, 0), 4);
+ pic, address_space,
+ PCI_DEVFN(11, 0), 4);
#if 0
pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
@@ -252,7 +253,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic)
return d->host_state.bus;
}
-PCIBus *pci_pmac_u3_init(qemu_irq *pic)
+PCIBus *pci_pmac_u3_init(qemu_irq *pic, MemoryRegion *address_space)
{
DeviceState *dev;
SysBusDevice *s;
@@ -267,7 +268,8 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic)
d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
pci_unin_set_irq, pci_unin_map_irq,
- pic, PCI_DEVFN(11, 0), 4);
+ pic, address_space,
+ PCI_DEVFN(11, 0), 4);
sysbus_mmio_map(s, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000);
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index baae4876ea..529fa3355d 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -99,13 +99,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0,
.bInterval = 0x01,
},
{
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0,
.bInterval = 0x01,
},
@@ -120,13 +120,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x09,
.bInterval = 0x01,
},
{
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x09,
.bInterval = 0x01,
},
@@ -141,13 +141,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x11,
.bInterval = 0x01,
},
{
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x11,
.bInterval = 0x01,
},
@@ -162,13 +162,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x19,
.bInterval = 0x01,
},
{
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x19,
.bInterval = 0x01,
},
@@ -183,13 +183,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x21,
.bInterval = 0x01,
},
{
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x21,
.bInterval = 0x01,
},
@@ -204,13 +204,13 @@ static const USBDescIface desc_iface_bluetooth[] = {
.eps = (USBDescEndpoint[]) {
{
.bEndpointAddress = USB_DIR_OUT | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x31,
.bInterval = 0x01,
},
{
.bEndpointAddress = USB_DIR_IN | USB_SCO_EP,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = 0x31,
.bInterval = 0x01,
},
@@ -294,9 +294,9 @@ static inline int usb_bt_fifo_dequeue(struct usb_hci_in_fifo_s *fifo,
if (likely(!fifo->len))
return USB_RET_STALL;
- len = MIN(p->len, fifo->fifo[fifo->start].len);
- memcpy(p->data, fifo->fifo[fifo->start].data, len);
- if (len == p->len) {
+ len = MIN(p->iov.size, fifo->fifo[fifo->start].len);
+ usb_packet_copy(p, fifo->fifo[fifo->start].data, len);
+ if (len == p->iov.size) {
fifo->fifo[fifo->start].len -= len;
fifo->fifo[fifo->start].data += len;
} else {
@@ -319,20 +319,13 @@ static inline void usb_bt_fifo_out_enqueue(struct USBBtState *s,
struct usb_hci_out_fifo_s *fifo,
void (*send)(struct HCIInfo *, const uint8_t *, int),
int (*complete)(const uint8_t *, int),
- const uint8_t *data, int len)
+ USBPacket *p)
{
- if (fifo->len) {
- memcpy(fifo->data + fifo->len, data, len);
- fifo->len += len;
- if (complete(fifo->data, fifo->len)) {
- send(s->hci, fifo->data, fifo->len);
- fifo->len = 0;
- }
- } else if (complete(data, len))
- send(s->hci, data, len);
- else {
- memcpy(fifo->data, data, len);
- fifo->len = len;
+ usb_packet_copy(p, fifo->data + fifo->len, p->iov.size);
+ fifo->len += p->iov.size;
+ if (complete(fifo->data, fifo->len)) {
+ send(s->hci, fifo->data, fifo->len);
+ fifo->len = 0;
}
/* TODO: do we need to loop? */
@@ -432,7 +425,7 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
if (s->config)
usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
- usb_bt_hci_cmd_complete, data, length);
+ usb_bt_hci_cmd_complete, p);
break;
default:
fail:
@@ -474,12 +467,12 @@ static int usb_bt_handle_data(USBDevice *dev, USBPacket *p)
switch (p->devep & 0xf) {
case USB_ACL_EP:
usb_bt_fifo_out_enqueue(s, &s->outacl, s->hci->acl_send,
- usb_bt_hci_acl_complete, p->data, p->len);
+ usb_bt_hci_acl_complete, p);
break;
case USB_SCO_EP:
usb_bt_fifo_out_enqueue(s, &s->outsco, s->hci->sco_send,
- usb_bt_hci_sco_complete, p->data, p->len);
+ usb_bt_hci_sco_complete, p);
break;
default:
@@ -548,10 +541,16 @@ USBDevice *usb_bt_init(HCIInfo *hci)
return dev;
}
+static const VMStateDescription vmstate_usb_bt = {
+ .name = "usb-bt",
+ .unmigratable = 1,
+};
+
static struct USBDeviceInfo bt_info = {
.product_desc = "QEMU BT dongle",
.qdev.name = "usb-bt-dongle",
.qdev.size = sizeof(struct USBBtState),
+ .qdev.vmsd = &vmstate_usb_bt,
.usb_desc = &desc_bluetooth,
.init = usb_bt_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index 2abce12de5..f1dd55eccd 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -82,12 +82,10 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int usb_qdev_exit(DeviceState *qdev)
{
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
- USBBus *bus = usb_bus_from_device(dev);
if (dev->attached) {
usb_device_detach(dev);
}
- bus->ops->device_destroy(bus, dev);
if (dev->info->handle_destroy) {
dev->info->handle_destroy(dev);
}
@@ -140,19 +138,55 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name)
return dev;
}
-void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
- USBPortOps *ops, int speedmask)
+static void usb_fill_port(USBPort *port, void *opaque, int index,
+ USBPortOps *ops, int speedmask)
{
port->opaque = opaque;
port->index = index;
- port->opaque = opaque;
- port->index = index;
port->ops = ops;
port->speedmask = speedmask;
+ usb_port_location(port, NULL, index + 1);
+}
+
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+ USBPortOps *ops, int speedmask)
+{
+ usb_fill_port(port, opaque, index, ops, speedmask);
QTAILQ_INSERT_TAIL(&bus->free, port, next);
bus->nfree++;
}
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+ uint32_t portcount, uint32_t firstport,
+ void *opaque, USBPortOps *ops, int speedmask)
+{
+ USBBus *bus;
+ int i;
+
+ QTAILQ_FOREACH(bus, &busses, next) {
+ if (strcmp(bus->qbus.name, masterbus) == 0) {
+ break;
+ }
+ }
+
+ if (!bus || !bus->ops->register_companion) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
+ "an USB masterbus");
+ if (bus) {
+ error_printf_unless_qmp(
+ "USB bus '%s' does not allow companion controllers\n",
+ masterbus);
+ }
+ return -1;
+ }
+
+ for (i = 0; i < portcount; i++) {
+ usb_fill_port(ports[i], opaque, i, ops, speedmask);
+ }
+
+ return bus->ops->register_companion(bus, ports, portcount, firstport);
+}
+
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
{
if (upstream) {
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index d3922998c5..66aeb211af 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -934,16 +934,16 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
{
CCID_Header *ccid_header;
- if (p->len + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
+ if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
return USB_RET_STALL;
}
ccid_header = (CCID_Header *)s->bulk_out_data;
- memcpy(s->bulk_out_data + s->bulk_out_pos, p->data, p->len);
- s->bulk_out_pos += p->len;
- if (p->len == CCID_MAX_PACKET_SIZE) {
+ usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
+ s->bulk_out_pos += p->iov.size;
+ if (p->iov.size == CCID_MAX_PACKET_SIZE) {
DPRINTF(s, D_VERBOSE,
- "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
- p->len, ccid_header->dwLength);
+ "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
+ p->iov.size, ccid_header->dwLength);
return 0;
}
if (s->bulk_out_pos < 10) {
@@ -1006,15 +1006,17 @@ static int ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
return 0;
}
-static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
+static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
{
int ret = 0;
- assert(len > 0);
+ assert(p->iov.size > 0);
ccid_bulk_in_get(s);
if (s->current_bulk_in != NULL) {
- ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos, len);
- memcpy(data, s->current_bulk_in->data + s->current_bulk_in->pos, ret);
+ ret = MIN(s->current_bulk_in->len - s->current_bulk_in->pos,
+ p->iov.size);
+ usb_packet_copy(p, s->current_bulk_in->data +
+ s->current_bulk_in->pos, ret);
s->current_bulk_in->pos += ret;
if (s->current_bulk_in->pos == s->current_bulk_in->len) {
ccid_bulk_in_release(s);
@@ -1025,11 +1027,13 @@ static int ccid_bulk_in_copy_to_guest(USBCCIDState *s, uint8_t *data, int len)
}
if (ret > 0) {
DPRINTF(s, D_MORE_INFO,
- "%s: %d/%d req/act to guest (BULK_IN)\n", __func__, len, ret);
+ "%s: %zd/%d req/act to guest (BULK_IN)\n",
+ __func__, p->iov.size, ret);
}
- if (ret != USB_RET_NAK && ret < len) {
+ if (ret != USB_RET_NAK && ret < p->iov.size) {
DPRINTF(s, 1,
- "%s: returning short (EREMOTEIO) %d < %d\n", __func__, ret, len);
+ "%s: returning short (EREMOTEIO) %d < %zd\n",
+ __func__, ret, p->iov.size);
}
return ret;
}
@@ -1038,8 +1042,7 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
int ret = 0;
- uint8_t *data = p->data;
- int len = p->len;
+ uint8_t buf[2];
switch (p->pid) {
case USB_TOKEN_OUT:
@@ -1049,24 +1052,25 @@ static int ccid_handle_data(USBDevice *dev, USBPacket *p)
case USB_TOKEN_IN:
switch (p->devep & 0xf) {
case CCID_BULK_IN_EP:
- if (!len) {
+ if (!p->iov.size) {
ret = USB_RET_NAK;
} else {
- ret = ccid_bulk_in_copy_to_guest(s, data, len);
+ ret = ccid_bulk_in_copy_to_guest(s, p);
}
break;
case CCID_INT_IN_EP:
if (s->notify_slot_change) {
/* page 56, RDR_to_PC_NotifySlotChange */
- data[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
- data[1] = s->bmSlotICCState;
+ buf[0] = CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange;
+ buf[1] = s->bmSlotICCState;
+ usb_packet_copy(p, buf, 2);
ret = 2;
s->notify_slot_change = false;
s->bmSlotICCState &= ~SLOT_0_CHANGED_MASK;
DPRINTF(s, D_INFO,
"handle_data: int_in: notify_slot_change %X, "
- "requested len %d\n",
- s->bmSlotICCState, len);
+ "requested len %zd\n",
+ s->bmSlotICCState, p->iov.size);
}
break;
default:
@@ -1104,20 +1108,9 @@ static Answer *ccid_peek_next_answer(USBCCIDState *s)
: &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
}
-static void ccid_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
-{
- CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
- CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
-
- if (info->print) {
- info->print(mon, card, indent);
- }
-}
-
static struct BusInfo ccid_bus_info = {
.name = "ccid-bus",
.size = sizeof(CCIDBus),
- .print_dev = ccid_bus_dev_print,
.props = (Property[]) {
DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 91fb7dea93..2b43895315 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -20,9 +20,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * TODO:
- * o Downstream port handoff
*/
#include "hw.h"
@@ -31,6 +28,7 @@
#include "pci.h"
#include "monitor.h"
#include "trace.h"
+#include "dma.h"
#define EHCI_DEBUG 0
@@ -103,10 +101,10 @@
#define PORTSC_BEGIN PORTSC
#define PORTSC_END (PORTSC + 4 * NB_PORTS)
/*
- * Bits that are reserverd or are read-only are masked out of values
+ * Bits that are reserved or are read-only are masked out of values
* written to us by software
*/
-#define PORTSC_RO_MASK 0x007021c5
+#define PORTSC_RO_MASK 0x007001c0
#define PORTSC_RWC_MASK 0x0000002a
#define PORTSC_WKOC_E (1 << 22) // Wake on Over Current Enable
#define PORTSC_WKDS_E (1 << 21) // Wake on Disconnect Enable
@@ -133,7 +131,7 @@
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
-#define NB_PORTS 4 // Number of downstream ports
+#define NB_PORTS 6 // Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_ITERATIONS 20 // Max number of QH before we break the loop
#define MAX_QH 100 // Max allowable queue heads in a chain
@@ -272,6 +270,7 @@ typedef struct EHCIqtd {
uint32_t bufptr[5]; // Standard buffer pointer
#define QTD_BUFPTR_MASK 0xfffff000
+#define QTD_BUFPTR_SH 12
} EHCIqtd;
/* EHCI spec version 1.0 Section 3.6
@@ -360,7 +359,7 @@ struct EHCIQueue {
uint32_t qtdaddr; // address QTD read from
USBPacket packet;
- uint8_t buffer[BUFF_SIZE];
+ QEMUSGList sgl;
int pid;
uint32_t tbytes;
enum async_state async;
@@ -373,7 +372,7 @@ struct EHCIState {
qemu_irq irq;
target_phys_addr_t mem_base;
int mem;
- int num_ports;
+ int companion_count;
/* properties */
uint32_t freq;
@@ -409,6 +408,7 @@ struct EHCIState {
int astate; // Current state in asynchronous schedule
int pstate; // Current state in periodic schedule
USBPort ports[NB_PORTS];
+ USBPort *companion_ports[NB_PORTS];
uint32_t usbsts_pending;
QTAILQ_HEAD(, EHCIQueue) queues;
@@ -416,7 +416,7 @@ struct EHCIState {
uint32_t p_fetch_addr; // which address to look at next
USBPacket ipacket;
- uint8_t ibuffer[BUFF_SIZE];
+ QEMUSGList isgl;
int isoch_pause;
uint64_t last_run_ns;
@@ -731,17 +731,17 @@ static void ehci_attach(USBPort *port)
trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
+ if (*portsc & PORTSC_POWNER) {
+ USBPort *companion = s->companion_ports[port->index];
+ companion->dev = port->dev;
+ companion->ops->attach(companion);
+ return;
+ }
+
*portsc |= PORTSC_CONNECT;
*portsc |= PORTSC_CSC;
- /*
- * If a high speed device is attached then we own this port(indicated
- * by zero in the PORTSC_POWNER bit field) so set the status bit
- * and set an interrupt if enabled.
- */
- if ( !(*portsc & PORTSC_POWNER)) {
- ehci_set_interrupt(s, USBSTS_PCD);
- }
+ ehci_set_interrupt(s, USBSTS_PCD);
}
static void ehci_detach(USBPort *port)
@@ -751,17 +751,88 @@ static void ehci_detach(USBPort *port)
trace_usb_ehci_port_detach(port->index);
- *portsc &= ~PORTSC_CONNECT;
+ if (*portsc & PORTSC_POWNER) {
+ USBPort *companion = s->companion_ports[port->index];
+ companion->ops->detach(companion);
+ companion->dev = NULL;
+ return;
+ }
+
+ ehci_queues_rip_device(s, port->dev);
+
+ *portsc &= ~(PORTSC_CONNECT|PORTSC_PED);
*portsc |= PORTSC_CSC;
- /*
- * If a high speed device is attached then we own this port(indicated
- * by zero in the PORTSC_POWNER bit field) so set the status bit
- * and set an interrupt if enabled.
- */
- if ( !(*portsc & PORTSC_POWNER)) {
- ehci_set_interrupt(s, USBSTS_PCD);
+ ehci_set_interrupt(s, USBSTS_PCD);
+}
+
+static void ehci_child_detach(USBPort *port, USBDevice *child)
+{
+ EHCIState *s = port->opaque;
+ uint32_t portsc = s->portsc[port->index];
+
+ if (portsc & PORTSC_POWNER) {
+ USBPort *companion = s->companion_ports[port->index];
+ companion->ops->child_detach(companion, child);
+ companion->dev = NULL;
+ return;
}
+
+ ehci_queues_rip_device(s, child);
+}
+
+static void ehci_wakeup(USBPort *port)
+{
+ EHCIState *s = port->opaque;
+ uint32_t portsc = s->portsc[port->index];
+
+ if (portsc & PORTSC_POWNER) {
+ USBPort *companion = s->companion_ports[port->index];
+ if (companion->ops->wakeup) {
+ companion->ops->wakeup(companion);
+ }
+ }
+}
+
+static int ehci_register_companion(USBBus *bus, USBPort *ports[],
+ uint32_t portcount, uint32_t firstport)
+{
+ EHCIState *s = container_of(bus, EHCIState, bus);
+ uint32_t i;
+
+ if (firstport + portcount > NB_PORTS) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "firstport",
+ "firstport on masterbus");
+ error_printf_unless_qmp(
+ "firstport value of %u makes companion take ports %u - %u, which "
+ "is outside of the valid range of 0 - %u\n", firstport, firstport,
+ firstport + portcount - 1, NB_PORTS - 1);
+ return -1;
+ }
+
+ for (i = 0; i < portcount; i++) {
+ if (s->companion_ports[firstport + i]) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "masterbus",
+ "an USB masterbus");
+ error_printf_unless_qmp(
+ "port %u on masterbus %s already has a companion assigned\n",
+ firstport + i, bus->qbus.name);
+ return -1;
+ }
+ }
+
+ for (i = 0; i < portcount; i++) {
+ s->companion_ports[firstport + i] = ports[i];
+ s->ports[firstport + i].speedmask |=
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL;
+ /* Ensure devs attached before the initial reset go to the companion */
+ s->portsc[firstport + i] = PORTSC_POWNER;
+ }
+
+ s->companion_count++;
+ s->mmio[0x05] = (s->companion_count << 4) | portcount;
+
+ return 0;
}
/* 4.1 host controller initialization */
@@ -769,9 +840,21 @@ static void ehci_reset(void *opaque)
{
EHCIState *s = opaque;
int i;
+ USBDevice *devs[NB_PORTS];
trace_usb_ehci_reset();
+ /*
+ * Do the detach before touching portsc, so that it correctly gets send to
+ * us or to our companion based on PORTSC_POWNER before the reset.
+ */
+ for(i = 0; i < NB_PORTS; i++) {
+ devs[i] = s->ports[i].dev;
+ if (devs[i]) {
+ usb_attach(&s->ports[i], NULL);
+ }
+ }
+
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
@@ -783,10 +866,13 @@ static void ehci_reset(void *opaque)
s->attach_poll_counter = 0;
for(i = 0; i < NB_PORTS; i++) {
- s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
-
- if (s->ports[i].dev) {
- usb_attach(&s->ports[i], s->ports[i].dev);
+ if (s->companion_ports[i]) {
+ s->portsc[i] = PORTSC_POWNER | PORTSC_PPOWER;
+ } else {
+ s->portsc[i] = PORTSC_PPOWER;
+ }
+ if (devs[i]) {
+ usb_attach(&s->ports[i], devs[i]);
}
}
ehci_queues_rip_all(s);
@@ -836,43 +922,67 @@ static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
exit(1);
}
+static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
+{
+ USBDevice *dev = s->ports[port].dev;
+ uint32_t *portsc = &s->portsc[port];
+ uint32_t orig;
+
+ if (s->companion_ports[port] == NULL)
+ return;
+
+ owner = owner & PORTSC_POWNER;
+ orig = *portsc & PORTSC_POWNER;
+
+ if (!(owner ^ orig)) {
+ return;
+ }
+
+ if (dev) {
+ usb_attach(&s->ports[port], NULL);
+ }
+
+ *portsc &= ~PORTSC_POWNER;
+ *portsc |= owner;
+
+ if (dev) {
+ usb_attach(&s->ports[port], dev);
+ }
+}
+
static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
{
uint32_t *portsc = &s->portsc[port];
- int rwc;
USBDevice *dev = s->ports[port].dev;
- rwc = val & PORTSC_RWC_MASK;
+ /* Clear rwc bits */
+ *portsc &= ~(val & PORTSC_RWC_MASK);
+ /* The guest may clear, but not set the PED bit */
+ *portsc &= val | ~PORTSC_PED;
+ /* POWNER is masked out by RO_MASK as it is RO when we've no companion */
+ handle_port_owner_write(s, port, val);
+ /* And finally apply RO_MASK */
val &= PORTSC_RO_MASK;
- // handle_read_write_clear(&val, portsc, PORTSC_PEDC | PORTSC_CSC);
-
- *portsc &= ~rwc;
-
if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
trace_usb_ehci_port_reset(port, 1);
}
if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
trace_usb_ehci_port_reset(port, 0);
- usb_attach(&s->ports[port], dev);
-
- // TODO how to handle reset of ports with no device
if (dev) {
+ usb_attach(&s->ports[port], dev);
usb_send_msg(dev, USB_MSG_RESET);
- }
-
- if (s->ports[port].dev) {
*portsc &= ~PORTSC_CSC;
}
- /* Table 2.16 Set the enable bit(and enable bit change) to indicate
+ /*
+ * Table 2.16 Set the enable bit(and enable bit change) to indicate
* to SW that this port has a high speed device attached
- *
- * TODO - when to disable?
*/
- val |= PORTSC_PED;
- val |= PORTSC_PEDC;
+ if (dev && (dev->speedmask & USB_SPEED_MASK_HIGH)) {
+ val |= PORTSC_PED;
+ }
}
*portsc &= ~PORTSC_RO_MASK;
@@ -955,7 +1065,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
val &= 0x1;
if (val) {
for(i = 0; i < NB_PORTS; i++)
- s->portsc[i] &= ~PORTSC_POWNER;
+ handle_port_owner_write(s, i, 0);
}
break;
@@ -1057,68 +1167,75 @@ static int ehci_qh_do_overlay(EHCIQueue *q)
return 0;
}
-static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
+static int ehci_init_transfer(EHCIQueue *q)
{
- int bufpos = 0;
- int cpage, offset;
- uint32_t head;
- uint32_t tail;
-
-
- if (!bytes) {
- return 0;
- }
-
- cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
- if (cpage > 4) {
- fprintf(stderr, "cpage out of range (%d)\n", cpage);
- return USB_RET_PROCERR;
- }
+ uint32_t cpage, offset, bytes, plen;
+ target_phys_addr_t page;
+ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+ bytes = get_field(q->qh.token, QTD_TOKEN_TBYTES);
offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+ qemu_sglist_init(&q->sgl, 5);
- do {
- /* start and end of this page */
- head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
- tail = head + ~QTD_BUFPTR_MASK + 1;
- /* add offset into page */
- head |= offset;
-
- if (bytes <= (tail - head)) {
- tail = head + bytes;
+ while (bytes > 0) {
+ if (cpage > 4) {
+ fprintf(stderr, "cpage out of range (%d)\n", cpage);
+ return USB_RET_PROCERR;
}
- trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
- cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
-
- bufpos += (tail - head);
- offset += (tail - head);
- bytes -= (tail - head);
-
- if (bytes > 0) {
- cpage++;
+ page = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
+ page += offset;
+ plen = bytes;
+ if (plen > 4096 - offset) {
+ plen = 4096 - offset;
offset = 0;
+ cpage++;
}
- } while (bytes > 0);
- /* save cpage */
- set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+ qemu_sglist_add(&q->sgl, page, plen);
+ bytes -= plen;
+ }
+ return 0;
+}
- /* save offset into cpage */
- q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
- q->qh.bufptr[0] |= offset;
+static void ehci_finish_transfer(EHCIQueue *q, int status)
+{
+ uint32_t cpage, offset;
- return 0;
+ qemu_sglist_destroy(&q->sgl);
+
+ if (status > 0) {
+ /* update cpage & offset */
+ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
+ offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
+
+ offset += status;
+ cpage += offset >> QTD_BUFPTR_SH;
+ offset &= ~QTD_BUFPTR_MASK;
+
+ set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
+ q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
+ q->qh.bufptr[0] |= offset;
+ }
}
-static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet)
+static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
{
- EHCIQueue *q = container_of(packet, EHCIQueue, packet);
+ EHCIQueue *q;
+ EHCIState *s = port->opaque;
+ uint32_t portsc = s->portsc[port->index];
+ if (portsc & PORTSC_POWNER) {
+ USBPort *companion = s->companion_ports[port->index];
+ companion->ops->complete(companion, packet);
+ return;
+ }
+
+ q = container_of(packet, EHCIQueue, packet);
trace_usb_ehci_queue_action(q, "wakeup");
assert(q->async == EHCI_ASYNC_INFLIGHT);
q->async = EHCI_ASYNC_FINISHED;
- q->usb_status = packet->len;
+ q->usb_status = packet->result;
}
static void ehci_execute_complete(EHCIQueue *q)
@@ -1178,10 +1295,6 @@ err:
}
if (q->tbytes && q->pid == USB_TOKEN_IN) {
- if (ehci_buffer_rw(q, q->usb_status, 1) != 0) {
- q->usb_status = USB_RET_PROCERR;
- return;
- }
q->tbytes -= q->usb_status;
} else {
q->tbytes = 0;
@@ -1190,6 +1303,8 @@ err:
DPRINTF("updating tbytes to %d\n", q->tbytes);
set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
}
+ ehci_finish_transfer(q, q->usb_status);
+ usb_packet_unmap(&q->packet);
q->qh.token ^= QTD_TOKEN_DTOGGLE;
q->qh.token &= ~QTD_TOKEN_ACTIVE;
@@ -1229,8 +1344,7 @@ static int ehci_execute(EHCIQueue *q)
default: fprintf(stderr, "bad token\n"); break;
}
- if ((q->tbytes && q->pid != USB_TOKEN_IN) &&
- (ehci_buffer_rw(q, q->tbytes, 0) != 0)) {
+ if (ehci_init_transfer(q) != 0) {
return USB_RET_PROCERR;
}
@@ -1239,30 +1353,26 @@ static int ehci_execute(EHCIQueue *q)
ret = USB_RET_NODEV;
+ usb_packet_setup(&q->packet, q->pid, devadr, endp);
+ usb_packet_map(&q->packet, &q->sgl);
+
// TO-DO: associating device with ehci port
for(i = 0; i < NB_PORTS; i++) {
port = &q->ehci->ports[i];
dev = port->dev;
- // TODO sometime we will also need to check if we are the port owner
-
if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
DPRINTF("Port %d, no exec, not connected(%08X)\n",
i, q->ehci->portsc[i]);
continue;
}
- q->packet.pid = q->pid;
- q->packet.devaddr = devadr;
- q->packet.devep = endp;
- q->packet.data = q->buffer;
- q->packet.len = q->tbytes;
-
ret = usb_handle_packet(dev, &q->packet);
- DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
+ DPRINTF("submit: qh %x next %x qtd %x pid %x len %zd "
+ "(total %d) endp %x ret %d\n",
q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
- q->packet.len, q->tbytes, endp, ret);
+ q->packet.iov.size, q->tbytes, endp, ret);
if (ret != USB_RET_NODEV) {
break;
@@ -1286,7 +1396,7 @@ static int ehci_process_itd(EHCIState *ehci,
USBPort *port;
USBDevice *dev;
int ret;
- uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp;
+ uint32_t i, j, len, pid, dir, devaddr, endp;
uint32_t pg, off, ptr1, ptr2, max, mult;
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
@@ -1311,45 +1421,31 @@ static int ehci_process_itd(EHCIState *ehci,
return USB_RET_PROCERR;
}
+ qemu_sglist_init(&ehci->isgl, 2);
if (off + len > 4096) {
/* transfer crosses page border */
- len2 = off + len - 4096;
- len1 = len - len2;
+ uint32_t len2 = off + len - 4096;
+ uint32_t len1 = len - len2;
+ qemu_sglist_add(&ehci->isgl, ptr1 + off, len1);
+ qemu_sglist_add(&ehci->isgl, ptr2, len2);
} else {
- len1 = len;
- len2 = 0;
+ qemu_sglist_add(&ehci->isgl, ptr1 + off, len);
}
- if (!dir) {
- pid = USB_TOKEN_OUT;
- trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0);
- cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0);
- if (len2) {
- trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1);
- cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0);
- }
- } else {
- pid = USB_TOKEN_IN;
- }
+ pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
- ret = USB_RET_NODEV;
+ usb_packet_setup(&ehci->ipacket, pid, devaddr, endp);
+ usb_packet_map(&ehci->ipacket, &ehci->isgl);
+ ret = USB_RET_NODEV;
for (j = 0; j < NB_PORTS; j++) {
port = &ehci->ports[j];
dev = port->dev;
- // TODO sometime we will also need to check if we are the port owner
-
if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
continue;
}
- ehci->ipacket.pid = pid;
- ehci->ipacket.devaddr = devaddr;
- ehci->ipacket.devep = endp;
- ehci->ipacket.data = ehci->ibuffer;
- ehci->ipacket.len = len;
-
ret = usb_handle_packet(dev, &ehci->ipacket);
if (ret != USB_RET_NODEV) {
@@ -1357,6 +1453,9 @@ static int ehci_process_itd(EHCIState *ehci,
}
}
+ usb_packet_unmap(&ehci->ipacket);
+ qemu_sglist_destroy(&ehci->isgl);
+
#if 0
/* In isoch, there is no facility to indicate a NAK so let's
* instead just complete a zero-byte transaction. Setting
@@ -1394,20 +1493,6 @@ static int ehci_process_itd(EHCIState *ehci,
set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
} else {
/* IN */
- if (len1 > ret) {
- len1 = ret;
- }
- if (len2 > ret - len1) {
- len2 = ret - len1;
- }
- if (len1) {
- trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0);
- cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1);
- }
- if (len2) {
- trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1);
- cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1);
- }
set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
}
@@ -2117,38 +2202,55 @@ static void ehci_map(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory(addr, size, s->mem);
}
-static void ehci_device_destroy(USBBus *bus, USBDevice *dev)
-{
- EHCIState *s = container_of(bus, EHCIState, bus);
-
- ehci_queues_rip_device(s, dev);
-}
-
static int usb_ehci_initfn(PCIDevice *dev);
static USBPortOps ehci_port_ops = {
.attach = ehci_attach,
.detach = ehci_detach,
+ .child_detach = ehci_child_detach,
+ .wakeup = ehci_wakeup,
.complete = ehci_async_complete_packet,
};
static USBBusOps ehci_bus_ops = {
- .device_destroy = ehci_device_destroy,
+ .register_companion = ehci_register_companion,
+};
+
+static const VMStateDescription vmstate_ehci = {
+ .name = "ehci",
+ .unmigratable = 1,
};
-static PCIDeviceInfo ehci_info = {
- .qdev.name = "usb-ehci",
- .qdev.size = sizeof(EHCIState),
- .init = usb_ehci_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801D,
- .revision = 0x10,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ),
- DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property ehci_properties[] = {
+ DEFINE_PROP_UINT32("freq", EHCIState, freq, FRAME_TIMER_FREQ),
+ DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static PCIDeviceInfo ehci_info[] = {
+ {
+ .qdev.name = "usb-ehci",
+ .qdev.size = sizeof(EHCIState),
+ .qdev.vmsd = &vmstate_ehci,
+ .init = usb_ehci_initfn,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
+ .revision = 0x10,
+ .class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = ehci_properties,
+ },{
+ .qdev.name = "ich9-usb-ehci1",
+ .qdev.size = sizeof(EHCIState),
+ .qdev.vmsd = &vmstate_ehci,
+ .init = usb_ehci_initfn,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
+ .revision = 0x03,
+ .class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = ehci_properties,
+ },{
+ /* end of list */
+ }
};
static int usb_ehci_initfn(PCIDevice *dev)
@@ -2206,7 +2308,6 @@ static int usb_ehci_initfn(PCIDevice *dev)
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
USB_SPEED_MASK_HIGH);
- usb_port_location(&s->ports[i], NULL, i+1);
s->ports[i].dev = 0;
}
@@ -2228,7 +2329,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
static void ehci_register(void)
{
- pci_qdev_register(&ehci_info);
+ pci_qdev_register_many(ehci_info);
}
device_init(ehci_register);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index d711b5c0be..e5d57de888 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -27,6 +27,7 @@
#include "usb.h"
#include "usb-desc.h"
#include "qemu-timer.h"
+#include "hid.h"
/* HID interface requests */
#define GET_REPORT 0xa101
@@ -41,46 +42,9 @@
#define USB_DT_REPORT 0x22
#define USB_DT_PHY 0x23
-#define USB_MOUSE 1
-#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 {
- 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];
- int32_t keys;
-} USBKeyboardState;
-
typedef struct USBHIDState {
USBDevice dev;
- union {
- USBMouseState ptr;
- USBKeyboardState kbd;
- };
- uint32_t head; /* index into circular queue */
- uint32_t n;
- int kind;
- int32_t protocol;
- uint8_t idle;
- int64_t next_idle_clock;
- int changed;
+ HIDState hid;
void *datain_opaque;
void (*datain)(void *);
} USBHIDState;
@@ -394,342 +358,29 @@ static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
0xc0, /* End Collection */
};
-#define USB_HID_USAGE_ERROR_ROLLOVER 0x01
-#define USB_HID_USAGE_POSTFAIL 0x02
-#define USB_HID_USAGE_ERROR_UNDEFINED 0x03
-
-/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
-static const uint8_t usb_hid_usage_keys[0x100] = {
- 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
- 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
- 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
- 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
- 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
- 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
- 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
- 0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
- 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
- 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
- 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
- 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
- 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
- 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
- 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
- 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static void usb_hid_changed(USBHIDState *hs)
-{
- hs->changed = 1;
-
- if (hs->datain)
- hs->datain(hs->datain_opaque);
-
- usb_wakeup(&hs->dev);
-}
-
-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;
- 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_keyboard_event(void *opaque, int keycode)
-{
- USBHIDState *hs = opaque;
- 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_process_keycode(USBHIDState *hs)
-{
- USBKeyboardState *s = &hs->kbd;
- uint8_t hid_code, key;
- 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))];
- s->modifiers &= ~(1 << 8);
-
- switch (hid_code) {
- case 0x00:
- return;
-
- case 0xe0:
- if (s->modifiers & (1 << 9)) {
- s->modifiers ^= 3 << 8;
- usb_hid_changed(hs);
- return;
- }
- case 0xe1 ... 0xe7:
- if (keycode & (1 << 7)) {
- s->modifiers &= ~(1 << (hid_code & 0x0f));
- usb_hid_changed(hs);
- return;
- }
- case 0xe8 ... 0xef:
- s->modifiers |= 1 << (hid_code & 0x0f);
- usb_hid_changed(hs);
- return;
- }
-
- if (keycode & (1 << 7)) {
- for (i = s->keys - 1; i >= 0; i --)
- if (s->key[i] == hid_code) {
- s->key[i] = s->key[-- s->keys];
- s->key[s->keys] = 0x00;
- break;
- }
- if (i < 0)
- return;
- } else {
- for (i = s->keys - 1; i >= 0; i --)
- if (s->key[i] == hid_code)
- break;
- if (i < 0) {
- if (s->keys < sizeof(s->key))
- s->key[s->keys ++] = hid_code;
- } else
- return;
- }
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
- if (val < vmin)
- return vmin;
- else if (val > vmax)
- return vmax;
- else
- return val;
-}
-
-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;
- }
-
- /* 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];
-
- 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 (e->buttons_state & MOUSE_EVENT_LBUTTON)
- b |= 0x01;
- if (e->buttons_state & MOUSE_EVENT_RBUTTON)
- b |= 0x02;
- if (e->buttons_state & MOUSE_EVENT_MBUTTON)
- b |= 0x04;
-
- if (hs->n &&
- !e->dz &&
- (hs->kind == USB_TABLET || (!e->xdx && !e->ydy))) {
- /* that deals with this event */
- QUEUE_INCR(hs->head);
- hs->n--;
- }
-
- /* Appears we have to invert the wheel direction */
- dz = 0 - dz;
- 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;
-
- default:
- abort();
- }
-
- return l;
-}
-
-static int usb_keyboard_poll(USBHIDState *hs, uint8_t *buf, int len)
+static void usb_hid_changed(HIDState *hs)
{
- 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)
- memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
- else
- memcpy(buf + 2, s->key, MIN(8, len) - 2);
-
- return MIN(8, len);
-}
+ USBHIDState *us = container_of(hs, USBHIDState, hid);
-static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
-{
- if (len > 0) {
- int ledstate = 0;
- /* 0x01: Num Lock LED
- * 0x02: Caps Lock LED
- * 0x04: Scroll Lock LED
- * 0x08: Compose LED
- * 0x10: Kana LED */
- s->leds = buf[0];
- if (s->leds & 0x04)
- ledstate |= QEMU_SCROLL_LOCK_LED;
- if (s->leds & 0x01)
- ledstate |= QEMU_NUM_LOCK_LED;
- if (s->leds & 0x02)
- ledstate |= QEMU_CAPS_LOCK_LED;
- kbd_put_ledstate(ledstate);
+ if (us->datain) {
+ us->datain(us->datain_opaque);
}
- return 0;
-}
-static void usb_mouse_handle_reset(USBDevice *dev)
-{
- USBHIDState *s = (USBHIDState *)dev;
-
- memset(s->ptr.queue, 0, sizeof (s->ptr.queue));
- s->head = 0;
- s->n = 0;
- s->protocol = 1;
+ usb_wakeup(&us->dev);
}
-static void usb_keyboard_handle_reset(USBDevice *dev)
+static void usb_hid_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;
-}
+ USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
-static void usb_hid_set_next_idle(USBHIDState *s, int64_t curtime)
-{
- s->next_idle_clock = curtime + (get_ticks_per_sec() * s->idle * 4) / 1000;
+ hid_reset(&us->hid);
}
static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
- USBHIDState *s = (USBHIDState *)dev;
+ USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+ HIDState *hs = &us->hid;
int ret;
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
@@ -738,7 +389,7 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
}
ret = 0;
- switch(request) {
+ switch (request) {
case DeviceRequest | USB_REQ_GET_INTERFACE:
data[0] = 0;
ret = 1;
@@ -748,17 +399,17 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
break;
/* hid specific requests */
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
- switch(value >> 8) {
+ switch (value >> 8) {
case 0x22:
- if (s->kind == USB_MOUSE) {
+ if (hs->kind == HID_MOUSE) {
memcpy(data, qemu_mouse_hid_report_descriptor,
sizeof(qemu_mouse_hid_report_descriptor));
ret = sizeof(qemu_mouse_hid_report_descriptor);
- } else if (s->kind == USB_TABLET) {
- memcpy(data, qemu_tablet_hid_report_descriptor,
+ } else if (hs->kind == HID_TABLET) {
+ memcpy(data, qemu_tablet_hid_report_descriptor,
sizeof(qemu_tablet_hid_report_descriptor));
ret = sizeof(qemu_tablet_hid_report_descriptor);
- } else if (s->kind == USB_KEYBOARD) {
+ } else if (hs->kind == HID_KEYBOARD) {
memcpy(data, qemu_keyboard_hid_report_descriptor,
sizeof(qemu_keyboard_hid_report_descriptor));
ret = sizeof(qemu_keyboard_hid_report_descriptor);
@@ -769,36 +420,40 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
}
break;
case GET_REPORT:
- 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, data, length);
+ if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+ ret = hid_pointer_poll(hs, data, length);
+ } else if (hs->kind == HID_KEYBOARD) {
+ ret = hid_keyboard_poll(hs, data, length);
+ }
break;
case SET_REPORT:
- if (s->kind == USB_KEYBOARD)
- ret = usb_keyboard_write(&s->kbd, data, length);
- else
+ if (hs->kind == HID_KEYBOARD) {
+ ret = hid_keyboard_write(hs, data, length);
+ } else {
goto fail;
+ }
break;
case GET_PROTOCOL:
- if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+ if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
goto fail;
+ }
ret = 1;
- data[0] = s->protocol;
+ data[0] = hs->protocol;
break;
case SET_PROTOCOL:
- if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
+ if (hs->kind != HID_KEYBOARD && hs->kind != HID_MOUSE) {
goto fail;
+ }
ret = 0;
- s->protocol = value;
+ hs->protocol = value;
break;
case GET_IDLE:
ret = 1;
- data[0] = s->idle;
+ data[0] = hs->idle;
break;
case SET_IDLE:
- s->idle = (uint8_t) (value >> 8);
- usb_hid_set_next_idle(s, qemu_get_clock_ns(vm_clock));
+ hs->idle = (uint8_t) (value >> 8);
+ hid_set_next_idle(hs, qemu_get_clock_ns(vm_clock));
ret = 0;
break;
default:
@@ -811,23 +466,26 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
{
- USBHIDState *s = (USBHIDState *)dev;
+ USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
+ HIDState *hs = &us->hid;
+ uint8_t buf[p->iov.size];
int ret = 0;
- switch(p->pid) {
+ switch (p->pid) {
case USB_TOKEN_IN:
if (p->devep == 1) {
int64_t curtime = qemu_get_clock_ns(vm_clock);
- if (!s->changed && (!s->idle || s->next_idle_clock - curtime > 0))
+ if (!hid_has_events(hs) &&
+ (!hs->idle || hs->next_idle_clock - curtime > 0)) {
return USB_RET_NAK;
- usb_hid_set_next_idle(s, curtime);
- 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);
+ hid_set_next_idle(hs, curtime);
+ if (hs->kind == HID_MOUSE || hs->kind == HID_TABLET) {
+ ret = hid_pointer_poll(hs, buf, p->iov.size);
+ } else if (hs->kind == HID_KEYBOARD) {
+ ret = hid_keyboard_poll(hs, buf, p->iov.size);
}
- s->changed = s->n > 0;
+ usb_packet_copy(p, buf, ret);
} else {
goto fail;
}
@@ -843,50 +501,33 @@ static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
static void usb_hid_handle_destroy(USBDevice *dev)
{
- USBHIDState *s = (USBHIDState *)dev;
+ USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
- switch(s->kind) {
- case USB_KEYBOARD:
- qemu_remove_kbd_event_handler();
- break;
- default:
- qemu_remove_mouse_event_handler(s->ptr.eh_entry);
- }
+ hid_free(&us->hid);
}
static int usb_hid_initfn(USBDevice *dev, int kind)
{
- USBHIDState *s = DO_UPCAST(USBHIDState, dev, dev);
+ USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev);
usb_desc_init(dev);
- s->kind = kind;
-
- if (s->kind == USB_MOUSE) {
- 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_pointer_event, s,
- 1, "QEMU USB Tablet");
- }
-
- /* Force poll routine to be run and grab input the first time. */
- s->changed = 1;
+ hid_init(&us->hid, kind, usb_hid_changed);
return 0;
}
static int usb_tablet_initfn(USBDevice *dev)
{
- return usb_hid_initfn(dev, USB_TABLET);
+ return usb_hid_initfn(dev, HID_TABLET);
}
static int usb_mouse_initfn(USBDevice *dev)
{
- return usb_hid_initfn(dev, USB_MOUSE);
+ return usb_hid_initfn(dev, HID_MOUSE);
}
static int usb_keyboard_initfn(USBDevice *dev)
{
- return usb_hid_initfn(dev, USB_KEYBOARD);
+ return usb_hid_initfn(dev, HID_KEYBOARD);
}
void usb_hid_datain_cb(USBDevice *dev, void *opaque, void (*datain)(void *))
@@ -901,8 +542,8 @@ 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_ns(vm_clock));
+ if (s->hid.idle) {
+ hid_set_next_idle(&s->hid, qemu_get_clock_ns(vm_clock));
}
return 0;
}
@@ -912,10 +553,10 @@ static const VMStateDescription vmstate_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_INT32(xdx, HIDPointerEvent),
+ VMSTATE_INT32(ydy, HIDPointerEvent),
+ VMSTATE_INT32(dz, HIDPointerEvent),
+ VMSTATE_INT32(buttons_state, HIDPointerEvent),
VMSTATE_END_OF_LIST()
}
};
@@ -926,12 +567,12 @@ static const VMStateDescription vmstate_usb_ptr = {
.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_STRUCT_ARRAY(hid.ptr.queue, USBHIDState, QUEUE_LENGTH, 0,
+ vmstate_usb_ptr_queue, HIDPointerEvent),
+ VMSTATE_UINT32(hid.head, USBHIDState),
+ VMSTATE_UINT32(hid.n, USBHIDState),
+ VMSTATE_INT32(hid.protocol, USBHIDState),
+ VMSTATE_UINT8(hid.idle, USBHIDState),
VMSTATE_END_OF_LIST()
}
};
@@ -943,15 +584,15 @@ static const VMStateDescription vmstate_usb_kbd = {
.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_UINT32_ARRAY(hid.kbd.keycodes, USBHIDState, QUEUE_LENGTH),
+ VMSTATE_UINT32(hid.head, USBHIDState),
+ VMSTATE_UINT32(hid.n, USBHIDState),
+ VMSTATE_UINT16(hid.kbd.modifiers, USBHIDState),
+ VMSTATE_UINT8(hid.kbd.leds, USBHIDState),
+ VMSTATE_UINT8_ARRAY(hid.kbd.key, USBHIDState, 16),
+ VMSTATE_INT32(hid.kbd.keys, USBHIDState),
+ VMSTATE_INT32(hid.protocol, USBHIDState),
+ VMSTATE_UINT8(hid.idle, USBHIDState),
VMSTATE_END_OF_LIST()
}
};
@@ -966,7 +607,7 @@ static struct USBDeviceInfo hid_info[] = {
.usb_desc = &desc_tablet,
.init = usb_tablet_initfn,
.handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_mouse_handle_reset,
+ .handle_reset = usb_hid_handle_reset,
.handle_control = usb_hid_handle_control,
.handle_data = usb_hid_handle_data,
.handle_destroy = usb_hid_handle_destroy,
@@ -979,7 +620,7 @@ static struct USBDeviceInfo hid_info[] = {
.usb_desc = &desc_mouse,
.init = usb_mouse_initfn,
.handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_mouse_handle_reset,
+ .handle_reset = usb_hid_handle_reset,
.handle_control = usb_hid_handle_control,
.handle_data = usb_hid_handle_data,
.handle_destroy = usb_hid_handle_destroy,
@@ -992,7 +633,7 @@ static struct USBDeviceInfo hid_info[] = {
.usb_desc = &desc_keyboard,
.init = usb_keyboard_initfn,
.handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_keyboard_handle_reset,
+ .handle_reset = usb_hid_handle_reset,
.handle_control = usb_hid_handle_control,
.handle_data = usb_hid_handle_data,
.handle_destroy = usb_hid_handle_destroy,
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 6e2a35839d..c49c547d0c 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -138,74 +138,6 @@ static const USBDesc desc_hub = {
.str = desc_strings,
};
-static const uint8_t qemu_hub_dev_descriptor[] = {
- 0x12, /* u8 bLength; */
- 0x01, /* u8 bDescriptorType; Device */
- 0x10, 0x01, /* u16 bcdUSB; v1.1 */
-
- 0x09, /* u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* u8 bDeviceSubClass; */
- 0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
- 0x08, /* u8 bMaxPacketSize0; 8 Bytes */
-
- 0x00, 0x00, /* u16 idVendor; */
- 0x00, 0x00, /* u16 idProduct; */
- 0x01, 0x01, /* u16 bcdDevice */
-
- 0x03, /* u8 iManufacturer; */
- 0x02, /* u8 iProduct; */
- 0x01, /* u8 iSerialNumber; */
- 0x01 /* u8 bNumConfigurations; */
-};
-
-/* XXX: patch interrupt size */
-static const uint8_t qemu_hub_config_descriptor[] = {
-
- /* one configuration */
- 0x09, /* u8 bLength; */
- 0x02, /* u8 bDescriptorType; Configuration */
- 0x19, 0x00, /* u16 wTotalLength; */
- 0x01, /* u8 bNumInterfaces; (1) */
- 0x01, /* u8 bConfigurationValue; */
- 0x00, /* u8 iConfiguration; */
- 0xe0, /* u8 bmAttributes;
- Bit 7: must be set,
- 6: Self-powered,
- 5: Remote wakeup,
- 4..0: resvd */
- 0x00, /* u8 MaxPower; */
-
- /* USB 1.1:
- * USB 2.0, single TT organization (mandatory):
- * one interface, protocol 0
- *
- * USB 2.0, multiple TT organization (optional):
- * two interfaces, protocols 1 (like single TT)
- * and 2 (multiple TT mode) ... config is
- * sometimes settable
- * NOT IMPLEMENTED
- */
-
- /* one interface */
- 0x09, /* u8 if_bLength; */
- 0x04, /* u8 if_bDescriptorType; Interface */
- 0x00, /* u8 if_bInterfaceNumber; */
- 0x00, /* u8 if_bAlternateSetting; */
- 0x01, /* u8 if_bNumEndpoints; */
- 0x09, /* u8 if_bInterfaceClass; HUB_CLASSCODE */
- 0x00, /* u8 if_bInterfaceSubClass; */
- 0x00, /* u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
- 0x00, /* u8 if_iInterface; */
-
- /* one endpoint (status change endpoint) */
- 0x07, /* u8 ep_bLength; */
- 0x05, /* u8 ep_bDescriptorType; Endpoint */
- 0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* u8 ep_bmAttributes; Interrupt */
- 0x02, 0x00, /* u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
- 0xff /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
-};
-
static const uint8_t qemu_hub_hub_descriptor[] =
{
0x00, /* u8 bLength; patched in later */
@@ -238,6 +170,9 @@ static void usb_hub_detach(USBPort *port1)
USBHubState *s = port1->opaque;
USBHubPort *port = &s->ports[port1->index];
+ /* Let upstream know the device on this port is gone */
+ s->dev.port->ops->child_detach(s->dev.port, port1->dev);
+
port->wPortStatus &= ~PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->wPortStatus & PORT_STAT_ENABLE) {
@@ -246,10 +181,18 @@ static void usb_hub_detach(USBPort *port1)
}
}
-static void usb_hub_wakeup(USBDevice *dev)
+static void usb_hub_child_detach(USBPort *port1, USBDevice *child)
+{
+ USBHubState *s = port1->opaque;
+
+ /* Pass along upstream */
+ s->dev.port->ops->child_detach(s->dev.port, child);
+}
+
+static void usb_hub_wakeup(USBPort *port1)
{
- USBHubState *s = dev->port->opaque;
- USBHubPort *port = &s->ports[dev->port->index];
+ USBHubState *s = port1->opaque;
+ USBHubPort *port = &s->ports[port1->index];
if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND;
@@ -257,9 +200,9 @@ static void usb_hub_wakeup(USBDevice *dev)
}
}
-static void usb_hub_complete(USBDevice *dev, USBPacket *packet)
+static void usb_hub_complete(USBPort *port, USBPacket *packet)
{
- USBHubState *s = dev->port->opaque;
+ USBHubState *s = port->opaque;
/*
* Just pass it along upstream for now.
@@ -451,11 +394,12 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
if (p->devep == 1) {
USBHubPort *port;
unsigned int status;
+ uint8_t buf[4];
int i, n;
n = (NUM_PORTS + 1 + 7) / 8;
- if (p->len == 1) { /* FreeBSD workaround */
+ if (p->iov.size == 1) { /* FreeBSD workaround */
n = 1;
- } else if (n > p->len) {
+ } else if (n > p->iov.size) {
return USB_RET_BABBLE;
}
status = 0;
@@ -466,8 +410,9 @@ static int usb_hub_handle_data(USBDevice *dev, USBPacket *p)
}
if (status != 0) {
for(i = 0; i < n; i++) {
- p->data[i] = status >> (8 * i);
+ buf[i] = status >> (8 * i);
}
+ usb_packet_copy(p, buf, n);
ret = n;
} else {
ret = USB_RET_NAK; /* usb11 11.13.1 */
@@ -537,6 +482,7 @@ static void usb_hub_handle_destroy(USBDevice *dev)
static USBPortOps usb_hub_port_ops = {
.attach = usb_hub_attach,
.detach = usb_hub_detach,
+ .child_detach = usb_hub_child_detach,
.wakeup = usb_hub_wakeup,
.complete = usb_hub_complete,
};
diff --git a/hw/usb-libhw.c b/hw/usb-libhw.c
new file mode 100644
index 0000000000..162b42bd5b
--- /dev/null
+++ b/hw/usb-libhw.c
@@ -0,0 +1,63 @@
+/*
+ * QEMU USB emulation, libhw bits.
+ *
+ * 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 "qemu-common.h"
+#include "cpu-common.h"
+#include "usb.h"
+#include "dma.h"
+
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl)
+{
+ int is_write = (p->pid == USB_TOKEN_IN);
+ target_phys_addr_t len;
+ void *mem;
+ int i;
+
+ for (i = 0; i < sgl->nsg; i++) {
+ len = sgl->sg[i].len;
+ mem = cpu_physical_memory_map(sgl->sg[i].base, &len,
+ is_write);
+ if (!mem) {
+ goto err;
+ }
+ qemu_iovec_add(&p->iov, mem, len);
+ if (len != sgl->sg[i].len) {
+ goto err;
+ }
+ }
+ return 0;
+
+err:
+ usb_packet_unmap(p);
+ return -1;
+}
+
+void usb_packet_unmap(USBPacket *p)
+{
+ int is_write = (p->pid == USB_TOKEN_IN);
+ int i;
+
+ for (i = 0; i < p->iov.niov; i++) {
+ cpu_physical_memory_unmap(p->iov.iov[i].iov_base,
+ p->iov.iov[i].iov_len, is_write,
+ p->iov.iov[i].iov_len);
+ }
+}
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 86582cc723..90e57fbf6b 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -4,7 +4,7 @@
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*/
#include "qemu-common.h"
@@ -43,8 +43,6 @@ typedef struct {
enum USBMSDMode mode;
uint32_t scsi_len;
uint8_t *scsi_buf;
- uint32_t usb_len;
- uint8_t *usb_buf;
uint32_t data_len;
uint32_t residue;
uint32_t tag;
@@ -176,20 +174,14 @@ static const USBDesc desc = {
.str = desc_strings,
};
-static void usb_msd_copy_data(MSDState *s)
+static void usb_msd_copy_data(MSDState *s, USBPacket *p)
{
uint32_t len;
- len = s->usb_len;
+ len = p->iov.size - p->result;
if (len > s->scsi_len)
len = s->scsi_len;
- if (s->mode == USB_MSDM_DATAIN) {
- memcpy(s->usb_buf, s->scsi_buf, len);
- } else {
- memcpy(s->scsi_buf, s->usb_buf, len);
- }
- s->usb_len -= len;
+ usb_packet_copy(p, s->scsi_buf, len);
s->scsi_len -= len;
- s->usb_buf += len;
s->scsi_buf += len;
s->data_len -= len;
if (s->scsi_len == 0 || s->data_len == 0) {
@@ -207,8 +199,9 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p)
csw.residue = s->residue;
csw.status = s->result;
- len = MIN(sizeof(csw), p->len);
- memcpy(p->data, &csw, len);
+ len = MIN(sizeof(csw), p->iov.size);
+ usb_packet_copy(p, &csw, len);
+ p->result = len;
}
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
@@ -216,16 +209,13 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
- if (req->tag != s->tag) {
- fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
- }
-
assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
s->scsi_len = len;
s->scsi_buf = scsi_req_get_buf(req);
if (p) {
- usb_msd_copy_data(s);
- if (s->packet && s->usb_len == 0) {
+ usb_msd_copy_data(s, p);
+ p = s->packet;
+ if (p && p->result == p->iov.size) {
/* Set s->packet to NULL before calling usb_packet_complete
because another request may be issued before
usb_packet_complete returns. */
@@ -241,9 +231,6 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
- if (req->tag != s->tag) {
- fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
- }
DPRINTF("Command complete %d\n", status);
s->residue = s->data_len;
s->result = status != 0;
@@ -255,11 +242,9 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status)
s->mode = USB_MSDM_CBW;
} else {
if (s->data_len) {
- s->data_len -= s->usb_len;
- if (s->mode == USB_MSDM_DATAIN) {
- memset(s->usb_buf, 0, s->usb_len);
- }
- s->usb_len = 0;
+ int len = (p->iov.size - p->result);
+ usb_packet_skip(p, len);
+ s->data_len -= len;
}
if (s->data_len == 0) {
s->mode = USB_MSDM_CSW;
@@ -349,8 +334,6 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
int ret = 0;
struct usb_msd_cbw cbw;
uint8_t devep = p->devep;
- uint8_t *data = p->data;
- int len = p->len;
switch (p->pid) {
case USB_TOKEN_OUT:
@@ -359,11 +342,11 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
switch (s->mode) {
case USB_MSDM_CBW:
- if (len != 31) {
+ if (p->iov.size != 31) {
fprintf(stderr, "usb-msd: Bad CBW size");
goto fail;
}
- memcpy(&cbw, data, 31);
+ usb_packet_copy(p, &cbw, 31);
if (le32_to_cpu(cbw.sig) != 0x43425355) {
fprintf(stderr, "usb-msd: Bad signature %08x\n",
le32_to_cpu(cbw.sig));
@@ -387,43 +370,46 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0;
s->scsi_len = 0;
- s->req = scsi_req_new(s->scsi_dev, s->tag, 0);
+ s->req = scsi_req_new(s->scsi_dev, s->tag, 0, NULL);
scsi_req_enqueue(s->req, cbw.cmd);
/* ??? Should check that USB and SCSI data transfer
directions match. */
if (s->mode != USB_MSDM_CSW && s->residue == 0) {
scsi_req_continue(s->req);
}
- ret = len;
+ ret = p->result;
break;
case USB_MSDM_DATAOUT:
- DPRINTF("Data out %d/%d\n", len, s->data_len);
- if (len > s->data_len)
+ DPRINTF("Data out %zd/%d\n", p->iov.size, s->data_len);
+ if (p->iov.size > s->data_len) {
goto fail;
+ }
- s->usb_buf = data;
- s->usb_len = len;
if (s->scsi_len) {
- usb_msd_copy_data(s);
+ usb_msd_copy_data(s, p);
}
- if (s->residue && s->usb_len) {
- s->data_len -= s->usb_len;
- if (s->data_len == 0)
- s->mode = USB_MSDM_CSW;
- s->usb_len = 0;
+ if (s->residue) {
+ int len = p->iov.size - p->result;
+ if (len) {
+ usb_packet_skip(p, len);
+ s->data_len -= len;
+ if (s->data_len == 0) {
+ s->mode = USB_MSDM_CSW;
+ }
+ }
}
- if (s->usb_len) {
+ if (p->result < p->iov.size) {
DPRINTF("Deferring packet %p\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
- ret = len;
+ ret = p->result;
}
break;
default:
- DPRINTF("Unexpected write (len %d)\n", len);
+ DPRINTF("Unexpected write (len %zd)\n", p->iov.size);
goto fail;
}
break;
@@ -434,18 +420,20 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
switch (s->mode) {
case USB_MSDM_DATAOUT:
- if (s->data_len != 0 || len < 13)
+ if (s->data_len != 0 || p->iov.size < 13) {
goto fail;
+ }
/* Waiting for SCSI write to complete. */
s->packet = p;
ret = USB_RET_ASYNC;
break;
case USB_MSDM_CSW:
- DPRINTF("Command status %d tag 0x%x, len %d\n",
- s->result, s->tag, len);
- if (len < 13)
+ DPRINTF("Command status %d tag 0x%x, len %zd\n",
+ s->result, s->tag, p->iov.size);
+ if (p->iov.size < 13) {
goto fail;
+ }
usb_msd_send_status(s, p);
s->mode = USB_MSDM_CBW;
@@ -453,32 +441,32 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
break;
case USB_MSDM_DATAIN:
- DPRINTF("Data in %d/%d, scsi_len %d\n", len, s->data_len, s->scsi_len);
- if (len > s->data_len)
- len = s->data_len;
- s->usb_buf = data;
- s->usb_len = len;
+ DPRINTF("Data in %zd/%d, scsi_len %d\n",
+ p->iov.size, s->data_len, s->scsi_len);
if (s->scsi_len) {
- usb_msd_copy_data(s);
+ usb_msd_copy_data(s, p);
}
- if (s->residue && s->usb_len) {
- s->data_len -= s->usb_len;
- memset(s->usb_buf, 0, s->usb_len);
- if (s->data_len == 0)
- s->mode = USB_MSDM_CSW;
- s->usb_len = 0;
+ if (s->residue) {
+ int len = p->iov.size - p->result;
+ if (len) {
+ usb_packet_skip(p, len);
+ s->data_len -= len;
+ if (s->data_len == 0) {
+ s->mode = USB_MSDM_CSW;
+ }
+ }
}
- if (s->usb_len) {
+ if (p->result < p->iov.size) {
DPRINTF("Deferring packet %p\n", p);
s->packet = p;
ret = USB_RET_ASYNC;
} else {
- ret = len;
+ ret = p->result;
}
break;
default:
- DPRINTF("Unexpected read (len %d)\n", len);
+ DPRINTF("Unexpected read (len %zd)\n", p->iov.size);
goto fail;
}
break;
@@ -623,11 +611,23 @@ static USBDevice *usb_msd_init(const char *filename)
return dev;
}
+static const VMStateDescription vmstate_usb_msd = {
+ .name = "usb-storage",
+ .unmigratable = 1, /* FIXME: handle transactions which are in flight */
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_USB_DEVICE(dev, MSDState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static struct USBDeviceInfo msd_info = {
.product_desc = "QEMU USB MSD",
.qdev.name = "usb-storage",
.qdev.fw_name = "storage",
.qdev.size = sizeof(MSDState),
+ .qdev.vmsd = &vmstate_usb_msd,
.usb_desc = &desc,
.init = usb_msd_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 21f35afa92..d3ccde9199 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -261,17 +261,18 @@
static void musb_attach(USBPort *port);
static void musb_detach(USBPort *port);
-static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
-static void musb_device_destroy(USBBus *bus, USBDevice *dev);
+static void musb_child_detach(USBPort *port, USBDevice *child);
+static void musb_schedule_cb(USBPort *port, USBPacket *p);
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
static USBPortOps musb_port_ops = {
.attach = musb_attach,
.detach = musb_detach,
+ .child_detach = musb_child_detach,
.complete = musb_schedule_cb,
};
static USBBusOps musb_bus_ops = {
- .device_destroy = musb_device_destroy,
};
typedef struct MUSBPacket MUSBPacket;
@@ -364,12 +365,13 @@ struct MUSBState *musb_init(qemu_irq *irqs)
s->ep[i].maxp[1] = 0x40;
s->ep[i].musb = s;
s->ep[i].epnum = i;
+ usb_packet_init(&s->ep[i].packey[0].p);
+ usb_packet_init(&s->ep[i].packey[1].p);
}
usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- usb_port_location(&s->port, NULL, 1);
return s;
}
@@ -498,10 +500,19 @@ static void musb_detach(USBPort *port)
{
MUSBState *s = (MUSBState *) port->opaque;
+ musb_async_cancel_device(s, port->dev);
+
musb_intr_set(s, musb_irq_disconnect, 1);
musb_session_update(s, 1, s->session);
}
+static void musb_child_detach(USBPort *port, USBDevice *child)
+{
+ MUSBState *s = (MUSBState *) port->opaque;
+
+ musb_async_cancel_device(s, child);
+}
+
static void musb_cb_tick0(void *opaque)
{
MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
@@ -518,7 +529,7 @@ static void musb_cb_tick1(void *opaque)
#define musb_cb_tick (dir ? musb_cb_tick1 : musb_cb_tick0)
-static void musb_schedule_cb(USBDevice *dev, USBPacket *packey)
+static void musb_schedule_cb(USBPort *port, USBPacket *packey)
{
MUSBPacket *p = container_of(packey, MUSBPacket, p);
MUSBEndPoint *ep = p->ep;
@@ -596,12 +607,10 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
ep->delayed_cb[dir] = cb;
- ep->packey[dir].p.pid = pid;
/* A wild guess on the FADDR semantics... */
- ep->packey[dir].p.devaddr = ep->faddr[idx];
- ep->packey[dir].p.devep = ep->type[idx] & 0xf;
- ep->packey[dir].p.data = (void *) ep->buf[idx];
- ep->packey[dir].p.len = len;
+ usb_packet_setup(&ep->packey[dir].p, pid, ep->faddr[idx],
+ ep->type[idx] & 0xf);
+ usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
ep->packey[dir].ep = ep;
ep->packey[dir].dir = dir;
@@ -616,7 +625,7 @@ static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
}
ep->status[dir] = ret;
- usb_packet_complete(s->port.dev, &ep->packey[dir].p);
+ musb_schedule_cb(&s->port, &ep->packey[dir].p);
}
static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
@@ -729,7 +738,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
if (ep->status[1] == USB_RET_STALL) {
ep->status[1] = 0;
- packey->len = 0;
+ packey->result = 0;
ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
if (!epnum)
@@ -743,7 +752,7 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
* Data-errors in Isochronous. */
if (ep->interrupt[1])
return musb_packet(s, ep, epnum, USB_TOKEN_IN,
- packey->len, musb_rx_packet_complete, 1);
+ packey->iov.size, musb_rx_packet_complete, 1);
ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
if (!epnum)
@@ -768,14 +777,14 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
/* TODO: check len for over/underruns of an OUT packet? */
/* TODO: perhaps make use of e->ext_size[1] here. */
- packey->len = ep->status[1];
+ packey->result = ep->status[1];
if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
if (!epnum)
ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
- ep->rxcount = packey->len; /* XXX: MIN(packey->len, ep->maxp[1]); */
+ ep->rxcount = packey->result; /* XXX: MIN(packey->len, ep->maxp[1]); */
/* In DMA mode: assert DMA request for this EP */
}
@@ -783,9 +792,8 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
musb_rx_intr_set(s, epnum, 1);
}
-static void musb_device_destroy(USBBus *bus, USBDevice *dev)
+static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
{
- MUSBState *s = container_of(bus, MUSBState, bus);
int ep, dir;
for (ep = 0; ep < 16; ep++) {
@@ -848,12 +856,12 @@ static void musb_rx_req(MUSBState *s, int epnum)
* 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
(ep->fifostart[1]) + ep->rxcount <
- ep->packey[1].p.len) {
+ ep->packey[1].p.iov.size) {
TRACE("0x%08x, %d", ep->fifostart[1], ep->rxcount );
ep->fifostart[1] += ep->rxcount;
ep->fifolen[1] = 0;
- ep->rxcount = MIN(ep->packey[0].p.len - (ep->fifostart[1]),
+ ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
ep->maxp[1]);
ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 9be709f7cf..0cb47d63b3 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -29,6 +29,7 @@
#include "net.h"
#include "qemu-queue.h"
#include "sysemu.h"
+#include "iov.h"
/*#define TRAFFIC_DEBUG*/
/* Thanks to NetChip Technologies for donating this product ID.
@@ -1121,28 +1122,23 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
static int usb_net_handle_statusin(USBNetState *s, USBPacket *p)
{
+ le32 buf[2];
int ret = 8;
- if (p->len < 8)
+ if (p->iov.size < 8) {
return USB_RET_STALL;
+ }
- ((le32 *) p->data)[0] = cpu_to_le32(1);
- ((le32 *) p->data)[1] = cpu_to_le32(0);
+ buf[0] = cpu_to_le32(1);
+ buf[1] = cpu_to_le32(0);
+ usb_packet_copy(p, buf, 8);
if (!s->rndis_resp.tqh_first)
ret = USB_RET_NAK;
#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: interrupt poll len %u return %d", p->len, ret);
- {
- int i;
- fprintf(stderr, ":");
- for (i = 0; i < ret; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", p->data[i]);
- }
- fprintf(stderr, "\n\n");
- }
+ fprintf(stderr, "usbnet: interrupt poll len %zu return %d",
+ p->iov.size, ret);
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
#endif
return ret;
@@ -1162,9 +1158,10 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
return ret;
}
ret = s->in_len - s->in_ptr;
- if (ret > p->len)
- ret = p->len;
- memcpy(p->data, &s->in_buf[s->in_ptr], ret);
+ if (ret > p->iov.size) {
+ ret = p->iov.size;
+ }
+ usb_packet_copy(p, &s->in_buf[s->in_ptr], ret);
s->in_ptr += ret;
if (s->in_ptr >= s->in_len &&
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
@@ -1173,17 +1170,8 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
}
#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data in len %u return %d", p->len, ret);
- {
- int i;
- fprintf(stderr, ":");
- for (i = 0; i < ret; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", p->data[i]);
- }
- fprintf(stderr, "\n\n");
- }
+ fprintf(stderr, "usbnet: data in len %zu return %d", p->iov.size, ret);
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", ret);
#endif
return ret;
@@ -1191,29 +1179,20 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
static int usb_net_handle_dataout(USBNetState *s, USBPacket *p)
{
- int ret = p->len;
+ int ret = p->iov.size;
int sz = sizeof(s->out_buf) - s->out_ptr;
struct rndis_packet_msg_type *msg =
(struct rndis_packet_msg_type *) s->out_buf;
uint32_t len;
#ifdef TRAFFIC_DEBUG
- fprintf(stderr, "usbnet: data out len %u\n", p->len);
- {
- int i;
- fprintf(stderr, ":");
- for (i = 0; i < p->len; i++) {
- if (!(i & 15))
- fprintf(stderr, "\n%04x:", i);
- fprintf(stderr, " %02x", p->data[i]);
- }
- fprintf(stderr, "\n\n");
- }
+ fprintf(stderr, "usbnet: data out len %zu\n", p->iov.size);
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "usbnet", p->iov.size);
#endif
if (sz > ret)
sz = ret;
- memcpy(&s->out_buf[s->out_ptr], p->data, sz);
+ usb_packet_copy(p, &s->out_buf[s->out_ptr], sz);
s->out_ptr += sz;
if (!is_rndis(s)) {
@@ -1277,8 +1256,8 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
}
if (ret == USB_RET_STALL)
fprintf(stderr, "usbnet: failed data transaction: "
- "pid 0x%x ep 0x%x len 0x%x\n",
- p->pid, p->devep, p->len);
+ "pid 0x%x ep 0x%x len 0x%zx\n",
+ p->pid, p->devep, p->iov.size);
return ret;
}
@@ -1414,11 +1393,17 @@ static USBDevice *usb_net_init(const char *cmdline)
return dev;
}
+static const VMStateDescription vmstate_usb_net = {
+ .name = "usb-net",
+ .unmigratable = 1,
+};
+
static struct USBDeviceInfo net_info = {
.product_desc = "QEMU USB Network Interface",
.qdev.name = "usb-net",
.qdev.fw_name = "network",
.qdev.size = sizeof(USBNetState),
+ .qdev.vmsd = &vmstate_usb_net,
.usb_desc = &desc_net,
.init = usb_net_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 1c29b9fa6c..d39bcb0c0d 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -62,7 +62,7 @@ typedef struct OHCIPort {
typedef struct {
USBBus bus;
qemu_irq irq;
- int mem;
+ MemoryRegion mem;
int num_ports;
const char *name;
@@ -124,6 +124,7 @@ struct ohci_hcca {
};
static void ohci_bus_stop(OHCIState *ohci);
+static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
/* Bitfields for the first word of an Endpoint Desciptor. */
#define OHCI_ED_FA_SHIFT 0
@@ -326,6 +327,7 @@ static void ohci_attach(USBPort *port1)
{
OHCIState *s = port1->opaque;
OHCIPort *port = &s->rhport[port1->index];
+ uint32_t old_state = port->ctrl;
/* set connect status */
port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC;
@@ -343,6 +345,10 @@ static void ohci_attach(USBPort *port1)
}
DPRINTF("usb-ohci: Attached port %d\n", port1->index);
+
+ if (old_state != port->ctrl) {
+ ohci_set_interrupt(s, OHCI_INTR_RHSC);
+ }
}
static void ohci_detach(USBPort *port1)
@@ -351,6 +357,8 @@ static void ohci_detach(USBPort *port1)
OHCIPort *port = &s->rhport[port1->index];
uint32_t old_state = port->ctrl;
+ ohci_async_cancel_device(s, port1->dev);
+
/* set connect status */
if (port->ctrl & OHCI_PORT_CCS) {
port->ctrl &= ~OHCI_PORT_CCS;
@@ -363,19 +371,18 @@ static void ohci_detach(USBPort *port1)
}
DPRINTF("usb-ohci: Detached port %d\n", port1->index);
- if (old_state != port->ctrl)
+ if (old_state != port->ctrl) {
ohci_set_interrupt(s, OHCI_INTR_RHSC);
+ }
}
-static void ohci_wakeup(USBDevice *dev)
+static void ohci_wakeup(USBPort *port1)
{
- USBBus *bus = usb_bus_from_device(dev);
- OHCIState *s = container_of(bus, OHCIState, bus);
- int portnum = dev->port->index;
- OHCIPort *port = &s->rhport[portnum];
+ OHCIState *s = port1->opaque;
+ OHCIPort *port = &s->rhport[port1->index];
uint32_t intr = 0;
if (port->ctrl & OHCI_PORT_PSS) {
- DPRINTF("usb-ohci: port %d: wakeup\n", portnum);
+ DPRINTF("usb-ohci: port %d: wakeup\n", port1->index);
port->ctrl |= OHCI_PORT_PSSC;
port->ctrl &= ~OHCI_PORT_PSS;
intr = OHCI_INTR_RHSC;
@@ -394,6 +401,13 @@ static void ohci_wakeup(USBDevice *dev)
ohci_set_interrupt(s, intr);
}
+static void ohci_child_detach(USBPort *port1, USBDevice *child)
+{
+ OHCIState *s = port1->opaque;
+
+ ohci_async_cancel_device(s, child);
+}
+
/* Reset the controller */
static void ohci_reset(void *opaque)
{
@@ -602,7 +616,7 @@ static void ohci_copy_iso_td(OHCIState *ohci,
static void ohci_process_lists(OHCIState *ohci, int completion);
-static void ohci_async_complete_packet(USBDevice *dev, USBPacket *packet)
+static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
{
OHCIState *ohci = container_of(packet, OHCIState, usb_packet);
#ifdef DEBUG_PACKET
@@ -763,18 +777,17 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
}
if (completion) {
- ret = ohci->usb_packet.len;
+ ret = ohci->usb_packet.result;
} else {
ret = USB_RET_NODEV;
for (i = 0; i < ohci->num_ports; i++) {
dev = ohci->rhport[i].port.dev;
if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
continue;
- ohci->usb_packet.pid = pid;
- ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
- ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
- ohci->usb_packet.data = ohci->usb_buf;
- ohci->usb_packet.len = len;
+ usb_packet_setup(&ohci->usb_packet, pid,
+ OHCI_BM(ed->flags, ED_FA),
+ OHCI_BM(ed->flags, ED_EN));
+ usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -945,7 +958,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
#endif
if (completion) {
- ret = ohci->usb_packet.len;
+ ret = ohci->usb_packet.result;
ohci->async_td = 0;
ohci->async_complete = 0;
} else {
@@ -966,11 +979,10 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
#endif
return 1;
}
- ohci->usb_packet.pid = pid;
- ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
- ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
- ohci->usb_packet.data = ohci->usb_buf;
- ohci->usb_packet.len = len;
+ usb_packet_setup(&ohci->usb_packet, pid,
+ OHCI_BM(ed->flags, ED_FA),
+ OHCI_BM(ed->flags, ED_EN));
+ usb_packet_addbuf(&ohci->usb_packet, ohci->usb_buf, len);
ret = usb_handle_packet(dev, &ohci->usb_packet);
if (ret != USB_RET_NODEV)
break;
@@ -1426,13 +1438,13 @@ static void ohci_port_set_status(OHCIState *ohci, int portnum, uint32_t val)
return;
}
-static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
+static uint64_t ohci_mem_read(void *opaque,
+ target_phys_addr_t addr,
+ unsigned size)
{
- OHCIState *ohci = ptr;
+ OHCIState *ohci = opaque;
uint32_t retval;
- addr &= 0xff;
-
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
fprintf(stderr, "usb-ohci: Mis-aligned read\n");
@@ -1549,11 +1561,12 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
return retval;
}
-static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
+static void ohci_mem_write(void *opaque,
+ target_phys_addr_t addr,
+ uint64_t val,
+ unsigned size)
{
- OHCIState *ohci = ptr;
-
- addr &= 0xff;
+ OHCIState *ohci = opaque;
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
@@ -1675,43 +1688,34 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
}
}
-static void ohci_device_destroy(USBBus *bus, USBDevice *dev)
+static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
{
- OHCIState *ohci = container_of(bus, OHCIState, bus);
-
if (ohci->async_td && ohci->usb_packet.owner == dev) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
}
-/* Only dword reads are defined on OHCI register space */
-static CPUReadMemoryFunc * const ohci_readfn[3]={
- ohci_mem_read,
- ohci_mem_read,
- ohci_mem_read
-};
-
-/* Only dword writes are defined on OHCI register space */
-static CPUWriteMemoryFunc * const ohci_writefn[3]={
- ohci_mem_write,
- ohci_mem_write,
- ohci_mem_write
+static const MemoryRegionOps ohci_mem_ops = {
+ .read = ohci_mem_read,
+ .write = ohci_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
.detach = ohci_detach,
+ .child_detach = ohci_child_detach,
.wakeup = ohci_wakeup,
.complete = ohci_async_complete_packet,
};
static USBBusOps ohci_bus_ops = {
- .device_destroy = ohci_device_destroy,
};
-static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
- int num_ports, uint32_t localmem_base)
+static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
+ int num_ports, uint32_t localmem_base,
+ char *masterbus, uint32_t firstport)
{
int i;
@@ -1731,43 +1735,62 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
usb_frame_time, usb_bit_time);
}
- ohci->mem = cpu_register_io_memory(ohci_readfn, ohci_writefn, ohci,
- DEVICE_LITTLE_ENDIAN);
+ ohci->num_ports = num_ports;
+ if (masterbus) {
+ USBPort *ports[OHCI_MAX_PORTS];
+ for(i = 0; i < num_ports; i++) {
+ ports[i] = &ohci->rhport[i].port;
+ }
+ if (usb_register_companion(masterbus, ports, num_ports,
+ firstport, ohci, &ohci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
+ return -1;
+ }
+ } else {
+ usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
+ for (i = 0; i < num_ports; i++) {
+ usb_register_port(&ohci->bus, &ohci->rhport[i].port,
+ ohci, i, &ohci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ }
+ }
+
+ memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256);
ohci->localmem_base = localmem_base;
ohci->name = dev->info->name;
-
- usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
- ohci->num_ports = num_ports;
- for (i = 0; i < num_ports; i++) {
- usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- usb_port_location(&ohci->rhport[i].port, NULL, i+1);
- }
+ usb_packet_init(&ohci->usb_packet);
ohci->async_td = 0;
qemu_register_reset(ohci_reset, ohci);
+
+ return 0;
}
typedef struct {
PCIDevice pci_dev;
OHCIState state;
+ char *masterbus;
+ uint32_t num_ports;
+ uint32_t firstport;
} OHCIPCIState;
static int usb_ohci_initfn_pci(struct PCIDevice *dev)
{
OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
- int num_ports = 3;
ohci->pci_dev.config[PCI_CLASS_PROG] = 0x10; /* OHCI */
/* TODO: RST# value should be 0. */
ohci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
- usb_ohci_init(&ohci->state, &dev->qdev, num_ports, 0);
+ if (usb_ohci_init(&ohci->state, &dev->qdev, ohci->num_ports, 0,
+ ohci->masterbus, ohci->firstport) != 0) {
+ return -1;
+ }
ohci->state.irq = ohci->pci_dev.irq[0];
/* TODO: avoid cast below by using dev */
- pci_register_bar_simple(&ohci->pci_dev, 0, 256, 0, ohci->state.mem);
+ pci_register_bar_region(&ohci->pci_dev, 0, 0, &ohci->state.mem);
return 0;
}
@@ -1787,9 +1810,10 @@ static int ohci_init_pxa(SysBusDevice *dev)
{
OHCISysBusState *s = FROM_SYSBUS(OHCISysBusState, dev);
- usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset);
+ /* Cannot fail as we pass NULL for masterbus */
+ usb_ohci_init(&s->ohci, &dev->qdev, s->num_ports, s->dma_offset, NULL, 0);
sysbus_init_irq(dev, &s->ohci.irq);
- sysbus_init_mmio(dev, 0x1000, s->ohci.mem);
+ sysbus_init_mmio_region(dev, &s->ohci.mem);
return 0;
}
@@ -1802,6 +1826,12 @@ static PCIDeviceInfo ohci_pci_info = {
.vendor_id = PCI_VENDOR_ID_APPLE,
.device_id = PCI_DEVICE_ID_APPLE_IPID_USB,
.class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+ DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+ DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ },
};
static SysBusDeviceInfo ohci_sysbus_info = {
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 59cb0fb2f7..bf2b775e83 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -5,7 +5,7 @@
* Copyright (c) 2008 Samuel Thibault <samuel.thibault@ens-lyon.org>
* Written by Paul Brook, reused for FTDI by Samuel Thibault
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*/
#include "qemu-common.h"
@@ -359,37 +359,42 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
{
USBSerialState *s = (USBSerialState *)dev;
- int ret = 0;
+ int i, ret = 0;
uint8_t devep = p->devep;
- uint8_t *data = p->data;
- int len = p->len;
- int first_len;
+ struct iovec *iov;
+ uint8_t header[2];
+ int first_len, len;
switch (p->pid) {
case USB_TOKEN_OUT:
if (devep != 2)
goto fail;
- qemu_chr_write(s->cs, data, len);
+ for (i = 0; i < p->iov.niov; i++) {
+ iov = p->iov.iov + i;
+ qemu_chr_write(s->cs, iov->iov_base, iov->iov_len);
+ }
break;
case USB_TOKEN_IN:
if (devep != 1)
goto fail;
first_len = RECV_BUF - s->recv_ptr;
+ len = p->iov.size;
if (len <= 2) {
ret = USB_RET_NAK;
break;
}
- *data++ = usb_get_modem_lines(s) | 1;
+ header[0] = usb_get_modem_lines(s) | 1;
/* We do not have the uart details */
/* handle serial break */
if (s->event_trigger && s->event_trigger & FTDI_BI) {
s->event_trigger &= ~FTDI_BI;
- *data = FTDI_BI;
+ header[1] = FTDI_BI;
+ usb_packet_copy(p, header, 2);
ret = 2;
break;
} else {
- *data++ = 0;
+ header[1] = 0;
}
len -= 2;
if (len > s->recv_used)
@@ -400,9 +405,10 @@ static int usb_serial_handle_data(USBDevice *dev, USBPacket *p)
}
if (first_len > len)
first_len = len;
- memcpy(data, s->recv_buf + s->recv_ptr, first_len);
+ usb_packet_copy(p, header, 2);
+ usb_packet_copy(p, s->recv_buf + s->recv_ptr, first_len);
if (len > first_len)
- memcpy(data + first_len, s->recv_buf, len - first_len);
+ usb_packet_copy(p, s->recv_buf, len - first_len);
s->recv_used -= len;
s->recv_ptr = (s->recv_ptr + len) % RECV_BUF;
ret = len + 2;
@@ -566,10 +572,16 @@ static USBDevice *usb_braille_init(const char *unused)
return dev;
}
+static const VMStateDescription vmstate_usb_serial = {
+ .name = "usb-serial",
+ .unmigratable = 1,
+};
+
static struct USBDeviceInfo serial_info = {
.product_desc = "QEMU USB Serial",
.qdev.name = "usb-serial",
.qdev.size = sizeof(USBSerialState),
+ .qdev.vmsd = &vmstate_usb_serial,
.usb_desc = &desc_serial,
.init = usb_serial_initfn,
.handle_packet = usb_generic_handle_packet,
@@ -589,6 +601,7 @@ static struct USBDeviceInfo braille_info = {
.product_desc = "QEMU USB Braille",
.qdev.name = "usb-braille",
.qdev.size = sizeof(USBSerialState),
+ .qdev.vmsd = &vmstate_usb_serial,
.usb_desc = &desc_braille,
.init = usb_serial_initfn,
.handle_packet = usb_generic_handle_packet,
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index 405fa7b65e..824e3a5e8b 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -30,6 +30,8 @@
#include "pci.h"
#include "qemu-timer.h"
#include "usb-uhci.h"
+#include "iov.h"
+#include "dma.h"
//#define DEBUG
//#define DEBUG_DUMP_DATA
@@ -93,17 +95,12 @@ static const char *pid2str(int pid)
#endif
#ifdef DEBUG_DUMP_DATA
-static void dump_data(const uint8_t *data, int len)
+static void dump_data(USBPacket *p, int ret)
{
- int i;
-
- printf("uhci: data: ");
- for(i = 0; i < len; i++)
- printf(" %02x", data[i]);
- printf("\n");
+ iov_hexdump(p->iov.iov, p->iov.niov, stderr, "uhci", ret);
}
#else
-static void dump_data(const uint8_t *data, int len) {}
+static void dump_data(USBPacket *p, int ret) {}
#endif
typedef struct UHCIState UHCIState;
@@ -115,6 +112,7 @@ typedef struct UHCIState UHCIState;
*/
typedef struct UHCIAsync {
USBPacket packet;
+ QEMUSGList sgl;
UHCIState *uhci;
QTAILQ_ENTRY(UHCIAsync) next;
uint32_t td;
@@ -122,7 +120,6 @@ typedef struct UHCIAsync {
int8_t valid;
uint8_t isoc;
uint8_t done;
- uint8_t buffer[2048];
} UHCIAsync;
typedef struct UHCIPort {
@@ -132,7 +129,7 @@ typedef struct UHCIPort {
struct UHCIState {
PCIDevice dev;
- USBBus bus;
+ USBBus bus; /* Note unused when we're a companion controller */
uint16_t cmd; /* cmd register */
uint16_t status;
uint16_t intr; /* interrupt enable register */
@@ -150,6 +147,10 @@ struct UHCIState {
/* Active packets */
QTAILQ_HEAD(,UHCIAsync) async_pending;
uint8_t num_ports_vmstate;
+
+ /* Properties */
+ char *masterbus;
+ uint32_t firstport;
};
typedef struct UHCI_TD {
@@ -175,12 +176,16 @@ static UHCIAsync *uhci_async_alloc(UHCIState *s)
async->token = 0;
async->done = 0;
async->isoc = 0;
+ usb_packet_init(&async->packet);
+ qemu_sglist_init(&async->sgl, 1);
return async;
}
static void uhci_async_free(UHCIState *s, UHCIAsync *async)
{
+ usb_packet_cleanup(&async->packet);
+ qemu_sglist_destroy(&async->sgl);
qemu_free(async);
}
@@ -606,6 +611,8 @@ static void uhci_detach(USBPort *port1)
UHCIState *s = port1->opaque;
UHCIPort *port = &s->ports[port1->index];
+ uhci_async_cancel_device(s, port1->dev);
+
/* set connect status */
if (port->ctrl & UHCI_PORT_CCS) {
port->ctrl &= ~UHCI_PORT_CCS;
@@ -620,11 +627,17 @@ static void uhci_detach(USBPort *port1)
uhci_resume(s);
}
-static void uhci_wakeup(USBDevice *dev)
+static void uhci_child_detach(USBPort *port1, USBDevice *child)
{
- USBBus *bus = usb_bus_from_device(dev);
- UHCIState *s = container_of(bus, UHCIState, bus);
- UHCIPort *port = s->ports + dev->port->index;
+ UHCIState *s = port1->opaque;
+
+ uhci_async_cancel_device(s, child);
+}
+
+static void uhci_wakeup(USBPort *port1)
+{
+ UHCIState *s = port1->opaque;
+ UHCIPort *port = &s->ports[port1->index];
if (port->ctrl & UHCI_PORT_SUSPEND && !(port->ctrl & UHCI_PORT_RD)) {
port->ctrl |= UHCI_PORT_RD;
@@ -636,10 +649,10 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
{
int i, ret;
- DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %d\n",
- pid2str(p->pid), p->devaddr, p->devep, p->len);
+ DPRINTF("uhci: packet enter. pid %s addr 0x%02x ep %d len %zd\n",
+ pid2str(p->pid), p->devaddr, p->devep, p->iov.size);
if (p->pid == USB_TOKEN_OUT || p->pid == USB_TOKEN_SETUP)
- dump_data(p->data, p->len);
+ dump_data(p, 0);
ret = USB_RET_NODEV;
for (i = 0; i < NB_PORTS && ret == USB_RET_NODEV; i++) {
@@ -650,14 +663,14 @@ static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
ret = usb_handle_packet(dev, p);
}
- DPRINTF("uhci: packet exit. ret %d len %d\n", ret, p->len);
+ DPRINTF("uhci: packet exit. ret %d len %zd\n", ret, p->iov.size);
if (p->pid == USB_TOKEN_IN && ret > 0)
- dump_data(p->data, ret);
+ dump_data(p, ret);
return ret;
}
-static void uhci_async_complete(USBDevice *dev, USBPacket *packet);
+static void uhci_async_complete(USBPort *port, USBPacket *packet);
static void uhci_process_frame(UHCIState *s);
/* return -1 if fatal error (frame must be stopped)
@@ -672,7 +685,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
- ret = async->packet.len;
+ ret = async->packet.result;
if (td->ctrl & TD_CTRL_IOS)
td->ctrl &= ~TD_CTRL_ACTIVE;
@@ -680,7 +693,7 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
if (ret < 0)
goto out;
- len = async->packet.len;
+ len = async->packet.result;
td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
/* The NAK bit may have been set by a previous frame, so clear it
@@ -696,11 +709,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_
goto out;
}
- if (len > 0) {
- /* write the data back */
- cpu_physical_memory_write(td->buffer, async->buffer, len);
- }
-
if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {
*int_mask |= 0x02;
/* short packet: do not update QH */
@@ -718,6 +726,9 @@ out:
td->ctrl |= TD_CTRL_STALL;
td->ctrl &= ~TD_CTRL_ACTIVE;
s->status |= UHCI_STS_USBERR;
+ if (td->ctrl & TD_CTRL_IOC) {
+ *int_mask |= 0x01;
+ }
uhci_update_irq(s);
return 1;
@@ -725,6 +736,9 @@ out:
td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
td->ctrl &= ~TD_CTRL_ACTIVE;
s->status |= UHCI_STS_USBERR;
+ if (td->ctrl & TD_CTRL_IOC) {
+ *int_mask |= 0x01;
+ }
uhci_update_irq(s);
/* frame interrupted */
return -1;
@@ -809,16 +823,14 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
max_len = ((td->token >> 21) + 1) & 0x7ff;
pid = td->token & 0xff;
- async->packet.pid = pid;
- async->packet.devaddr = (td->token >> 8) & 0x7f;
- async->packet.devep = (td->token >> 15) & 0xf;
- async->packet.data = async->buffer;
- async->packet.len = max_len;
+ usb_packet_setup(&async->packet, pid, (td->token >> 8) & 0x7f,
+ (td->token >> 15) & 0xf);
+ qemu_sglist_add(&async->sgl, td->buffer, max_len);
+ usb_packet_map(&async->packet, &async->sgl);
switch(pid) {
case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
- cpu_physical_memory_read(td->buffer, async->buffer, max_len);
len = uhci_broadcast_packet(s, &async->packet);
if (len >= 0)
len = max_len;
@@ -841,15 +853,16 @@ static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *in
return 2;
}
- async->packet.len = len;
+ async->packet.result = len;
done:
len = uhci_complete_td(s, td, async, int_mask);
+ usb_packet_unmap(&async->packet);
uhci_async_free(s, async);
return len;
}
-static void uhci_async_complete(USBDevice *dev, USBPacket *packet)
+static void uhci_async_complete(USBPort *port, USBPacket *packet)
{
UHCIAsync *async = container_of(packet, UHCIAsync, packet);
UHCIState *s = async->uhci;
@@ -1096,22 +1109,15 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
-static void uhci_device_destroy(USBBus *bus, USBDevice *dev)
-{
- UHCIState *s = container_of(bus, UHCIState, bus);
-
- uhci_async_cancel_device(s, dev);
-}
-
static USBPortOps uhci_port_ops = {
.attach = uhci_attach,
.detach = uhci_detach,
+ .child_detach = uhci_child_detach,
.wakeup = uhci_wakeup,
.complete = uhci_async_complete,
};
static USBBusOps uhci_bus_ops = {
- .device_destroy = uhci_device_destroy,
};
static int usb_uhci_common_initfn(PCIDevice *dev)
@@ -1125,11 +1131,22 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
- usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
- for(i = 0; i < NB_PORTS; i++) {
- usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
- USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
- usb_port_location(&s->ports[i].port, NULL, i+1);
+ if (s->masterbus) {
+ USBPort *ports[NB_PORTS];
+ for(i = 0; i < NB_PORTS; i++) {
+ ports[i] = &s->ports[i].port;
+ }
+ if (usb_register_companion(s->masterbus, ports, NB_PORTS,
+ s->firstport, s, &uhci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL) != 0) {
+ return -1;
+ }
+ } else {
+ usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
+ for (i = 0; i < NB_PORTS; i++) {
+ usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
+ }
}
s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
s->num_ports_vmstate = NB_PORTS;
@@ -1160,6 +1177,12 @@ static int usb_uhci_vt82c686b_initfn(PCIDevice *dev)
return usb_uhci_common_initfn(dev);
}
+static Property uhci_properties[] = {
+ DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
+ DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static PCIDeviceInfo uhci_info[] = {
{
.qdev.name = "piix3-usb-uhci",
@@ -1170,6 +1193,7 @@ static PCIDeviceInfo uhci_info[] = {
.device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
.revision = 0x01,
.class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = uhci_properties,
},{
.qdev.name = "piix4-usb-uhci",
.qdev.size = sizeof(UHCIState),
@@ -1179,6 +1203,7 @@ static PCIDeviceInfo uhci_info[] = {
.device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
.revision = 0x01,
.class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = uhci_properties,
},{
.qdev.name = "vt82c686b-usb-uhci",
.qdev.size = sizeof(UHCIState),
@@ -1188,6 +1213,37 @@ static PCIDeviceInfo uhci_info[] = {
.device_id = PCI_DEVICE_ID_VIA_UHCI,
.revision = 0x01,
.class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = uhci_properties,
+ },{
+ .qdev.name = "ich9-usb-uhci1",
+ .qdev.size = sizeof(UHCIState),
+ .qdev.vmsd = &vmstate_uhci,
+ .init = usb_uhci_common_initfn,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
+ .revision = 0x03,
+ .class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = uhci_properties,
+ },{
+ .qdev.name = "ich9-usb-uhci2",
+ .qdev.size = sizeof(UHCIState),
+ .qdev.vmsd = &vmstate_uhci,
+ .init = usb_uhci_common_initfn,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
+ .revision = 0x03,
+ .class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = uhci_properties,
+ },{
+ .qdev.name = "ich9-usb-uhci3",
+ .qdev.size = sizeof(UHCIState),
+ .qdev.vmsd = &vmstate_uhci,
+ .init = usb_uhci_common_initfn,
+ .vendor_id = PCI_VENDOR_ID_INTEL,
+ .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
+ .revision = 0x03,
+ .class_id = PCI_CLASS_SERIAL_USB,
+ .qdev.props = uhci_properties,
},{
/* end of list */
}
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 9d348e170e..25580067f2 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -308,6 +308,7 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
{
USBWacomState *s = (USBWacomState *) dev;
+ uint8_t buf[p->iov.size];
int ret = 0;
switch (p->pid) {
@@ -317,9 +318,10 @@ static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
return USB_RET_NAK;
s->changed = 0;
if (s->mode == WACOM_MODE_HID)
- ret = usb_mouse_poll(s, p->data, p->len);
+ ret = usb_mouse_poll(s, buf, p->iov.size);
else if (s->mode == WACOM_MODE_WACOM)
- ret = usb_wacom_poll(s, p->data, p->len);
+ ret = usb_wacom_poll(s, buf, p->iov.size);
+ usb_packet_copy(p, buf, ret);
break;
}
/* Fall through. */
@@ -349,6 +351,11 @@ static int usb_wacom_initfn(USBDevice *dev)
return 0;
}
+static const VMStateDescription vmstate_usb_wacom = {
+ .name = "usb-wacom",
+ .unmigratable = 1,
+};
+
static struct USBDeviceInfo wacom_info = {
.product_desc = "QEMU PenPartner Tablet",
.qdev.name = "usb-wacom-tablet",
@@ -356,6 +363,7 @@ static struct USBDeviceInfo wacom_info = {
.usbdevice_name = "wacom-tablet",
.usb_desc = &desc_wacom,
.qdev.size = sizeof(USBWacomState),
+ .qdev.vmsd = &vmstate_usb_wacom,
.init = usb_wacom_initfn,
.handle_packet = usb_generic_handle_packet,
.handle_reset = usb_wacom_handle_reset,
diff --git a/hw/usb.c b/hw/usb.c
index 4a39cbcc7d..685e775a00 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -25,6 +25,7 @@
*/
#include "qemu-common.h"
#include "usb.h"
+#include "iov.h"
void usb_attach(USBPort *port, USBDevice *dev)
{
@@ -40,19 +41,18 @@ void usb_attach(USBPort *port, USBDevice *dev)
} else {
/* detach */
dev = port->dev;
+ assert(dev);
port->ops->detach(port);
- if (dev) {
- usb_send_msg(dev, USB_MSG_DETACH);
- dev->port = NULL;
- port->dev = NULL;
- }
+ usb_send_msg(dev, USB_MSG_DETACH);
+ dev->port = NULL;
+ port->dev = NULL;
}
}
void usb_wakeup(USBDevice *dev)
{
if (dev->remote_wakeup && dev->port && dev->port->ops->wakeup) {
- dev->port->ops->wakeup(dev);
+ dev->port->ops->wakeup(dev->port);
}
}
@@ -73,10 +73,11 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
int request, value, index;
int ret = 0;
- if (p->len != 8)
+ if (p->iov.size != 8) {
return USB_RET_STALL;
-
- memcpy(s->setup_buf, p->data, 8);
+ }
+
+ usb_packet_copy(p, s->setup_buf, p->iov.size);
s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
s->setup_index = 0;
@@ -145,9 +146,10 @@ static int do_token_in(USBDevice *s, USBPacket *p)
case SETUP_STATE_DATA:
if (s->setup_buf[0] & USB_DIR_IN) {
int len = s->setup_len - s->setup_index;
- if (len > p->len)
- len = p->len;
- memcpy(p->data, s->data_buf + s->setup_index, len);
+ if (len > p->iov.size) {
+ len = p->iov.size;
+ }
+ usb_packet_copy(p, s->data_buf + s->setup_index, len);
s->setup_index += len;
if (s->setup_index >= s->setup_len)
s->setup_state = SETUP_STATE_ACK;
@@ -180,9 +182,10 @@ static int do_token_out(USBDevice *s, USBPacket *p)
case SETUP_STATE_DATA:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
int len = s->setup_len - s->setup_index;
- if (len > p->len)
- len = p->len;
- memcpy(s->data_buf + s->setup_index, p->data, len);
+ if (len > p->iov.size) {
+ len = p->iov.size;
+ }
+ usb_packet_copy(p, s->data_buf + s->setup_index, len);
s->setup_index += len;
if (s->setup_index >= s->setup_len)
s->setup_state = SETUP_STATE_ACK;
@@ -252,22 +255,22 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
usb_packet_complete to complete their async control packets. */
void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p)
{
- if (p->len < 0) {
+ if (p->result < 0) {
s->setup_state = SETUP_STATE_IDLE;
}
switch (s->setup_state) {
case SETUP_STATE_SETUP:
- if (p->len < s->setup_len) {
- s->setup_len = p->len;
+ if (p->result < s->setup_len) {
+ s->setup_len = p->result;
}
s->setup_state = SETUP_STATE_DATA;
- p->len = 8;
+ p->result = 8;
break;
case SETUP_STATE_ACK:
s->setup_state = SETUP_STATE_IDLE;
- p->len = 0;
+ p->result = 0;
break;
default:
@@ -335,7 +338,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
{
/* Note: p->owner != dev is possible in case dev is a hub */
assert(p->owner != NULL);
- dev->port->ops->complete(dev, p);
+ dev->port->ops->complete(dev->port, p);
p->owner = NULL;
}
@@ -348,3 +351,57 @@ void usb_cancel_packet(USBPacket * p)
p->owner->info->cancel_packet(p->owner, p);
p->owner = NULL;
}
+
+
+void usb_packet_init(USBPacket *p)
+{
+ qemu_iovec_init(&p->iov, 1);
+}
+
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep)
+{
+ p->pid = pid;
+ p->devaddr = addr;
+ p->devep = ep;
+ p->result = 0;
+ qemu_iovec_reset(&p->iov);
+}
+
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len)
+{
+ qemu_iovec_add(&p->iov, ptr, len);
+}
+
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes)
+{
+ assert(p->result >= 0);
+ assert(p->result + bytes <= p->iov.size);
+ switch (p->pid) {
+ case USB_TOKEN_SETUP:
+ case USB_TOKEN_OUT:
+ iov_to_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+ break;
+ case USB_TOKEN_IN:
+ iov_from_buf(p->iov.iov, p->iov.niov, ptr, p->result, bytes);
+ break;
+ default:
+ fprintf(stderr, "%s: invalid pid: %x\n", __func__, p->pid);
+ abort();
+ }
+ p->result += bytes;
+}
+
+void usb_packet_skip(USBPacket *p, size_t bytes)
+{
+ assert(p->result >= 0);
+ assert(p->result + bytes <= p->iov.size);
+ if (p->pid == USB_TOKEN_IN) {
+ iov_clear(p->iov.iov, p->iov.niov, p->result, bytes);
+ }
+ p->result += bytes;
+}
+
+void usb_packet_cleanup(USBPacket *p)
+{
+ qemu_iovec_destroy(&p->iov);
+}
diff --git a/hw/usb.h b/hw/usb.h
index 076e2ffce4..84d04df2e1 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -252,8 +252,18 @@ struct USBDeviceInfo {
typedef struct USBPortOps {
void (*attach)(USBPort *port);
void (*detach)(USBPort *port);
- void (*wakeup)(USBDevice *dev);
- void (*complete)(USBDevice *dev, USBPacket *p);
+ /*
+ * This gets called when a device downstream from the device attached to
+ * the port (iow attached through a hub) gets detached.
+ */
+ void (*child_detach)(USBPort *port, USBDevice *child);
+ void (*wakeup)(USBPort *port);
+ /*
+ * Note that port->dev will be different then the device from which
+ * the packet originated when a hub is involved, if you want the orginating
+ * device use p->owner
+ */
+ void (*complete)(USBPort *port, USBPacket *p);
} USBPortOps;
/* USB port on which a device can be connected */
@@ -275,12 +285,21 @@ struct USBPacket {
int pid;
uint8_t devaddr;
uint8_t devep;
- uint8_t *data;
- int len;
+ QEMUIOVector iov;
+ int result; /* transfer length or USB_RET_* status code */
/* Internal use by the USB layer. */
USBDevice *owner;
};
+void usb_packet_init(USBPacket *p);
+void usb_packet_setup(USBPacket *p, int pid, uint8_t addr, uint8_t ep);
+void usb_packet_addbuf(USBPacket *p, void *ptr, size_t len);
+int usb_packet_map(USBPacket *p, QEMUSGList *sgl);
+void usb_packet_unmap(USBPacket *p);
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
+void usb_packet_skip(USBPacket *p, size_t bytes);
+void usb_packet_cleanup(USBPacket *p);
+
int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
@@ -344,7 +363,8 @@ struct USBBus {
};
struct USBBusOps {
- void (*device_destroy)(USBBus *bus, USBDevice *dev);
+ int (*register_companion)(USBBus *bus, USBPort *ports[],
+ uint32_t portcount, uint32_t firstport);
};
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
@@ -356,6 +376,9 @@ USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice *usbdevice_create(const char *cmdline);
void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
USBPortOps *ops, int speedmask);
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+ uint32_t portcount, uint32_t firstport,
+ void *opaque, USBPortOps *ops, int speedmask);
void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
void usb_unregister_port(USBBus *bus, USBPort *port);
int usb_device_attach(USBDevice *dev);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 8e75ffccfb..cffe387187 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -4,12 +4,13 @@
* Copyright (c) 2006-2009 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the LGPL.
+ * This code is licensed under the LGPL.
*/
#include "sysbus.h"
#include "pci.h"
#include "pci_host.h"
+#include "exec-memory.h"
typedef struct {
SysBusDevice busdev;
@@ -111,6 +112,7 @@ static int pci_vpb_init(SysBusDevice *dev)
}
bus = pci_register_bus(&dev->qdev, "pci",
pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
+ get_system_memory(),
PCI_DEVFN(11, 0), 4);
/* ??? Register memory space. */
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 46b6a3f383..147fe29b61 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 CodeSourcery.
* Written by Paul Brook
*
- * This code is licenced under the GPL.
+ * This code is licensed under the GPL.
*/
#include "sysbus.h"
diff --git a/hw/vga_int.h b/hw/vga_int.h
index d2811bdf1c..eee91a84f3 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -106,13 +106,13 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
typedef struct VGACommonState {
uint8_t *vram_ptr;
ram_addr_t vram_offset;
+ target_phys_addr_t lfb_addr;
+ target_phys_addr_t lfb_end;
+ target_phys_addr_t map_addr;
+ target_phys_addr_t map_end;
uint32_t vram_size;
- uint32_t lfb_addr;
- uint32_t lfb_end;
- uint32_t map_addr;
- uint32_t map_end;
- uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
uint32_t latch;
+ uint32_t lfb_vram_mapped; /* whether 0xa0000 is mapped as ram */
uint8_t sr_index;
uint8_t sr[256];
uint8_t gr_index;
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 70a8710343..072a88a382 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -1,7 +1,9 @@
/*
- * Virtio Block Device
+ * Virtio Balloon Device
*
* Copyright IBM, Corp. 2008
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
@@ -43,6 +45,7 @@ typedef struct VirtIOBalloon
size_t stats_vq_offset;
MonitorCompletion *stats_callback;
void *stats_opaque_callback_data;
+ DeviceState *qdev;
} VirtIOBalloon;
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
@@ -199,36 +202,44 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
return f;
}
-static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
- MonitorCompletion cb, void *cb_data)
+static void virtio_balloon_stat(void *opaque, MonitorCompletion cb,
+ void *cb_data)
{
VirtIOBalloon *dev = opaque;
- if (target > ram_size)
- target = ram_size;
+ /* For now, only allow one request at a time. This restriction can be
+ * removed later by queueing callback and data pairs.
+ */
+ if (dev->stats_callback != NULL) {
+ return;
+ }
+ dev->stats_callback = cb;
+ dev->stats_opaque_callback_data = cb_data;
+
+ if (ENABLE_GUEST_STATS
+ && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
+ virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
+ virtio_notify(&dev->vdev, dev->svq);
+ return;
+ }
+
+ /* Stats are not supported. Clear out any stale values that might
+ * have been set by a more featureful guest kernel.
+ */
+ reset_stats(dev);
+ complete_stats_request(dev);
+}
+static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
+{
+ VirtIOBalloon *dev = opaque;
+
+ if (target > ram_size) {
+ target = ram_size;
+ }
if (target) {
dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
virtio_notify_config(&dev->vdev);
- } else {
- /* For now, only allow one request at a time. This restriction can be
- * removed later by queueing callback and data pairs.
- */
- if (dev->stats_callback != NULL) {
- return;
- }
- dev->stats_callback = cb;
- dev->stats_opaque_callback_data = cb_data;
- if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) {
- virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
- virtio_notify(&dev->vdev, dev->svq);
- } else {
- /* Stats are not supported. Clear out any stale values that might
- * have been set by a more featureful guest kernel.
- */
- reset_stats(dev);
- complete_stats_request(dev);
- }
}
}
@@ -259,6 +270,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
VirtIODevice *virtio_balloon_init(DeviceState *dev)
{
VirtIOBalloon *s;
+ int ret;
s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
VIRTIO_ID_BALLOON,
@@ -268,15 +280,29 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
s->vdev.set_config = virtio_balloon_set_config;
s->vdev.get_features = virtio_balloon_get_features;
+ ret = qemu_add_balloon_handler(virtio_balloon_to_target,
+ virtio_balloon_stat, s);
+ if (ret < 0) {
+ virtio_cleanup(&s->vdev);
+ return NULL;
+ }
+
s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output);
s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats);
reset_stats(s);
- qemu_add_balloon_handler(virtio_balloon_to_target, s);
+ s->qdev = dev;
register_savevm(dev, "virtio-balloon", -1, 1,
virtio_balloon_save, virtio_balloon_load, s);
return &s->vdev;
}
+
+void virtio_balloon_exit(VirtIODevice *vdev)
+{
+ VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+ unregister_savevm(s->qdev, "virtio-balloon", s);
+ virtio_cleanup(vdev);
+}
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index b076331d37..fe5e188bf4 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -12,6 +12,7 @@
#include "qemu-char.h"
#include "qemu-error.h"
+#include "trace.h"
#include "virtio-serial.h"
typedef struct VirtConsole {
@@ -24,8 +25,26 @@ typedef struct VirtConsole {
static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
{
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-
- return qemu_chr_write(vcon->chr, buf, len);
+ ssize_t ret;
+
+ ret = qemu_chr_write(vcon->chr, buf, len);
+ trace_virtio_console_flush_buf(port->id, len, ret);
+
+ if (ret < 0) {
+ /*
+ * Ideally we'd get a better error code than just -1, but
+ * that's what the chardev interface gives us right now. If
+ * we had a finer-grained message, like -EPIPE, we could close
+ * this connection. Absent such error messages, the most we
+ * can do is to return 0 here.
+ *
+ * This will prevent stray -1 values to go to
+ * virtio-serial-bus.c and cause abort()s in
+ * do_flush_queued_data().
+ */
+ ret = 0;
+ }
+ return ret;
}
/* Callback function that's called when the guest opens the port */
@@ -57,6 +76,7 @@ static void chr_read(void *opaque, const uint8_t *buf, int size)
{
VirtConsole *vcon = opaque;
+ trace_virtio_console_chr_read(vcon->port.id, size);
virtio_serial_write(&vcon->port, buf, size);
}
@@ -64,6 +84,7 @@ static void chr_event(void *opaque, int event)
{
VirtConsole *vcon = opaque;
+ trace_virtio_console_chr_event(vcon->port.id, event);
switch (event) {
case CHR_EVENT_OPENED:
virtio_serial_open(&vcon->port);
@@ -118,9 +139,7 @@ static VirtIOSerialPortInfo virtconsole_info = {
.init = virtconsole_initfn,
.exit = virtconsole_exitfn,
.qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_STRING("name", VirtConsole, port.name),
DEFINE_PROP_END_OF_LIST(),
},
};
@@ -137,9 +156,7 @@ static VirtIOSerialPortInfo virtserialport_info = {
.init = virtconsole_initfn,
.exit = virtconsole_exitfn,
.qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_STRING("name", VirtConsole, port.name),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 09c665babe..3f10391f3e 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -657,7 +657,7 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
/* copy in packet. ugh */
len = iov_from_buf(sg, elem.in_num,
- buf + offset, size - offset);
+ buf + offset, 0, size - offset);
total += len;
offset += len;
/* If buffers can't be merged, at this point we
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 4f770fe185..f3b3293db0 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -788,10 +788,22 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
VirtIODevice *vdev;
vdev = virtio_balloon_init(&pci_dev->qdev);
+ if (!vdev) {
+ return -1;
+ }
virtio_init_pci(proxy, vdev);
return 0;
}
+static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ virtio_pci_stop_ioeventfd(proxy);
+ virtio_balloon_exit(proxy->vdev);
+ return virtio_exit_pci(pci_dev);
+}
+
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name = "virtio-blk-pci",
@@ -866,7 +878,7 @@ static PCIDeviceInfo virtio_info[] = {
.qdev.alias = "virtio-balloon",
.qdev.size = sizeof(VirtIOPCIProxy),
.init = virtio_balloon_init_pci,
- .exit = virtio_exit_pci,
+ .exit = virtio_balloon_exit_pci,
.vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
.device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
.revision = VIRTIO_PCI_ABI_VERSION,
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 7f6db7bffe..c5eb931095 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -19,6 +19,7 @@
#include "monitor.h"
#include "qemu-queue.h"
#include "sysbus.h"
+#include "trace.h"
#include "virtio-serial.h"
/* The virtio-serial bus on top of which the ports will ride as devices */
@@ -103,7 +104,7 @@ static size_t write_to_port(VirtIOSerialPort *port,
}
len = iov_from_buf(elem.in_sg, elem.in_num,
- buf + offset, size - offset);
+ buf + offset, 0, size - offset);
offset += len;
virtqueue_push(vq, &elem, len);
@@ -221,6 +222,7 @@ static size_t send_control_event(VirtIOSerialPort *port, uint16_t event,
stw_p(&cpkt.event, event);
stw_p(&cpkt.value, value);
+ trace_virtio_serial_send_control_event(port->id, event, value);
return send_control_msg(port, &cpkt, sizeof(cpkt));
}
@@ -302,6 +304,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
return;
}
+ trace_virtio_serial_throttle_port(port->id, throttle);
port->throttled = throttle;
if (throttle) {
return;
@@ -328,6 +331,8 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
cpkt.event = lduw_p(&gcpkt->event);
cpkt.value = lduw_p(&gcpkt->value);
+ trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
+
if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
if (!cpkt.value) {
error_report("virtio-serial-bus: Guest failure in adding device %s",
@@ -346,11 +351,13 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
port = find_port_by_id(vser, ldl_p(&gcpkt->id));
if (!port) {
- error_report("virtio-serial-bus: Unexpected port id %u for device %s\n",
+ error_report("virtio-serial-bus: Unexpected port id %u for device %s",
ldl_p(&gcpkt->id), vser->bus.qbus.name);
return;
}
+ trace_virtio_serial_handle_control_message_port(port->id);
+
info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
switch(cpkt.event) {
@@ -661,20 +668,22 @@ static struct BusInfo virtser_bus_info = {
.name = "virtio-serial-bus",
.size = sizeof(VirtIOSerialBus),
.print_dev = virtser_bus_dev_print,
+ .props = (Property[]) {
+ DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
+ DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
+ DEFINE_PROP_END_OF_LIST()
+ }
};
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
- monitor_printf(mon, "%*s dev-prop-int: id: %u\n",
- indent, "", port->id);
- monitor_printf(mon, "%*s dev-prop-int: guest_connected: %d\n",
- indent, "", port->guest_connected);
- monitor_printf(mon, "%*s dev-prop-int: host_connected: %d\n",
- indent, "", port->host_connected);
- monitor_printf(mon, "%*s dev-prop-int: throttled: %d\n",
- indent, "", port->throttled);
+ monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
+ indent, "", port->id,
+ port->guest_connected ? "on" : "off",
+ port->host_connected ? "on" : "off",
+ port->throttled ? "on" : "off");
}
/* This function is only used if a port id is not provided by the user */
diff --git a/hw/virtio.h b/hw/virtio.h
index 0fd0bb0ac5..c1292647fe 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -213,6 +213,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
void virtio_net_exit(VirtIODevice *vdev);
void virtio_blk_exit(VirtIODevice *vdev);
void virtio_serial_exit(VirtIODevice *vdev);
+void virtio_balloon_exit(VirtIODevice *vdev);
#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
DEFINE_PROP_BIT("indirect_desc", _state, _field, \
diff --git a/hw/xen.h b/hw/xen.h
index d435ca0ce5..21621115e4 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -24,22 +24,13 @@ extern int xen_allowed;
static inline int xen_enabled(void)
{
-#ifdef CONFIG_XEN
+#if defined(CONFIG_XEN_BACKEND) && !defined(CONFIG_NO_XEN)
return xen_allowed;
#else
return 0;
#endif
}
-static inline int xen_mapcache_enabled(void)
-{
-#ifdef CONFIG_XEN_MAPCACHE
- return xen_enabled();
-#else
- return 0;
-#endif
-}
-
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
void xen_piix3_set_irq(void *opaque, int irq_num, int level);
void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
@@ -50,6 +41,7 @@ qemu_irq *xen_interrupt_controller_init(void);
int xen_init(void);
int xen_hvm_init(void);
void xen_vcpu_init(void);
+void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size);
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 2c79af64d0..0409ac7971 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -85,6 +85,18 @@ static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid,
return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
}
+static inline struct xs_handle *xs_open(unsigned long flags)
+{
+ return xs_daemon_open();
+}
+
+static inline void xs_close(struct xs_handle *xsh)
+{
+ if (xsh != NULL) {
+ xs_daemon_close(xsh);
+ }
+}
+
/* Xen 4.1 */
#else
diff --git a/hw/xen_console.c b/hw/xen_console.c
index c6c8163813..8ef104c9ac 100644
--- a/hw/xen_console.c
+++ b/hw/xen_console.c
@@ -179,7 +179,9 @@ static void xencons_send(struct XenConsole *con)
static int con_init(struct XenDevice *xendev)
{
struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
- char *type, *dom;
+ char *type, *dom, label[32];
+ int ret = 0;
+ const char *output;
/* setup */
dom = xs_get_domain_path(xenstore, con->xendev.dom);
@@ -189,16 +191,25 @@ static int con_init(struct XenDevice *xendev)
type = xenstore_read_str(con->console, "type");
if (!type || strcmp(type, "ioemu") != 0) {
xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
- return -1;
+ ret = -1;
+ goto out;
}
- if (!serial_hds[con->xendev.dev])
- xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
- con->xendev.dev);
- else
+ output = xenstore_read_str(con->console, "output");
+
+ /* no Xen override, use qemu output device */
+ if (output == NULL) {
con->chr = serial_hds[con->xendev.dev];
+ } else {
+ snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
+ con->chr = qemu_chr_open(label, output, NULL);
+ }
- return 0;
+ xenstore_store_pv_console_info(con->xendev.dev, con->chr);
+
+out:
+ qemu_free(type);
+ return ret;
}
static int con_connect(struct XenDevice *xendev)
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index 3a9215566d..6926c54f4f 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -126,8 +126,8 @@ int xen_config_dev_nic(NICInfo *nic)
char mac[20];
snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
- nic->macaddr[0], nic->macaddr[1], nic->macaddr[2],
- nic->macaddr[3], nic->macaddr[4], nic->macaddr[5]);
+ nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
+ nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", nic->vlan->id, mac);
xen_config_dev_dirs("vif", "qnic", nic->vlan->id, fe, be, sizeof(fe));
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 0c298afa8d..add815f273 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -616,12 +616,14 @@ static int blk_init(struct XenDevice *xendev)
{
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
int index, qflags, have_barriers, info = 0;
- char *h;
/* read xenstore entries */
if (blkdev->params == NULL) {
+ char *h = NULL;
blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
- h = strchr(blkdev->params, ':');
+ if (blkdev->params != NULL) {
+ h = strchr(blkdev->params, ':');
+ }
if (h != NULL) {
blkdev->fileproto = blkdev->params;
blkdev->filename = h+1;
@@ -631,6 +633,9 @@ static int blk_init(struct XenDevice *xendev)
blkdev->filename = blkdev->params;
}
}
+ if (!strcmp("aio", blkdev->fileproto)) {
+ blkdev->fileproto = "raw";
+ }
if (blkdev->mode == NULL) {
blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
}
@@ -649,7 +654,7 @@ static int blk_init(struct XenDevice *xendev)
blkdev->mode == NULL ||
blkdev->type == NULL ||
blkdev->dev == NULL) {
- return -1;
+ goto out_error;
}
/* read-only ? */
@@ -672,10 +677,15 @@ static int blk_init(struct XenDevice *xendev)
/* setup via xenbus -> create new block driver instance */
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
blkdev->bs = bdrv_new(blkdev->dev);
- if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
- bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
- bdrv_delete(blkdev->bs);
- return -1;
+ if (blkdev->bs) {
+ if (bdrv_open(blkdev->bs, blkdev->filename, qflags,
+ bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
+ bdrv_delete(blkdev->bs);
+ blkdev->bs = NULL;
+ }
+ }
+ if (!blkdev->bs) {
+ goto out_error;
}
} else {
/* setup via qemu cmdline -> already setup for us */
@@ -704,6 +714,19 @@ static int blk_init(struct XenDevice *xendev)
xenstore_write_be_int(&blkdev->xendev, "sectors",
blkdev->file_size / blkdev->file_blk);
return 0;
+
+out_error:
+ qemu_free(blkdev->params);
+ blkdev->params = NULL;
+ qemu_free(blkdev->mode);
+ blkdev->mode = NULL;
+ qemu_free(blkdev->type);
+ blkdev->type = NULL;
+ qemu_free(blkdev->dev);
+ blkdev->dev = NULL;
+ qemu_free(blkdev->devtype);
+ blkdev->devtype = NULL;
+ return -1;
}
static int blk_connect(struct XenDevice *xendev)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index f43e175b4e..fb6be6a464 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -76,6 +76,35 @@ static void log_writeb(PCIXenPlatformState *s, char val)
}
/* Xen Platform, Fixed IOPort */
+#define UNPLUG_ALL_IDE_DISKS 1
+#define UNPLUG_ALL_NICS 2
+#define UNPLUG_AUX_IDE_DISKS 4
+
+static void unplug_nic(PCIBus *b, PCIDevice *d)
+{
+ if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
+ PCI_CLASS_NETWORK_ETHERNET) {
+ qdev_unplug(&(d->qdev));
+ }
+}
+
+static void pci_unplug_nics(PCIBus *bus)
+{
+ pci_for_each_device(bus, 0, unplug_nic);
+}
+
+static void unplug_disks(PCIBus *b, PCIDevice *d)
+{
+ if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
+ PCI_CLASS_STORAGE_IDE) {
+ qdev_unplug(&(d->qdev));
+ }
+}
+
+static void pci_unplug_disks(PCIBus *bus)
+{
+ pci_for_each_device(bus, 0, unplug_disks);
+}
static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
@@ -83,10 +112,22 @@ static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t v
switch (addr - XEN_PLATFORM_IOPORT) {
case 0:
- /* TODO: */
/* Unplug devices. Value is a bitmask of which devices to
unplug, with bit 0 the IDE devices, bit 1 the network
devices, and bit 2 the non-primary-master IDE devices. */
+ if (val & UNPLUG_ALL_IDE_DISKS) {
+ DPRINTF("unplug disks\n");
+ qemu_aio_flush();
+ bdrv_flush_all();
+ pci_unplug_disks(s->pci_dev.bus);
+ }
+ if (val & UNPLUG_ALL_NICS) {
+ DPRINTF("unplug nics\n");
+ pci_unplug_nics(s->pci_dev.bus);
+ }
+ if (val & UNPLUG_AUX_IDE_DISKS) {
+ DPRINTF("unplug auxiliary disks not supported\n");
+ }
break;
case 2:
switch (val) {
diff --git a/hw/xenfb.c b/hw/xenfb.c
index 1db75fbe49..0a01ae30cc 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -347,13 +347,6 @@ static void xenfb_mouse_event(void *opaque,
static int input_init(struct XenDevice *xendev)
{
- struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-
- if (!in->c.ds) {
- xen_be_printf(xendev, 1, "ds not set (yet)\n");
- return -1;
- }
-
xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
return 0;
}
@@ -367,6 +360,18 @@ static int input_connect(struct XenDevice *xendev)
&in->abs_pointer_wanted) == -1)
in->abs_pointer_wanted = 0;
+ if (!in->c.ds) {
+ char *vfb = xenstore_read_str(NULL, "device/vfb");
+ if (vfb == NULL) {
+ /* there is no vfb, run vkbd on its own */
+ in->c.ds = get_displaystate();
+ } else {
+ qemu_free(vfb);
+ xen_be_printf(xendev, 1, "ds not set (yet)\n");
+ return -1;
+ }
+ }
+
rc = common_bind(&in->c);
if (rc != 0)
return rc;
diff --git a/hw/z2.c b/hw/z2.c
new file mode 100644
index 0000000000..f93a1bf0fe
--- /dev/null
+++ b/hw/z2.c
@@ -0,0 +1,358 @@
+/*
+ * PXA270-based Zipit Z2 device
+ *
+ * Copyright (c) 2011 by Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Code is based on mainstone platform.
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "hw.h"
+#include "pxa.h"
+#include "arm-misc.h"
+#include "devices.h"
+#include "i2c.h"
+#include "ssi.h"
+#include "boards.h"
+#include "sysemu.h"
+#include "flash.h"
+#include "blockdev.h"
+#include "console.h"
+#include "audio/audio.h"
+
+#ifdef DEBUG_Z2
+#define DPRINTF(fmt, ...) \
+ printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static struct keymap map[0x100] = {
+ [0 ... 0xff] = { -1, -1 },
+ [0x3b] = {0, 0}, /* Option = F1 */
+ [0xc8] = {0, 1}, /* Up */
+ [0xd0] = {0, 2}, /* Down */
+ [0xcb] = {0, 3}, /* Left */
+ [0xcd] = {0, 4}, /* Right */
+ [0xcf] = {0, 5}, /* End */
+ [0x0d] = {0, 6}, /* KPPLUS */
+ [0xc7] = {1, 0}, /* Home */
+ [0x10] = {1, 1}, /* Q */
+ [0x17] = {1, 2}, /* I */
+ [0x22] = {1, 3}, /* G */
+ [0x2d] = {1, 4}, /* X */
+ [0x1c] = {1, 5}, /* Enter */
+ [0x0c] = {1, 6}, /* KPMINUS */
+ [0xc9] = {2, 0}, /* PageUp */
+ [0x11] = {2, 1}, /* W */
+ [0x18] = {2, 2}, /* O */
+ [0x23] = {2, 3}, /* H */
+ [0x2e] = {2, 4}, /* C */
+ [0x38] = {2, 5}, /* LeftAlt */
+ [0xd1] = {3, 0}, /* PageDown */
+ [0x12] = {3, 1}, /* E */
+ [0x19] = {3, 2}, /* P */
+ [0x24] = {3, 3}, /* J */
+ [0x2f] = {3, 4}, /* V */
+ [0x2a] = {3, 5}, /* LeftShift */
+ [0x01] = {4, 0}, /* Esc */
+ [0x13] = {4, 1}, /* R */
+ [0x1e] = {4, 2}, /* A */
+ [0x25] = {4, 3}, /* K */
+ [0x30] = {4, 4}, /* B */
+ [0x1d] = {4, 5}, /* LeftCtrl */
+ [0x0f] = {5, 0}, /* Tab */
+ [0x14] = {5, 1}, /* T */
+ [0x1f] = {5, 2}, /* S */
+ [0x26] = {5, 3}, /* L */
+ [0x31] = {5, 4}, /* N */
+ [0x39] = {5, 5}, /* Space */
+ [0x3c] = {6, 0}, /* Stop = F2 */
+ [0x15] = {6, 1}, /* Y */
+ [0x20] = {6, 2}, /* D */
+ [0x0e] = {6, 3}, /* Backspace */
+ [0x32] = {6, 4}, /* M */
+ [0x33] = {6, 5}, /* Comma */
+ [0x3d] = {7, 0}, /* Play = F3 */
+ [0x16] = {7, 1}, /* U */
+ [0x21] = {7, 2}, /* F */
+ [0x2c] = {7, 3}, /* Z */
+ [0x27] = {7, 4}, /* Semicolon */
+ [0x34] = {7, 5}, /* Dot */
+};
+
+#define Z2_RAM_SIZE 0x02000000
+#define Z2_FLASH_BASE 0x00000000
+#define Z2_FLASH_SIZE 0x00800000
+
+static struct arm_boot_info z2_binfo = {
+ .loader_start = PXA2XX_SDRAM_BASE,
+ .ram_size = Z2_RAM_SIZE,
+};
+
+#define Z2_GPIO_SD_DETECT 96
+#define Z2_GPIO_AC_IN 0
+#define Z2_GPIO_KEY_ON 1
+#define Z2_GPIO_LCD_CS 88
+
+typedef struct {
+ SSISlave ssidev;
+ int32_t selected;
+ int32_t enabled;
+ uint8_t buf[3];
+ uint32_t cur_reg;
+ int pos;
+} ZipitLCD;
+
+static uint32_t zipit_lcd_transfer(SSISlave *dev, uint32_t value)
+{
+ ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+ uint16_t val;
+ if (z->selected) {
+ z->buf[z->pos] = value & 0xff;
+ z->pos++;
+ }
+ if (z->pos == 3) {
+ switch (z->buf[0]) {
+ case 0x74:
+ DPRINTF("%s: reg: 0x%.2x\n", __func__, z->buf[2]);
+ z->cur_reg = z->buf[2];
+ break;
+ case 0x76:
+ val = z->buf[1] << 8 | z->buf[2];
+ DPRINTF("%s: value: 0x%.4x\n", __func__, val);
+ if (z->cur_reg == 0x22 && val == 0x0000) {
+ z->enabled = 1;
+ printf("%s: LCD enabled\n", __func__);
+ } else if (z->cur_reg == 0x10 && val == 0x0000) {
+ z->enabled = 0;
+ printf("%s: LCD disabled\n", __func__);
+ }
+ break;
+ default:
+ DPRINTF("%s: unknown command!\n", __func__);
+ break;
+ }
+ z->pos = 0;
+ }
+ return 0;
+}
+
+static void z2_lcd_cs(void *opaque, int line, int level)
+{
+ ZipitLCD *z2_lcd = opaque;
+ z2_lcd->selected = !level;
+}
+
+static int zipit_lcd_init(SSISlave *dev)
+{
+ ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
+ z->selected = 0;
+ z->enabled = 0;
+ z->pos = 0;
+
+ return 0;
+}
+
+static VMStateDescription vmstate_zipit_lcd_state = {
+ .name = "zipit-lcd",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(selected, ZipitLCD),
+ VMSTATE_INT32(enabled, ZipitLCD),
+ VMSTATE_BUFFER(buf, ZipitLCD),
+ VMSTATE_UINT32(cur_reg, ZipitLCD),
+ VMSTATE_INT32(pos, ZipitLCD),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static SSISlaveInfo zipit_lcd_info = {
+ .qdev.name = "zipit-lcd",
+ .qdev.size = sizeof(ZipitLCD),
+ .qdev.vmsd = &vmstate_zipit_lcd_state,
+ .init = zipit_lcd_init,
+ .transfer = zipit_lcd_transfer
+};
+
+typedef struct {
+ i2c_slave i2c;
+ int len;
+ uint8_t buf[3];
+} AER915State;
+
+static int aer915_send(i2c_slave *i2c, uint8_t data)
+{
+ AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
+ s->buf[s->len] = data;
+ if (s->len++ > 2) {
+ DPRINTF("%s: message too long (%i bytes)\n",
+ __func__, s->len);
+ return 1;
+ }
+
+ if (s->len == 2) {
+ DPRINTF("%s: reg %d value 0x%02x\n", __func__,
+ s->buf[0], s->buf[1]);
+ }
+
+ return 0;
+}
+
+static void aer915_event(i2c_slave *i2c, enum i2c_event event)
+{
+ AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
+ switch (event) {
+ case I2C_START_SEND:
+ s->len = 0;
+ break;
+ case I2C_START_RECV:
+ if (s->len != 1) {
+ DPRINTF("%s: short message!?\n", __func__);
+ }
+ break;
+ case I2C_FINISH:
+ break;
+ default:
+ break;
+ }
+}
+
+static int aer915_recv(i2c_slave *slave)
+{
+ int retval = 0x00;
+ AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
+
+ switch (s->buf[0]) {
+ /* Return hardcoded battery voltage,
+ * 0xf0 means ~4.1V
+ */
+ case 0x02:
+ retval = 0xf0;
+ break;
+ /* Return 0x00 for other regs,
+ * we don't know what they are for,
+ * anyway they return 0x00 on real hardware.
+ */
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+static int aer915_init(i2c_slave *i2c)
+{
+ /* Nothing to do. */
+ return 0;
+}
+
+static VMStateDescription vmstate_aer915_state = {
+ .name = "aer915",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(len, AER915State),
+ VMSTATE_BUFFER(buf, AER915State),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static I2CSlaveInfo aer915_info = {
+ .qdev.name = "aer915",
+ .qdev.size = sizeof(AER915State),
+ .qdev.vmsd = &vmstate_aer915_state,
+ .init = aer915_init,
+ .event = aer915_event,
+ .recv = aer915_recv,
+ .send = aer915_send
+};
+
+static void z2_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)
+{
+ uint32_t sector_len = 0x10000;
+ PXA2xxState *cpu;
+ DriveInfo *dinfo;
+ int be;
+ void *z2_lcd;
+ i2c_bus *bus;
+ DeviceState *wm;
+
+ if (!cpu_model) {
+ cpu_model = "pxa270-c5";
+ }
+
+ /* Setup CPU & memory */
+ cpu = pxa270_init(z2_binfo.ram_size, cpu_model);
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ be = 1;
+#else
+ be = 0;
+#endif
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (!dinfo) {
+ fprintf(stderr, "Flash image must be given with the "
+ "'pflash' parameter\n");
+ exit(1);
+ }
+
+ if (!pflash_cfi01_register(Z2_FLASH_BASE,
+ qemu_ram_alloc(NULL, "z2.flash0", Z2_FLASH_SIZE),
+ dinfo->bdrv, sector_len,
+ Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
+ be)) {
+ fprintf(stderr, "qemu: Error registering flash memory.\n");
+ exit(1);
+ }
+
+ /* setup keypad */
+ pxa27x_register_keypad(cpu->kp, map, 0x100);
+
+ /* MMC/SD host */
+ pxa2xx_mmci_handlers(cpu->mmc,
+ NULL,
+ qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT));
+
+ ssi_register_slave(&zipit_lcd_info);
+ i2c_register_slave(&aer915_info);
+ z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd");
+ bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+ i2c_create_slave(bus, "aer915", 0x55);
+ wm = i2c_create_slave(bus, "wm8750", 0x1b);
+ cpu->i2s->opaque = wm;
+ cpu->i2s->codec_out = wm8750_dac_dat;
+ cpu->i2s->codec_in = wm8750_adc_dat;
+ wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
+
+ qdev_connect_gpio_out(cpu->gpio, Z2_GPIO_LCD_CS,
+ qemu_allocate_irqs(z2_lcd_cs, z2_lcd, 1)[0]);
+
+ if (kernel_filename) {
+ z2_binfo.kernel_filename = kernel_filename;
+ z2_binfo.kernel_cmdline = kernel_cmdline;
+ z2_binfo.initrd_filename = initrd_filename;
+ z2_binfo.board_id = 0x6dd;
+ arm_load_kernel(cpu->env, &z2_binfo);
+ }
+}
+
+static QEMUMachine z2_machine = {
+ .name = "z2",
+ .desc = "Zipit Z2 (PXA27x)",
+ .init = z2_init,
+};
+
+static void z2_machine_init(void)
+{
+ qemu_register_machine(&z2_machine);
+}
+
+machine_init(z2_machine_init);