*
* Copyright (c) 2008 Jan Kiszka
*
- * This code is licenced under the GNU GPL v2.
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
*/
#include "sysbus.h"
#include "hw.h"
#define MP_AUDIO_CLOCK_24MHZ (1 << 9)
#define MP_AUDIO_MONO (1 << 14)
-#ifdef HAS_AUDIO
typedef struct mv88w8618_audio_state {
SysBusDevice busdev;
+ MemoryRegion iomem;
qemu_irq irq;
uint32_t playback_mode;
uint32_t status;
uint32_t irq_enable;
- unsigned long phys_buf;
+ uint32_t phys_buf;
uint32_t target_buffer;
- unsigned int threshold;
- unsigned int play_pos;
- unsigned int last_free;
+ uint32_t threshold;
+ uint32_t play_pos;
+ uint32_t last_free;
uint32_t clock_div;
- DeviceState *wm;
+ void *wm;
} mv88w8618_audio_state;
static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
int8_t *mem_buffer;
int pos, block_size;
- if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN))
+ if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
return;
-
- if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE)
+ }
+ if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
free_out <<= 1;
-
- if (!(s->playback_mode & MP_AUDIO_MONO))
+ }
+ if (!(s->playback_mode & MP_AUDIO_MONO)) {
free_out <<= 1;
-
+ }
block_size = s->threshold / 2;
- if (free_out - s->last_free < block_size)
+ if (free_out - s->last_free < block_size) {
return;
-
- if (block_size > 4096)
+ }
+ if (block_size > 4096) {
return;
-
+ }
cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf,
block_size);
mem_buffer = buf;
*codec_buffer++ = *(int16_t *)mem_buffer;
mem_buffer += 2;
}
- } else
+ } else {
memcpy(wm8750_dac_buffer(s->wm, block_size >> 2),
(uint32_t *)mem_buffer, block_size);
+ }
} else {
if (s->playback_mode & MP_AUDIO_MONO) {
codec_buffer = wm8750_dac_buffer(s->wm, block_size);
s->play_pos = 0;
}
- if (s->status & s->irq_enable)
+ if (s->status & s->irq_enable) {
qemu_irq_raise(s->irq);
+ }
}
static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s)
{
int rate;
- if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ)
+ if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) {
rate = 24576000 / 64; /* 24.576MHz */
- else
+ } else {
rate = 11289600 / 64; /* 11.2896MHz */
-
+ }
rate /= ((s->clock_div >> 8) & 0xff) + 1;
wm8750_set_bclk_in(s->wm, rate);
}
-static uint32_t mv88w8618_audio_read(void *opaque, target_phys_addr_t offset)
+static uint64_t mv88w8618_audio_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
{
mv88w8618_audio_state *s = opaque;
}
static void mv88w8618_audio_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
+ uint64_t value, unsigned size)
{
mv88w8618_audio_state *s = opaque;
case MP_AUDIO_IRQ_ENABLE:
s->irq_enable = value;
- if (s->status & s->irq_enable)
+ if (s->status & s->irq_enable) {
qemu_irq_raise(s->irq);
+ }
break;
case MP_AUDIO_TX_START_LO:
}
}
-static void mv88w8618_audio_reset(void *opaque)
+static void mv88w8618_audio_reset(DeviceState *d)
{
- mv88w8618_audio_state *s = opaque;
+ mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state,
+ sysbus_from_qdev(d));
s->playback_mode = 0;
s->status = 0;
s->irq_enable = 0;
+ s->clock_div = 0;
+ s->threshold = 0;
+ s->phys_buf = 0;
}
-static CPUReadMemoryFunc * const mv88w8618_audio_readfn[] = {
- mv88w8618_audio_read,
- mv88w8618_audio_read,
- mv88w8618_audio_read
-};
-
-static CPUWriteMemoryFunc * const mv88w8618_audio_writefn[] = {
- mv88w8618_audio_write,
- mv88w8618_audio_write,
- mv88w8618_audio_write
+static const MemoryRegionOps mv88w8618_audio_ops = {
+ .read = mv88w8618_audio_read,
+ .write = mv88w8618_audio_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
static int mv88w8618_audio_init(SysBusDevice *dev)
{
mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, dev);
- int iomemtype;
sysbus_init_irq(dev, &s->irq);
wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
- iomemtype = cpu_register_io_memory(mv88w8618_audio_readfn,
- mv88w8618_audio_writefn, s);
- sysbus_init_mmio(dev, MP_AUDIO_SIZE, iomemtype);
-
- qemu_register_reset(mv88w8618_audio_reset, s);
+ memory_region_init_io(&s->iomem, &mv88w8618_audio_ops, s,
+ "audio", MP_AUDIO_SIZE);
+ sysbus_init_mmio(dev, &s->iomem);
return 0;
}
-static SysBusDeviceInfo mv88w8618_audio_info = {
- .init = mv88w8618_audio_init,
- .qdev.name = "mv88w8618_audio",
- .qdev.size = sizeof(mv88w8618_audio_state),
- .qdev.props = (Property[]) {
- {
- .name = "wm8750",
- .info = &qdev_prop_ptr,
- .offset = offsetof(mv88w8618_audio_state, wm),
- },
- {/* end of list */}
+static const VMStateDescription mv88w8618_audio_vmsd = {
+ .name = "mv88w8618_audio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
+ VMSTATE_UINT32(status, mv88w8618_audio_state),
+ VMSTATE_UINT32(irq_enable, mv88w8618_audio_state),
+ VMSTATE_UINT32(phys_buf, mv88w8618_audio_state),
+ VMSTATE_UINT32(target_buffer, mv88w8618_audio_state),
+ VMSTATE_UINT32(threshold, mv88w8618_audio_state),
+ VMSTATE_UINT32(play_pos, mv88w8618_audio_state),
+ VMSTATE_UINT32(last_free, mv88w8618_audio_state),
+ VMSTATE_UINT32(clock_div, mv88w8618_audio_state),
+ VMSTATE_END_OF_LIST()
}
};
-#endif
-static void mv88w8618_register_devices(void)
+static Property mv88w8618_audio_properties[] = {
+ DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
+ {/* end of list */},
+};
+
+static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_audio_init;
+ dc->reset = mv88w8618_audio_reset;
+ dc->vmsd = &mv88w8618_audio_vmsd;
+ dc->props = mv88w8618_audio_properties;
+}
+
+static TypeInfo mv88w8618_audio_info = {
+ .name = "mv88w8618_audio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_audio_state),
+ .class_init = mv88w8618_audio_class_init,
+};
+
+static void mv88w8618_register_types(void)
{
-#ifdef HAS_AUDIO
- sysbus_register_withprop(&mv88w8618_audio_info);
-#endif
+ type_register_static(&mv88w8618_audio_info);
}
-device_init(mv88w8618_register_devices)
+type_init(mv88w8618_register_types)