Commit 63e1968a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull sound fixes from Takashi Iwai:
 "A collection of small, mostly device-specific fixes.

  The significant one is the regression fix for USB-audio implicit
  feedback devices due to the incorrect frame size calculation, which
  landed in 5.8 and stable trees.

  In addition, a few usual HD-audio and USB-audio quirks, Intel HDMI
  fixes, ASoC fsl and rt5682 fixes, as well as the fix in
  compress-offload partial drain operation"

* tag 'sound-5.8-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: compress: fix partial_drain completion state
  ALSA: usb-audio: Add implicit feedback quirk for RTX6001
  ALSA: usb-audio: add quirk for MacroSilicon MS2109
  ALSA: hda/realtek: Enable headset mic of Acer Veriton N4660G with ALC269VC
  ALSA: hda/realtek: Enable headset mic of Acer C20-820 with ALC269VC
  ALSA: hda/realtek - Enable audio jacks of Acer vCopperbox with ALC269VC
  ALSA: hda/realtek - Fix Lenovo Thinkpad X1 Carbon 7th quirk subdevice id
  ALSA: hda/hdmi: improve debug traces for stream lookups
  ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
  ALSA: opl3: fix infoleak in opl3
  ALSA: usb-audio: Replace s/frame/packet/ where appropriate
  ALSA: usb-audio: Fix packet size calculation
  AsoC: amd: add missing snd- module prefix to the acp3x-rn driver kernel module
  ALSA: hda - let hs_mic be picked ahead of hp_mic
  ASoC: rt5682: fix the pop noise while OMTP type headset plugin
  ASoC: fsl_mqs: Fix unchecked return value for clk_prepare_enable
  ASoC: fsl_mqs: Don't check clock is NULL before calling clk API
