aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKnut Petersen <Knut_Petersen@t-online.de>2013-08-21 03:18:54 -0400
committerTakashi Iwai <tiwai@suse.de>2013-08-22 05:54:57 -0400
commit528ba522e18b95d25adc62367f04290776c390e5 (patch)
tree65f4fff4b10d155aa6fc5a21be2b52f4f4d2ccac
parentb43dd416be21bc8ad60984e13def032f01aaaa18 (diff)
ALSA: rme96: Add PM support v3
Without proper power management handling, the first use of a Digi96/8 anytime after a suspend / resume cycle will start playback with distortions. v3: Abort if vmalloc() of suspend buffers fail, but do not leak memory in that case. [fixed wrong memory leak fix again -- tiwai] Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/rme96.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 4e9a5563eeca..0506530de5a5 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -239,6 +239,13 @@ struct rme96 {
239 239
240 u8 rev; /* card revision number */ 240 u8 rev; /* card revision number */
241 241
242#ifdef CONFIG_PM
243 u32 playback_pointer;
244 u32 capture_pointer;
245 void *playback_suspend_buffer;
246 void *capture_suspend_buffer;
247#endif
248
242 struct snd_pcm_substream *playback_substream; 249 struct snd_pcm_substream *playback_substream;
243 struct snd_pcm_substream *capture_substream; 250 struct snd_pcm_substream *capture_substream;
244 251
@@ -370,6 +377,7 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info =
370 .info = (SNDRV_PCM_INFO_MMAP_IOMEM | 377 .info = (SNDRV_PCM_INFO_MMAP_IOMEM |
371 SNDRV_PCM_INFO_MMAP_VALID | 378 SNDRV_PCM_INFO_MMAP_VALID |
372 SNDRV_PCM_INFO_SYNC_START | 379 SNDRV_PCM_INFO_SYNC_START |
380 SNDRV_PCM_INFO_RESUME |
373 SNDRV_PCM_INFO_INTERLEAVED | 381 SNDRV_PCM_INFO_INTERLEAVED |
374 SNDRV_PCM_INFO_PAUSE), 382 SNDRV_PCM_INFO_PAUSE),
375 .formats = (SNDRV_PCM_FMTBIT_S16_LE | 383 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -400,6 +408,7 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info =
400 .info = (SNDRV_PCM_INFO_MMAP_IOMEM | 408 .info = (SNDRV_PCM_INFO_MMAP_IOMEM |
401 SNDRV_PCM_INFO_MMAP_VALID | 409 SNDRV_PCM_INFO_MMAP_VALID |
402 SNDRV_PCM_INFO_SYNC_START | 410 SNDRV_PCM_INFO_SYNC_START |
411 SNDRV_PCM_INFO_RESUME |
403 SNDRV_PCM_INFO_INTERLEAVED | 412 SNDRV_PCM_INFO_INTERLEAVED |
404 SNDRV_PCM_INFO_PAUSE), 413 SNDRV_PCM_INFO_PAUSE),
405 .formats = (SNDRV_PCM_FMTBIT_S16_LE | 414 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -430,6 +439,7 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info =
430 .info = (SNDRV_PCM_INFO_MMAP_IOMEM | 439 .info = (SNDRV_PCM_INFO_MMAP_IOMEM |
431 SNDRV_PCM_INFO_MMAP_VALID | 440 SNDRV_PCM_INFO_MMAP_VALID |
432 SNDRV_PCM_INFO_SYNC_START | 441 SNDRV_PCM_INFO_SYNC_START |
442 SNDRV_PCM_INFO_RESUME |
433 SNDRV_PCM_INFO_INTERLEAVED | 443 SNDRV_PCM_INFO_INTERLEAVED |
434 SNDRV_PCM_INFO_PAUSE), 444 SNDRV_PCM_INFO_PAUSE),
435 .formats = (SNDRV_PCM_FMTBIT_S16_LE | 445 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -456,6 +466,7 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info =
456 .info = (SNDRV_PCM_INFO_MMAP_IOMEM | 466 .info = (SNDRV_PCM_INFO_MMAP_IOMEM |
457 SNDRV_PCM_INFO_MMAP_VALID | 467 SNDRV_PCM_INFO_MMAP_VALID |
458 SNDRV_PCM_INFO_SYNC_START | 468 SNDRV_PCM_INFO_SYNC_START |
469 SNDRV_PCM_INFO_RESUME |
459 SNDRV_PCM_INFO_INTERLEAVED | 470 SNDRV_PCM_INFO_INTERLEAVED |
460 SNDRV_PCM_INFO_PAUSE), 471 SNDRV_PCM_INFO_PAUSE),
461 .formats = (SNDRV_PCM_FMTBIT_S16_LE | 472 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
@@ -1386,6 +1397,7 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
1386 } 1397 }
1387 break; 1398 break;
1388 1399
1400 case SNDRV_PCM_TRIGGER_SUSPEND:
1389 case SNDRV_PCM_TRIGGER_STOP: 1401 case SNDRV_PCM_TRIGGER_STOP:
1390 if (RME96_ISPLAYING(rme96)) { 1402 if (RME96_ISPLAYING(rme96)) {
1391 if (substream != rme96->playback_substream) 1403 if (substream != rme96->playback_substream)
@@ -1401,6 +1413,7 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream,
1401 : RME96_STOP_PLAYBACK); 1413 : RME96_STOP_PLAYBACK);
1402 break; 1414 break;
1403 1415
1416 case SNDRV_PCM_TRIGGER_RESUME:
1404 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1417 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1405 if (!RME96_ISPLAYING(rme96)) 1418 if (!RME96_ISPLAYING(rme96))
1406 snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH 1419 snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
@@ -1441,6 +1454,7 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
1441 } 1454 }
1442 break; 1455 break;
1443 1456
1457 case SNDRV_PCM_TRIGGER_SUSPEND:
1444 case SNDRV_PCM_TRIGGER_STOP: 1458 case SNDRV_PCM_TRIGGER_STOP:
1445 if (RME96_ISRECORDING(rme96)) { 1459 if (RME96_ISRECORDING(rme96)) {
1446 if (substream != rme96->capture_substream) 1460 if (substream != rme96->capture_substream)
@@ -1456,6 +1470,7 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream,
1456 : RME96_STOP_CAPTURE); 1470 : RME96_STOP_CAPTURE);
1457 break; 1471 break;
1458 1472
1473 case SNDRV_PCM_TRIGGER_RESUME:
1459 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1474 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1460 if (!RME96_ISRECORDING(rme96)) 1475 if (!RME96_ISRECORDING(rme96))
1461 snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH 1476 snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH
@@ -1556,6 +1571,10 @@ snd_rme96_free(void *private_data)
1556 pci_release_regions(rme96->pci); 1571 pci_release_regions(rme96->pci);
1557 rme96->port = 0; 1572 rme96->port = 0;
1558 } 1573 }
1574#ifdef CONFIG_PM
1575 vfree(rme96->playback_suspend_buffer);
1576 vfree(rme96->capture_suspend_buffer);
1577#endif
1559 pci_disable_device(rme96->pci); 1578 pci_disable_device(rme96->pci);
1560} 1579}
1561 1580
@@ -2354,6 +2373,83 @@ snd_rme96_create_switches(struct snd_card *card,
2354 * Card initialisation 2373 * Card initialisation
2355 */ 2374 */
2356 2375
2376#ifdef CONFIG_PM
2377
2378static int
2379snd_rme96_suspend(struct pci_dev *pci,
2380 pm_message_t state)
2381{
2382 struct snd_card *card = pci_get_drvdata(pci);
2383 struct rme96 *rme96 = card->private_data;
2384
2385 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
2386 snd_pcm_suspend(rme96->playback_substream);
2387 snd_pcm_suspend(rme96->capture_substream);
2388
2389 /* save capture & playback pointers */
2390 rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS)
2391 & RME96_RCR_AUDIO_ADDR_MASK;
2392 rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS)
2393 & RME96_RCR_AUDIO_ADDR_MASK;
2394
2395 /* save playback and capture buffers */
2396 memcpy_fromio(rme96->playback_suspend_buffer,
2397 rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE);
2398 memcpy_fromio(rme96->capture_suspend_buffer,
2399 rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE);
2400
2401 /* disable the DAC */
2402 rme96->areg &= ~RME96_AR_DAC_EN;
2403 writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
2404
2405 pci_disable_device(pci);
2406 pci_save_state(pci);
2407
2408 return 0;
2409}
2410
2411static int
2412snd_rme96_resume(struct pci_dev *pci)
2413{
2414 struct snd_card *card = pci_get_drvdata(pci);
2415 struct rme96 *rme96 = card->private_data;
2416
2417 pci_restore_state(pci);
2418 pci_enable_device(pci);
2419
2420 /* reset playback and record buffer pointers */
2421 writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
2422 + rme96->playback_pointer);
2423 writel(0, rme96->iobase + RME96_IO_SET_REC_POS
2424 + rme96->capture_pointer);
2425
2426 /* restore playback and capture buffers */
2427 memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER,
2428 rme96->playback_suspend_buffer, RME96_BUFFER_SIZE);
2429 memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER,
2430 rme96->capture_suspend_buffer, RME96_BUFFER_SIZE);
2431
2432 /* reset the ADC */
2433 writel(rme96->areg | RME96_AR_PD2,
2434 rme96->iobase + RME96_IO_ADDITIONAL_REG);
2435 writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
2436
2437 /* reset and enable DAC, restore analog volume */
2438 snd_rme96_reset_dac(rme96);
2439 rme96->areg |= RME96_AR_DAC_EN;
2440 writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
2441 if (RME96_HAS_ANALOG_OUT(rme96)) {
2442 usleep_range(3000, 10000);
2443 snd_rme96_apply_dac_volume(rme96);
2444 }
2445
2446 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
2447
2448 return 0;
2449}
2450
2451#endif
2452
2357static void snd_rme96_card_free(struct snd_card *card) 2453static void snd_rme96_card_free(struct snd_card *card)
2358{ 2454{
2359 snd_rme96_free(card->private_data); 2455 snd_rme96_free(card->private_data);
@@ -2390,6 +2486,23 @@ snd_rme96_probe(struct pci_dev *pci,
2390 return err; 2486 return err;
2391 } 2487 }
2392 2488
2489#ifdef CONFIG_PM
2490 rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
2491 if (!rme96->playback_suspend_buffer) {
2492 snd_printk(KERN_ERR
2493 "Failed to allocate playback suspend buffer!\n");
2494 snd_card_free(card);
2495 return -ENOMEM;
2496 }
2497 rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE);
2498 if (!rme96->capture_suspend_buffer) {
2499 snd_printk(KERN_ERR
2500 "Failed to allocate capture suspend buffer!\n");
2501 snd_card_free(card);
2502 return -ENOMEM;
2503 }
2504#endif
2505
2393 strcpy(card->driver, "Digi96"); 2506 strcpy(card->driver, "Digi96");
2394 switch (rme96->pci->device) { 2507 switch (rme96->pci->device) {
2395 case PCI_DEVICE_ID_RME_DIGI96: 2508 case PCI_DEVICE_ID_RME_DIGI96:
@@ -2432,6 +2545,10 @@ static struct pci_driver rme96_driver = {
2432 .id_table = snd_rme96_ids, 2545 .id_table = snd_rme96_ids,
2433 .probe = snd_rme96_probe, 2546 .probe = snd_rme96_probe,
2434 .remove = snd_rme96_remove, 2547 .remove = snd_rme96_remove,
2548#ifdef CONFIG_PM
2549 .suspend = snd_rme96_suspend,
2550 .resume = snd_rme96_resume,
2551#endif
2435}; 2552};
2436 2553
2437module_pci_driver(rme96_driver); 2554module_pci_driver(rme96_driver);