Skip to content

Commit

Permalink
Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "Mostly HD-audio and USB-audio regression fixes:
   - Oops fix at unloading of snd-hda-codec-conexant module
   - A few trivial regression fixes for Cirrus and Conexant HD-audio
     codecs
   - Relax the USB-audio descriptor parse errors as non-fatal
   - Fix locking of HD-audio CA0132 DSP loader
   - Fix the generic HD-audio parser for VIA codecs"

* tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda - Fix DAC assignment for independent HP
  ALSA: hda - Fix abuse of snd_hda_lock_devices() for DSP loader
  ALSA: hda - Fix typo in checking IEC958 emphasis bit
  ALSA: snd-usb: mixer: ignore -EINVAL in snd_usb_mixer_controls()
  ALSA: snd-usb: mixer: propagate errors up the call chain
  ALSA: usb: Parse UAC2 extension unit like for UAC1
  ALSA: hda - Fix yet missing GPIO/EAPD setup in cirrus driver
  ALSA: hda/cirrus - Fix the digital beep registration
  ALSA: hda - Fix missing beep detach in patch_conexant.c
  ALSA: documentation: Fix typo in Documentation/sound
  • Loading branch information
Linus Torvalds committed Mar 22, 2013
2 parents 1e0695c + 55a63d4 commit 70dc52f
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 41 deletions.
2 changes: 1 addition & 1 deletion Documentation/sound/alsa/ALSA-Configuration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
models depending on the codec chip. The list of available models
is found in HD-Audio-Models.txt

The model name "genric" is treated as a special case. When this
The model name "generic" is treated as a special case. When this
model is given, the driver uses the generic codec parser without
"codec-patch". It's sometimes good for testing and debugging.

Expand Down
2 changes: 1 addition & 1 deletion Documentation/sound/alsa/seq_oss.html
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ <H4>
<H4>
7.2.4 Close Callback</H4>
The <TT>close</TT> callback is called when this device is closed by the
applicaion. If any private data was allocated in open callback, it must
application. If any private data was allocated in open callback, it must
be released in the close callback. The deletion of ALSA port should be
done here, too. This callback must not be NULL.
<H4>
Expand Down
2 changes: 1 addition & 1 deletion sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -3144,7 +3144,7 @@ static unsigned int convert_to_spdif_status(unsigned short val)
if (val & AC_DIG1_PROFESSIONAL)
sbits |= IEC958_AES0_PROFESSIONAL;
if (sbits & IEC958_AES0_PROFESSIONAL) {
if (sbits & AC_DIG1_EMPHASIS)
if (val & AC_DIG1_EMPHASIS)
sbits |= IEC958_AES0_PRO_EMPHASIS_5015;
} else {
if (val & AC_DIG1_EMPHASIS)
Expand Down
46 changes: 46 additions & 0 deletions sound/pci/hda/hda_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,8 @@ enum {
BAD_NO_EXTRA_SURR_DAC = 0x101,
/* Primary DAC shared with main surrounds */
BAD_SHARED_SURROUND = 0x100,
/* No independent HP possible */
BAD_NO_INDEP_HP = 0x40,
/* Primary DAC shared with main CLFE */
BAD_SHARED_CLFE = 0x10,
/* Primary DAC shared with extra surrounds */
Expand Down Expand Up @@ -1392,6 +1394,43 @@ static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
return snd_hda_get_path_idx(codec, path);
}

/* check whether the independent HP is available with the current config */
static bool indep_hp_possible(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->autocfg;
struct nid_path *path;
int i, idx;

if (cfg->line_out_type == AUTO_PIN_HP_OUT)
idx = spec->out_paths[0];
else
idx = spec->hp_paths[0];
path = snd_hda_get_path_from_idx(codec, idx);
if (!path)
return false;

/* assume no path conflicts unless aamix is involved */
if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid))
return true;

/* check whether output paths contain aamix */
for (i = 0; i < cfg->line_outs; i++) {
if (spec->out_paths[i] == idx)
break;
path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
if (path && is_nid_contained(path, spec->mixer_nid))
return false;
}
for (i = 0; i < cfg->speaker_outs; i++) {
path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]);
if (path && is_nid_contained(path, spec->mixer_nid))
return false;
}

return true;
}

/* fill the empty entries in the dac array for speaker/hp with the
* shared dac pointed by the paths
*/
Expand Down Expand Up @@ -1545,6 +1584,9 @@ static int fill_and_eval_dacs(struct hda_codec *codec,
badness += BAD_MULTI_IO;
}

