diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-11-17 10:14:10 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:27:58 -0500 |
commit | 09668b441dacdf4640509b640ad73e24efd5204f (patch) | |
tree | 177d0548acbcca4432f82ce6f3aa397cba5ba528 /sound/pci | |
parent | fe8be10786c040bce53c18048d75b1b23aec64ae (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')
-rw-r--r-- | sound/pci/emu10k1/emu10k1.c | 144 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_main.c | 308 | ||||
-rw-r--r-- | sound/pci/emu10k1/emufx.c | 121 | ||||
-rw-r--r-- | sound/pci/emu10k1/emupcm.c | 14 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.c | 43 |
5 files changed, 462 insertions, 168 deletions
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 9be900224771..2dfa932f7825 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -125,65 +125,43 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, | |||
125 | if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], | 125 | if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], |
126 | (long)max_buffer_size[dev] * 1024 * 1024, | 126 | (long)max_buffer_size[dev] * 1024 * 1024, |
127 | enable_ir[dev], subsystem[dev], | 127 | enable_ir[dev], subsystem[dev], |
128 | &emu)) < 0) { | 128 | &emu)) < 0) |
129 | snd_card_free(card); | 129 | goto error; |
130 | return err; | 130 | card->private_data = emu; |
131 | } | 131 | if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) |
132 | if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) { | 132 | goto error; |
133 | snd_card_free(card); | 133 | if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) |
134 | return err; | 134 | goto error; |
135 | } | 135 | if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) |
136 | if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) { | 136 | goto error; |
137 | snd_card_free(card); | ||
138 | return err; | ||
139 | } | ||
140 | if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) { | ||
141 | snd_card_free(card); | ||
142 | return err; | ||
143 | } | ||
144 | /* This stores the periods table. */ | 137 | /* This stores the periods table. */ |
145 | if (emu->card_capabilities->ca0151_chip) { /* P16V */ | 138 | if (emu->card_capabilities->ca0151_chip) { /* P16V */ |
146 | if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) { | 139 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), |
147 | snd_p16v_free(emu); | 140 | 1024, &emu->p16v_buffer)) < 0) |
148 | return -ENOMEM; | 141 | goto error; |
149 | } | ||
150 | } | 142 | } |
151 | 143 | ||
152 | if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) { | 144 | if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) |
153 | snd_card_free(card); | 145 | goto error; |
154 | return err; | ||
155 | } | ||
156 | 146 | ||
157 | if ((err = snd_emu10k1_timer(emu, 0)) < 0) { | 147 | if ((err = snd_emu10k1_timer(emu, 0)) < 0) |
158 | snd_card_free(card); | 148 | goto error; |
159 | return err; | ||
160 | } | ||
161 | 149 | ||
162 | if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) { | 150 | if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) |
163 | snd_card_free(card); | 151 | goto error; |
164 | return err; | 152 | if (emu->card_capabilities->ca0151_chip) { /* P16V */ |
165 | } | 153 | if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) |
166 | if (emu->card_capabilities->ca0151_chip) { /* P16V */ | 154 | goto error; |
167 | if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) { | ||
168 | snd_card_free(card); | ||
169 | return err; | ||
170 | } | ||
171 | } | 155 | } |
172 | if (emu->audigy) { | 156 | if (emu->audigy) { |
173 | if ((err = snd_emu10k1_audigy_midi(emu)) < 0) { | 157 | if ((err = snd_emu10k1_audigy_midi(emu)) < 0) |
174 | snd_card_free(card); | 158 | goto error; |
175 | return err; | ||
176 | } | ||
177 | } else { | 159 | } else { |
178 | if ((err = snd_emu10k1_midi(emu)) < 0) { | 160 | if ((err = snd_emu10k1_midi(emu)) < 0) |
179 | snd_card_free(card); | 161 | goto error; |
180 | return err; | ||
181 | } | ||
182 | } | ||
183 | if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0) { | ||
184 | snd_card_free(card); | ||
185 | return err; | ||
186 | } | 162 | } |
163 | if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0) | ||
164 | goto error; | ||
187 | #ifdef ENABLE_SYNTH | 165 | #ifdef ENABLE_SYNTH |
188 | if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, | 166 | if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, |
189 | sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 || | 167 | sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 || |
@@ -206,13 +184,16 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, | |||
206 | "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", | 184 | "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", |
207 | card->shortname, emu->revision, emu->serial, emu->port, emu->irq); | 185 | card->shortname, emu->revision, emu->serial, emu->port, emu->irq); |
208 | 186 | ||
209 | if ((err = snd_card_register(card)) < 0) { | 187 | if ((err = snd_card_register(card)) < 0) |
210 | snd_card_free(card); | 188 | goto error; |
211 | return err; | 189 | |
212 | } | ||
213 | pci_set_drvdata(pci, card); | 190 | pci_set_drvdata(pci, card); |
214 | dev++; | 191 | dev++; |
215 | return 0; | 192 | return 0; |
193 | |||
194 | error: | ||
195 | snd_card_free(card); | ||
196 | return err; | ||
216 | } | 197 | } |
217 | 198 | ||
218 | static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) | 199 | static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) |
@@ -221,11 +202,68 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) | |||
221 | pci_set_drvdata(pci, NULL); | 202 | pci_set_drvdata(pci, NULL); |
222 | } | 203 | } |
223 | 204 | ||
205 | |||
206 | #ifdef CONFIG_PM | ||
207 | static int snd_emu10k1_suspend(struct pci_dev *pci, pm_message_t state) | ||
208 | { | ||
209 | struct snd_card *card = pci_get_drvdata(pci); | ||
210 | struct snd_emu10k1 *emu = card->private_data; | ||
211 | |||
212 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
213 | |||
214 | snd_pcm_suspend_all(emu->pcm); | ||
215 | snd_pcm_suspend_all(emu->pcm_mic); | ||
216 | snd_pcm_suspend_all(emu->pcm_efx); | ||
217 | snd_pcm_suspend_all(emu->pcm_multi); | ||
218 | snd_pcm_suspend_all(emu->pcm_p16v); | ||
219 | |||
220 | snd_ac97_suspend(emu->ac97); | ||
221 | |||
222 | snd_emu10k1_efx_suspend(emu); | ||
223 | snd_emu10k1_suspend_regs(emu); | ||
224 | if (emu->card_capabilities->ca0151_chip) | ||
225 | snd_p16v_suspend(emu); | ||
226 | |||
227 | snd_emu10k1_done(emu); | ||
228 | |||
229 | pci_set_power_state(pci, PCI_D3hot); | ||
230 | pci_disable_device(pci); | ||
231 | pci_save_state(pci); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | int snd_emu10k1_resume(struct pci_dev *pci) | ||
236 | { | ||
237 | struct snd_card *card = pci_get_drvdata(pci); | ||
238 | struct snd_emu10k1 *emu = card->private_data; | ||
239 | |||
240 | pci_restore_state(pci); | ||
241 | pci_enable_device(pci); | ||
242 | pci_set_power_state(pci, PCI_D0); | ||
243 | pci_set_master(pci); | ||
244 | |||
245 | snd_emu10k1_resume_init(emu); | ||
246 | snd_emu10k1_efx_resume(emu); | ||
247 | snd_ac97_resume(emu->ac97); | ||
248 | snd_emu10k1_resume_regs(emu); | ||
249 | |||
250 | if (emu->card_capabilities->ca0151_chip) | ||
251 | snd_p16v_resume(emu); | ||
252 | |||
253 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
254 | return 0; | ||
255 | } | ||
256 | #endif | ||
257 | |||
224 | static struct pci_driver driver = { | 258 | static struct pci_driver driver = { |
225 | .name = "EMU10K1_Audigy", | 259 | .name = "EMU10K1_Audigy", |
226 | .id_table = snd_emu10k1_ids, | 260 | .id_table = snd_emu10k1_ids, |
227 | .probe = snd_card_emu10k1_probe, | 261 | .probe = snd_card_emu10k1_probe, |
228 | .remove = __devexit_p(snd_card_emu10k1_remove), | 262 | .remove = __devexit_p(snd_card_emu10k1_remove), |
263 | #ifdef CONFIG_PM | ||
264 | .suspend = snd_emu10k1_suspend, | ||
265 | .resume = snd_emu10k1_resume, | ||
266 | #endif | ||
229 | }; | 267 | }; |
230 | 268 | ||
231 | static int __init alsa_card_emu10k1_init(void) | 269 | static int __init alsa_card_emu10k1_init(void) |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index f9855073a0a9..cc36b748d9a5 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -42,12 +42,6 @@ | |||
42 | #include "p16v.h" | 42 | #include "p16v.h" |
43 | #include "tina2.h" | 43 | #include "tina2.h" |
44 | 44 | ||
45 | #if 0 | ||
46 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Creative Labs, Inc."); | ||
47 | MODULE_DESCRIPTION("Routines for control of EMU10K1 chips"); | ||
48 | MODULE_LICENSE("GPL"); | ||
49 | #endif | ||
50 | |||
51 | /************************************************************************* | 45 | /************************************************************************* |
52 | * EMU10K1 init / done | 46 | * EMU10K1 init / done |
53 | *************************************************************************/ | 47 | *************************************************************************/ |
@@ -97,17 +91,14 @@ void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int ch) | |||
97 | } | 91 | } |
98 | } | 92 | } |
99 | 93 | ||
100 | static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir) | 94 | static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) |
101 | { | 95 | { |
102 | int ch, idx, err; | ||
103 | unsigned int silent_page; | 96 | unsigned int silent_page; |
104 | 97 | int ch; | |
105 | emu->fx8010.itram_size = (16 * 1024)/2; | ||
106 | emu->fx8010.etram_pages.area = NULL; | ||
107 | emu->fx8010.etram_pages.bytes = 0; | ||
108 | 98 | ||
109 | /* disable audio and lock cache */ | 99 | /* disable audio and lock cache */ |
110 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); | 100 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, |
101 | emu->port + HCFG); | ||
111 | 102 | ||
112 | /* reset recording buffers */ | 103 | /* reset recording buffers */ |
113 | snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); | 104 | snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); |
@@ -128,48 +119,17 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir) | |||
128 | /* set SPDIF bypass mode */ | 119 | /* set SPDIF bypass mode */ |
129 | snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); | 120 | snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); |
130 | /* enable rear left + rear right AC97 slots */ | 121 | /* enable rear left + rear right AC97 slots */ |
131 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT | AC97SLOT_REAR_LEFT); | 122 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT | |
123 | AC97SLOT_REAR_LEFT); | ||
132 | } | 124 | } |
133 | 125 | ||
134 | /* init envelope engine */ | 126 | /* init envelope engine */ |
135 | for (ch = 0; ch < NUM_G; ch++) { | 127 | for (ch = 0; ch < NUM_G; ch++) |
136 | emu->voices[ch].emu = emu; | ||
137 | emu->voices[ch].number = ch; | ||
138 | snd_emu10k1_voice_init(emu, ch); | 128 | snd_emu10k1_voice_init(emu, ch); |
139 | } | ||
140 | 129 | ||
141 | /* | 130 | snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0]); |
142 | * Init to 0x02109204 : | 131 | snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1]); |
143 | * Clock accuracy = 0 (1000ppm) | 132 | snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2]); |
144 | * Sample Rate = 2 (48kHz) | ||
145 | * Audio Channel = 1 (Left of 2) | ||
146 | * Source Number = 0 (Unspecified) | ||
147 | * Generation Status = 1 (Original for Cat Code 12) | ||
148 | * Cat Code = 12 (Digital Signal Mixer) | ||
149 | * Mode = 0 (Mode 0) | ||
150 | * Emphasis = 0 (None) | ||
151 | * CP = 1 (Copyright unasserted) | ||
152 | * AN = 0 (Audio data) | ||
153 | * P = 0 (Consumer) | ||
154 | */ | ||
155 | snd_emu10k1_ptr_write(emu, SPCS0, 0, | ||
156 | emu->spdif_bits[0] = | ||
157 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
158 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
159 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
160 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
161 | snd_emu10k1_ptr_write(emu, SPCS1, 0, | ||
162 | emu->spdif_bits[1] = | ||
163 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
164 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
165 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
166 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
167 | snd_emu10k1_ptr_write(emu, SPCS2, 0, | ||
168 | emu->spdif_bits[2] = | ||
169 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
170 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
171 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
172 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
173 | 133 | ||
174 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ | 134 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ |
175 | /* Hacks for Alice3 to work independent of haP16V driver */ | 135 | /* Hacks for Alice3 to work independent of haP16V driver */ |
@@ -196,7 +156,7 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir) | |||
196 | /* Hacks for Alice3 to work independent of haP16V driver */ | 156 | /* Hacks for Alice3 to work independent of haP16V driver */ |
197 | u32 tmp; | 157 | u32 tmp; |
198 | 158 | ||
199 | snd_printk(KERN_ERR "Audigy2 value:Special config.\n"); | 159 | snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); |
200 | //Setup SRCMulti_I2S SamplingRate | 160 | //Setup SRCMulti_I2S SamplingRate |
201 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | 161 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); |
202 | tmp &= 0xfffff1ff; | 162 | tmp &= 0xfffff1ff; |
@@ -221,14 +181,6 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir) | |||
221 | outl(tmp, emu->port + A_IOCFG); | 181 | outl(tmp, emu->port + A_IOCFG); |
222 | } | 182 | } |
223 | 183 | ||
224 | |||
225 | /* | ||
226 | * Clear page with silence & setup all pointers to this page | ||
227 | */ | ||
228 | memset(emu->silent_page.area, 0, PAGE_SIZE); | ||
229 | silent_page = emu->silent_page.addr << 1; | ||
230 | for (idx = 0; idx < MAXPAGES; idx++) | ||
231 | ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); | ||
232 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); | 184 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); |
233 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ | 185 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ |
234 | snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ | 186 | snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ |
@@ -287,12 +239,11 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir) | |||
287 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); | 239 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); |
288 | } | 240 | } |
289 | 241 | ||
290 | /* | 242 | return 0; |
291 | * Initialize the effect engine | 243 | } |
292 | */ | ||
293 | if ((err = snd_emu10k1_init_efx(emu)) < 0) | ||
294 | return err; | ||
295 | 244 | ||
245 | static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) | ||
246 | { | ||
296 | /* | 247 | /* |
297 | * Enable the audio bit | 248 | * Enable the audio bit |
298 | */ | 249 | */ |
@@ -335,15 +286,9 @@ static int __devinit snd_emu10k1_init(struct snd_emu10k1 * emu, int enable_ir) | |||
335 | #endif | 286 | #endif |
336 | 287 | ||
337 | snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); | 288 | snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); |
338 | |||
339 | emu->reserved_page = (struct snd_emu10k1_memblk *)snd_emu10k1_synth_alloc(emu, 4096); | ||
340 | if (emu->reserved_page) | ||
341 | emu->reserved_page->map_locked = 1; | ||
342 | |||
343 | return 0; | ||
344 | } | 289 | } |
345 | 290 | ||
346 | static int snd_emu10k1_done(struct snd_emu10k1 * emu) | 291 | int snd_emu10k1_done(struct snd_emu10k1 * emu) |
347 | { | 292 | { |
348 | int ch; | 293 | int ch; |
349 | 294 | ||
@@ -382,18 +327,10 @@ static int snd_emu10k1_done(struct snd_emu10k1 * emu) | |||
382 | snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); | 327 | snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); |
383 | snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); | 328 | snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); |
384 | 329 | ||
385 | /* remove reserved page */ | ||
386 | if (emu->reserved_page != NULL) { | ||
387 | snd_emu10k1_synth_free(emu, (struct snd_util_memblk *)emu->reserved_page); | ||
388 | emu->reserved_page = NULL; | ||
389 | } | ||
390 | |||
391 | /* disable audio and lock cache */ | 330 | /* disable audio and lock cache */ |
392 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); | 331 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); |
393 | snd_emu10k1_ptr_write(emu, PTB, 0, 0); | 332 | snd_emu10k1_ptr_write(emu, PTB, 0, 0); |
394 | 333 | ||
395 | snd_emu10k1_free_efx(emu); | ||
396 | |||
397 | return 0; | 334 | return 0; |
398 | } | 335 | } |
399 | 336 | ||
@@ -609,11 +546,22 @@ static int __devinit snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) | |||
609 | * Create the EMU10K1 instance | 546 | * Create the EMU10K1 instance |
610 | */ | 547 | */ |
611 | 548 | ||
549 | #ifdef CONFIG_PM | ||
550 | static int alloc_pm_buffer(struct snd_emu10k1 *emu); | ||
551 | static void free_pm_buffer(struct snd_emu10k1 *emu); | ||
552 | #endif | ||
553 | |||
612 | static int snd_emu10k1_free(struct snd_emu10k1 *emu) | 554 | static int snd_emu10k1_free(struct snd_emu10k1 *emu) |
613 | { | 555 | { |
614 | if (emu->port) { /* avoid access to already used hardware */ | 556 | if (emu->port) { /* avoid access to already used hardware */ |
615 | snd_emu10k1_fx8010_tram_setup(emu, 0); | 557 | snd_emu10k1_fx8010_tram_setup(emu, 0); |
616 | snd_emu10k1_done(emu); | 558 | snd_emu10k1_done(emu); |
559 | /* remove reserved page */ | ||
560 | if (emu->reserved_page) { | ||
561 | snd_emu10k1_synth_free(emu, (struct snd_util_memblk *)emu->reserved_page); | ||
562 | emu->reserved_page = NULL; | ||
563 | } | ||
564 | snd_emu10k1_free_efx(emu); | ||
617 | } | 565 | } |
618 | if (emu->memhdr) | 566 | if (emu->memhdr) |
619 | snd_util_memhdr_free(emu->memhdr); | 567 | snd_util_memhdr_free(emu->memhdr); |
@@ -623,13 +571,16 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) | |||
623 | snd_dma_free_pages(&emu->ptb_pages); | 571 | snd_dma_free_pages(&emu->ptb_pages); |
624 | vfree(emu->page_ptr_table); | 572 | vfree(emu->page_ptr_table); |
625 | vfree(emu->page_addr_table); | 573 | vfree(emu->page_addr_table); |
574 | #ifdef CONFIG_PM | ||
575 | free_pm_buffer(emu); | ||
576 | #endif | ||
626 | if (emu->irq >= 0) | 577 | if (emu->irq >= 0) |
627 | free_irq(emu->irq, (void *)emu); | 578 | free_irq(emu->irq, (void *)emu); |
628 | if (emu->port) | 579 | if (emu->port) |
629 | pci_release_regions(emu->pci); | 580 | pci_release_regions(emu->pci); |
630 | pci_disable_device(emu->pci); | ||
631 | if (emu->card_capabilities->ca0151_chip) /* P16V */ | 581 | if (emu->card_capabilities->ca0151_chip) /* P16V */ |
632 | snd_p16v_free(emu); | 582 | snd_p16v_free(emu); |
583 | pci_disable_device(emu->pci); | ||
633 | kfree(emu); | 584 | kfree(emu); |
634 | return 0; | 585 | return 0; |
635 | } | 586 | } |
@@ -900,9 +851,10 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
900 | struct snd_emu10k1 ** remu) | 851 | struct snd_emu10k1 ** remu) |
901 | { | 852 | { |
902 | struct snd_emu10k1 *emu; | 853 | struct snd_emu10k1 *emu; |
903 | int err; | 854 | int idx, err; |
904 | int is_audigy; | 855 | int is_audigy; |
905 | unsigned char revision; | 856 | unsigned char revision; |
857 | unsigned int silent_page; | ||
906 | const struct snd_emu_chip_details *c; | 858 | const struct snd_emu_chip_details *c; |
907 | static struct snd_device_ops ops = { | 859 | static struct snd_device_ops ops = { |
908 | .dev_free = snd_emu10k1_dev_free, | 860 | .dev_free = snd_emu10k1_dev_free, |
@@ -1012,34 +964,34 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1012 | emu->port = pci_resource_start(pci, 0); | 964 | emu->port = pci_resource_start(pci, 0); |
1013 | 965 | ||
1014 | if (request_irq(pci->irq, snd_emu10k1_interrupt, SA_INTERRUPT|SA_SHIRQ, "EMU10K1", (void *)emu)) { | 966 | if (request_irq(pci->irq, snd_emu10k1_interrupt, SA_INTERRUPT|SA_SHIRQ, "EMU10K1", (void *)emu)) { |
1015 | snd_emu10k1_free(emu); | 967 | err = -EBUSY; |
1016 | return -EBUSY; | 968 | goto error; |
1017 | } | 969 | } |
1018 | emu->irq = pci->irq; | 970 | emu->irq = pci->irq; |
1019 | 971 | ||
1020 | emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; | 972 | emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; |
1021 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | 973 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), |
1022 | 32 * 1024, &emu->ptb_pages) < 0) { | 974 | 32 * 1024, &emu->ptb_pages) < 0) { |
1023 | snd_emu10k1_free(emu); | 975 | err = -ENOMEM; |
1024 | return -ENOMEM; | 976 | goto error; |
1025 | } | 977 | } |
1026 | 978 | ||
1027 | emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*)); | 979 | emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*)); |
1028 | emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long)); | 980 | emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long)); |
1029 | if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) { | 981 | if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) { |
1030 | snd_emu10k1_free(emu); | 982 | err = -ENOMEM; |
1031 | return -ENOMEM; | 983 | goto error; |
1032 | } | 984 | } |
1033 | 985 | ||
1034 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | 986 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), |
1035 | EMUPAGESIZE, &emu->silent_page) < 0) { | 987 | EMUPAGESIZE, &emu->silent_page) < 0) { |
1036 | snd_emu10k1_free(emu); | 988 | err = -ENOMEM; |
1037 | return -ENOMEM; | 989 | goto error; |
1038 | } | 990 | } |
1039 | emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE); | 991 | emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE); |
1040 | if (emu->memhdr == NULL) { | 992 | if (emu->memhdr == NULL) { |
1041 | snd_emu10k1_free(emu); | 993 | err = -ENOMEM; |
1042 | return -ENOMEM; | 994 | goto error; |
1043 | } | 995 | } |
1044 | emu->memhdr->block_extra_size = sizeof(struct snd_emu10k1_memblk) - | 996 | emu->memhdr->block_extra_size = sizeof(struct snd_emu10k1_memblk) - |
1045 | sizeof(struct snd_util_memblk); | 997 | sizeof(struct snd_util_memblk); |
@@ -1053,40 +1005,184 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1053 | extout_mask = 0x7fff; | 1005 | extout_mask = 0x7fff; |
1054 | emu->fx8010.extin_mask = extin_mask; | 1006 | emu->fx8010.extin_mask = extin_mask; |
1055 | emu->fx8010.extout_mask = extout_mask; | 1007 | emu->fx8010.extout_mask = extout_mask; |
1008 | emu->enable_ir = enable_ir; | ||
1056 | 1009 | ||
1057 | if (emu->card_capabilities->ecard) { | 1010 | if (emu->card_capabilities->ecard) { |
1058 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) { | 1011 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) |
1059 | snd_emu10k1_free(emu); | 1012 | goto error; |
1060 | return err; | ||
1061 | } | ||
1062 | } else if (emu->card_capabilities->ca_cardbus_chip) { | 1013 | } else if (emu->card_capabilities->ca_cardbus_chip) { |
1063 | if ((err = snd_emu10k1_cardbus_init(emu)) < 0) { | 1014 | if ((err = snd_emu10k1_cardbus_init(emu)) < 0) |
1064 | snd_emu10k1_free(emu); | 1015 | goto error; |
1065 | return err; | ||
1066 | } | ||
1067 | } else { | 1016 | } else { |
1068 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version | 1017 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version |
1069 | does not support this, it shouldn't do any harm */ | 1018 | does not support this, it shouldn't do any harm */ |
1070 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); | 1019 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); |
1071 | } | 1020 | } |
1072 | 1021 | ||
1073 | if ((err = snd_emu10k1_init(emu, enable_ir)) < 0) { | 1022 | /* initialize TRAM setup */ |
1074 | snd_emu10k1_free(emu); | 1023 | emu->fx8010.itram_size = (16 * 1024)/2; |
1075 | return err; | 1024 | emu->fx8010.etram_pages.area = NULL; |
1076 | } | 1025 | emu->fx8010.etram_pages.bytes = 0; |
1077 | 1026 | ||
1078 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) { | 1027 | /* |
1079 | snd_emu10k1_free(emu); | 1028 | * Init to 0x02109204 : |
1080 | return err; | 1029 | * Clock accuracy = 0 (1000ppm) |
1030 | * Sample Rate = 2 (48kHz) | ||
1031 | * Audio Channel = 1 (Left of 2) | ||
1032 | * Source Number = 0 (Unspecified) | ||
1033 | * Generation Status = 1 (Original for Cat Code 12) | ||
1034 | * Cat Code = 12 (Digital Signal Mixer) | ||
1035 | * Mode = 0 (Mode 0) | ||
1036 | * Emphasis = 0 (None) | ||
1037 | * CP = 1 (Copyright unasserted) | ||
1038 | * AN = 0 (Audio data) | ||
1039 | * P = 0 (Consumer) | ||
1040 | */ | ||
1041 | emu->spdif_bits[0] = emu->spdif_bits[1] = | ||
1042 | emu->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
1043 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
1044 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
1045 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; | ||
1046 | |||
1047 | emu->reserved_page = (struct snd_emu10k1_memblk *) | ||
1048 | snd_emu10k1_synth_alloc(emu, 4096); | ||
1049 | if (emu->reserved_page) | ||
1050 | emu->reserved_page->map_locked = 1; | ||
1051 | |||
1052 | /* Clear silent pages and set up pointers */ | ||
1053 | memset(emu->silent_page.area, 0, PAGE_SIZE); | ||
1054 | silent_page = emu->silent_page.addr << 1; | ||
1055 | for (idx = 0; idx < MAXPAGES; idx++) | ||
1056 | ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); | ||
1057 | |||
1058 | /* set up voice indices */ | ||
1059 | for (idx = 0; idx < NUM_G; idx++) { | ||
1060 | emu->voices[idx].emu = emu; | ||
1061 | emu->voices[idx].number = idx; | ||
1081 | } | 1062 | } |
1082 | 1063 | ||
1064 | if ((err = snd_emu10k1_init(emu, enable_ir, 0)) < 0) | ||
1065 | goto error; | ||
1066 | #ifdef CONFIG_PM | ||
1067 | if ((err = alloc_pm_buffer(emu)) < 0) | ||
1068 | goto error; | ||
1069 | #endif | ||
1070 | |||
1071 | /* Initialize the effect engine */ | ||
1072 | if ((err = snd_emu10k1_init_efx(emu)) < 0) | ||
1073 | goto error; | ||
1074 | snd_emu10k1_audio_enable(emu); | ||
1075 | |||
1076 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) | ||
1077 | goto error; | ||
1078 | |||
1083 | snd_emu10k1_proc_init(emu); | 1079 | snd_emu10k1_proc_init(emu); |
1084 | 1080 | ||
1085 | snd_card_set_dev(card, &pci->dev); | 1081 | snd_card_set_dev(card, &pci->dev); |
1086 | *remu = emu; | 1082 | *remu = emu; |
1087 | return 0; | 1083 | return 0; |
1084 | |||
1085 | error: | ||
1086 | snd_emu10k1_free(emu); | ||
1087 | return err; | ||
1088 | } | 1088 | } |
1089 | 1089 | ||
1090 | #ifdef CONFIG_PM | ||
1091 | static unsigned char saved_regs[] = { | ||
1092 | CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP, | ||
1093 | FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL, | ||
1094 | ATKHLDM, DCYSUSM, LFOVAL2, IP, IFATN, PEFE, FMMOD, TREMFRQ, FM2FRQ2, | ||
1095 | TEMPENV, ADCCR, FXWC, MICBA, ADCBA, FXBA, | ||
1096 | MICBS, ADCBS, FXBS, CDCS, GPSCS, SPCS0, SPCS1, SPCS2, | ||
1097 | SPBYPASS, AC97SLOT, CDSRCS, GPSRCS, ZVSRCS, MICIDX, ADCIDX, FXIDX, | ||
1098 | 0xff /* end */ | ||
1099 | }; | ||
1100 | static unsigned char saved_regs_audigy[] = { | ||
1101 | A_ADCIDX, A_MICIDX, A_FXWC1, A_FXWC2, A_SAMPLE_RATE, | ||
1102 | A_FXRT2, A_SENDAMOUNTS, A_FXRT1, | ||
1103 | 0xff /* end */ | ||
1104 | }; | ||
1105 | |||
1106 | static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu) | ||
1107 | { | ||
1108 | int size; | ||
1109 | |||
1110 | size = ARRAY_SIZE(saved_regs); | ||
1111 | if (emu->audigy) | ||
1112 | size += ARRAY_SIZE(saved_regs_audigy); | ||
1113 | emu->saved_ptr = vmalloc(4 * NUM_G * size); | ||
1114 | if (! emu->saved_ptr) | ||
1115 | return -ENOMEM; | ||
1116 | if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0) | ||
1117 | return -ENOMEM; | ||
1118 | if (emu->card_capabilities->ca0151_chip && | ||
1119 | snd_p16v_alloc_pm_buffer(emu) < 0) | ||
1120 | return -ENOMEM; | ||
1121 | return 0; | ||
1122 | } | ||
1123 | |||
1124 | static void free_pm_buffer(struct snd_emu10k1 *emu) | ||
1125 | { | ||
1126 | vfree(emu->saved_ptr); | ||
1127 | snd_emu10k1_efx_free_pm_buffer(emu); | ||
1128 | if (emu->card_capabilities->ca0151_chip) | ||
1129 | snd_p16v_free_pm_buffer(emu); | ||
1130 | } | ||
1131 | |||
1132 | void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu) | ||
1133 | { | ||
1134 | int i; | ||
1135 | unsigned char *reg; | ||
1136 | unsigned int *val; | ||
1137 | |||
1138 | val = emu->saved_ptr; | ||
1139 | for (reg = saved_regs; *reg != 0xff; reg++) | ||
1140 | for (i = 0; i < NUM_G; i++, val++) | ||
1141 | *val = snd_emu10k1_ptr_read(emu, *reg, i); | ||
1142 | if (emu->audigy) { | ||
1143 | for (reg = saved_regs_audigy; *reg != 0xff; reg++) | ||
1144 | for (i = 0; i < NUM_G; i++, val++) | ||
1145 | *val = snd_emu10k1_ptr_read(emu, *reg, i); | ||
1146 | } | ||
1147 | if (emu->audigy) | ||
1148 | emu->saved_a_iocfg = inl(emu->port + A_IOCFG); | ||
1149 | emu->saved_hcfg = inl(emu->port + HCFG); | ||
1150 | } | ||
1151 | |||
1152 | void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) | ||
1153 | { | ||
1154 | if (emu->card_capabilities->ecard) | ||
1155 | snd_emu10k1_ecard_init(emu); | ||
1156 | else | ||
1157 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); | ||
1158 | snd_emu10k1_init(emu, emu->enable_ir, 1); | ||
1159 | } | ||
1160 | |||
1161 | void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu) | ||
1162 | { | ||
1163 | int i; | ||
1164 | unsigned char *reg; | ||
1165 | unsigned int *val; | ||
1166 | |||
1167 | snd_emu10k1_audio_enable(emu); | ||
1168 | |||
1169 | /* resore for spdif */ | ||
1170 | if (emu->audigy) | ||
1171 | outl(emu->port + A_IOCFG, emu->saved_a_iocfg); | ||
1172 | outl(emu->port + HCFG, emu->saved_hcfg); | ||
1173 | |||
1174 | val = emu->saved_ptr; | ||
1175 | for (reg = saved_regs; *reg != 0xff; reg++) | ||
1176 | for (i = 0; i < NUM_G; i++, val++) | ||
1177 | snd_emu10k1_ptr_write(emu, *reg, i, *val); | ||
1178 | if (emu->audigy) { | ||
1179 | for (reg = saved_regs_audigy; *reg != 0xff; reg++) | ||
1180 | for (i = 0; i < NUM_G; i++, val++) | ||
1181 | snd_emu10k1_ptr_write(emu, *reg, i, *val); | ||
1182 | } | ||
1183 | } | ||
1184 | #endif | ||
1185 | |||
1090 | /* memory.c */ | 1186 | /* memory.c */ |
1091 | EXPORT_SYMBOL(snd_emu10k1_synth_alloc); | 1187 | EXPORT_SYMBOL(snd_emu10k1_synth_alloc); |
1092 | EXPORT_SYMBOL(snd_emu10k1_synth_free); | 1188 | EXPORT_SYMBOL(snd_emu10k1_synth_free); |
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) | |||
1071 | u32 *gpr_map; | 1071 | u32 *gpr_map; |
1072 | mm_segment_t seg; | 1072 | mm_segment_t seg; |
1073 | 1073 | ||
1074 | spin_lock_init(&emu->fx8010.irq_lock); | ||
1075 | INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); | ||
1076 | |||
1077 | if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL || | 1074 | if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL || |
1078 | (icode->gpr_map = (u_int32_t __user *) | 1075 | (icode->gpr_map = (u_int32_t __user *) |
1079 | kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), | 1076 | 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) | |||
1541 | u32 *gpr_map; | 1538 | u32 *gpr_map; |
1542 | mm_segment_t seg; | 1539 | mm_segment_t seg; |
1543 | 1540 | ||
1544 | spin_lock_init(&emu->fx8010.irq_lock); | ||
1545 | INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); | ||
1546 | |||
1547 | if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL) | 1541 | if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL) |
1548 | return -ENOMEM; | 1542 | return -ENOMEM; |
1549 | if ((icode->gpr_map = (u_int32_t __user *) | 1543 | if ((icode->gpr_map = (u_int32_t __user *) |
@@ -2102,6 +2096,8 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) | |||
2102 | 2096 | ||
2103 | int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu) | 2097 | int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu) |
2104 | { | 2098 | { |
2099 | spin_lock_init(&emu->fx8010.irq_lock); | ||
2100 | INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); | ||
2105 | if (emu->audigy) | 2101 | if (emu->audigy) |
2106 | return _snd_emu10k1_audigy_init_efx(emu); | 2102 | return _snd_emu10k1_audigy_init_efx(emu); |
2107 | else | 2103 | else |
@@ -2171,7 +2167,7 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size) | |||
2171 | snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg); | 2167 | snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg); |
2172 | spin_lock_irq(&emu->emu_lock); | 2168 | spin_lock_irq(&emu->emu_lock); |
2173 | outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); | 2169 | outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); |
2174 | spin_unlock_irq(&emu->emu_lock); | 2170 | spin_unlock_irq(&emu->emu_lock); |
2175 | } | 2171 | } |
2176 | 2172 | ||
2177 | return 0; | 2173 | return 0; |
@@ -2387,3 +2383,114 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct | |||
2387 | *rhwdep = hw; | 2383 | *rhwdep = hw; |
2388 | return 0; | 2384 | return 0; |
2389 | } | 2385 | } |
2386 | |||
2387 | #ifdef CONFIG_PM | ||
2388 | int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu) | ||
2389 | { | ||
2390 | int len; | ||
2391 | |||
2392 | len = emu->audigy ? 0x200 : 0x100; | ||
2393 | emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL); | ||
2394 | if (! emu->saved_gpr) | ||
2395 | return -ENOMEM; | ||
2396 | len = emu->audigy ? 0x100 : 0xa0; | ||
2397 | emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL); | ||
2398 | emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL); | ||
2399 | if (! emu->tram_val_saved || ! emu->tram_addr_saved) | ||
2400 | return -ENOMEM; | ||
2401 | len = emu->audigy ? 2 * 1024 : 2 * 512; | ||
2402 | emu->saved_icode = vmalloc(len * 4); | ||
2403 | if (! emu->saved_icode) | ||
2404 | return -ENOMEM; | ||
2405 | return 0; | ||
2406 | } | ||
2407 | |||
2408 | void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu) | ||
2409 | { | ||
2410 | kfree(emu->saved_gpr); | ||
2411 | kfree(emu->tram_val_saved); | ||
2412 | kfree(emu->tram_addr_saved); | ||
2413 | vfree(emu->saved_icode); | ||
2414 | } | ||
2415 | |||
2416 | /* | ||
2417 | * save/restore GPR, TRAM and codes | ||
2418 | */ | ||
2419 | void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu) | ||
2420 | { | ||
2421 | int i, len; | ||
2422 | |||
2423 | len = emu->audigy ? 0x200 : 0x100; | ||
2424 | for (i = 0; i < len; i++) | ||
2425 | emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0); | ||
2426 | |||
2427 | len = emu->audigy ? 0x100 : 0xa0; | ||
2428 | for (i = 0; i < len; i++) { | ||
2429 | emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0); | ||
2430 | emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0); | ||
2431 | if (emu->audigy) { | ||
2432 | emu->tram_addr_saved[i] >>= 12; | ||
2433 | emu->tram_addr_saved[i] |= | ||
2434 | snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20; | ||
2435 | } | ||
2436 | } | ||
2437 | |||
2438 | len = emu->audigy ? 2 * 1024 : 2 * 512; | ||
2439 | for (i = 0; i < len; i++) | ||
2440 | emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i); | ||
2441 | } | ||
2442 | |||
2443 | void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu) | ||
2444 | { | ||
2445 | int i, len; | ||
2446 | |||
2447 | /* set up TRAM */ | ||
2448 | if (emu->fx8010.etram_pages.bytes > 0) { | ||
2449 | unsigned size, size_reg = 0; | ||
2450 | size = emu->fx8010.etram_pages.bytes / 2; | ||
2451 | size = (size - 1) >> 13; | ||
2452 | while (size) { | ||
2453 | size >>= 1; | ||
2454 | size_reg++; | ||
2455 | } | ||
2456 | outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG); | ||
2457 | snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr); | ||
2458 | snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg); | ||
2459 | outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); | ||
2460 | } | ||
2461 | |||
2462 | if (emu->audigy) | ||
2463 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP); | ||
2464 | else | ||
2465 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP); | ||
2466 | |||
2467 | len = emu->audigy ? 0x200 : 0x100; | ||
2468 | for (i = 0; i < len; i++) | ||
2469 | snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]); | ||
2470 | |||
2471 | len = emu->audigy ? 0x100 : 0xa0; | ||
2472 | for (i = 0; i < len; i++) { | ||
2473 | snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0, | ||
2474 | emu->tram_val_saved[i]); | ||
2475 | if (! emu->audigy) | ||
2476 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0, | ||
2477 | emu->tram_addr_saved[i]); | ||
2478 | else { | ||
2479 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0, | ||
2480 | emu->tram_addr_saved[i] << 12); | ||
2481 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0, | ||
2482 | emu->tram_addr_saved[i] >> 20); | ||
2483 | } | ||
2484 | } | ||
2485 | |||
2486 | len = emu->audigy ? 2 * 1024 : 2 * 512; | ||
2487 | for (i = 0; i < len; i++) | ||
2488 | snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]); | ||
2489 | |||
2490 | /* start FX processor when the DSP code is updated */ | ||
2491 | if (emu->audigy) | ||
2492 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg); | ||
2493 | else | ||
2494 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg); | ||
2495 | } | ||
2496 | #endif | ||
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 8e6caf581c0c..717e92ec9e0a 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -551,6 +551,7 @@ static struct snd_pcm_hardware snd_emu10k1_efx_playback = | |||
551 | { | 551 | { |
552 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED | | 552 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED | |
553 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 553 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
554 | SNDRV_PCM_INFO_RESUME | | ||
554 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), | 555 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), |
555 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 556 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
556 | .rates = SNDRV_PCM_RATE_48000, | 557 | .rates = SNDRV_PCM_RATE_48000, |
@@ -739,6 +740,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, | |||
739 | snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]); | 740 | snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]); |
740 | /* follow thru */ | 741 | /* follow thru */ |
741 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 742 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
743 | case SNDRV_PCM_TRIGGER_RESUME: | ||
742 | mix = &emu->pcm_mixer[substream->number]; | 744 | mix = &emu->pcm_mixer[substream->number]; |
743 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); | 745 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); |
744 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); | 746 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); |
@@ -750,6 +752,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, | |||
750 | break; | 752 | break; |
751 | case SNDRV_PCM_TRIGGER_STOP: | 753 | case SNDRV_PCM_TRIGGER_STOP: |
752 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 754 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
755 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
753 | epcm->running = 0; | 756 | epcm->running = 0; |
754 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]); | 757 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]); |
755 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]); | 758 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]); |
@@ -774,6 +777,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, | |||
774 | spin_lock(&emu->reg_lock); | 777 | spin_lock(&emu->reg_lock); |
775 | switch (cmd) { | 778 | switch (cmd) { |
776 | case SNDRV_PCM_TRIGGER_START: | 779 | case SNDRV_PCM_TRIGGER_START: |
780 | case SNDRV_PCM_TRIGGER_RESUME: | ||
777 | // hmm this should cause full and half full interrupt to be raised? | 781 | // hmm this should cause full and half full interrupt to be raised? |
778 | outl(epcm->capture_ipr, emu->port + IPR); | 782 | outl(epcm->capture_ipr, emu->port + IPR); |
779 | snd_emu10k1_intr_enable(emu, epcm->capture_inte); | 783 | snd_emu10k1_intr_enable(emu, epcm->capture_inte); |
@@ -797,6 +801,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, | |||
797 | epcm->first_ptr = 1; | 801 | epcm->first_ptr = 1; |
798 | break; | 802 | break; |
799 | case SNDRV_PCM_TRIGGER_STOP: | 803 | case SNDRV_PCM_TRIGGER_STOP: |
804 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
800 | epcm->running = 0; | 805 | epcm->running = 0; |
801 | snd_emu10k1_intr_disable(emu, epcm->capture_inte); | 806 | snd_emu10k1_intr_disable(emu, epcm->capture_inte); |
802 | outl(epcm->capture_ipr, emu->port + IPR); | 807 | outl(epcm->capture_ipr, emu->port + IPR); |
@@ -871,6 +876,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, | |||
871 | 876 | ||
872 | /* follow thru */ | 877 | /* follow thru */ |
873 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 878 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
879 | case SNDRV_PCM_TRIGGER_RESUME: | ||
874 | snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); | 880 | snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); |
875 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0, | 881 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0, |
876 | &emu->efx_pcm_mixer[0]); | 882 | &emu->efx_pcm_mixer[0]); |
@@ -883,6 +889,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, | |||
883 | snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0); | 889 | snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0); |
884 | epcm->running = 1; | 890 | epcm->running = 1; |
885 | break; | 891 | break; |
892 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
886 | case SNDRV_PCM_TRIGGER_STOP: | 893 | case SNDRV_PCM_TRIGGER_STOP: |
887 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 894 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
888 | epcm->running = 0; | 895 | epcm->running = 0; |
@@ -925,6 +932,7 @@ static struct snd_pcm_hardware snd_emu10k1_playback = | |||
925 | { | 932 | { |
926 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 933 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
927 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 934 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
935 | SNDRV_PCM_INFO_RESUME | | ||
928 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), | 936 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), |
929 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | 937 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, |
930 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000, | 938 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000, |
@@ -948,6 +956,7 @@ static struct snd_pcm_hardware snd_emu10k1_capture = | |||
948 | { | 956 | { |
949 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 957 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
950 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 958 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
959 | SNDRV_PCM_INFO_RESUME | | ||
951 | SNDRV_PCM_INFO_MMAP_VALID), | 960 | SNDRV_PCM_INFO_MMAP_VALID), |
952 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 961 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
953 | .rates = SNDRV_PCM_RATE_8000_48000, | 962 | .rates = SNDRV_PCM_RATE_8000_48000, |
@@ -1309,7 +1318,7 @@ int __devinit snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct | |||
1309 | pcm->info_flags = 0; | 1318 | pcm->info_flags = 0; |
1310 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | 1319 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
1311 | strcpy(pcm->name, "Multichannel Playback"); | 1320 | strcpy(pcm->name, "Multichannel Playback"); |
1312 | emu->pcm = pcm; | 1321 | emu->pcm_multi = pcm; |
1313 | 1322 | ||
1314 | for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) | 1323 | for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) |
1315 | if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) | 1324 | if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) |
@@ -1556,6 +1565,7 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre | |||
1556 | case SNDRV_PCM_TRIGGER_START: | 1565 | case SNDRV_PCM_TRIGGER_START: |
1557 | /* follow thru */ | 1566 | /* follow thru */ |
1558 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1567 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1568 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1559 | #ifdef EMU10K1_SET_AC3_IEC958 | 1569 | #ifdef EMU10K1_SET_AC3_IEC958 |
1560 | { | 1570 | { |
1561 | int i; | 1571 | int i; |
@@ -1576,6 +1586,7 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre | |||
1576 | break; | 1586 | break; |
1577 | case SNDRV_PCM_TRIGGER_STOP: | 1587 | case SNDRV_PCM_TRIGGER_STOP: |
1578 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1588 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1589 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1579 | snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; | 1590 | snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; |
1580 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); | 1591 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); |
1581 | pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); | 1592 | pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); |
@@ -1605,6 +1616,7 @@ static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(struct snd_pcm_subs | |||
1605 | static struct snd_pcm_hardware snd_emu10k1_fx8010_playback = | 1616 | static struct snd_pcm_hardware snd_emu10k1_fx8010_playback = |
1606 | { | 1617 | { |
1607 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1618 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1619 | SNDRV_PCM_INFO_RESUME | | ||
1608 | /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), | 1620 | /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), |
1609 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | 1621 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, |
1610 | .rates = SNDRV_PCM_RATE_48000, | 1622 | .rates = SNDRV_PCM_RATE_48000, |
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 90470de8bb8e..adce6af98d01 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -125,6 +125,7 @@ static struct snd_pcm_hardware snd_p16v_playback_hw = { | |||
125 | .info = (SNDRV_PCM_INFO_MMAP | | 125 | .info = (SNDRV_PCM_INFO_MMAP | |
126 | SNDRV_PCM_INFO_INTERLEAVED | | 126 | SNDRV_PCM_INFO_INTERLEAVED | |
127 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 127 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
128 | SNDRV_PCM_INFO_RESUME | | ||
128 | SNDRV_PCM_INFO_MMAP_VALID), | 129 | SNDRV_PCM_INFO_MMAP_VALID), |
129 | .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ | 130 | .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ |
130 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, | 131 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, |
@@ -144,6 +145,7 @@ static struct snd_pcm_hardware snd_p16v_capture_hw = { | |||
144 | .info = (SNDRV_PCM_INFO_MMAP | | 145 | .info = (SNDRV_PCM_INFO_MMAP | |
145 | SNDRV_PCM_INFO_INTERLEAVED | | 146 | SNDRV_PCM_INFO_INTERLEAVED | |
146 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 147 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
148 | SNDRV_PCM_INFO_RESUME | | ||
147 | SNDRV_PCM_INFO_MMAP_VALID), | 149 | SNDRV_PCM_INFO_MMAP_VALID), |
148 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | 150 | .formats = SNDRV_PCM_FMTBIT_S32_LE, |
149 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, | 151 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, |
@@ -611,7 +613,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) | |||
611 | pcm->info_flags = 0; | 613 | pcm->info_flags = 0; |
612 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | 614 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
613 | strcpy(pcm->name, "p16v"); | 615 | strcpy(pcm->name, "p16v"); |
614 | emu->pcm = pcm; | 616 | emu->pcm_p16v = pcm; |
615 | 617 | ||
616 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | 618 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
617 | substream; | 619 | substream; |
@@ -1030,3 +1032,42 @@ int snd_p16v_mixer(struct snd_emu10k1 *emu) | |||
1030 | return 0; | 1032 | return 0; |
1031 | } | 1033 | } |
1032 | 1034 | ||
1035 | #ifdef CONFIG_PM | ||
1036 | |||
1037 | #define NUM_CHS 1 /* up to 4, but only first channel is used */ | ||
1038 | |||
1039 | int __devinit snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu) | ||
1040 | { | ||
1041 | emu->p16v_saved = vmalloc(NUM_CHS * 4 * 0x80); | ||
1042 | if (! emu->p16v_saved) | ||
1043 | return -ENOMEM; | ||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | void snd_p16v_free_pm_buffer(struct snd_emu10k1 *emu) | ||
1048 | { | ||
1049 | vfree(emu->p16v_saved); | ||
1050 | } | ||
1051 | |||
1052 | void snd_p16v_suspend(struct snd_emu10k1 *emu) | ||
1053 | { | ||
1054 | int i, ch; | ||
1055 | unsigned int *val; | ||
1056 | |||
1057 | val = emu->p16v_saved; | ||
1058 | for (ch = 0; ch < NUM_CHS; ch++) | ||
1059 | for (i = 0; i < 0x80; i++, val++) | ||
1060 | *val = snd_emu10k1_ptr20_read(emu, i, ch); | ||
1061 | } | ||
1062 | |||
1063 | void snd_p16v_resume(struct snd_emu10k1 *emu) | ||
1064 | { | ||
1065 | int i, ch; | ||
1066 | unsigned int *val; | ||
1067 | |||
1068 | val = emu->p16v_saved; | ||
1069 | for (ch = 0; ch < NUM_CHS; ch++) | ||
1070 | for (i = 0; i < 0x80; i++, val++) | ||
1071 | snd_emu10k1_ptr20_write(emu, i, ch, *val); | ||
1072 | } | ||
1073 | #endif | ||