summaryrefslogtreecommitdiff
path: root/sound/pci/cs46xx/dsp_spos.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-12-22 11:00:14 +0300
committerTakashi Iwai <tiwai@suse.de>2009-12-22 11:00:14 +0300
commit41116e926cb92292fa4fcbe888ae8133fa0038e6 (patch)
treee241c705eab65745e162fda4b68a31b5c816696d /sound/pci/cs46xx/dsp_spos.c
parent8374e24c23448cabf6e78db2c83841c56c5df1e1 (diff)
downloadlinux-41116e926cb92292fa4fcbe888ae8133fa0038e6.tar.xz
ALSA: cs46xx - Fix suspend/resume with new DSP
Fix the basic suspend/resume of snd-cs46xx drivers with new DSP. References: https://bugzilla.redhat.com/show_bug.cgi?id=498287 https://bugzilla.redhat.com/show_bug.cgi?id=160751 Tested-by: Florian Zumbiehl <florz@florz.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/cs46xx/dsp_spos.c')
-rw-r--r--sound/pci/cs46xx/dsp_spos.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index f4f0c8f5dad7..3e5ca8fb519f 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -298,6 +298,9 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
if (ins->scbs[i].deleted) continue;
cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
+#ifdef CONFIG_PM
+ kfree(ins->scbs[i].data);
+#endif
}
kfree(ins->code.data);
@@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam
index = find_free_scb_index (ins);
+ memset(&ins->scbs[index], 0, sizeof(ins->scbs[index]));
strcpy(ins->scbs[index].scb_name, name);
ins->scbs[index].address = dest;
ins->scbs[index].index = index;
- ins->scbs[index].proc_info = NULL;
ins->scbs[index].ref_count = 1;
- ins->scbs[index].deleted = 0;
- spin_lock_init(&ins->scbs[index].lock);
desc = (ins->scbs + index);
ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
@@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
return desc;
}
+#define SCB_BYTES (0x10 * 4)
+
struct dsp_scb_descriptor *
cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest)
{
struct dsp_scb_descriptor * desc;
+#ifdef CONFIG_PM
+ /* copy the data for resume */
+ scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
+ if (!scb_data)
+ return NULL;
+#endif
+
desc = _map_scb (chip,name,dest);
if (desc) {
desc->data = scb_data;
_dsp_create_scb(chip,scb_data,dest);
} else {
snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
+#ifdef CONFIG_PM
+ kfree(scb_data);
+#endif
}
return desc;
@@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip)
continue;
_dsp_create_scb(chip, s->data, s->address);
}
-
+ for (i = 0; i < ins->nscb; i++) {
+ struct dsp_scb_descriptor *s = &ins->scbs[i];
+ if (s->deleted)
+ continue;
+ if (s->updated)
+ cs46xx_dsp_spos_update_scb(chip, s);
+ if (s->volume_set)
+ cs46xx_dsp_scb_set_volume(chip, s,
+ s->volume[0], s->volume[1]);
+ }
+ if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
+ cs46xx_dsp_enable_spdif_hw(chip);
+ snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2,
+ (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10);
+ if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN)
+ cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV,
+ ins->spdif_csuv_stream);
+ }
+ if (chip->dsp_spos_instance->spdif_status_in) {
+ cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005);
+ cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff);
+ }
return 0;
}
#endif