Commit 5cd8846c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "A collection of small fixes, as expected for the middle rc:
   - A couple of fixes for potential NULL dereferences and out-of-range
     array accesses revealed by static code parsers
   - A fix for the wrong error handling detected by trinity
   - A regression fix for missing audio on some MacBooks
   - CA0132 DSP loader fixes
   - Fix for EAPD control of IDT codecs on machines w/o speaker
   - Fix a regression in the HD-audio widget list parser code
   - Workaround for the NuForce UDH-100 USB audio"

* tag 'sound-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda - Fix missing EAPD/GPIO setup for Cirrus codecs
  sound: sequencer: cap array index in seq_chn_common_event()
  ALSA: hda/ca0132 - Remove extra setting of dsp_state.
  ALSA: hda/ca0132 - Check download state of DSP.
  ALSA: hda/ca0132 - Check if dspload_image succeeded.
  ALSA: hda - Disable IDT eapd_switch if there are no internal speakers
  ALSA: hda - Fix snd_hda_get_num_raw_conns() to return a correct value
  ALSA: usb-audio: add a workaround for the NuForce UDH-100
  ALSA: asihpi - fix potential NULL pointer dereference
  ALSA: seq: Fix missing error handling in snd_seq_timer_open()
parents c7f17deb 6d3073e1
...@@ -290,11 +290,11 @@ int snd_seq_timer_open(struct snd_seq_queue *q) ...@@ -290,11 +290,11 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
tid.device = SNDRV_TIMER_GLOBAL_SYSTEM; tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
err = snd_timer_open(&t, str, &tid, q->queue); err = snd_timer_open(&t, str, &tid, q->queue);
} }
}
if (err < 0) { if (err < 0) {
snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err); snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err);
return err; return err;
} }
}
t->callback = snd_seq_timer_interrupt; t->callback = snd_seq_timer_interrupt;
t->callback_data = q; t->callback_data = q;
t->flags |= SNDRV_TIMER_IFLG_AUTO; t->flags |= SNDRV_TIMER_IFLG_AUTO;
......
...@@ -545,6 +545,9 @@ static void seq_chn_common_event(unsigned char *event_rec) ...@@ -545,6 +545,9 @@ static void seq_chn_common_event(unsigned char *event_rec)
case MIDI_PGM_CHANGE: case MIDI_PGM_CHANGE:
if (seq_mode == SEQ_2) if (seq_mode == SEQ_2)
{ {
if (chn > 15)
break;
synth_devs[dev]->chn_info[chn].pgm_num = p1; synth_devs[dev]->chn_info[chn].pgm_num = p1;
if ((int) dev >= num_synths) if ((int) dev >= num_synths)
synth_devs[dev]->set_instr(dev, chn, p1); synth_devs[dev]->set_instr(dev, chn, p1);
...@@ -596,6 +599,9 @@ static void seq_chn_common_event(unsigned char *event_rec) ...@@ -596,6 +599,9 @@ static void seq_chn_common_event(unsigned char *event_rec)
case MIDI_PITCH_BEND: case MIDI_PITCH_BEND:
if (seq_mode == SEQ_2) if (seq_mode == SEQ_2)
{ {
if (chn > 15)
break;
synth_devs[dev]->chn_info[chn].bender_value = w14; synth_devs[dev]->chn_info[chn].bender_value = w14;
if ((int) dev < num_synths) if ((int) dev < num_synths)
......
...@@ -2549,7 +2549,7 @@ static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, ...@@ -2549,7 +2549,7 @@ static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
{ {
struct snd_card *card = asihpi->card; struct snd_card *card;
unsigned int idx = 0; unsigned int idx = 0;
unsigned int subindex = 0; unsigned int subindex = 0;
int err; int err;
...@@ -2557,6 +2557,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) ...@@ -2557,6 +2557,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (snd_BUG_ON(!asihpi)) if (snd_BUG_ON(!asihpi))
return -EINVAL; return -EINVAL;
card = asihpi->card;
strcpy(card->mixername, "Asihpi Mixer"); strcpy(card->mixername, "Asihpi Mixer");
err = err =
......
...@@ -494,7 +494,7 @@ static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid) ...@@ -494,7 +494,7 @@ static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid) int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid)
{ {
return get_num_conns(codec, nid) & AC_CLIST_LENGTH; return snd_hda_get_raw_connections(codec, nid, NULL, 0);
} }
/** /**
...@@ -517,9 +517,6 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, ...@@ -517,9 +517,6 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t prev_nid; hda_nid_t prev_nid;
int null_count = 0; int null_count = 0;
if (snd_BUG_ON(!conn_list || max_conns <= 0))
return -EINVAL;
parm = get_num_conns(codec, nid); parm = get_num_conns(codec, nid);
if (!parm) if (!parm)
return 0; return 0;
...@@ -545,6 +542,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, ...@@ -545,6 +542,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
AC_VERB_GET_CONNECT_LIST, 0); AC_VERB_GET_CONNECT_LIST, 0);
if (parm == -1 && codec->bus->rirb_error) if (parm == -1 && codec->bus->rirb_error)
return -EIO; return -EIO;
if (conn_list)
conn_list[0] = parm & mask; conn_list[0] = parm & mask;
return 1; return 1;
} }
...@@ -580,14 +578,20 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, ...@@ -580,14 +578,20 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
continue; continue;
} }
for (n = prev_nid + 1; n <= val; n++) { for (n = prev_nid + 1; n <= val; n++) {
if (conn_list) {
if (conns >= max_conns) if (conns >= max_conns)
return -ENOSPC; return -ENOSPC;
conn_list[conns++] = n; conn_list[conns] = n;
}
conns++;
} }
} else { } else {
if (conn_list) {
if (conns >= max_conns) if (conns >= max_conns)
return -ENOSPC; return -ENOSPC;
conn_list[conns++] = val; conn_list[conns] = val;
}
conns++;
} }
prev_nid = val; prev_nid = val;
} }
......
...@@ -3239,7 +3239,7 @@ static int ca0132_set_vipsource(struct hda_codec *codec, int val) ...@@ -3239,7 +3239,7 @@ static int ca0132_set_vipsource(struct hda_codec *codec, int val)
struct ca0132_spec *spec = codec->spec; struct ca0132_spec *spec = codec->spec;
unsigned int tmp; unsigned int tmp;
if (!dspload_is_loaded(codec)) if (spec->dsp_state != DSP_DOWNLOADED)
return 0; return 0;
/* if CrystalVoice if off, vipsource should be 0 */ /* if CrystalVoice if off, vipsource should be 0 */
...@@ -4267,11 +4267,12 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) ...@@ -4267,11 +4267,12 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
*/ */
static void ca0132_setup_defaults(struct hda_codec *codec) static void ca0132_setup_defaults(struct hda_codec *codec)
{ {
struct ca0132_spec *spec = codec->spec;
unsigned int tmp; unsigned int tmp;
int num_fx; int num_fx;
int idx, i; int idx, i;
if (!dspload_is_loaded(codec)) if (spec->dsp_state != DSP_DOWNLOADED)
return; return;
/* out, in effects + voicefx */ /* out, in effects + voicefx */
...@@ -4351,12 +4352,16 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec) ...@@ -4351,12 +4352,16 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
return false; return false;
dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
dspload_image(codec, dsp_os_image, 0, 0, true, 0); if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
pr_err("ca0132 dspload_image failed.\n");
goto exit_download;
}
dsp_loaded = dspload_wait_loaded(codec); dsp_loaded = dspload_wait_loaded(codec);
exit_download:
release_firmware(fw_entry); release_firmware(fw_entry);
return dsp_loaded; return dsp_loaded;
} }
...@@ -4367,16 +4372,13 @@ static void ca0132_download_dsp(struct hda_codec *codec) ...@@ -4367,16 +4372,13 @@ static void ca0132_download_dsp(struct hda_codec *codec)
#ifndef CONFIG_SND_HDA_CODEC_CA0132_DSP #ifndef CONFIG_SND_HDA_CODEC_CA0132_DSP
return; /* NOP */ return; /* NOP */
#endif #endif
spec->dsp_state = DSP_DOWNLOAD_INIT;
if (spec->dsp_state == DSP_DOWNLOAD_INIT) {
chipio_enable_clocks(codec); chipio_enable_clocks(codec);
spec->dsp_state = DSP_DOWNLOADING; spec->dsp_state = DSP_DOWNLOADING;
if (!ca0132_download_dsp_images(codec)) if (!ca0132_download_dsp_images(codec))
spec->dsp_state = DSP_DOWNLOAD_FAILED; spec->dsp_state = DSP_DOWNLOAD_FAILED;
else else
spec->dsp_state = DSP_DOWNLOADED; spec->dsp_state = DSP_DOWNLOADED;
}
if (spec->dsp_state == DSP_DOWNLOADED) if (spec->dsp_state == DSP_DOWNLOADED)
ca0132_set_dsp_msr(codec, true); ca0132_set_dsp_msr(codec, true);
......
...@@ -506,6 +506,8 @@ static int patch_cs420x(struct hda_codec *codec) ...@@ -506,6 +506,8 @@ static int patch_cs420x(struct hda_codec *codec)
if (!spec) if (!spec)
return -ENOMEM; return -ENOMEM;
spec->gen.automute_hook = cs_automute;
snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
cs420x_fixups); cs420x_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
...@@ -893,6 +895,8 @@ static int patch_cs4210(struct hda_codec *codec) ...@@ -893,6 +895,8 @@ static int patch_cs4210(struct hda_codec *codec)
if (!spec) if (!spec)
return -ENOMEM; return -ENOMEM;
spec->gen.automute_hook = cs_automute;
snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
cs421x_fixups); cs421x_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
......
...@@ -815,6 +815,29 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) ...@@ -815,6 +815,29 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
return 0; return 0;
} }
/* check whether a built-in speaker is included in parsed pins */
static bool has_builtin_speaker(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
hda_nid_t *nid_pin;
int nids, i;
if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
nid_pin = spec->gen.autocfg.line_out_pins;
nids = spec->gen.autocfg.line_outs;
} else {
nid_pin = spec->gen.autocfg.speaker_pins;
nids = spec->gen.autocfg.speaker_outs;
}
for (i = 0; i < nids; i++) {
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid_pin[i]);
if (snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT)
return true;
}
return false;
}
/* /*
* PC beep controls * PC beep controls
*/ */
...@@ -3890,6 +3913,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec) ...@@ -3890,6 +3913,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
return err; return err;
} }
/* Don't GPIO-mute speakers if there are no internal speakers, because
* the GPIO might be necessary for Headphone
*/
if (spec->eapd_switch && !has_builtin_speaker(codec))
spec->eapd_switch = 0;
codec->proc_widget_hook = stac92hd7x_proc_hook; codec->proc_widget_hook = stac92hd7x_proc_hook;
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
......
...@@ -243,6 +243,21 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -243,6 +243,21 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
struct usb_interface_assoc_descriptor *assoc = struct usb_interface_assoc_descriptor *assoc =
usb_ifnum_to_if(dev, ctrlif)->intf_assoc; usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
if (!assoc) {
/*
* Firmware writers cannot count to three. So to find
* the IAD on the NuForce UDH-100, also check the next
* interface.
*/
struct usb_interface *iface =
usb_ifnum_to_if(dev, ctrlif + 1);
if (iface &&
iface->intf_assoc &&
iface->intf_assoc->bFunctionClass == USB_CLASS_AUDIO &&
iface->intf_assoc->bFunctionProtocol == UAC_VERSION_2)
assoc = iface->intf_assoc;
}
if (!assoc) { if (!assoc) {
snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n"); snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n");
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment