Re: [alsa-devel] PROBLEM: snd-au8830: dead after software suspend

Takashi Iwai
2007-08-06T13:30:59Z

At Sat, 04 Aug 2007 02:51:44 +0200,
Gert Robben wrote:
>
> >>> Have you reported this to the ALSA people?
> >> No, I thought this might as well be something for PCI or PM people, and
> >> I expected some ALSA people are also reading this list.
> >> If not, where else should I report this exactly?
> > alsa-devel [...] the author of the driver
> Done (original message below). Thanks again :)
>
> Gert Robben wrote:
> > After a suspend-resume cycle (using Suspend2), my sound card doesn't
> > work anymore. It works again after reloading the module.
> >
> > dmesg, initial boot:
> >> Linux version 2.6.22-ck1
> > ----8<----
> >> PCI driver au8830 lacks driver specific resume support.
> >
> > dmesg, after resume, trying to use the card:
> >> vortex: ac97 codec stuck busy
> >
> > Thanks for any help!
> >
> > Gert Robben

The below is an untested fix. Give it a try.

Takashi

diff -r 23fc708178e1 pci/au88x0/au88x0.c
--- a/pci/au88x0/au88x0.c Mon Aug 06 14:05:27 2007 +0200
+++ b/pci/au88x0/au88x0.c Mon Aug 06 15:19:16 2007 +0200
@@ -78,7 +78,7 @@ static void vortex_fix_agp_bridge(struct
}
}

-static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix)
+static void snd_vortex_workaround(struct pci_dev *vortex, int fix)
{
struct pci_dev *via = NULL;

@@ -117,6 +117,50 @@ static void __devinit snd_vortex_workaro
pci_dev_put(via);
}

+/*
+ * Power management code
+ */
+#ifdef CONFIG_PM
+static int snd_vortex_suspend(struct pci_dev *pci, pm_message_t state)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_vortex *chip = card->private_data;
+ int i;
+
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
+ for (i = 0; i < VORTEX_PCM_LAST; i++)
+ snd_pcm_suspend_all(chip->pcm[i]);
+ snd_ac97_suspend(chip->codec);
+ vortex_core_shutdown(chip);
+ pci_disable_device(pci);
+ pci_save_state(pci);
+ return 0;
+}
+
+static int snd_vortex_resume(struct pci_dev *pci)
+{
+ struct snd_card *card = pci_get_drvdata(pci);
+ struct snd_vortex *chip = card->private_data;
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_restore_state(pci);
+ if (pci_enable_device(pci) < 0) {
+ printk(KERN_ERR "au88x0: pci_enable_device failed, "
+ "disabling device\n");
+ snd_card_disconnect(card);
+ return -EIO;
+ }
+ pci_set_master(pci);
+ vortex_core_init(chip, 1);
+ snd_vortex_workaround(pci, chip->pcifix);
+ snd_ac97_resume(chip->codec);
+ vortex_connect_default(chip, 1);
+ vortex_enable_int(chip);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
// component-destructor
// (see "Management of Cards and Components")
static int snd_vortex_dev_free(struct snd_device *device)
@@ -192,7 +236,7 @@ snd_vortex_create(struct snd_card *card,
/* Init audio core.
* This must be done before we do request_irq otherwise we can get spurious
* interupts that we do not handle properly and make a mess of things */
- if ((err = vortex_core_init(chip)) != 0) {
+ if ((err = vortex_core_init(chip, 0)) != 0) {
printk(KERN_ERR "hw core init failed\n");
goto core_out;
}
@@ -262,7 +306,9 @@ snd_vortex_probe(struct pci_dev *pci, co
snd_card_free(card);
return err;
}
- snd_vortex_workaround(pci, pcifix[dev]);
+ card->private_data = chip;
+ chip->pcifix = pcifix[dev];
+ snd_vortex_workaround(pci, chip->pcifix);

// Card details needed in snd_vortex_midi
strcpy(card->driver, CARD_NAME_SHORT);
@@ -382,6 +428,10 @@ static struct pci_driver driver = {
.id_table = snd_vortex_ids,
.probe = snd_vortex_probe,
.remove = __devexit_p(snd_vortex_remove),
+#ifdef CONFIG_PM
+ .suspend = snd_vortex_suspend,
+ .resume = snd_vortex_resume,
+#endif
};

// initialization of the module
diff -r 23fc708178e1 pci/au88x0/au88x0.h
--- a/pci/au88x0/au88x0.h Mon Aug 06 14:05:27 2007 +0200
+++ b/pci/au88x0/au88x0.h Mon Aug 06 15:19:16 2007 +0200
@@ -178,7 +178,7 @@ struct snd_vortex {
/* PCI hardware resources */
unsigned long io;
void __iomem *mmio;
- unsigned int irq;
+ int irq;
spinlock_t lock;

/* PCI device */
@@ -186,6 +186,7 @@ struct snd_vortex {
u16 vendor;
u16 device;
u8 rev;
+ int pcifix;
};

/* Functions. */
@@ -233,7 +234,7 @@ static unsigned short vortex_codec_read(
static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short addr);
static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode);

-static int vortex_core_init(vortex_t * card);
+static int vortex_core_init(vortex_t * card, int do_resume);
static int vortex_core_shutdown(vortex_t * card);
static void vortex_enable_int(vortex_t * card);
static irqreturn_t vortex_interrupt(int irq, void *dev_id);
diff -r 23fc708178e1 pci/au88x0/au88x0_a3d.c
--- a/pci/au88x0/au88x0_a3d.c Mon Aug 06 14:05:27 2007 +0200
+++ b/pci/au88x0/au88x0_a3d.c Mon Aug 06 15:19:16 2007 +0200
@@ -593,7 +593,7 @@ static int vortex_a3d_register_controls(
static int vortex_a3d_register_controls(vortex_t * vortex);
static void vortex_a3d_unregister_controls(vortex_t * vortex);
/* A3D base support init/shudown */
-static void __devinit vortex_Vort3D_enable(vortex_t * v)
+static void vortex_Vort3D_enable(vortex_t * v)
{
int i;

diff -r 23fc708178e1 pci/au88x0/au88x0_core.c
--- a/pci/au88x0/au88x0_core.c Mon Aug 06 14:05:27 2007 +0200
+++ b/pci/au88x0/au88x0_core.c Mon Aug 06 15:19:16 2007 +0200
@@ -2658,7 +2658,7 @@ static void vortex_spdif_init(vortex_t *

/* Initialization */

-static int __devinit vortex_core_init(vortex_t * vortex)
+static int vortex_core_init(vortex_t * vortex, int do_resume)
{

printk(KERN_INFO "Vortex: init.... ");
@@ -2688,7 +2688,8 @@ static int __devinit vortex_core_init(vo
vortex_mixer_init(vortex);
vortex_srcblock_init(vortex);
#ifndef CHIP_AU8820
- vortex_eq_init(vortex);
+ if (!do_resume)
+ vortex_eq_init(vortex);
vortex_spdif_init(vortex, 48000, 1);
vortex_Vort3D_enable(vortex);
#endif