if (spec->indep_hp && !indep_hp_possible(codec))
badness += BAD_NO_INDEP_HP;

/* re-fill the shared DAC for speaker / headphone */
if (cfg->line_out_type != AUTO_PIN_HP_OUT)
refill_shared_dacs(codec, cfg->hp_outs,
Expand Down Expand Up @@ -1758,6 +1800,10 @@ static int parse_output_paths(struct hda_codec *codec)
cfg->speaker_pins, val);
}

/* clear indep_hp flag if not available */
if (spec->indep_hp && !indep_hp_possible(codec))
spec->indep_hp = 0;

kfree(best_cfg);
return 0;
}
Expand Down
132 changes: 109 additions & 23 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ struct azx_dev {
unsigned int opened :1;
unsigned int running :1;
unsigned int irq_pending :1;
unsigned int prepared:1;
unsigned int locked:1;
/*
* For VIA:
* A flag to ensure DMA position is 0
Expand All @@ -426,8 +428,25 @@ struct azx_dev {

struct timecounter azx_tc;
struct cyclecounter azx_cc;

#ifdef CONFIG_SND_HDA_DSP_LOADER
struct mutex dsp_mutex;
#endif
};

/* DSP lock helpers */
#ifdef CONFIG_SND_HDA_DSP_LOADER
#define dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex)
#define dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex)
#define dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex)
#define dsp_is_locked(dev) ((dev)->locked)
#else
#define dsp_lock_init(dev) do {} while (0)
#define dsp_lock(dev) do {} while (0)
#define dsp_unlock(dev) do {} while (0)
#define dsp_is_locked(dev) 0
#endif

/* CORB/RIRB */
struct azx_rb {
u32 *buf; /* CORB/RIRB buffer
Expand Down Expand Up @@ -527,6 +546,10 @@ struct azx {

/* card list (for power_save trigger) */
struct list_head list;

#ifdef CONFIG_SND_HDA_DSP_LOADER
struct azx_dev saved_azx_dev;
#endif
};

#define CREATE_TRACE_POINTS
Expand Down Expand Up @@ -1793,15 +1816,25 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
dev = chip->capture_index_offset;
nums = chip->capture_streams;
}
for (i = 0; i < nums; i++, dev++)
if (!chip->azx_dev[dev].opened) {
res = &chip->azx_dev[dev];
if (res->assigned_key == key)
break;
for (i = 0; i < nums; i++, dev++) {
struct azx_dev *azx_dev = &chip->azx_dev[dev];
dsp_lock(azx_dev);
if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
res = azx_dev;
if (res->assigned_key == key) {
res->opened = 1;
res->assigned_key = key;
dsp_unlock(azx_dev);
return azx_dev;
}
}
dsp_unlock(azx_dev);
}
if (res) {
dsp_lock(res);
res->opened = 1;
res->assigned_key = key;
dsp_unlock(res);
}
return res;
}
Expand Down Expand Up @@ -2009,15 +2042,23 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
struct azx_dev *azx_dev = get_azx_dev(substream);
int ret;

dsp_lock(azx_dev);
if (dsp_is_locked(azx_dev)) {
ret = -EBUSY;
goto unlock;
}

mark_runtime_wc(chip, azx_dev, substream, false);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
ret = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (ret < 0)
return ret;
goto unlock;
mark_runtime_wc(chip, azx_dev, substream, true);
unlock:
dsp_unlock(azx_dev);
return ret;
}

Expand All @@ -2029,16 +2070,21 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];

/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_sd_writel(azx_dev, SD_CTL, 0);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
dsp_lock(azx_dev);
if (!dsp_is_locked(azx_dev)) {
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
azx_sd_writel(azx_dev, SD_CTL, 0);
azx_dev->bufsize = 0;
azx_dev->period_bytes = 0;
azx_dev->format_val = 0;
}

snd_hda_codec_cleanup(apcm->codec, hinfo, substream);

mark_runtime_wc(chip, azx_dev, substream, false);
azx_dev->prepared = 0;
dsp_unlock(azx_dev);
return snd_pcm_lib_free_pages(substream);
}

Expand All @@ -2055,6 +2101,12 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid);
unsigned short ctls = spdif ? spdif->ctls : 0;

dsp_lock(azx_dev);
if (dsp_is_locked(azx_dev)) {
err = -EBUSY;
goto unlock;
}

azx_stream_reset(chip, azx_dev);
format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
Expand All @@ -2065,7 +2117,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
snd_printk(KERN_ERR SFX
"%s: invalid format_val, rate=%d, ch=%d, format=%d\n",
pci_name(chip->pci), runtime->rate, runtime->channels, runtime->format);
return -EINVAL;
err = -EINVAL;
goto unlock;
}

