Signed-off-by: Patrick Jackson <patricksjack...@gmail.com> --- Makefile.target | 2 +- hw/android_arm.c | 18 +++++ hw/goldfish_device.h | 2 + hw/goldfish_switch.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 1 deletions(-) create mode 100644 hw/goldfish_switch.c
diff --git a/Makefile.target b/Makefile.target index 593594b..fbabd6d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -362,7 +362,7 @@ obj-arm-y += strongarm.o obj-arm-y += collie.o obj-arm-y += android_arm.o goldfish_device.o goldfish_interrupt.o goldfish_timer.o obj-arm-y += goldfish_tty.o goldfish_nand.o goldfish_fb.o goldfish_memlog.o -obj-arm-y += goldfish_battery.o +obj-arm-y += goldfish_battery.o goldfish_switch.o obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o diff --git a/hw/android_arm.c b/hw/android_arm.c index 3fffc93..5d8372d 100644 --- a/hw/android_arm.c +++ b/hw/android_arm.c @@ -29,6 +29,15 @@ static struct arm_boot_info info = { .board_id = 1441, }; +#define TEST_SWITCH 0 +#if TEST_SWITCH +static uint32_t switch_test_write(void *opaque, uint32_t state) +{ + goldfish_switch_set_state(opaque, state); + return state; +} +#endif + static void android_arm_init_(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -70,6 +79,15 @@ static void android_arm_init_(ram_addr_t ram_size, goldfish_battery_create(gbus); goldfish_nand_create(gbus); +#if TEST_SWITCH + { + void *sw; + sw = goldfish_switch_create(gbus, "test", NULL, NULL, 0); + goldfish_switch_set_state(sw, 1); + goldfish_switch_create(gbus, "test2", switch_test_write, sw, 1); + } +#endif + info.ram_size = ram_size; info.kernel_filename = kernel_filename; info.kernel_cmdline = kernel_cmdline; diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h index 19af64a..7e987c3 100644 --- a/hw/goldfish_device.h +++ b/hw/goldfish_device.h @@ -50,6 +50,7 @@ DeviceState *goldfish_nand_create(GoldfishBus *gbus); DeviceState *goldfish_fb_create(GoldfishBus *gbus, int id); DeviceState *goldfish_memlog_create(GoldfishBus *gbus, uint32_t base); DeviceState *goldfish_battery_create(GoldfishBus *gbus); +DeviceState *goldfish_switch_create(GoldfishBus *gbus, const char *name_dev, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id); /* Global functions provided by Goldfish devices */ void goldfish_bus_register_withprop(GoldfishDeviceInfo *info); @@ -58,6 +59,7 @@ void goldfish_device_init(DeviceState *dev, uint32_t base, uint32_t irq); void goldfish_device_set_irq(GoldfishDevice *dev, int irq, int level); void goldfish_battery_set_prop(void *opaque, int ac, int property, int value); void goldfish_battery_display(void *opaque, void (* callback)(void *data, const char* string), void *data); +void goldfish_switch_set_state(void *opaque, uint32_t state); /** TEMP FILE SUPPORT ** diff --git a/hw/goldfish_switch.c b/hw/goldfish_switch.c new file mode 100644 index 0000000..0d08e50 --- /dev/null +++ b/hw/goldfish_switch.c @@ -0,0 +1,168 @@ +/* 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 "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 +}; + + +typedef struct GoldfishSwitchDevice { + GoldfishDevice 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; +} GoldfishSwitchDevice; + +static uint32_t goldfish_switch_read(void *opaque, target_phys_addr_t offset) +{ + GoldfishSwitchDevice *s = (GoldfishSwitchDevice *)opaque; + offset -= 1024; + + //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) +{ + GoldfishSwitchDevice *s = (GoldfishSwitchDevice *)opaque; + offset -= 1026; + + //printf("goldfish_switch_read %x %x %x\n", offset, value, size); + + switch(offset) { + case SW_NAME_PTR: + cpu_memory_rw_debug(cpu_single_env, value, (void*)s->name, strlen(s->name), 1); + 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) +{ + GoldfishSwitchDevice *s = (GoldfishSwitchDevice *)opaque; + s->state_changed = 1; + s->state = state; + if(s->int_enable) + goldfish_device_set_irq(&s->dev, 0, 1); +} + +static int goldfish_switch_init(GoldfishDevice *dev) +{ + return 0; +} + +DeviceState *goldfish_switch_create(GoldfishBus *gbus, const char *name_dev, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id) +{ + DeviceState *dev; + GoldfishDevice *gdev; + GoldfishSwitchDevice *sdev; + char *name = (char *)"goldfish-switch"; + + dev = qdev_create(&gbus->bus, name); + qdev_prop_set_string(dev, "name", name); + qdev_prop_set_string(dev, "name_dev", (char *)name_dev); + qdev_prop_set_uint32(dev, "id", id); + qdev_prop_set_ptr(dev, "writeopaque", writeopaque); + qdev_init_nofail(dev); + gdev = (GoldfishDevice *)dev; + sdev = DO_UPCAST(GoldfishSwitchDevice, dev, gdev); + sdev->writefn = writefn; + + return dev; +} + +static GoldfishDeviceInfo goldfish_switch_info = { + .init = goldfish_switch_init, + .readfn = goldfish_switch_readfn, + .writefn = goldfish_switch_writefn, + .qdev.name = "goldfish-switch", + .qdev.size = sizeof(GoldfishSwitchDevice), + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("base", GoldfishDevice, base, 0), + DEFINE_PROP_UINT32("id", GoldfishDevice, id, -1), + DEFINE_PROP_UINT32("size", GoldfishDevice, size, 0x1000), + DEFINE_PROP_UINT32("irq", GoldfishDevice, irq, 0), + DEFINE_PROP_UINT32("irq_count", GoldfishDevice, irq_count, 1), + DEFINE_PROP_STRING("name", GoldfishDevice, name), + DEFINE_PROP_STRING("name_dev", GoldfishSwitchDevice, name), + DEFINE_PROP_PTR("writeopaque", GoldfishSwitchDevice, writeopaque), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +static void goldfish_switch_register(void) +{ + goldfish_bus_register_withprop(&goldfish_switch_info); +} +device_init(goldfish_switch_register); -- 1.7.4.1