diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-02-23 10:57:04 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-02-23 10:57:04 -0500 |
commit | a65d629ceb4cff5e7d5edadfd6bf1f64c370a517 (patch) | |
tree | afe9fc6ca83c7e2261ec3032eca34739376514cf /sound/pci/hda/hda_codec.c | |
parent | 209b14033652f0509912da97fb4a5c8001e64ec0 (diff) |
ALSA: hda - Add pseudo device-locking for clear/reconfig
Added the pseudo device-locking using card->shutdown flag to avoid
the crash via clear/reconfig during operations.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a13480fa8e74..5dceee8a113b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1445,9 +1445,52 @@ void snd_hda_ctls_clear(struct hda_codec *codec) | |||
1445 | snd_array_free(&codec->mixers); | 1445 | snd_array_free(&codec->mixers); |
1446 | } | 1446 | } |
1447 | 1447 | ||
1448 | void snd_hda_codec_reset(struct hda_codec *codec) | 1448 | /* pseudo device locking |
1449 | * toggle card->shutdown to allow/disallow the device access (as a hack) | ||
1450 | */ | ||
1451 | static int hda_lock_devices(struct snd_card *card) | ||
1449 | { | 1452 | { |
1450 | int i; | 1453 | spin_lock(&card->files_lock); |
1454 | if (card->shutdown) { | ||
1455 | spin_unlock(&card->files_lock); | ||
1456 | return -EINVAL; | ||
1457 | } | ||
1458 | card->shutdown = 1; | ||
1459 | spin_unlock(&card->files_lock); | ||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | static void hda_unlock_devices(struct snd_card *card) | ||
1464 | { | ||
1465 | spin_lock(&card->files_lock); | ||
1466 | card->shutdown = 0; | ||
1467 | spin_unlock(&card->files_lock); | ||
1468 | } | ||
1469 | |||
1470 | int snd_hda_codec_reset(struct hda_codec *codec) | ||
1471 | { | ||
1472 | struct snd_card *card = codec->bus->card; | ||
1473 | int i, pcm; | ||
1474 | |||
1475 | if (hda_lock_devices(card) < 0) | ||
1476 | return -EBUSY; | ||
1477 | /* check whether the codec isn't used by any mixer or PCM streams */ | ||
1478 | if (!list_empty(&card->ctl_files)) { | ||
1479 | hda_unlock_devices(card); | ||
1480 | return -EBUSY; | ||
1481 | } | ||
1482 | for (pcm = 0; pcm < codec->num_pcms; pcm++) { | ||
1483 | struct hda_pcm *cpcm = &codec->pcm_info[pcm]; | ||
1484 | if (!cpcm->pcm) | ||
1485 | continue; | ||
1486 | if (cpcm->pcm->streams[0].substream_opened || | ||
1487 | cpcm->pcm->streams[1].substream_opened) { | ||
1488 | hda_unlock_devices(card); | ||
1489 | return -EBUSY; | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | /* OK, let it free */ | ||
1451 | 1494 | ||
1452 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1495 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1453 | cancel_delayed_work(&codec->power_work); | 1496 | cancel_delayed_work(&codec->power_work); |
@@ -1457,8 +1500,7 @@ void snd_hda_codec_reset(struct hda_codec *codec) | |||
1457 | /* relase PCMs */ | 1500 | /* relase PCMs */ |
1458 | for (i = 0; i < codec->num_pcms; i++) { | 1501 | for (i = 0; i < codec->num_pcms; i++) { |
1459 | if (codec->pcm_info[i].pcm) { | 1502 | if (codec->pcm_info[i].pcm) { |
1460 | snd_device_free(codec->bus->card, | 1503 | snd_device_free(card, codec->pcm_info[i].pcm); |
1461 | codec->pcm_info[i].pcm); | ||
1462 | clear_bit(codec->pcm_info[i].device, | 1504 | clear_bit(codec->pcm_info[i].device, |
1463 | codec->bus->pcm_dev_bits); | 1505 | codec->bus->pcm_dev_bits); |
1464 | } | 1506 | } |
@@ -1479,6 +1521,10 @@ void snd_hda_codec_reset(struct hda_codec *codec) | |||
1479 | codec->preset = NULL; | 1521 | codec->preset = NULL; |
1480 | module_put(codec->owner); | 1522 | module_put(codec->owner); |
1481 | codec->owner = NULL; | 1523 | codec->owner = NULL; |
1524 | |||
1525 | /* allow device access again */ | ||
1526 | hda_unlock_devices(card); | ||
1527 | return 0; | ||
1482 | } | 1528 | } |
1483 | #endif /* CONFIG_SND_HDA_RECONFIG */ | 1529 | #endif /* CONFIG_SND_HDA_RECONFIG */ |
1484 | 1530 | ||