]> Git Repo - qemu.git/blobdiff - hw/ac97.c
s390: new contributions GPLv2 or later
[qemu.git] / hw / ac97.c
index 177f729d4819382727d9e2f0999c83278cb7bfb9..6c565e755c0fac1b6d10c29bf01faac3cbaa2603 100644 (file)
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -20,8 +20,8 @@
 #include "hw.h"
 #include "audiodev.h"
 #include "audio/audio.h"
-#include "pci.h"
-#include "dma.h"
+#include "pci/pci.h"
+#include "sysemu/dma.h"
 
 enum {
     AC97_Reset                     = 0x00,
@@ -54,6 +54,8 @@ enum {
     AC97_6Ch_Vol_C_LFE_Mute        = 0x36,
     AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
     AC97_Vendor_Reserved           = 0x58,
+    AC97_Sigmatel_Analog           = 0x6c, /* We emulate a Sigmatel codec */
+    AC97_Sigmatel_Dac2Invert       = 0x6e, /* We emulate a Sigmatel codec */
     AC97_Vendor_ID1                = 0x7c,
     AC97_Vendor_ID2                = 0x7e
 };
@@ -342,7 +344,7 @@ static uint16_t mixer_load (AC97LinkState *s, uint32_t i)
     uint16_t val = 0xffff;
 
     if (i + 2 > sizeof (s->mixer_data)) {
-        dolog ("mixer_store: index %d out of bounds %zd\n",
+        dolog ("mixer_load: index %d out of bounds %zd\n",
                i, sizeof (s->mixer_data));
     }
     else {
@@ -456,8 +458,7 @@ static void update_combined_volume_out (AC97LinkState *s)
 
     get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1,
                 &mute, &lvol, &rvol);
-    /* FIXME: should be 1f according to spec */
-    get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1,
+    get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1,
                 &pmute, &plvol, &prvol);
 
     mute = mute | pmute;
@@ -480,11 +481,22 @@ static void update_volume_in (AC97LinkState *s)
 
 static void set_volume (AC97LinkState *s, int index, uint32_t val)
 {
-    mixer_store (s, index, val);
-    if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) {
+    switch (index) {
+    case AC97_Master_Volume_Mute:
+        val &= 0xbf3f;
+        mixer_store (s, index, val);
         update_combined_volume_out (s);
-    } else if (index == AC97_Record_Gain_Mute) {
+        break;
+    case AC97_PCM_Out_Volume_Mute:
+        val &= 0x9f1f;
+        mixer_store (s, index, val);
+        update_combined_volume_out (s);
+        break;
+    case AC97_Record_Gain_Mute:
+        val &= 0x8f0f;
+        mixer_store (s, index, val);
         update_volume_in (s);
+        break;
     }
 }
 
@@ -503,14 +515,17 @@ static void mixer_reset (AC97LinkState *s)
     memset (s->mixer_data, 0, sizeof (s->mixer_data));
     memset (active, 0, sizeof (active));
     mixer_store (s, AC97_Reset                   , 0x0000); /* 6940 */
-    mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000);
+    mixer_store (s, AC97_Headphone_Volume_Mute   , 0x0000);
+    mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000);
+    mixer_store (s, AC97_Master_Tone_RL,           0x0000);
     mixer_store (s, AC97_PC_BEEP_Volume_Mute     , 0x0000);
-
-    mixer_store (s, AC97_Phone_Volume_Mute       , 0x8008);
-    mixer_store (s, AC97_Mic_Volume_Mute         , 0x8008);
-    mixer_store (s, AC97_CD_Volume_Mute          , 0x8808);
-    mixer_store (s, AC97_Aux_Volume_Mute         , 0x8808);
-    mixer_store (s, AC97_Record_Gain_Mic_Mute    , 0x8000);
+    mixer_store (s, AC97_Phone_Volume_Mute       , 0x0000);
+    mixer_store (s, AC97_Mic_Volume_Mute         , 0x0000);
+    mixer_store (s, AC97_Line_In_Volume_Mute     , 0x0000);
+    mixer_store (s, AC97_CD_Volume_Mute          , 0x0000);
+    mixer_store (s, AC97_Video_Volume_Mute       , 0x0000);
+    mixer_store (s, AC97_Aux_Volume_Mute         , 0x0000);
+    mixer_store (s, AC97_Record_Gain_Mic_Mute    , 0x0000);
     mixer_store (s, AC97_General_Purpose         , 0x0000);
     mixer_store (s, AC97_3D_Control              , 0x0000);
     mixer_store (s, AC97_Powerdown_Ctrl_Stat     , 0x000f);
@@ -532,7 +547,7 @@ static void mixer_reset (AC97LinkState *s)
     record_select (s, 0);
     set_volume (s, AC97_Master_Volume_Mute, 0x8000);
     set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808);
-    set_volume (s, AC97_Line_In_Volume_Mute, 0x8808);
+    set_volume (s, AC97_Record_Gain_Mute, 0x8808);
 
     reset_voices (s, active);
 }
@@ -588,14 +603,13 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
         mixer_reset (s);
         break;
     case AC97_Powerdown_Ctrl_Stat:
-        val &= ~0xf;
+        val &= ~0x800f;
         val |= mixer_load (s, index) & 0xf;
         mixer_store (s, index, val);
         break;
     case AC97_PCM_Out_Volume_Mute:
     case AC97_Master_Volume_Mute:
     case AC97_Record_Gain_Mute:
-    case AC97_Line_In_Volume_Mute:
         set_volume (s, index, val);
         break;
     case AC97_Record_Select:
@@ -657,6 +671,23 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
                     val);
         }
         break;
