From: Takashi Iwai Date: Thu, 30 Oct 2008 19:10:15 +0000 (+0000) Subject: ALSA: hda - Add reboot notifier X-Git-Tag: v2.6.27.5~52 X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a858c06703057cfdd142184e536c3ba36c45000e;p=pandora-kernel.git ALSA: hda - Add reboot notifier commit 0cbf00980f0fc4cc064a15ab3dfce19b5fae9130 upstream The current snd-hda-intel driver seems blocking the power-off on some devices like eeepc. Although this is likely a BIOS problem, we can add a workaround by disabling IRQ lines before power-off operation. This patch adds the reboot notifier to achieve it. The detailed problem description is found in bug#11889: http://bugme.linux-foundation.org/show_bug.cgi?id=11889 Tested-by: Luiz Fernando N. Capitulino Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1c53e337ecb2..0f014b1ce641 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include "hda_codec.h" @@ -385,6 +386,9 @@ struct azx { /* for pending irqs */ struct work_struct irq_pending_work; + + /* reboot notifier (for mysterious hangup problem at power-down) */ + struct notifier_block reboot_notifier; }; /* driver types */ @@ -1889,6 +1893,28 @@ static int azx_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ +/* + * reboot notifier for hang-up problem at power-down + */ +static int azx_halt(struct notifier_block *nb, unsigned long event, void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +static void azx_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = azx_halt; + register_reboot_notifier(&chip->reboot_notifier); +} + +static void azx_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} + /* * destructor */ @@ -1896,6 +1922,8 @@ static int azx_free(struct azx *chip) { int i; + azx_notifier_unregister(chip); + if (chip->initialized) { azx_clear_irq_pending(chip); for (i = 0; i < chip->num_streams; i++) @@ -2250,6 +2278,7 @@ static int __devinit azx_probe(struct pci_dev *pci, pci_set_drvdata(pci, card); chip->running = 1; power_down_all_codecs(chip); + azx_notifier_register(chip); dev++; return err;