From d06080cf08e6b59971959d9be3d0587c6e033292 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 7 Dec 2012 16:32:26 +0530 Subject: [PATCH 01/16] ASoC: tpa6130a2: Use devm_* APIs Converted to use devm_gpio_request and devm_regulator_get APIs. These are device managed and make error handling and cleanup a bit simpler. Cc: Peter Ujfalusi Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- sound/soc/codecs/tpa6130a2.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 565ff39ad3a3..ec78073e3588 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -398,7 +398,8 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, TPA6130A2_MUTE_L; if (data->power_gpio >= 0) { - ret = gpio_request(data->power_gpio, "tpa6130a2 enable"); + ret = devm_gpio_request(dev, data->power_gpio, + "tpa6130a2 enable"); if (ret < 0) { dev_err(dev, "Failed to request power GPIO (%d)\n", data->power_gpio); @@ -419,16 +420,16 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, break; } - data->supply = regulator_get(dev, regulator); + data->supply = devm_regulator_get(dev, regulator); if (IS_ERR(data->supply)) { ret = PTR_ERR(data->supply); dev_err(dev, "Failed to request supply: %d\n", ret); - goto err_regulator; + goto err_gpio; } ret = tpa6130a2_power(1); if (ret != 0) - goto err_power; + goto err_gpio; /* Read version */ @@ -440,15 +441,10 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client, /* Disable the chip */ ret = tpa6130a2_power(0); if (ret != 0) - goto err_power; + goto err_gpio; return 0; -err_power: - regulator_put(data->supply); -err_regulator: - if (data->power_gpio >= 0) - gpio_free(data->power_gpio); err_gpio: tpa6130a2_client = NULL; @@ -457,14 +453,7 @@ err_gpio: static int __devexit tpa6130a2_remove(struct i2c_client *client) { - struct tpa6130a2_data *data = i2c_get_clientdata(client); - tpa6130a2_power(0); - - if (data->power_gpio >= 0) - gpio_free(data->power_gpio); - - regulator_put(data->supply); tpa6130a2_client = NULL; return 0; From a3adb1432d7a3ad86bb17a1638e44414537e4118 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Dec 2012 18:30:51 +0100 Subject: [PATCH 02/16] ASoC: sigmadsp: Fix endianness conversion issue The 'addr' field of the sigma_action struct is stored as big endian in the firmware file. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/sigmadsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index 5be42bf56996..4068f2491232 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c @@ -225,7 +225,7 @@ EXPORT_SYMBOL(process_sigma_firmware); static int sigma_action_write_regmap(void *control_data, const struct sigma_action *sa, size_t len) { - return regmap_raw_write(control_data, le16_to_cpu(sa->addr), + return regmap_raw_write(control_data, be16_to_cpu(sa->addr), sa->payload, len - 2); } From a1ad500e369183796820bffb4012b876a8685219 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 7 Dec 2012 14:53:42 -0600 Subject: [PATCH 03/16] ASoC: cs42l73: Add DMIC's as DAPM inputs. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 2c08c4cb465a..476679510dff 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -589,6 +589,8 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { }; static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMICA"), + SND_SOC_DAPM_INPUT("DMICB"), SND_SOC_DAPM_INPUT("LINEINA"), SND_SOC_DAPM_INPUT("LINEINB"), SND_SOC_DAPM_INPUT("MIC1"), @@ -795,6 +797,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"ADC Left", NULL, "PGA Left"}, {"ADC Right", NULL, "PGA Right"}, + {"DMIC Left", NULL, "DMICA"}, + {"DMIC Right", NULL, "DMICB"}, {"Input Left Capture", "ADC Left Input", "ADC Left"}, {"Input Right Capture", "ADC Right Input", "ADC Right"}, From 41df0829cee9e4c4ba68de33b4ca26cb18ac8ed7 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 7 Dec 2012 14:53:43 -0600 Subject: [PATCH 04/16] ASoC: cs42l73: Add DAPM events for power down. Add power down delays between setting PDN and MCLKDIS for spk amp, spklo amp, and ear amp. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 80 ++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 476679510dff..fb9b178d6ffe 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -40,6 +40,7 @@ struct cs42l73_private { u32 sysclk; u8 mclksel; u32 mclk; + int shutdwn_delay; }; static const struct reg_default cs42l73_reg_defaults[] = { @@ -588,6 +589,57 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { SOC_ENUM("XSPOUT Mono/Stereo Select", xsp_output_mux_enum), }; +static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 150 ms delay between setting PDN and MCLKDIS */ + priv->shutdwn_delay = 150; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 50 ms delay between setting PDN and MCLKDIS */ + if (priv->shutdwn_delay < 50) + priv->shutdwn_delay = 50; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + + +static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); + switch (event) { + case SND_SOC_DAPM_POST_PMD: + /* 30 ms delay between setting PDN and MCLKDIS */ + if (priv->shutdwn_delay < 30) + priv->shutdwn_delay = 30; + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMICA"), SND_SOC_DAPM_INPUT("DMICB"), @@ -676,16 +728,20 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_PGA("SPK DAC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("ESL DAC", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SWITCH("HP Amp", CS42L73_PWRCTL3, 0, 1, - &hp_amp_ctl), + SND_SOC_DAPM_SWITCH_E("HP Amp", CS42L73_PWRCTL3, 0, 1, + &hp_amp_ctl, cs42l73_hp_amp_event, + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SWITCH("LO Amp", CS42L73_PWRCTL3, 1, 1, &lo_amp_ctl), - SND_SOC_DAPM_SWITCH("SPK Amp", CS42L73_PWRCTL3, 2, 1, - &spk_amp_ctl), - SND_SOC_DAPM_SWITCH("EAR Amp", CS42L73_PWRCTL3, 3, 1, - &ear_amp_ctl), - SND_SOC_DAPM_SWITCH("SPKLO Amp", CS42L73_PWRCTL3, 4, 1, - &spklo_amp_ctl), + SND_SOC_DAPM_SWITCH_E("SPK Amp", CS42L73_PWRCTL3, 2, 1, + &spk_amp_ctl, cs42l73_spklo_spk_amp_event, + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SWITCH_E("EAR Amp", CS42L73_PWRCTL3, 3, 1, + &ear_amp_ctl, cs42l73_ear_amp_event, + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SWITCH_E("SPKLO Amp", CS42L73_PWRCTL3, 4, 1, + &spklo_amp_ctl, cs42l73_spklo_spk_amp_event, + SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("HPOUTA"), SND_SOC_DAPM_OUTPUT("HPOUTB"), @@ -1171,6 +1227,14 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1); + if (cs42l73->shutdwn_delay > 0) { + mdelay(cs42l73->shutdwn_delay); + cs42l73->shutdwn_delay = 0; + } else { + mdelay(15); /* Min amount of time requred to power + * down. + */ + } snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1); break; } From 7f3dd4a8e31cdaed5f80f24b798cedcab644830b Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Fri, 7 Dec 2012 14:53:44 -0600 Subject: [PATCH 05/16] ASoC: cs42l73: Change VSPIN/VSPOUT to VSPINOUT Since VSP only has one power bit, only provide one DAPM widget. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index fb9b178d6ffe..dd0d9b2ebdbf 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -658,9 +658,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { CS42L73_PWRCTL2, 3, 1), SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL, 0, CS42L73_PWRCTL2, 3, 1), - SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL, 0, - CS42L73_PWRCTL2, 4, 1), - SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL, 0, + SND_SOC_DAPM_AIF_OUT("VSPINOUT", NULL, 0, CS42L73_PWRCTL2, 4, 1), SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -686,8 +684,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_MIXER("ASPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("XSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("XSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("VSP Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0, CS42L73_PWRCTL2, 0, 1), @@ -703,7 +700,7 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0, CS42L73_PWRCTL2, 2, 1), - SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0, + SND_SOC_DAPM_AIF_IN("VSPINOUT", NULL, 0, CS42L73_PWRCTL2, 4, 1), SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -763,7 +760,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"ESL DAC", "ESL-ASP Mono Volume", "ESL Mixer"}, {"ESL DAC", "ESL-XSP Mono Volume", "ESL Mixer"}, - {"ESL DAC", "ESL-VSP Mono Volume", "VSPIN"}, + {"ESL DAC", "ESL-VSP Mono Volume", "VSPINOUT"}, /* Loopback */ {"ESL DAC", "ESL-IP Mono Volume", "Input Left Capture"}, {"ESL DAC", "ESL-IP Mono Volume", "Input Right Capture"}, @@ -785,7 +782,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"SPK DAC", "SPK-ASP Mono Volume", "SPK Mixer"}, {"SPK DAC", "SPK-XSP Mono Volume", "SPK Mixer"}, - {"SPK DAC", "SPK-VSP Mono Volume", "VSPIN"}, + {"SPK DAC", "SPK-VSP Mono Volume", "VSPINOUT"}, /* Loopback */ {"SPK DAC", "SPK-IP Mono Volume", "Input Left Capture"}, {"SPK DAC", "SPK-IP Mono Volume", "Input Right Capture"}, @@ -828,8 +825,8 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"HL Right Mixer", NULL, "ASPINR"}, {"HL Left Mixer", NULL, "XSPINL"}, {"HL Right Mixer", NULL, "XSPINR"}, - {"HL Left Mixer", NULL, "VSPIN"}, - {"HL Right Mixer", NULL, "VSPIN"}, + {"HL Left Mixer", NULL, "VSPINOUT"}, + {"HL Right Mixer", NULL, "VSPINOUT"}, {"ASPINL", NULL, "ASP Playback"}, {"ASPINM", NULL, "ASP Playback"}, @@ -837,7 +834,7 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"XSPINL", NULL, "XSP Playback"}, {"XSPINM", NULL, "XSP Playback"}, {"XSPINR", NULL, "XSP Playback"}, - {"VSPIN", NULL, "VSP Playback"}, + {"VSPINOUT", NULL, "VSP Playback"}, /* Capture Paths */ {"MIC1", NULL, "MIC1 Bias"}, @@ -879,21 +876,18 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = { {"XSPOUTR", NULL, "XSPR Output Mixer"}, /* Voice Capture */ - {"VSPL Output Mixer", NULL, "Input Left Capture"}, - {"VSPR Output Mixer", NULL, "Input Left Capture"}, + {"VSP Output Mixer", NULL, "Input Left Capture"}, + {"VSP Output Mixer", NULL, "Input Right Capture"}, - {"VSPOUTL", "VSP-IP Volume", "VSPL Output Mixer"}, - {"VSPOUTR", "VSP-IP Volume", "VSPR Output Mixer"}, + {"VSPINOUT", "VSP-IP Volume", "VSP Output Mixer"}, - {"VSPOUTL", NULL, "VSPL Output Mixer"}, - {"VSPOUTR", NULL, "VSPR Output Mixer"}, + {"VSPINOUT", NULL, "VSP Output Mixer"}, {"ASP Capture", NULL, "ASPOUTL"}, {"ASP Capture", NULL, "ASPOUTR"}, {"XSP Capture", NULL, "XSPOUTL"}, {"XSP Capture", NULL, "XSPOUTR"}, - {"VSP Capture", NULL, "VSPOUTL"}, - {"VSP Capture", NULL, "VSPOUTR"}, + {"VSP Capture", NULL, "VSPINOUT"}, }; struct cs42l73_mclk_div { From c871bd0b2e627ff387d0ff055d8175879c80d01f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 10 Dec 2012 16:19:52 +0900 Subject: [PATCH 06/16] ASoC: core: Fix splitting of log messages Don't wrap log messages over multiple lines, it makes them hard to grep for. Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cee37ee6f180..0d42afb3c552 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -4155,9 +4155,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, ret = of_property_read_string_index(np, propname, 2 * i, &routes[i].sink); if (ret) { - dev_err(card->dev, "ASoC: Property '%s' index %d" - " could not be read: %d\n", propname, 2 * i, - ret); + dev_err(card->dev, + "ASoC: Property '%s' index %d could not be read: %d\n", + propname, 2 * i, ret); kfree(routes); return -EINVAL; } @@ -4165,8 +4165,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, (2 * i) + 1, &routes[i].source); if (ret) { dev_err(card->dev, - "ASoC: Property '%s' index %d could not be" - " read: %d\n", propname, (2 * i) + 1, ret); + "ASoC: Property '%s' index %d could not be read: %d\n", + propname, (2 * i) + 1, ret); kfree(routes); return -EINVAL; } From 8ae5865ec77c22462c736846a0679947a6953548 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Dec 2012 14:33:42 +0100 Subject: [PATCH 07/16] ALSA: hda - Fix pin configuration of HP Pavilion dv7 Fix the quirk entry for HP Pavilion dv7 in order to make the bass speaker working. Reported-and-tested-by: Tomas Pospisek Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index df13c0f84899..a86547ca17c8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1725,7 +1725,7 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + "HP Pavilion dv7", STAC_HP_DV7_4000), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, From 6169b673618bf0b2518ce413b54925782a603f06 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Dec 2012 10:22:35 +0100 Subject: [PATCH 08/16] ALSA: hda - Always turn on pins for HDMI/DP We've seen the broken HDMI *video* output on some machines with GM965, and the debugging session pointed that the culprit is the disabled audio output pins. Toggling these pins dynamically on demand caused flickering of HDMI TV. This patch changes the behavior to keep the pin ON constantly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51421 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0fcfa6f406b8..37dd06dd96be 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -431,9 +431,11 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Disable pin out until stream is active*/ + /* Enable pin out: some machines with GM965 gets broken output when + * the pin is disabled or changed while using with HDMI + */ snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); } static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) @@ -1341,7 +1343,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; int pin_idx = hinfo_to_pin_index(spec, hinfo); hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; - int pinctl; bool non_pcm; non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); @@ -1350,11 +1351,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); - pinctl = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } @@ -1374,7 +1370,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, int cvt_idx, pin_idx; struct hdmi_spec_per_cvt *per_cvt; struct hdmi_spec_per_pin *per_pin; - int pinctl; if (hinfo->nid) { cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); @@ -1391,11 +1386,6 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, return -EINVAL; per_pin = &spec->pins[pin_idx]; - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl & ~PIN_OUT); snd_hda_spdif_ctls_unassign(codec, pin_idx); per_pin->chmap_set = false; memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); From df68f106436b684520212494a5ce0e3823b485da Mon Sep 17 00:00:00 2001 From: Eldad Zack Date: Sat, 15 Dec 2012 05:30:33 +0100 Subject: [PATCH 09/16] ALSA: usb-audio: ignore-quirk for HP Wireless Audio As Joe Cooper reported, "On most HP Envy laptops the snd-usb-audio module causes the system to become unresponsive and Gnome Shell 3 to crash.". See also: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-December/057729.html Add a quirk to ignore this device (for now) to solve the instability issue and allow other USB audio devices to be used. Reported-by: Joe Cooper Tested-by: Isaac Smith Signed-off-by: Eldad Zack Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 49f9af995d7a..579cf6f6901c 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -98,6 +98,42 @@ .bInterfaceClass = USB_CLASS_AUDIO, }, +/* + * HP Wireless Audio + * When not ignored, causes instability issues for some users, forcing them to + * blacklist the entire module. + */ +{ + USB_DEVICE(0x0424, 0xb832), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Standard Microsystems Corp.", + .product_name = "HP Wireless Audio", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + /* Mixer */ + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Playback */ + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Capture */ + { + .ifnum = 2, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* HID Device, .ifnum = 3 */ + { + .ifnum = -1, + } + } + } +}, + /* * Logitech QuickCam: bDeviceClass is vendor-specific, so generic interface * class matches do not take effect without an explicit ID match. From 9bffb1fb7c22c96d51d4ba06e2e023dd568a5872 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Thu, 13 Dec 2012 12:23:05 -0600 Subject: [PATCH 10/16] ASoC: Prevent pop_wait overwrite pop_wait is used to determine if a deferred playback close needs to be cancelled when the a PCM is open or if after the power-down delay expires it needs to run. pop_wait is associated with the CODEC DAI, so the CODEC DAI must be unique. This holds true for most CODECs, except for the dummy CODEC and its DAI. In DAI links with non-unique dummy CODECs (e.g. front-ends), pop_wait can be overwritten by another DAI link using also a dummy CODEC. Failure to cancel a deferred close can cause mute due to the DAPM STOP event sent in the deferred work. One scenario where pop_wait is overwritten and causing mute is below (where hw:0,0 and hw:0,1 are two front-ends with default pmdown_time = 5 secs): aplay /dev/urandom -D hw:0,0 -c 2 -r 48000 -f S16_LE -d 1 sleep 1 aplay /dev/urandom -D hw:0,1 -c 2 -r 48000 -f S16_LE -d 3 & aplay /dev/urandom -D hw:0,0 -c 2 -r 48000 -f S16_LE Since CODECs may not be unique, pop_wait is moved to the PCM runtime structure. Creating separate dummy CODECs for each DAI link can also solve the problem, but at this point it's only pop_wait variable in the CODEC DAI that has negative effects by not being unique. Signed-off-by: Misael Lopez Cruz Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 1 - include/sound/soc.h | 1 + sound/soc/soc-compress.c | 2 +- sound/soc/soc-pcm.c | 12 ++++++------ 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 628db7bca4fd..3953cea0ecfb 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -242,7 +242,6 @@ struct snd_soc_dai { unsigned int symmetric_rates:1; struct snd_pcm_runtime *runtime; unsigned int active; - unsigned char pop_wait:1; unsigned char probed:1; struct snd_soc_dapm_widget *playback_widget; diff --git a/include/sound/soc.h b/include/sound/soc.h index 91244a096c19..769e27c774a3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1039,6 +1039,7 @@ struct snd_soc_pcm_runtime { struct snd_soc_dpcm_runtime dpcm[2]; long pmdown_time; + unsigned char pop_wait:1; /* runtime devices */ struct snd_pcm *pcm; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 967d0e173e1b..5fbfb06e8083 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -113,7 +113,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); } else - codec_dai->pop_wait = 1; + rtd->pop_wait = 1; schedule_delayed_work(&rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } else { diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ef22d0bd9e9e..3a2423bd84b2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -333,11 +333,11 @@ static void close_delayed_work(struct work_struct *work) pr_debug("pop wq checking: %s status: %s waiting: %s\n", codec_dai->driver->playback.stream_name, codec_dai->playback_active ? "active" : "inactive", - codec_dai->pop_wait ? "yes" : "no"); + rtd->pop_wait ? "yes" : "no"); /* are we waiting on this codec DAI stream */ - if (codec_dai->pop_wait == 1) { - codec_dai->pop_wait = 0; + if (rtd->pop_wait == 1) { + rtd->pop_wait = 0; snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_STOP); } @@ -407,7 +407,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) SND_SOC_DAPM_STREAM_STOP); } else { /* start delayed pop wq here for playback streams */ - codec_dai->pop_wait = 1; + rtd->pop_wait = 1; schedule_delayed_work(&rtd->delayed_work, msecs_to_jiffies(rtd->pmdown_time)); } @@ -478,8 +478,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - codec_dai->pop_wait) { - codec_dai->pop_wait = 0; + rtd->pop_wait) { + rtd->pop_wait = 0; cancel_delayed_work(&rtd->delayed_work); } From 315656bc3bf5b24e560ab1d9e2d49a5e987b49b4 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Thu, 13 Dec 2012 10:05:07 +0800 Subject: [PATCH 11/16] ASoC: atmel-ssc: change disable to disable in dts node Change the value of status to disabled to keep the consistent Signed-off-by: Bo Shen Signed-off-by: Mark Brown --- arch/arm/boot/dts/at91sam9260.dtsi | 2 +- arch/arm/boot/dts/at91sam9263.dtsi | 4 ++-- arch/arm/boot/dts/at91sam9g45.dtsi | 4 ++-- arch/arm/boot/dts/at91sam9x5.dtsi | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index aaa42d8d4f88..03c56cbd050d 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -217,7 +217,7 @@ compatible = "atmel,at91rm9200-ssc"; reg = <0xfffbc000 0x4000>; interrupts = <14 4 5>; - status = "disable"; + status = "disabled"; }; adc0: adc@fffe0000 { diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 3b721ee59b10..15f12dd803ea 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -179,14 +179,14 @@ compatible = "atmel,at91rm9200-ssc"; reg = <0xfff98000 0x4000>; interrupts = <16 4 5>; - status = "disable"; + status = "disabled"; }; ssc1: ssc@fff9c000 { compatible = "atmel,at91rm9200-ssc"; reg = <0xfff9c000 0x4000>; interrupts = <17 4 5>; - status = "disable"; + status = "disabled"; }; macb0: ethernet@fffbc000 { diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index acfa207162ff..44a38d0fe597 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -232,14 +232,14 @@ compatible = "atmel,at91sam9g45-ssc"; reg = <0xfff9c000 0x4000>; interrupts = <16 4 5>; - status = "disable"; + status = "disabled"; }; ssc1: ssc@fffa0000 { compatible = "atmel,at91sam9g45-ssc"; reg = <0xfffa0000 0x4000>; interrupts = <17 4 5>; - status = "disable"; + status = "disabled"; }; adc0: adc@fffb0000 { diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 69667d0ac347..0beff720caf9 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -92,7 +92,7 @@ compatible = "atmel,at91sam9g45-ssc"; reg = <0xf0010000 0x4000>; interrupts = <28 4 5>; - status = "disable"; + status = "disabled"; }; tcb0: timer@f8008000 { From 1098b7c2285d6d4c0d523563be580a56b07f11c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Dec 2012 20:03:15 +0100 Subject: [PATCH 12/16] ALSA: hda - Set codec->single_adc_amp flag for Realtek codecs It turned out that Realtek codecs (ALC260, etc) with input amps in audio-input widgets don't handle the multiple individual input amps. Thus we need to set codec->single_adc_amp flag for them in general. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7743775f6abb..16d210a7f158 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4373,6 +4373,7 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) if (!spec) return -ENOMEM; codec->spec = spec; + codec->single_adc_amp = 1; spec->mixer_nid = mixer_nid; snd_hda_gen_init(&spec->gen); snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); From b78562b10fa66175e30b76073e32a0ad8d92aa83 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 17 Dec 2012 20:06:49 +0100 Subject: [PATCH 13/16] ALSA: hda - Fix the wrong pincaps set in ALC861VD dallas/hp fixup The workaround to force VREF50 for dallas/hp model with ALC861VD was introduced in commit 8fdcb6fe4204bdb4c6991652717ab5063751414e, but it contained wrong pincap override bits. This patch fixes to exclude VREF80 pincap bit correctly. Cc: [v3.2+] Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 16d210a7f158..6ee34593774a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6570,8 +6570,8 @@ static void alc861vd_fixup_dallas(struct hda_codec *codec, const struct alc_fixup *fix, int action) { if (action == ALC_FIXUP_ACT_PRE_PROBE) { - snd_hda_override_pin_caps(codec, 0x18, 0x00001714); - snd_hda_override_pin_caps(codec, 0x19, 0x0000171c); + snd_hda_override_pin_caps(codec, 0x18, 0x00000734); + snd_hda_override_pin_caps(codec, 0x19, 0x0000073c); } } From 6ffe168f822cf7f777987cddc00ade542fd73bf0 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Tue, 18 Dec 2012 16:59:15 -0500 Subject: [PATCH 14/16] ALSA: hda - bug fix for invalid connection list of Haswell HDMI codec pins Haswell HDMI codec pins may report invalid connection list entries, which will cause failure to play audio via HDMI or Display Port. So this patch adds fixup for Haswell to workaround this hardware issue: enable DP1.2 mode and override the pins' connection list entries with proper value. Signed-off-by: Mengdong Lin Signed-off-by: Xingchao Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 37dd06dd96be..b6c21ea187ca 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1681,6 +1681,30 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = { .unsol_event = hdmi_unsol_event, }; +static void intel_haswell_fixup_connect_list(struct hda_codec *codec) +{ + unsigned int vendor_param; + hda_nid_t list[3] = {0x2, 0x3, 0x4}; + + vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0); + if (vendor_param == -1 || vendor_param & 0x02) + return; + + /* enable DP1.2 mode */ + vendor_param |= 0x02; + snd_hda_codec_read(codec, 0x08, 0, 0x781, vendor_param); + + vendor_param = snd_hda_codec_read(codec, 0x08, 0, 0xf81, 0); + if (vendor_param == -1 || !(vendor_param & 0x02)) + return; + + /* override 3 pins connection list */ + snd_hda_override_conn_list(codec, 0x05, 3, list); + snd_hda_override_conn_list(codec, 0x06, 3, list); + snd_hda_override_conn_list(codec, 0x07, 3, list); +} + + static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1690,6 +1714,10 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; + + if (codec->vendor_id == 0x80862807) + intel_haswell_fixup_connect_list(codec); + if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec); From 44728e97c35ef31d649dafbbada665e37176f5da Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Tue, 18 Dec 2012 23:59:33 +0800 Subject: [PATCH 15/16] ALSA: HDA: Fix sound resume hang Resuming a switcheroo'd HDA controller hangs since the completion is one-shot (thus works the first time). Fix by using completions that explictly need rearming, so remain fired before. Signed-off-by: Daniel J Blueman Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0f3d3db0df71..cca87277baf0 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2876,7 +2876,7 @@ static int azx_free(struct azx *chip) azx_notifier_unregister(chip); chip->init_failed = 1; /* to be sure */ - complete(&chip->probe_wait); + complete_all(&chip->probe_wait); if (use_vga_switcheroo(chip)) { if (chip->disabled && chip->bus) @@ -3504,7 +3504,7 @@ static int azx_probe(struct pci_dev *pci, pm_runtime_put_noidle(&pci->dev); dev++; - complete(&chip->probe_wait); + complete_all(&chip->probe_wait); return 0; out_free: From cb99864d40e46dea9c2aa3eaa97517b776f91024 Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Wed, 19 Dec 2012 11:27:22 +0100 Subject: [PATCH 16/16] ALSA: usb-audio: Support for Digidesign Mbox 2 USB sound card: This patch is the result of a lot of trial and error, since there are no specs available for the device. Full duplex support is provided, i.e. playback and recording in stereo. The format is hardcoded at 48000Hz @ 24 bit, which is the maximum that the device supports. Also, MIDI in and MIDI out both work. Users will notice that the S/PDIF light also flashes when playback or recording is active. I believe this means that S/PDIF input/output is simultaneously activated with the analogue i/o during use. But this particular functionality remains untested. Note that this particular version of the patch is so far untested on the physical hardware because I have not compiled a full kernel with the changes. However, extensive testing has been done by many users of the hardware who believe other versions of my patch have worked since circa 2009. [Modified to make a function static by tiwai] Signed-off-by: Damien Zammit Signed-off-by: Takashi Iwai --- sound/usb/midi.c | 4 ++ sound/usb/quirks-table.h | 87 ++++++++++++++++++++++++++++++++++++++ sound/usb/quirks.c | 91 ++++++++++++++++++++++++++++++++++++++++ sound/usb/usbaudio.h | 1 + 4 files changed, 183 insertions(+) diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 34b9bb7fe87c..c183d34842ac 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -2181,6 +2181,10 @@ int snd_usbmidi_create(struct snd_card *card, umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; + case QUIRK_MIDI_MBOX2: + umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops; + err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); + break; case QUIRK_MIDI_RAW_BYTES: umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; /* diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 579cf6f6901c..cdcf6b45e8a8 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2921,6 +2921,93 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, + +/* DIGIDESIGN MBOX 2 */ +{ + USB_DEVICE(0x0dba, 0x3000), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Digidesign", + .product_name = "Mbox 2", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 2, + .altsetting = 2, + .altset_idx = 1, + .attributes = 0x00, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_SYNC_ASYNC, + .maxpacksize = 0x128, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 3, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 4, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3BE, + .channels = 2, + .iface = 4, + .altsetting = 2, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x85, + .ep_attr = USB_ENDPOINT_SYNC_SYNC, + .maxpacksize = 0x128, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + { + .ifnum = 5, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 6, + .type = QUIRK_MIDI_MBOX2, + .data = &(const struct snd_usb_midi_endpoint_info) { + .out_ep = 0x02, + .out_cables = 0x0001, + .in_ep = 0x81, + .in_interval = 0x01, + .in_cables = 0x0001 + } + }, + { + .ifnum = -1 + } + } + } +}, { /* Tascam US122 MKII - playback-only support */ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 0f58b4b6d702..203d72b8a037 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -306,6 +306,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_MBOX2] = create_any_midi_quirk, [QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk, [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, [QUIRK_MIDI_CME] = create_any_midi_quirk, @@ -497,6 +498,92 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev) return -EAGAIN; } +static void mbox2_setup_48_24_magic(struct usb_device *dev) +{ + u8 srate[3]; + u8 temp[12]; + + /* Choose 48000Hz permanently */ + srate[0] = 0x80; + srate[1] = 0xbb; + srate[2] = 0x00; + + /* Send the magic! */ + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x01, 0x22, 0x0100, 0x0085, &temp, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0085, &srate, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0086, &srate, 0x0003); + snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), + 0x81, 0xa2, 0x0100, 0x0003, &srate, 0x0003); + return; +} + +/* Digidesign Mbox 2 needs to load firmware onboard + * and driver must wait a few seconds for initialisation. + */ + +#define MBOX2_FIRMWARE_SIZE 646 +#define MBOX2_BOOT_LOADING 0x01 /* Hard coded into the device */ +#define MBOX2_BOOT_READY 0x02 /* Hard coded into the device */ + +int snd_usb_mbox2_boot_quirk(struct usb_device *dev) +{ + struct usb_host_config *config = dev->actconfig; + int err; + u8 bootresponse; + int fwsize; + int count; + + fwsize = le16_to_cpu(get_cfg_desc(config)->wTotalLength); + + if (fwsize != MBOX2_FIRMWARE_SIZE) { + snd_printk(KERN_ERR "usb-audio: Invalid firmware size=%d.\n", fwsize); + return -ENODEV; + } + + snd_printd("usb-audio: Sending Digidesign Mbox 2 boot sequence...\n"); + + count = 0; + bootresponse = MBOX2_BOOT_LOADING; + while ((bootresponse == MBOX2_BOOT_LOADING) && (count < 10)) { + msleep(500); /* 0.5 second delay */ + snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), + /* Control magic - load onboard firmware */ + 0x85, 0xc0, 0x0001, 0x0000, &bootresponse, 0x0012); + if (bootresponse == MBOX2_BOOT_READY) + break; + snd_printd("usb-audio: device not ready, resending boot sequence...\n"); + count++; + } + + if (bootresponse != MBOX2_BOOT_READY) { + snd_printk(KERN_ERR "usb-audio: Unknown bootresponse=%d, or timed out, ignoring device.\n", bootresponse); + return -ENODEV; + } + + snd_printdd("usb-audio: device initialised!\n"); + + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, + &dev->descriptor, sizeof(dev->descriptor)); + config = dev->actconfig; + if (err < 0) + snd_printd("error usb_get_descriptor: %d\n", err); + + err = usb_reset_configuration(dev); + if (err < 0) + snd_printd("error usb_reset_configuration: %d\n", err); + snd_printdd("mbox2_boot: new boot length = %d\n", + le16_to_cpu(get_cfg_desc(config)->wTotalLength)); + + mbox2_setup_48_24_magic(dev); + + snd_printk(KERN_INFO "usb-audio: Digidesign Mbox 2: 24bit 48kHz"); + + return 0; /* Successful boot */ +} + /* * Setup quirks */ @@ -655,6 +742,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, case USB_ID(0x0ccd, 0x00b1): /* Terratec Aureon 7.1 USB */ return snd_usb_cm6206_boot_quirk(dev); + case USB_ID(0x0dba, 0x3000): + /* Digidesign Mbox 2 */ + return snd_usb_mbox2_boot_quirk(dev); + case USB_ID(0x133e, 0x0815): /* Access Music VirusTI Desktop */ return snd_usb_accessmusic_boot_quirk(dev); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 1ac3fd9cc5a6..a8172c119796 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -76,6 +76,7 @@ enum quirk_type { QUIRK_MIDI_YAMAHA, QUIRK_MIDI_MIDIMAN, QUIRK_MIDI_NOVATION, + QUIRK_MIDI_MBOX2, QUIRK_MIDI_RAW_BYTES, QUIRK_MIDI_EMAGIC, QUIRK_MIDI_CME,