aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_hdmi.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-10-17 12:03:24 -0400
committerTakashi Iwai <tiwai@suse.de>2013-10-17 13:23:40 -0400
commitcbbaa603a03cc46681e24d6b2804b62fde95a2af (patch)
treee6e2be9cd9a7c53c1dc527ab8c7c4e99910ea8e4 /sound/pci/hda/patch_hdmi.c
parent4758fed912d7cd0ba53d2694e89b884114de6580 (diff)
ALSA: hda - Fix possible races in HDMI driver
Some per_pin fields and ELD contents might be changed dynamically in multiple ways where the concurrent accesses are still opened in the current code. This patch fixes such possible races by using eld->lock in appropriate places. Reported-by: Anssi Hannula <anssi.hannula@iki.fi> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_hdmi.c')
-rw-r--r--sound/pci/hda/patch_hdmi.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index b899eba6f279..c2bad9587d54 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1342,6 +1342,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
1342 bool update_eld = false; 1342 bool update_eld = false;
1343 bool eld_changed = false; 1343 bool eld_changed = false;
1344 1344
1345 mutex_lock(&pin_eld->lock);
1345 pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); 1346 pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
1346 if (pin_eld->monitor_present) 1347 if (pin_eld->monitor_present)
1347 eld->eld_valid = !!(present & AC_PINSENSE_ELDV); 1348 eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
@@ -1371,11 +1372,10 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
1371 queue_delayed_work(codec->bus->workq, 1372 queue_delayed_work(codec->bus->workq,
1372 &per_pin->work, 1373 &per_pin->work,
1373 msecs_to_jiffies(300)); 1374 msecs_to_jiffies(300));
1374 return; 1375 goto unlock;
1375 } 1376 }
1376 } 1377 }
1377 1378
1378 mutex_lock(&pin_eld->lock);
1379 if (pin_eld->eld_valid && !eld->eld_valid) { 1379 if (pin_eld->eld_valid && !eld->eld_valid) {
1380 update_eld = true; 1380 update_eld = true;
1381 eld_changed = true; 1381 eld_changed = true;
@@ -1400,12 +1400,13 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
1400 hdmi_setup_audio_infoframe(codec, per_pin, 1400 hdmi_setup_audio_infoframe(codec, per_pin,
1401 per_pin->non_pcm); 1401 per_pin->non_pcm);
1402 } 1402 }
1403 mutex_unlock(&pin_eld->lock);
1404 1403
1405 if (eld_changed) 1404 if (eld_changed)
1406 snd_ctl_notify(codec->bus->card, 1405 snd_ctl_notify(codec->bus->card,
1407 SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, 1406 SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
1408 &per_pin->eld_ctl->id); 1407 &per_pin->eld_ctl->id);
1408 unlock:
1409 mutex_unlock(&pin_eld->lock);
1409} 1410}
1410 1411
1411static void hdmi_repoll_eld(struct work_struct *work) 1412static void hdmi_repoll_eld(struct work_struct *work)
@@ -1576,10 +1577,12 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1576 bool non_pcm; 1577 bool non_pcm;
1577 1578
1578 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); 1579 non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
1580 mutex_lock(&per_pin->sink_eld.lock);
1579 per_pin->channels = substream->runtime->channels; 1581 per_pin->channels = substream->runtime->channels;
1580 per_pin->setup = true; 1582 per_pin->setup = true;
1581 1583
1582 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); 1584 hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
1585 mutex_unlock(&per_pin->sink_eld.lock);
1583 1586
1584 return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); 1587 return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
1585} 1588}
@@ -1617,11 +1620,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1617 per_pin = get_pin(spec, pin_idx); 1620 per_pin = get_pin(spec, pin_idx);
1618 1621
1619 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1622 snd_hda_spdif_ctls_unassign(codec, pin_idx);
1623
1624 mutex_lock(&per_pin->sink_eld.lock);
1620 per_pin->chmap_set = false; 1625 per_pin->chmap_set = false;
1621 memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); 1626 memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
1622 1627
1623 per_pin->setup = false; 1628 per_pin->setup = false;
1624 per_pin->channels = 0; 1629 per_pin->channels = 0;
1630 mutex_unlock(&per_pin->sink_eld.lock);
1625 } 1631 }
1626 1632
1627 return 0; 1633 return 0;
@@ -1750,10 +1756,12 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1750 ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); 1756 ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
1751 if (ca < 0) 1757 if (ca < 0)
1752 return -EINVAL; 1758 return -EINVAL;
1759 mutex_lock(&per_pin->sink_eld.lock);
1753 per_pin->chmap_set = true; 1760 per_pin->chmap_set = true;
1754 memcpy(per_pin->chmap, chmap, sizeof(chmap)); 1761 memcpy(per_pin->chmap, chmap, sizeof(chmap));
1755 if (prepared) 1762 if (prepared)
1756 hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); 1763 hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
1764 mutex_unlock(&per_pin->sink_eld.lock);
1757 1765
1758 return 0; 1766 return 0;
1759} 1767}