diff options
-rw-r--r-- | sound/pci/hda/hda_codec.c | 54 | ||||
-rw-r--r-- | sound/pci/hda/hda_hwdep.c | 15 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 2 |
3 files changed, 64 insertions, 7 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 | ||
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index c660383ef381..4af484b8240c 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -155,7 +155,13 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) | |||
155 | 155 | ||
156 | static int clear_codec(struct hda_codec *codec) | 156 | static int clear_codec(struct hda_codec *codec) |
157 | { | 157 | { |
158 | snd_hda_codec_reset(codec); | 158 | int err; |
159 | |||
160 | err = snd_hda_codec_reset(codec); | ||
161 | if (err < 0) { | ||
162 | snd_printk(KERN_ERR "The codec is being used, can't free.\n"); | ||
163 | return err; | ||
164 | } | ||
159 | clear_hwdep_elements(codec); | 165 | clear_hwdep_elements(codec); |
160 | return 0; | 166 | return 0; |
161 | } | 167 | } |
@@ -165,7 +171,12 @@ static int reconfig_codec(struct hda_codec *codec) | |||
165 | int err; | 171 | int err; |
166 | 172 | ||
167 | snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); | 173 | snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); |
168 | snd_hda_codec_reset(codec); | 174 | err = snd_hda_codec_reset(codec); |
175 | if (err < 0) { | ||
176 | snd_printk(KERN_ERR | ||
177 | "The codec is being used, can't reconfigure.\n"); | ||
178 | return err; | ||
179 | } | ||
169 | err = snd_hda_codec_configure(codec); | 180 | err = snd_hda_codec_configure(codec); |
170 | if (err < 0) | 181 | if (err < 0) |
171 | return err; | 182 | return err; |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 84e2cf644fd7..4bd82a37a4c8 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -98,7 +98,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | |||
98 | const char *name); | 98 | const char *name); |
99 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | 99 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, |
100 | unsigned int *tlv, const char **slaves); | 100 | unsigned int *tlv, const char **slaves); |
101 | void snd_hda_codec_reset(struct hda_codec *codec); | 101 | int snd_hda_codec_reset(struct hda_codec *codec); |
102 | int snd_hda_codec_configure(struct hda_codec *codec); | 102 | int snd_hda_codec_configure(struct hda_codec *codec); |
103 | 103 | ||
104 | /* amp value bits */ | 104 | /* amp value bits */ |