diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-10-12 11:28:18 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-10-15 03:55:48 -0400 |
commit | 128960a9ad67e2d119738f5211956e0304517551 (patch) | |
tree | 1b81778fa4184861fe85cb168511153d8808cbc5 | |
parent | e73fa21b4e6ce10934cc8016a9a512d7152a860b (diff) |
ALSA: hda - Fix registration race of VGA switcheroo
Delay the registration of VGA switcheroo client to the end of the
probing. Otherwise a too quick switching may result in Oops during
probing.
Also add the check of the return value from snd_hda_lock_devices().
Reported-and-tested-by: Daniel J Blueman <daniel@quora.org>
Cc: <stable@vger.kernel.org> [v3.5+]
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/hda_intel.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 69810b21f7f4..ecf277506ad1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -501,6 +501,7 @@ struct azx { | |||
501 | 501 | ||
502 | /* VGA-switcheroo setup */ | 502 | /* VGA-switcheroo setup */ |
503 | unsigned int use_vga_switcheroo:1; | 503 | unsigned int use_vga_switcheroo:1; |
504 | unsigned int vga_switcheroo_registered:1; | ||
504 | unsigned int init_failed:1; /* delayed init failed */ | 505 | unsigned int init_failed:1; /* delayed init failed */ |
505 | unsigned int disabled:1; /* disabled by VGA-switcher */ | 506 | unsigned int disabled:1; /* disabled by VGA-switcher */ |
506 | 507 | ||
@@ -2640,7 +2641,9 @@ static void azx_vs_set_state(struct pci_dev *pci, | |||
2640 | if (disabled) { | 2641 | if (disabled) { |
2641 | azx_suspend(&pci->dev); | 2642 | azx_suspend(&pci->dev); |
2642 | chip->disabled = true; | 2643 | chip->disabled = true; |
2643 | snd_hda_lock_devices(chip->bus); | 2644 | if (snd_hda_lock_devices(chip->bus)) |
2645 | snd_printk(KERN_WARNING SFX | ||
2646 | "Cannot lock devices!\n"); | ||
2644 | } else { | 2647 | } else { |
2645 | snd_hda_unlock_devices(chip->bus); | 2648 | snd_hda_unlock_devices(chip->bus); |
2646 | chip->disabled = false; | 2649 | chip->disabled = false; |
@@ -2683,14 +2686,20 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { | |||
2683 | 2686 | ||
2684 | static int __devinit register_vga_switcheroo(struct azx *chip) | 2687 | static int __devinit register_vga_switcheroo(struct azx *chip) |
2685 | { | 2688 | { |
2689 | int err; | ||
2690 | |||
2686 | if (!chip->use_vga_switcheroo) | 2691 | if (!chip->use_vga_switcheroo) |
2687 | return 0; | 2692 | return 0; |
2688 | /* FIXME: currently only handling DIS controller | 2693 | /* FIXME: currently only handling DIS controller |
2689 | * is there any machine with two switchable HDMI audio controllers? | 2694 | * is there any machine with two switchable HDMI audio controllers? |
2690 | */ | 2695 | */ |
2691 | return vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, | 2696 | err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, |
2692 | VGA_SWITCHEROO_DIS, | 2697 | VGA_SWITCHEROO_DIS, |
2693 | chip->bus != NULL); | 2698 | chip->bus != NULL); |
2699 | if (err < 0) | ||
2700 | return err; | ||
2701 | chip->vga_switcheroo_registered = 1; | ||
2702 | return 0; | ||
2694 | } | 2703 | } |
2695 | #else | 2704 | #else |
2696 | #define init_vga_switcheroo(chip) /* NOP */ | 2705 | #define init_vga_switcheroo(chip) /* NOP */ |
@@ -2712,7 +2721,8 @@ static int azx_free(struct azx *chip) | |||
2712 | if (use_vga_switcheroo(chip)) { | 2721 | if (use_vga_switcheroo(chip)) { |
2713 | if (chip->disabled && chip->bus) | 2722 | if (chip->disabled && chip->bus) |
2714 | snd_hda_unlock_devices(chip->bus); | 2723 | snd_hda_unlock_devices(chip->bus); |
2715 | vga_switcheroo_unregister_client(chip->pci); | 2724 | if (chip->vga_switcheroo_registered) |
2725 | vga_switcheroo_unregister_client(chip->pci); | ||
2716 | } | 2726 | } |
2717 | 2727 | ||
2718 | if (chip->initialized) { | 2728 | if (chip->initialized) { |
@@ -3060,14 +3070,6 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
3060 | } | 3070 | } |
3061 | 3071 | ||
3062 | ok: | 3072 | ok: |
3063 | err = register_vga_switcheroo(chip); | ||
3064 | if (err < 0) { | ||
3065 | snd_printk(KERN_ERR SFX | ||
3066 | "Error registering VGA-switcheroo client\n"); | ||
3067 | azx_free(chip); | ||
3068 | return err; | ||
3069 | } | ||
3070 | |||
3071 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | 3073 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); |
3072 | if (err < 0) { | 3074 | if (err < 0) { |
3073 | snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); | 3075 | snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); |
@@ -3338,6 +3340,13 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
3338 | if (pci_dev_run_wake(pci)) | 3340 | if (pci_dev_run_wake(pci)) |
3339 | pm_runtime_put_noidle(&pci->dev); | 3341 | pm_runtime_put_noidle(&pci->dev); |
3340 | 3342 | ||
3343 | err = register_vga_switcheroo(chip); | ||
3344 | if (err < 0) { | ||
3345 | snd_printk(KERN_ERR SFX | ||
3346 | "Error registering VGA-switcheroo client\n"); | ||
3347 | goto out_free; | ||
3348 | } | ||
3349 | |||
3341 | dev++; | 3350 | dev++; |
3342 | return 0; | 3351 | return 0; |
3343 | 3352 | ||