parents 6ec4476a f79a732a
...@@ -66,6 +66,7 @@ struct snd_compr_runtime { ...@@ -66,6 +66,7 @@ struct snd_compr_runtime {
* @direction: stream direction, playback/recording * @direction: stream direction, playback/recording
* @metadata_set: metadata set flag, true when set * @metadata_set: metadata set flag, true when set
* @next_track: has userspace signal next track transition, true when set * @next_track: has userspace signal next track transition, true when set
* @partial_drain: undergoing partial_drain for stream, true when set
* @private_data: pointer to DSP private data * @private_data: pointer to DSP private data
* @dma_buffer: allocated buffer if any * @dma_buffer: allocated buffer if any
*/ */
...@@ -78,6 +79,7 @@ struct snd_compr_stream { ...@@ -78,6 +79,7 @@ struct snd_compr_stream {
enum snd_compr_direction direction; enum snd_compr_direction direction;
bool metadata_set; bool metadata_set;
bool next_track; bool next_track;
bool partial_drain;
void *private_data; void *private_data;
struct snd_dma_buffer dma_buffer; struct snd_dma_buffer dma_buffer;
}; };
...@@ -182,7 +184,13 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream) ...@@ -182,7 +184,13 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream)
if (snd_BUG_ON(!stream)) if (snd_BUG_ON(!stream))
return; return;
/* for partial_drain case we are back to running state on success */
if (stream->partial_drain) {
stream->runtime->state = SNDRV_PCM_STATE_RUNNING;
stream->partial_drain = false; /* clear this flag as well */
} else {
stream->runtime->state = SNDRV_PCM_STATE_SETUP; stream->runtime->state = SNDRV_PCM_STATE_SETUP;
}
wake_up(&stream->runtime->sleep); wake_up(&stream->runtime->sleep);
} }
......
...@@ -764,6 +764,9 @@ static int snd_compr_stop(struct snd_compr_stream *stream) ...@@ -764,6 +764,9 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
if (!retval) { if (!retval) {
/* clear flags and stop any drain wait */
stream->partial_drain = false;
stream->metadata_set = false;
snd_compr_drain_notify(stream); snd_compr_drain_notify(stream);
stream->runtime->total_bytes_available = 0; stream->runtime->total_bytes_available = 0;
stream->runtime->total_bytes_transferred = 0; stream->runtime->total_bytes_transferred = 0;
...@@ -921,6 +924,7 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream) ...@@ -921,6 +924,7 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
if (stream->next_track == false) if (stream->next_track == false)
return -EPERM; return -EPERM;
stream->partial_drain = true;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN); retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
if (retval) { if (retval) {
pr_debug("Partial drain returned failure\n"); pr_debug("Partial drain returned failure\n");
......
...@@ -91,6 +91,8 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file, ...@@ -91,6 +91,8 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
{ {
struct snd_dm_fm_info info; struct snd_dm_fm_info info;
memset(&info, 0, sizeof(info));
info.fm_mode = opl3->fm_mode; info.fm_mode = opl3->fm_mode;
info.rhythm = opl3->rhythm; info.rhythm = opl3->rhythm;
if (copy_to_user(argp, &info, sizeof(struct snd_dm_fm_info))) if (copy_to_user(argp, &info, sizeof(struct snd_dm_fm_info)))
......
...@@ -72,6 +72,12 @@ static int compare_input_type(const void *ap, const void *bp) ...@@ -72,6 +72,12 @@ static int compare_input_type(const void *ap, const void *bp)
if (a->type != b->type) if (a->type != b->type)
return (int)(a->type - b->type); return (int)(a->type - b->type);
/* If has both hs_mic and hp_mic, pick the hs_mic ahead of hp_mic. */
if (a->is_headset_mic && b->is_headphone_mic)
return -1; /* don't swap */
else if (a->is_headphone_mic && b->is_headset_mic)
return 1; /* swap */
/* In case one has boost and the other one has not, /* In case one has boost and the other one has not,
pick the one with boost first. */ pick the one with boost first. */
return (int)(b->has_boost_on_pin - a->has_boost_on_pin); return (int)(b->has_boost_on_pin - a->has_boost_on_pin);
......
...@@ -259,7 +259,7 @@ static int hinfo_to_pcm_index(struct hda_codec *codec, ...@@ -259,7 +259,7 @@ static int hinfo_to_pcm_index(struct hda_codec *codec,
if (get_pcm_rec(spec, pcm_idx)->stream == hinfo) if (get_pcm_rec(spec, pcm_idx)->stream == hinfo)
return pcm_idx; return pcm_idx;
codec_warn(codec, "HDMI: hinfo %p not registered\n", hinfo); codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo);
return -EINVAL; return -EINVAL;
} }
...@@ -277,7 +277,8 @@ static int hinfo_to_pin_index(struct hda_codec *codec, ...@@ -277,7 +277,8 @@ static int hinfo_to_pin_index(struct hda_codec *codec,
return pin_idx; return pin_idx;
} }
codec_dbg(codec, "HDMI: hinfo %p not registered\n", hinfo); codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo,
hinfo_to_pcm_index(codec, hinfo));
return -EINVAL; return -EINVAL;
} }
...@@ -1804,33 +1805,43 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) ...@@ -1804,33 +1805,43 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
static int hdmi_parse_codec(struct hda_codec *codec) static int hdmi_parse_codec(struct hda_codec *codec)
{ {
hda_nid_t nid; hda_nid_t start_nid;
unsigned int caps;
int i, nodes; int i, nodes;
nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &nid); nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
if (!nid || nodes < 0) { if (!start_nid || nodes < 0) {
codec_warn(codec, "HDMI: failed to get afg sub nodes\n"); codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < nodes; i++, nid++) { /*
unsigned int caps; * hdmi_add_pin() assumes total amount of converters to
unsigned int type; * be known, so first discover all converters
*/
for (i = 0; i < nodes; i++) {
hda_nid_t nid = start_nid + i;
caps = get_wcaps(codec, nid); caps = get_wcaps(codec, nid);
type = get_wcaps_type(caps);
if (!(caps & AC_WCAP_DIGITAL)) if (!(caps & AC_WCAP_DIGITAL))
continue; continue;
switch (type) { if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
case AC_WID_AUD_OUT:
hdmi_add_cvt(codec, nid); hdmi_add_cvt(codec, nid);
break;
case AC_WID_PIN:
hdmi_add_pin(codec, nid);
break;
} }
/* discover audio pins */
for (i = 0; i < nodes; i++) {
hda_nid_t nid = start_nid + i;
caps = get_wcaps(codec, nid);
if (!(caps & AC_WCAP_DIGITAL))
continue;
if (get_wcaps_type(caps) == AC_WID_PIN)
hdmi_add_pin(codec, nid);
} }
return 0; return 0;
......
...@@ -6149,6 +6149,9 @@ enum { ...@@ -6149,6 +6149,9 @@ enum {
ALC236_FIXUP_HP_MUTE_LED, ALC236_FIXUP_HP_MUTE_LED,
ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC295_FIXUP_ASUS_MIC_NO_PRESENCE, ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS,
ALC269VC_FIXUP_ACER_HEADSET_MIC,
ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
}; };
static const struct hda_fixup alc269_fixups[] = { static const struct hda_fixup alc269_fixups[] = {
...@@ -7327,6 +7330,35 @@ static const struct hda_fixup alc269_fixups[] = { ...@@ -7327,6 +7330,35 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true, .chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE .chain_id = ALC269_FIXUP_HEADSET_MODE
}, },
[ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x14, 0x90100120 }, /* use as internal speaker */
{ 0x18, 0x02a111f0 }, /* use as headset mic, without its own jack detect */
{ 0x1a, 0x01011020 }, /* use as line out */
{ },
},
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MIC
},
[ALC269VC_FIXUP_ACER_HEADSET_MIC] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x18, 0x02a11030 }, /* use as headset mic */
{ }
},
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MIC
},
[ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x18, 0x01a11130 }, /* use as headset mic, without its own jack detect */
{ }
},
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MIC
},
}; };
static const struct snd_pci_quirk alc269_fixup_tbl[] = { static const struct snd_pci_quirk alc269_fixup_tbl[] = {
...@@ -7342,10 +7374,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -7342,10 +7374,13 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x1025, 0x1099, "Acer Aspire E5-523G", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x1099, "Acer Aspire E5-523G", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK), SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK),
SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
...@@ -7571,8 +7606,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -7571,8 +7606,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK), SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK), SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Renoir platform Support # Renoir platform Support
snd-rn-pci-acp3x-objs := rn-pci-acp3x.o snd-rn-pci-acp3x-objs := rn-pci-acp3x.o
snd-acp3x-pdm-dma-objs := acp3x-pdm-dma.o snd-acp3x-pdm-dma-objs := acp3x-pdm-dma.o
snd-acp3x-rn-objs := acp3x-rn.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-rn-pci-acp3x.o obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-rn-pci-acp3x.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-acp3x-pdm-dma.o obj-$(CONFIG_SND_SOC_AMD_RENOIR) += snd-acp3x-pdm-dma.o
obj-$(CONFIG_SND_SOC_AMD_RENOIR_MACH) += acp3x-rn.o obj-$(CONFIG_SND_SOC_AMD_RENOIR_MACH) += snd-acp3x-rn.o
...@@ -932,7 +932,9 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) ...@@ -932,7 +932,9 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
RT5682_PWR_ANLG_1, RT5682_PWR_FV2, RT5682_PWR_FV2); RT5682_PWR_ANLG_1, RT5682_PWR_FV2, RT5682_PWR_FV2);
snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3,
RT5682_PWR_CBJ, RT5682_PWR_CBJ); RT5682_PWR_CBJ, RT5682_PWR_CBJ);
snd_soc_component_update_bits(component,
RT5682_HP_CHARGE_PUMP_1,
RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH); RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
...@@ -956,6 +958,11 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) ...@@ -956,6 +958,11 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
rt5682->jack_type = SND_JACK_HEADPHONE; rt5682->jack_type = SND_JACK_HEADPHONE;
break; break;
} }
snd_soc_component_update_bits(component,
RT5682_HP_CHARGE_PUMP_1,
RT5682_OSW_L_MASK | RT5682_OSW_R_MASK,
RT5682_OSW_L_EN | RT5682_OSW_R_EN);
} else { } else {
rt5682_enable_push_button_irq(component, false); rt5682_enable_push_button_irq(component, false);
snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
......
...@@ -265,12 +265,20 @@ static int fsl_mqs_remove(struct platform_device *pdev) ...@@ -265,12 +265,20 @@ static int fsl_mqs_remove(struct platform_device *pdev)
static int fsl_mqs_runtime_resume(struct device *dev) static int fsl_mqs_runtime_resume(struct device *dev)
{ {
struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); struct fsl_mqs *mqs_priv = dev_get_drvdata(dev);
int ret;
if (mqs_priv->ipg) ret = clk_prepare_enable(mqs_priv->ipg);
clk_prepare_enable(mqs_priv->ipg); if (ret) {
dev_err(dev, "failed to enable ipg clock\n");
return ret;
}
if (mqs_priv->mclk) ret = clk_prepare_enable(mqs_priv->mclk);
clk_prepare_enable(mqs_priv->mclk); if (ret) {
dev_err(dev, "failed to enable mclk clock\n");
clk_disable_unprepare(mqs_priv->ipg);
return ret;
}
if (mqs_priv->use_gpr) if (mqs_priv->use_gpr)
regmap_write(mqs_priv->regmap, IOMUXC_GPR2, regmap_write(mqs_priv->regmap, IOMUXC_GPR2,
...@@ -292,10 +300,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev) ...@@ -292,10 +300,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev)
regmap_read(mqs_priv->regmap, REG_MQS_CTRL, regmap_read(mqs_priv->regmap, REG_MQS_CTRL,
&mqs_priv->reg_mqs_ctrl); &mqs_priv->reg_mqs_ctrl);
if (mqs_priv->mclk)
clk_disable_unprepare(mqs_priv->mclk); clk_disable_unprepare(mqs_priv->mclk);
if (mqs_priv->ipg)
clk_disable_unprepare(mqs_priv->ipg); clk_disable_unprepare(mqs_priv->ipg);
return 0; return 0;
......
...@@ -84,10 +84,10 @@ struct snd_usb_endpoint { ...@@ -84,10 +84,10 @@ struct snd_usb_endpoint {
dma_addr_t sync_dma; /* DMA address of syncbuf */ dma_addr_t sync_dma; /* DMA address of syncbuf */
unsigned int pipe; /* the data i/o pipe */ unsigned int pipe; /* the data i/o pipe */
unsigned int framesize[2]; /* small/large frame sizes in samples */ unsigned int packsize[2]; /* small/large packet sizes in samples */
unsigned int sample_rem; /* remainder from division fs/fps */ unsigned int sample_rem; /* remainder from division fs/pps */
unsigned int sample_accum; /* sample accumulator */ unsigned int sample_accum; /* sample accumulator */
unsigned int fps; /* frames per second */ unsigned int pps; /* packets per second */
unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
int freqshift; /* how much to shift the feedback value to get Q16.16 */ int freqshift; /* how much to shift the feedback value to get Q16.16 */
......
...@@ -159,11 +159,11 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep) ...@@ -159,11 +159,11 @@ int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep)
return ep->maxframesize; return ep->maxframesize;
ep->sample_accum += ep->sample_rem; ep->sample_accum += ep->sample_rem;
if (ep->sample_accum >= ep->fps) { if (ep->sample_accum >= ep->pps) {
ep->sample_accum -= ep->fps; ep->sample_accum -= ep->pps;
ret = ep->framesize[1]; ret = ep->packsize[1];
} else { } else {
ret = ep->framesize[0]; ret = ep->packsize[0];
} }
return ret; return ret;
...@@ -1088,15 +1088,15 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, ...@@ -1088,15 +1088,15 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) { if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) {
ep->freqn = get_usb_full_speed_rate(rate); ep->freqn = get_usb_full_speed_rate(rate);
ep->fps = 1000; ep->pps = 1000 >> ep->datainterval;
} else { } else {
ep->freqn = get_usb_high_speed_rate(rate); ep->freqn = get_usb_high_speed_rate(rate);
ep->fps = 8000; ep->pps = 8000 >> ep->datainterval;
} }
ep->sample_rem = rate % ep->fps; ep->sample_rem = rate % ep->pps;
ep->framesize[0] = rate / ep->fps; ep->packsize[0] = rate / ep->pps;
ep->framesize[1] = (rate + (ep->fps - 1)) / ep->fps; ep->packsize[1] = (rate + (ep->pps - 1)) / ep->pps;
/* calculate the frequency in 16.16 format */ /* calculate the frequency in 16.16 format */
ep->freqm = ep->freqn; ep->freqm = ep->freqn;
......
...@@ -368,6 +368,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, ...@@ -368,6 +368,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
goto add_sync_ep_from_ifnum; goto add_sync_ep_from_ifnum;
case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ case USB_ID(0x07fd, 0x0008): /* MOTU M Series */
case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */ case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */
case USB_ID(0x0d9a, 0x00df): /* RTX6001 */
ep = 0x81; ep = 0x81;
ifnum = 2; ifnum = 2;
goto add_sync_ep_from_ifnum; goto add_sync_ep_from_ifnum;
......
...@@ -3633,4 +3633,56 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */ ...@@ -3633,4 +3633,56 @@ ALC1220_VB_DESKTOP(0x26ce, 0x0a01), /* Asrock TRX40 Creator */
} }
}, },
/*
* MacroSilicon MS2109 based HDMI capture cards
*
* These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
* They also need QUIRK_AUDIO_ALIGN_TRANSFER, which makes one wonder if
* they pretend to be 96kHz mono as a workaround for stereo being broken
* by that...
*
* They also have swapped L-R channels, but that's for userspace to deal
* with.
*/
{
USB_DEVICE(0x534d, 0x2109),
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
.vendor_name = "MacroSilicon",
.product_name = "MS2109",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_COMPOSITE,
.data = &(const struct snd_usb_audio_quirk[]) {
{
.ifnum = 2,
.type = QUIRK_AUDIO_ALIGN_TRANSFER,
},
{
.ifnum = 2,
.type = QUIRK_AUDIO_STANDARD_MIXER,
},
{
.ifnum = 3,
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
.data = &(const struct audioformat) {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels = 2,
.iface = 3,
.altsetting = 1,
.altset_idx = 1,
.attributes = 0,
.endpoint = 0x82,
.ep_attr = USB_ENDPOINT_XFER_ISOC |
USB_ENDPOINT_SYNC_ASYNC,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 48000,
.rate_max = 48000,
}
},
{
.ifnum = -1
}
}
}
},
#undef USB_DEVICE_VENDOR_SPEC #undef USB_DEVICE_VENDOR_SPEC
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