aboutsummaryrefslogtreecommitdiff
path: root/hw/ac97.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ac97.c')
-rw-r--r--hw/ac97.c102
1 files changed, 69 insertions, 33 deletions
diff --git a/hw/ac97.c b/hw/ac97.c
index ba4ea1e51..55c65df4f 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -158,6 +158,7 @@ typedef struct AC97LinkState {
SWVoiceIn *voice_pi;
SWVoiceOut *voice_po;
SWVoiceIn *voice_mc;
+ int invalid_freq[3];
uint8_t silence[128];
uint32_t base[2];
int bup_flag;
@@ -360,39 +361,61 @@ static void open_voice (AC97LinkState *s, int index, int freq)
as.fmt = AUD_FMT_S16;
as.endianness = 0;
- switch (index) {
- case PI_INDEX:
- s->voice_pi = AUD_open_in (
- &s->card,
- s->voice_pi,
- "ac97.pi",
- s,
- pi_callback,
- &as
- );
- break;
+ if (freq > 0) {
+ s->invalid_freq[index] = 0;
+ switch (index) {
+ case PI_INDEX:
+ s->voice_pi = AUD_open_in (
+ &s->card,
+ s->voice_pi,
+ "ac97.pi",
+ s,
+ pi_callback,
+ &as
+ );
+ break;
- case PO_INDEX:
- s->voice_po = AUD_open_out (
- &s->card,
- s->voice_po,
- "ac97.po",
- s,
- po_callback,
- &as
- );
- break;
+ case PO_INDEX:
+ s->voice_po = AUD_open_out (
+ &s->card,
+ s->voice_po,
+ "ac97.po",
+ s,
+ po_callback,
+ &as
+ );
+ break;
- case MC_INDEX:
- s->voice_mc = AUD_open_in (
- &s->card,
- s->voice_mc,
- "ac97.mc",
- s,
- mc_callback,
- &as
- );
- break;
+ case MC_INDEX:
+ s->voice_mc = AUD_open_in (
+ &s->card,
+ s->voice_mc,
+ "ac97.mc",
+ s,
+ mc_callback,
+ &as
+ );
+ break;
+ }
+ }
+ else {
+ s->invalid_freq[index] = freq;
+ switch (index) {
+ case PI_INDEX:
+ AUD_close_in (&s->card, s->voice_pi);
+ s->voice_pi = NULL;
+ break;
+
+ case PO_INDEX:
+ AUD_close_out (&s->card, s->voice_po);
+ s->voice_po = NULL;
+ break;
+
+ case MC_INDEX:
+ AUD_close_in (&s->card, s->voice_mc);
+ s->voice_mc = NULL;
+ break;
+ }
}
}
@@ -1065,6 +1088,12 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed)
AC97BusMasterRegs *r = &s->bm_regs[index];
int written = 0, stop = 0;
+ if (s->invalid_freq[index]) {
+ AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n",
+ index, s->invalid_freq[index]);
+ return;
+ }
+
if (r->sr & SR_DCH) {
if (r->cr & CR_RPBM) {
switch (index) {
@@ -1161,6 +1190,8 @@ static void ac97_save (QEMUFile *f, void *opaque)
uint8_t active[LAST_INDEX];
AC97LinkState *s = opaque;
+ pci_device_save (s->pci_dev, f);
+
qemu_put_be32s (f, &s->glob_cnt);
qemu_put_be32s (f, &s->glob_sta);
qemu_put_be32s (f, &s->cas);
@@ -1188,13 +1219,18 @@ static void ac97_save (QEMUFile *f, void *opaque)
static int ac97_load (QEMUFile *f, void *opaque, int version_id)
{
+ int ret;
size_t i;
uint8_t active[LAST_INDEX];
AC97LinkState *s = opaque;
- if (version_id != 1)
+ if (version_id != 2)
return -EINVAL;
+ ret = pci_device_load (s->pci_dev, f);
+ if (ret)
+ return ret;
+
qemu_get_be32s (f, &s->glob_cnt);
qemu_get_be32s (f, &s->glob_sta);
qemu_get_be32s (f, &s->cas);
@@ -1341,7 +1377,7 @@ int ac97_init (PCIBus *bus, AudioState *audio)
pci_register_io_region (&d->dev, 0, 256 * 4, PCI_ADDRESS_SPACE_IO, ac97_map);
pci_register_io_region (&d->dev, 1, 64 * 4, PCI_ADDRESS_SPACE_IO, ac97_map);
- register_savevm ("ac97", 0, 1, ac97_save, ac97_load, s);
+ register_savevm ("ac97", 0, 2, ac97_save, ac97_load, s);
qemu_register_reset (ac97_on_reset, s);
AUD_register_card (audio, "ac97", &s->card);
ac97_on_reset (s);