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 {
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 {
compatible = "atmel,at91sam9g45-ssc";
reg = <0xf0010000 0x4000>;
interrupts = <28 4 5>;
- status = "disable";
+ status = "disabled";
};
tcb0: timer@f8008000 {
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;
struct snd_soc_dpcm_runtime dpcm[2];
long pmdown_time;
+ unsigned char pop_wait:1;
/* runtime devices */
struct snd_pcm *pcm;
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)
pm_runtime_put_noidle(&pci->dev);
dev++;
- complete(&chip->probe_wait);
+ complete_all(&chip->probe_wait);
return 0;
out_free:
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)
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);
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);
}
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);
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));
.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;
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);
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);
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);
}
}
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,
u32 sysclk;
u8 mclksel;
u32 mclk;
+ int shutdwn_delay;
};
static const struct reg_default cs42l73_reg_defaults[] = {
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"),
SND_SOC_DAPM_INPUT("LINEINA"),
SND_SOC_DAPM_INPUT("LINEINB"),
SND_SOC_DAPM_INPUT("MIC1"),
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),
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),
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),
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"),
{"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"},
{"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"},
{"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"},
{"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"},
{"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"},
{"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 {
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;
}
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);
}
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);
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 */
/* 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;
static int 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;
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 {
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;
}
(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;
}
dev_dbg(rtd->dev, "ASoC: 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);
}
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));
}
/* 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);
}
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;
/*
.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.
}
},
+
+/* 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,
[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,
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
*/
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);
QUIRK_MIDI_YAMAHA,
QUIRK_MIDI_MIDIMAN,
QUIRK_MIDI_NOVATION,
+ QUIRK_MIDI_MBOX2,
QUIRK_MIDI_RAW_BYTES,
QUIRK_MIDI_EMAGIC,
QUIRK_MIDI_CME,