aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-02-23 10:57:04 -0500
committerTakashi Iwai <tiwai@suse.de>2009-02-23 10:57:04 -0500
commita65d629ceb4cff5e7d5edadfd6bf1f64c370a517 (patch)
treeafe9fc6ca83c7e2261ec3032eca34739376514cf /sound/pci/hda/hda_codec.c
parent209b14033652f0509912da97fb4a5c8001e64ec0 (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.c54
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
1448void 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 */
1451static 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
1463static 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
1470int 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