bufsize = snd_pcm_lib_buffer_bytes(substream);
Expand All @@ -2084,7 +2137,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
azx_dev->no_period_wakeup = runtime->no_period_wakeup;
err = azx_setup_periods(chip, substream, azx_dev);
if (err < 0)
return err;
goto unlock;
}

/* wallclk has 24Mhz clock source */
Expand All @@ -2101,8 +2154,14 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) &&
stream_tag > chip->capture_streams)
stream_tag -= chip->capture_streams;
return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag,
azx_dev->format_val, substream);

unlock:
if (!err)
azx_dev->prepared = 1;
dsp_unlock(azx_dev);
return err;
}

static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
Expand All @@ -2117,6 +2176,9 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
azx_dev = get_azx_dev(substream);
trace_azx_pcm_trigger(chip, azx_dev, cmd);

if (dsp_is_locked(azx_dev) || !azx_dev->prepared)
return -EPIPE;

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
rstart = 1;
Expand Down Expand Up @@ -2621,17 +2683,27 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
struct azx_dev *azx_dev;
int err;

if (snd_hda_lock_devices(bus))
return -EBUSY;
azx_dev = azx_get_dsp_loader_dev(chip);

dsp_lock(azx_dev);
spin_lock_irq(&chip->reg_lock);
if (azx_dev->running || azx_dev->locked) {
spin_unlock_irq(&chip->reg_lock);
err = -EBUSY;
goto unlock;
}
azx_dev->prepared = 0;
chip->saved_azx_dev = *azx_dev;
azx_dev->locked = 1;
spin_unlock_irq(&chip->reg_lock);

err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
byte_size, bufp);
if (err < 0)
goto unlock;
goto err_alloc;

mark_pages_wc(chip, bufp, true);
azx_dev = azx_get_dsp_loader_dev(chip);
azx_dev->bufsize = byte_size;
azx_dev->period_bytes = byte_size;
azx_dev->format_val = format;
Expand All @@ -2649,13 +2721,20 @@ static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format,
goto error;

azx_setup_controller(chip, azx_dev);
dsp_unlock(azx_dev);
return azx_dev->stream_tag;

error:
mark_pages_wc(chip, bufp, false);
snd_dma_free_pages(bufp);
unlock:
snd_hda_unlock_devices(bus);
err_alloc:
spin_lock_irq(&chip->reg_lock);
if (azx_dev->opened)
*azx_dev = chip->saved_azx_dev;
azx_dev->locked = 0;
spin_unlock_irq(&chip->reg_lock);
unlock:
dsp_unlock(azx_dev);
return err;
}

Expand All @@ -2677,9 +2756,10 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
struct azx *chip = bus->private_data;
struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip);

if (!dmab->area)
if (!dmab->area || !azx_dev->locked)
return;

dsp_lock(azx_dev);
/* reset BDL address */
azx_sd_writel(azx_dev, SD_BDLPL, 0);
azx_sd_writel(azx_dev, SD_BDLPU, 0);
Expand All @@ -2692,7 +2772,12 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
snd_dma_free_pages(dmab);
dmab->area = NULL;

snd_hda_unlock_devices(bus);
spin_lock_irq(&chip->reg_lock);
if (azx_dev->opened)
*azx_dev = chip->saved_azx_dev;
azx_dev->locked = 0;
spin_unlock_irq(&chip->reg_lock);
dsp_unlock(azx_dev);
}
#endif /* CONFIG_SND_HDA_DSP_LOADER */

Expand Down Expand Up @@ -3481,6 +3566,7 @@ static int azx_first_init(struct azx *chip)
}

for (i = 0; i < chip->num_streams; i++) {
dsp_lock_init(&chip->azx_dev[i]);
/* allocate memory for the BDL for each stream */
err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
Expand Down
4 changes: 2 additions & 2 deletions sound/pci/hda/patch_cirrus.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@ static void cs_automute(struct hda_codec *codec)
snd_hda_gen_update_outputs(codec);

if (spec->gpio_eapd_hp) {
unsigned int gpio = spec->gen.hp_jack_present ?
spec->gpio_data = spec->gen.hp_jack_present ?
spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
snd_hda_codec_write(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA, gpio);
AC_VERB_SET_GPIO_DATA, spec->gpio_data);
}
}

Expand Down
Loading

0 comments on commit 70dc52f

Please sign in to comment.