Files
qemu-ios/hw/arm/ipod_touch_sysic.c
T

130 lines
3.9 KiB
C

#include "hw/arm/ipod_touch_sysic.h"
static uint64_t ipod_touch_sysic_read(void *opaque, hwaddr addr, unsigned size)
{
IPodTouchSYSICState *s = (IPodTouchSYSICState *) opaque;
//fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr);
switch (addr) {
case POWER_ID:
return s->power_id;
case POWER_SETSTATE:
case POWER_STATE:
return s->power_state;
case 0x7a:
case 0x7c:
return 1;
case GPIO_INTLEVEL ... (GPIO_INTLEVEL + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTLEVEL) / 4;
return s->gpio_int_level[group];
}
case GPIO_INTSTAT ... (GPIO_INTSTAT + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTSTAT) / 4;
return s->gpio_int_status[group];
}
case GPIO_INTEN ... (GPIO_INTEN + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTEN) / 4;
return s->gpio_int_enabled[group];
}
case GPIO_INTTYPE ... (GPIO_INTTYPE + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTTYPE) / 4;
return s->gpio_int_type[group];
}
default:
break;
}
return 0;
}
static void ipod_touch_sysic_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
{
IPodTouchSYSICState *s = (IPodTouchSYSICState *) opaque;
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr);
switch (addr) {
case POWER_ID:
s->power_id = val;
break;
case POWER_ONCTRL:
if((val & 0x20) != 0 || (val & 0x4) != 0 || (val & POWER_ID_ADM) != 0) { break; } // make sure that we do not record the 'on' state of some devices so it appears like they are turned on immediately.
s->power_state = val;
break;
case POWER_OFFCTRL:
s->power_state = val;
break;
case GPIO_INTLEVEL ... (GPIO_INTLEVEL + (GPIO_NUMINTGROUPS - 1) * 4):
{
break;
}
case GPIO_INTSTAT ... (GPIO_INTSTAT + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTSTAT) / 4;
// acknowledge the interrupts and clear the corresponding bits
s->gpio_int_status[group] = s->gpio_int_status[group] & ~val;
qemu_irq_lower(s->gpio_irqs[group]);
break;
}
case GPIO_INTEN ... (GPIO_INTEN + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTEN) / 4;
s->gpio_int_enabled[group] = val;
break;
}
case GPIO_INTTYPE ... (GPIO_INTTYPE + (GPIO_NUMINTGROUPS - 1) * 4):
{
uint8_t group = (addr - GPIO_INTTYPE) / 4;
s->gpio_int_type[group] = val;
break;
}
default:
break;
}
}
static const MemoryRegionOps ipod_touch_sysic_ops = {
.read = ipod_touch_sysic_read,
.write = ipod_touch_sysic_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void ipod_touch_sysic_init(Object *obj)
{
IPodTouchSYSICState *s = IPOD_TOUCH_SYSIC(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
memory_region_init_io(&s->iomem, obj, &ipod_touch_sysic_ops, s, TYPE_IPOD_TOUCH_SYSIC, 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
for(int grp = 0; grp < GPIO_NUMINTGROUPS; grp++) {
sysbus_init_irq(sbd, &s->gpio_irqs[grp]);
}
}
static void ipod_touch_sysic_class_init(ObjectClass *klass, void *data)
{
}
static const TypeInfo ipod_touch_sysic_type_info = {
.name = TYPE_IPOD_TOUCH_SYSIC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IPodTouchSYSICState),
.instance_init = ipod_touch_sysic_init,
.class_init = ipod_touch_sysic_class_init,
};
static void ipod_touch_sysic_register_types(void)
{
type_register_static(&ipod_touch_sysic_type_info);
}
type_init(ipod_touch_sysic_register_types)