#include "audiodev.h"
#include "intel-hda.h"
#include "intel-hda-defs.h"
+#include "dma.h"
/* --------------------------------------------------------------------- */
/* hda bus */
-static struct BusInfo hda_codec_bus_info = {
- .name = "HDA",
- .size = sizeof(HDACodecBus),
- .props = (Property[]) {
- DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property hda_props[] = {
+ DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static const TypeInfo hda_codec_bus_info = {
+ .name = TYPE_HDA_BUS,
+ .parent = TYPE_BUS,
+ .instance_size = sizeof(HDACodecBus),
};
void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
hda_codec_response_func response,
hda_codec_xfer_func xfer)
{
- qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL);
+ qbus_create_inplace(&bus->qbus, TYPE_HDA_BUS, dev, NULL);
bus->response = response;
bus->xfer = xfer;
}
-static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+static int hda_codec_dev_init(DeviceState *qdev)
{
HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+ HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
- dev->info = info;
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
return -1;
}
bus->next_cad = dev->cad + 1;
- return info->init(dev);
+ return cdc->init(dev);
}
static int hda_codec_dev_exit(DeviceState *qdev)
{
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
- if (dev->info->exit) {
- dev->info->exit(dev);
+ if (cdc->exit) {
+ cdc->exit(dev);
}
return 0;
}
-void hda_codec_register(HDACodecDeviceInfo *info)
-{
- info->qdev.init = hda_codec_dev_init;
- info->qdev.exit = hda_codec_dev_exit;
- info->qdev.bus_info = &hda_codec_bus_info;
- qdev_register(&info->qdev);
-}
-
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
{
- DeviceState *qdev;
+ BusChild *kid;
HDACodecDevice *cdev;
- QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+ QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->cad == cad) {
return cdev;
IntelHDAStream st[8];
/* state */
- int mmio_addr;
+ MemoryRegion mmio;
uint32_t rirb_count;
int64_t wall_base_ns;
return addr;
}
-static void stl_phys_le(target_phys_addr_t addr, uint32_t value)
-{
- uint32_t value_le = cpu_to_le32(value);
- cpu_physical_memory_write(addr, (uint8_t*)(&value_le), sizeof(value_le));
-}
-
-static uint32_t ldl_phys_le(target_phys_addr_t addr)
-{
- uint32_t value_le;
- cpu_physical_memory_read(addr, (uint8_t*)(&value_le), sizeof(value_le));
- return le32_to_cpu(value_le);
-}
-
static void intel_hda_update_int_sts(IntelHDAState *d)
{
uint32_t sts = 0;
{
uint32_t cad, nid, data;
HDACodecDevice *codec;
+ HDACodecDeviceClass *cdc;
cad = (verb >> 28) & 0x0f;
if (verb & (1 << 27)) {
dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
return -1;
}
- codec->info->command(codec, nid, data);
+ cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
+ cdc->command(codec, nid, data);
return 0;
}
rp = (d->corb_rp + 1) & 0xff;
addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
- verb = ldl_phys_le(addr + 4*rp);
+ verb = ldl_le_pci_dma(&d->pci, addr + 4*rp);
d->corb_rp = rp;
dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
ex = (solicited ? 0 : (1 << 4)) | dev->cad;
wp = (d->rirb_wp + 1) & 0xff;
addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
- stl_phys_le(addr + 8*wp, response);
- stl_phys_le(addr + 8*wp + 4, ex);
+ stl_le_pci_dma(&d->pci, addr + 8*wp, response);
+ stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex);
d->rirb_wp = wp;
dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
{
HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
- IntelHDAStream *st = NULL;
target_phys_addr_t addr;
uint32_t s, copy, left;
+ IntelHDAStream *st;
bool irq = false;
- for (s = 0; s < ARRAY_SIZE(d->st); s++) {
- if (stnr == ((d->st[s].ctl >> 20) & 0x0f)) {
- st = d->st + s;
+ st = output ? d->st + 4 : d->st;
+ for (s = 0; s < 4; s++) {
+ if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
+ st = st + s;
break;
}
}
- if (st == NULL) {
+ if (s == 4) {
return false;
}
if (st->bpl == NULL) {
dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
st->be, st->bp, st->bpl[st->be].len, copy);
- cpu_physical_memory_rw(st->bpl[st->be].addr + st->bp,
- buf, copy, !output);
+ pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output);
st->lpib += copy;
st->bp += copy;
buf += copy;
}
if (d->dp_lbase & 0x01) {
addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
- stl_phys_le(addr + 8*s, st->lpib);
+ stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib);
}
dprint(d, 3, "dma: --\n");
addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
st->bentries = st->lvi +1;
- qemu_free(st->bpl);
- st->bpl = qemu_malloc(sizeof(bpl) * st->bentries);
+ g_free(st->bpl);
+ st->bpl = g_malloc(sizeof(bpl) * st->bentries);
for (i = 0; i < st->bentries; i++, addr += 16) {
- cpu_physical_memory_read(addr, buf, 16);
+ pci_dma_read(&d->pci, addr, buf, 16);
st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf);
st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8));
st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
st->bp = 0;
}
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running)
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
{
- DeviceState *qdev;
+ BusChild *kid;
HDACodecDevice *cdev;
- QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ HDACodecDeviceClass *cdc;
+
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (cdev->info->stream) {
- cdev->info->stream(cdev, stream, running);
+ cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
+ if (cdc->stream) {
+ cdc->stream(cdev, stream, running, output);
}
}
}
static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
{
+ bool output = reg->stream >= 4;
IntelHDAStream *st = d->st + reg->stream;
if (st->ctl & 0x01) {
dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
reg->stream, stnr, st->cbl);
intel_hda_parse_bdl(d, st);
- intel_hda_notify_codecs(d, stnr, true);
+ intel_hda_notify_codecs(d, stnr, true, output);
} else {
/* stop */
dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
- intel_hda_notify_codecs(d, stnr, false);
+ intel_hda_notify_codecs(d, stnr, false, output);
}
}
intel_hda_update_irq(d);
return intel_hda_reg_read(d, reg, 0xffffffff);
}
-static CPUReadMemoryFunc * const intel_hda_mmio_read[3] = {
- intel_hda_mmio_readb,
- intel_hda_mmio_readw,
- intel_hda_mmio_readl,
-};
-
-static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
- intel_hda_mmio_writeb,
- intel_hda_mmio_writew,
- intel_hda_mmio_writel,
+static const MemoryRegionOps intel_hda_mmio_ops = {
+ .old_mmio = {
+ .read = {
+ intel_hda_mmio_readb,
+ intel_hda_mmio_readw,
+ intel_hda_mmio_readl,
+ },
+ .write = {
+ intel_hda_mmio_writeb,
+ intel_hda_mmio_writew,
+ intel_hda_mmio_writel,
+ },
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
-static void intel_hda_map(PCIDevice *pci, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
- cpu_register_physical_memory(addr, 0x4000, d->mmio_addr);
-}
-
/* --------------------------------------------------------------------- */
static void intel_hda_reset(DeviceState *dev)
{
+ BusChild *kid;
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
- DeviceState *qdev;
HDACodecDevice *cdev;
intel_hda_regs_reset(d);
- d->wall_base_ns = qemu_get_clock(vm_clock);
+ d->wall_base_ns = qemu_get_clock_ns(vm_clock);
/* reset codecs */
- QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (qdev->info->reset) {
- qdev->info->reset(qdev);
- }
+ device_reset(DEVICE(cdev));
d->state_sts |= (1 << cdev->cad);
}
intel_hda_update_irq(d);
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
uint8_t *conf = d->pci.config;
- d->name = d->pci.qdev.info->name;
+ d->name = object_get_typename(OBJECT(d));
- pci_config_set_vendor_id(conf, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(conf, 0x2668);
- pci_config_set_revision(conf, 1);
- pci_config_set_class(conf, PCI_CLASS_MULTIMEDIA_HD_AUDIO);
pci_config_set_interrupt_pin(conf, 1);
/* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
conf[0x40] = 0x01;
- d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
- intel_hda_mmio_write, d,
- DEVICE_NATIVE_ENDIAN);
- pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
- intel_hda_map);
+ memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
+ "intel-hda", 0x4000);
+ pci_register_bar(&d->pci, 0, 0, &d->mmio);
if (d->msi) {
msi_init(&d->pci, 0x50, 1, true, false);
}
{
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
- if (d->msi) {
- msi_uninit(&d->pci);
- }
- cpu_unregister_io_memory(d->mmio_addr);
+ msi_uninit(&d->pci);
+ memory_region_destroy(&d->mmio);
return 0;
}
-static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
- uint32_t val, int len)
-{
- IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
- pci_default_write_config(pci, addr, val, len);
- if (d->msi) {
- msi_write_config(pci, addr, val, len);
- }
-}
-
static int intel_hda_post_load(void *opaque, int version)
{
IntelHDAState* d = opaque;
}
};
-static PCIDeviceInfo intel_hda_info = {
- .qdev.name = "intel-hda",
- .qdev.desc = "Intel HD Audio Controller",
- .qdev.size = sizeof(IntelHDAState),
- .qdev.vmsd = &vmstate_intel_hda,
- .qdev.reset = intel_hda_reset,
- .init = intel_hda_init,
- .exit = intel_hda_exit,
- .config_write = intel_hda_write_config,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
- DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property intel_hda_properties[] = {
+ DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+ DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+ DEFINE_PROP_END_OF_LIST(),
};
-static void intel_hda_register(void)
+static void intel_hda_class_init(ObjectClass *klass, void *data)
{
- pci_qdev_register(&intel_hda_info);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = intel_hda_init;
+ k->exit = intel_hda_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = 0x2668;
+ k->revision = 1;
+ k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
+ dc->desc = "Intel HD Audio Controller";
+ dc->reset = intel_hda_reset;
+ dc->vmsd = &vmstate_intel_hda;
+ dc->props = intel_hda_properties;
}
-device_init(intel_hda_register);
+
+static TypeInfo intel_hda_info = {
+ .name = "intel-hda",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(IntelHDAState),
+ .class_init = intel_hda_class_init,
+};
+
+static void hda_codec_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = hda_codec_dev_init;
+ k->exit = hda_codec_dev_exit;
+ k->bus_type = TYPE_HDA_BUS;
+ k->props = hda_props;
+}
+
+static TypeInfo hda_codec_device_type_info = {
+ .name = TYPE_HDA_CODEC_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(HDACodecDevice),
+ .abstract = true,
+ .class_size = sizeof(HDACodecDeviceClass),
+ .class_init = hda_codec_device_class_init,
+};
+
+static void intel_hda_register_types(void)
+{
+ type_register_static(&hda_codec_bus_info);
+ type_register_static(&intel_hda_info);
+ type_register_static(&hda_codec_device_type_info);
+}
+
+type_init(intel_hda_register_types)
/*
* create intel hda controller with codec attached to it,