aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/emu10k1/emufx.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-11-17 16:14:10 +0100
committerJaroslav Kysela <perex@suse.cz>2006-01-03 12:27:58 +0100
commit09668b441dacdf4640509b640ad73e24efd5204f (patch)
tree177d0548acbcca4432f82ce6f3aa397cba5ba528 /sound/pci/emu10k1/emufx.c
parentfe8be10786c040bce53c18048d75b1b23aec64ae (diff)
[ALSA] emu10k1 - Add PM support
Modules: EMU10K1/EMU10K2 driver Add PM support to emu10k1 driver. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/emu10k1/emufx.c')
-rw-r--r--sound/pci/emu10k1/emufx.c121
1 files changed, 114 insertions, 7 deletions
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index f4452c5cb4cd..a44e4fdfc025 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1071,9 +1071,6 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
u32 *gpr_map;
mm_segment_t seg;
- spin_lock_init(&emu->fx8010.irq_lock);
- INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
-
if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
(icode->gpr_map = (u_int32_t __user *)
kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
@@ -1541,9 +1538,6 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
u32 *gpr_map;
mm_segment_t seg;
- spin_lock_init(&emu->fx8010.irq_lock);
- INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
-
if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
return -ENOMEM;
if ((icode->gpr_map = (u_int32_t __user *)
@@ -2102,6 +2096,8 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
{
+ spin_lock_init(&emu->fx8010.irq_lock);
+ INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
if (emu->audigy)
return _snd_emu10k1_audigy_init_efx(emu);
else
@@ -2171,7 +2167,7 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
spin_lock_irq(&emu->emu_lock);
outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
- spin_unlock_irq(&emu->emu_lock);
+ spin_unlock_irq(&emu->emu_lock);
}
return 0;
@@ -2387,3 +2383,114 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct
*rhwdep = hw;
return 0;
}
+
+#ifdef CONFIG_PM
+int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
+{
+ int len;
+
+ len = emu->audigy ? 0x200 : 0x100;
+ emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
+ if (! emu->saved_gpr)
+ return -ENOMEM;
+ len = emu->audigy ? 0x100 : 0xa0;
+ emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
+ emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
+ if (! emu->tram_val_saved || ! emu->tram_addr_saved)
+ return -ENOMEM;
+ len = emu->audigy ? 2 * 1024 : 2 * 512;
+ emu->saved_icode = vmalloc(len * 4);
+ if (! emu->saved_icode)
+ return -ENOMEM;
+ return 0;
+}
+
+void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
+{
+ kfree(emu->saved_gpr);
+ kfree(emu->tram_val_saved);
+ kfree(emu->tram_addr_saved);
+ vfree(emu->saved_icode);
+}
+
+/*
+ * save/restore GPR, TRAM and codes
+ */
+void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
+{
+ int i, len;
+
+ len = emu->audigy ? 0x200 : 0x100;
+ for (i = 0; i < len; i++)
+ emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
+
+ len = emu->audigy ? 0x100 : 0xa0;
+ for (i = 0; i < len; i++) {
+ emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
+ emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
+ if (emu->audigy) {
+ emu->tram_addr_saved[i] >>= 12;
+ emu->tram_addr_saved[i] |=
+ snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
+ }
+ }
+
+ len = emu->audigy ? 2 * 1024 : 2 * 512;
+ for (i = 0; i < len; i++)
+ emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
+}
+
+void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
+{
+ int i, len;
+
+ /* set up TRAM */
+ if (emu->fx8010.etram_pages.bytes > 0) {
+ unsigned size, size_reg = 0;
+ size = emu->fx8010.etram_pages.bytes / 2;
+ size = (size - 1) >> 13;
+ while (size) {
+ size >>= 1;
+ size_reg++;
+ }
+ outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
+ snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
+ snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
+ outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
+ }
+
+ if (emu->audigy)
+ snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
+ else
+ snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
+
+ len = emu->audigy ? 0x200 : 0x100;
+ for (i = 0; i < len; i++)
+ snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
+
+ len = emu->audigy ? 0x100 : 0xa0;
+ for (i = 0; i < len; i++) {
+ snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
+ emu->tram_val_saved[i]);
+ if (! emu->audigy)
+ snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
+ emu->tram_addr_saved[i]);
+ else {
+ snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
+ emu->tram_addr_saved[i] << 12);
+ snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
+ emu->tram_addr_saved[i] >> 20);
+ }
+ }
+
+ len = emu->audigy ? 2 * 1024 : 2 * 512;
+ for (i = 0; i < len; i++)
+ snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
+
+ /* start FX processor when the DSP code is updated */
+ if (emu->audigy)
+ snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
+ else
+ snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
+}
+#endif