+    case AC97_Headphone_Volume_Mute:
+    case AC97_Master_Volume_Mono_Mute:
+    case AC97_Master_Tone_RL:
+    case AC97_PC_BEEP_Volume_Mute:
+    case AC97_Phone_Volume_Mute:
+    case AC97_Mic_Volume_Mute:
+    case AC97_Line_In_Volume_Mute:
+    case AC97_CD_Volume_Mute:
+    case AC97_Video_Volume_Mute:
+    case AC97_Aux_Volume_Mute:
+    case AC97_Record_Gain_Mic_Mute:
+    case AC97_General_Purpose:
+    case AC97_3D_Control:
+    case AC97_Sigmatel_Analog:
+    case AC97_Sigmatel_Dac2Invert:
+        /* None of the features in these regs are emulated, so they are RO */
+        break;
     default:
         dolog ("U nam writew %#x <- %#x\n", addr, val);
         mixer_store (s, index, val);
@@ -1158,8 +1189,8 @@ static int ac97_post_load (void *opaque, int version_id)
                 mixer_load (s, AC97_Master_Volume_Mute));
     set_volume (s, AC97_PCM_Out_Volume_Mute,
                 mixer_load (s, AC97_PCM_Out_Volume_Mute));
-    set_volume (s, AC97_Line_In_Volume_Mute,
-                mixer_load (s, AC97_Line_In_Volume_Mute));
+    set_volume (s, AC97_Record_Gain_Mute,
+                mixer_load (s, AC97_Record_Gain_Mute));
 
     active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
     active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
@@ -1195,32 +1226,101 @@ static const VMStateDescription vmstate_ac97 = {
     }
 };
 
-static const MemoryRegionPortio nam_portio[] = {
-    { 0, 256 * 1, 1, .read = nam_readb, },
-    { 0, 256 * 2, 2, .read = nam_readw, },
-    { 0, 256 * 4, 4, .read = nam_readl, },
-    { 0, 256 * 1, 1, .write = nam_writeb, },
-    { 0, 256 * 2, 2, .write = nam_writew, },
-    { 0, 256 * 4, 4, .write = nam_writel, },
-    PORTIO_END_OF_LIST (),
-};
+static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size)
+{
+    if ((addr / size) > 256) {
+        return -1;
+    }
+
+    switch (size) {
+    case 1:
+        return nam_readb(opaque, addr);
+    case 2:
+        return nam_readw(opaque, addr);
+    case 4:
+        return nam_readl(opaque, addr);
+    default:
+        return -1;
+    }
+}
+
+static void nam_write(void *opaque, hwaddr addr, uint64_t val,
+                      unsigned size)
+{
+    if ((addr / size) > 256) {
+        return;
+    }
+
+    switch (size) {
+    case 1:
+        nam_writeb(opaque, addr, val);
+        break;
+    case 2:
+        nam_writew(opaque, addr, val);
+        break;
+    case 4:
+        nam_writel(opaque, addr, val);
+        break;
+    }
+}
 
 static const MemoryRegionOps ac97_io_nam_ops = {
-    .old_portio = nam_portio,
+    .read = nam_read,
+    .write = nam_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static const MemoryRegionPortio nabm_portio[] = {
-    { 0, 64 * 1, 1, .read = nabm_readb, },
-    { 0, 64 * 2, 2, .read = nabm_readw, },
-    { 0, 64 * 4, 4, .read = nabm_readl, },
-    { 0, 64 * 1, 1, .write = nabm_writeb, },
-    { 0, 64 * 2, 2, .write = nabm_writew, },
-    { 0, 64 * 4, 4, .write = nabm_writel, },
-    PORTIO_END_OF_LIST ()
-};
+static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size)
+{
+    if ((addr / size) > 64) {
+        return -1;
+    }
+
+    switch (size) {
+    case 1:
+        return nabm_readb(opaque, addr);
+    case 2:
+        return nabm_readw(opaque, addr);
+    case 4:
+        return nabm_readl(opaque, addr);
+    default:
+        return -1;
+    }
+}
+
+static void nabm_write(void *opaque, hwaddr addr, uint64_t val,
+                      unsigned size)
+{
+    if ((addr / size) > 64) {
+        return;
+    }
+
+    switch (size) {
+    case 1:
+        nabm_writeb(opaque, addr, val);
+        break;
+    case 2:
+        nabm_writew(opaque, addr, val);
+        break;
+    case 4:
+        nabm_writel(opaque, addr, val);
+        break;
+    }
+}
+
 
 static const MemoryRegionOps ac97_io_nabm_ops = {
-    .old_portio = nabm_portio,
+    .read = nabm_read,
+    .write = nabm_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
 static void ac97_on_reset (void *opaque)
@@ -1288,13 +1388,12 @@ static int ac97_initfn (PCIDevice *dev)
     return 0;
 }
 
-static int ac97_exitfn (PCIDevice *dev)
+static void ac97_exitfn (PCIDevice *dev)
 {
     AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
 
     memory_region_destroy (&s->io_nam);
     memory_region_destroy (&s->io_nabm);
-    return 0;
 }
 
 int ac97_init (PCIBus *bus)
@@ -1324,7 +1423,7 @@ static void ac97_class_init (ObjectClass *klass, void *data)
     dc->props = ac97_properties;
 }
 
-static TypeInfo ac97_info = {
+static const TypeInfo ac97_info = {
     .name          = "AC97",
     .parent        = TYPE_PCI_DEVICE,
     .instance_size = sizeof (AC97LinkState),
This page took 0.034694 seconds and 4 git commands to generate.