aboutsummaryrefslogtreecommitdiffstats
path: root/hw/goldfish_switch.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (patch)
tree550ce922ea0e125ac6a9738210ce2939bf2fe901 /hw/goldfish_switch.c
parent413f05aaf54fa08c0ae7e997327a4f4a473c0a8d (diff)
downloadexternal_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.zip
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.gz
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.bz2
Initial Contribution
Diffstat (limited to 'hw/goldfish_switch.c')
-rw-r--r--hw/goldfish_switch.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/hw/goldfish_switch.c b/hw/goldfish_switch.c
new file mode 100644
index 0000000..04fcad7
--- /dev/null
+++ b/hw/goldfish_switch.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+*/
+#include "vl.h"
+#include "goldfish_device.h"
+
+enum {
+ SW_NAME_LEN = 0x00,
+ SW_NAME_PTR = 0x04,
+ SW_FLAGS = 0x08,
+ SW_STATE = 0x0c,
+ SW_INT_STATUS = 0x10,
+ SW_INT_ENABLE = 0x14,
+
+ SW_FLAGS_OUTPUT = 1U << 0
+};
+
+
+struct switch_state {
+ struct goldfish_device dev;
+ char *name;
+ uint32_t state;
+ uint32_t state_changed : 1;
+ uint32_t int_enable : 1;
+ uint32_t (*writefn)(void *opaque, uint32_t state);
+ void *writeopaque;
+};
+
+#define GOLDFISH_SWITCH_SAVE_VERSION 1
+
+static void goldfish_switch_save(QEMUFile* f, void* opaque)
+{
+ struct switch_state* s = opaque;
+
+ qemu_put_be32(f, s->state);
+ qemu_put_byte(f, s->state_changed);
+ qemu_put_byte(f, s->int_enable);
+}
+
+static int goldfish_switch_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct switch_state* s = opaque;
+
+ if (version_id != GOLDFISH_SWITCH_SAVE_VERSION)
+ return -1;
+
+ s->state = qemu_get_be32(f);
+ s->state_changed = qemu_get_byte(f);
+ s->int_enable = qemu_get_byte(f);
+
+ return 0;
+}
+
+static uint32_t goldfish_switch_read(void *opaque, target_phys_addr_t offset)
+{
+ struct switch_state *s = (struct switch_state *)opaque;
+ offset -= s->dev.base;
+
+ //printf("goldfish_switch_read %x %x\n", offset, size);
+
+ switch (offset) {
+ case SW_NAME_LEN:
+ return strlen(s->name);
+ case SW_FLAGS:
+ return s->writefn ? SW_FLAGS_OUTPUT : 0;
+ case SW_STATE:
+ return s->state;
+ case SW_INT_STATUS:
+ if(s->state_changed && s->int_enable) {
+ s->state_changed = 0;
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ return 1;
+ }
+ return 0;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_switch_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_switch_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct switch_state *s = (struct switch_state *)opaque;
+ offset -= s->dev.base;
+
+ //printf("goldfish_switch_read %x %x %x\n", offset, value, size);
+
+ switch(offset) {
+ case SW_NAME_PTR:
+ pmemcpy(value, s->name, strlen(s->name));
+ break;
+
+ case SW_STATE:
+ if(s->writefn) {
+ uint32_t new_state;
+ new_state = s->writefn(s->writeopaque, value);
+ if(new_state != s->state) {
+ goldfish_switch_set_state(s, new_state);
+ }
+ }
+ else
+ cpu_abort (cpu_single_env, "goldfish_switch_write: write to SW_STATE on input\n");
+ break;
+
+ case SW_INT_ENABLE:
+ value &= 1;
+ if(s->state_changed && s->int_enable != value)
+ goldfish_device_set_irq(&s->dev, 0, value);
+ s->int_enable = value;
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_switch_write: Bad offset %x\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *goldfish_switch_readfn[] = {
+ goldfish_switch_read,
+ goldfish_switch_read,
+ goldfish_switch_read
+};
+
+static CPUWriteMemoryFunc *goldfish_switch_writefn[] = {
+ goldfish_switch_write,
+ goldfish_switch_write,
+ goldfish_switch_write
+};
+
+void goldfish_switch_set_state(void *opaque, uint32_t state)
+{
+ struct switch_state *s = opaque;
+ s->state_changed = 1;
+ s->state = state;
+ if(s->int_enable)
+ goldfish_device_set_irq(&s->dev, 0, 1);
+}
+
+void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id)
+{
+ int ret;
+ struct switch_state *s;
+
+ s = qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish-switch";
+ s->dev.id = id;
+ s->dev.size = 0x1000;
+ s->dev.irq_count = 1;
+ s->name = name;
+ s->writefn = writefn;
+ s->writeopaque = writeopaque;
+
+
+ ret = goldfish_device_add(&s->dev, goldfish_switch_readfn, goldfish_switch_writefn, s);
+ if(ret) {
+ qemu_free(s);
+ return NULL;
+ }
+
+ register_savevm( "goldfish_switch", 0, GOLDFISH_SWITCH_SAVE_VERSION,
+ goldfish_switch_save, goldfish_switch_load, s);
+
+ return s;
+}
+