Commit dca45efb authored by Linus Torvalds's avatar Linus Torvalds

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

Pull sound fixes from Takashi Iwai:
 "Here are a few remaining patches for 6.1-rc1.

  The major changes are the hibernation fixes for HD-audio CS35L41 codec
  and the USB-audio small fixes against the last change. In addition, a
  couple of HD-audio regression fixes and a couple of potential
  mutex-deadlock fixes with OSS emulation in ALSA core side are seen"

* tag 'sound-fix-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ALSA: hda: cs35l41: Support System Suspend
  ALSA: hda: cs35l41: Remove suspend/resume hda hooks
  ALSA: hda/cs_dsp_ctl: Fix mutex inversion when creating controls
  ALSA: hda: hda_cs_dsp_ctl: Ensure pwr_lock is held before reading/writing controls
  ALSA: hda: hda_cs_dsp_ctl: Minor clean and redundant code removal
  ALSA: oss: Fix potential deadlock at unregistration
  ALSA: rawmidi: Drop register_mutex in snd_rawmidi_free()
  ALSA: hda/realtek: Add Intel Reference SSID to support headset keys
  ALSA: hda/realtek: Add quirk for ASUS GV601R laptop
  ALSA: hda/realtek: Correct pin configs for ASUS G533Z
  ALSA: usb-audio: Avoid superfluous endpoint setup
  ALSA: usb-audio: Correct the return code from snd_usb_endpoint_set_params()
  ALSA: usb-audio: Apply mutex around snd_usb_endpoint_set_params()
  ALSA: usb-audio: Avoid unnecessary interface change at EP close
  ALSA: hda: Update register polling macros
  ALSA: hda/realtek: remove ALC289_FIXUP_DUAL_SPK for Dell 5530
parents 5964c927 88672826
...@@ -592,11 +592,11 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, ...@@ -592,11 +592,11 @@ int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus,
#define snd_hdac_stream_readb(dev, reg) \ #define snd_hdac_stream_readb(dev, reg) \
snd_hdac_reg_readb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg) snd_hdac_reg_readb((dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
#define snd_hdac_stream_readb_poll(dev, reg, val, cond, delay_us, timeout_us) \ #define snd_hdac_stream_readb_poll(dev, reg, val, cond, delay_us, timeout_us) \
readb_poll_timeout((dev)->sd_addr + AZX_REG_ ## reg, val, cond, \ read_poll_timeout_atomic(snd_hdac_reg_readb, val, cond, delay_us, timeout_us, \
delay_us, timeout_us) false, (dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
#define snd_hdac_stream_readl_poll(dev, reg, val, cond, delay_us, timeout_us) \ #define snd_hdac_stream_readl_poll(dev, reg, val, cond, delay_us, timeout_us) \
readl_poll_timeout((dev)->sd_addr + AZX_REG_ ## reg, val, cond, \ read_poll_timeout_atomic(snd_hdac_reg_readl, val, cond, delay_us, timeout_us, \
delay_us, timeout_us) false, (dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
/* update a register, pass without AZX_REG_ prefix */ /* update a register, pass without AZX_REG_ prefix */
#define snd_hdac_stream_updatel(dev, reg, mask, val) \ #define snd_hdac_stream_updatel(dev, reg, mask, val) \
......
...@@ -1899,10 +1899,8 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi) ...@@ -1899,10 +1899,8 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
snd_info_free_entry(rmidi->proc_entry); snd_info_free_entry(rmidi->proc_entry);
rmidi->proc_entry = NULL; rmidi->proc_entry = NULL;
mutex_lock(&register_mutex);
if (rmidi->ops && rmidi->ops->dev_unregister) if (rmidi->ops && rmidi->ops->dev_unregister)
rmidi->ops->dev_unregister(rmidi); rmidi->ops->dev_unregister(rmidi);
mutex_unlock(&register_mutex);
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]); snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
......
...@@ -162,7 +162,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) ...@@ -162,7 +162,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
mutex_unlock(&sound_oss_mutex); mutex_unlock(&sound_oss_mutex);
return -ENOENT; return -ENOENT;
} }
unregister_sound_special(minor);
switch (SNDRV_MINOR_OSS_DEVICE(minor)) { switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
case SNDRV_MINOR_OSS_PCM: case SNDRV_MINOR_OSS_PCM:
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO); track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
...@@ -174,12 +173,18 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) ...@@ -174,12 +173,18 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1); track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break; break;
} }
if (track2 >= 0) { if (track2 >= 0)
unregister_sound_special(track2);
snd_oss_minors[track2] = NULL; snd_oss_minors[track2] = NULL;
}
snd_oss_minors[minor] = NULL; snd_oss_minors[minor] = NULL;
mutex_unlock(&sound_oss_mutex); mutex_unlock(&sound_oss_mutex);
/* call unregister_sound_special() outside sound_oss_mutex;
* otherwise may deadlock, as it can trigger the release of a card
*/
unregister_sound_special(minor);
if (track2 >= 0)
unregister_sound_special(track2);
kfree(mptr); kfree(mptr);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -16,6 +16,4 @@ struct hda_component { ...@@ -16,6 +16,4 @@ struct hda_component {
char name[HDA_MAX_NAME_SIZE]; char name[HDA_MAX_NAME_SIZE];
struct hda_codec *codec; struct hda_codec *codec;
void (*playback_hook)(struct device *dev, int action); void (*playback_hook)(struct device *dev, int action);
int (*suspend_hook)(struct device *dev);
int (*resume_hook)(struct device *dev);
}; };
...@@ -97,7 +97,7 @@ static unsigned int wmfw_convert_flags(unsigned int in) ...@@ -97,7 +97,7 @@ static unsigned int wmfw_convert_flags(unsigned int in)
return out; return out;
} }
static int hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name) static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name)
{ {
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
struct snd_kcontrol_new kcontrol = {0}; struct snd_kcontrol_new kcontrol = {0};
...@@ -107,7 +107,7 @@ static int hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char ...@@ -107,7 +107,7 @@ static int hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char
if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) { if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) {
dev_err(cs_ctl->dsp->dev, "KControl %s: length %zu exceeds maximum %d\n", name, dev_err(cs_ctl->dsp->dev, "KControl %s: length %zu exceeds maximum %d\n", name,
cs_ctl->len, ADSP_MAX_STD_CTRL_SIZE); cs_ctl->len, ADSP_MAX_STD_CTRL_SIZE);
return -EINVAL; return;
} }
kcontrol.name = name; kcontrol.name = name;
...@@ -120,24 +120,21 @@ static int hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char ...@@ -120,24 +120,21 @@ static int hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char
/* Save ctl inside private_data, ctl is owned by cs_dsp, /* Save ctl inside private_data, ctl is owned by cs_dsp,
* and will be freed when cs_dsp removes the control */ * and will be freed when cs_dsp removes the control */
kctl = snd_ctl_new1(&kcontrol, (void *)ctl); kctl = snd_ctl_new1(&kcontrol, (void *)ctl);
if (!kctl) { if (!kctl)
ret = -ENOMEM; return;
return ret;
}
ret = snd_ctl_add(ctl->card, kctl); ret = snd_ctl_add(ctl->card, kctl);
if (ret) { if (ret) {
dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret); dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret);
return ret; return;
} }
dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name); dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name);
ctl->kctl = kctl; ctl->kctl = kctl;
return 0;
} }
int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ctl_info *info) static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl,
const struct hda_cs_dsp_ctl_info *info)
{ {
struct cs_dsp *cs_dsp = cs_ctl->dsp; struct cs_dsp *cs_dsp = cs_ctl->dsp;
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
...@@ -145,13 +142,10 @@ int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ct ...@@ -145,13 +142,10 @@ int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ct
const char *region_name; const char *region_name;
int ret; int ret;
if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
return 0;
region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type); region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
if (!region_name) { if (!region_name) {
dev_err(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type); dev_warn(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type);
return -EINVAL; return;
} }
ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %.12s %x", info->device_name, ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %.12s %x", info->device_name,
...@@ -171,22 +165,39 @@ int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ct ...@@ -171,22 +165,39 @@ int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ct
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
if (!ctl) if (!ctl)
return -ENOMEM; return;
ctl->cs_ctl = cs_ctl; ctl->cs_ctl = cs_ctl;
ctl->card = info->card; ctl->card = info->card;
cs_ctl->priv = ctl; cs_ctl->priv = ctl;
ret = hda_cs_dsp_add_kcontrol(ctl, name); hda_cs_dsp_add_kcontrol(ctl, name);
if (ret) { }
dev_err(cs_dsp->dev, "Error (%d) adding control %s\n", ret, name);
kfree(ctl);
return ret;
}
return 0; void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info)
{
struct cs_dsp_coeff_ctl *cs_ctl;
/*
* pwr_lock would cause mutex inversion with ALSA control lock compared
* to the get/put functions.
* It is safe to walk the list without holding a mutex because entries
* are persistent and only cs_dsp_power_up() or cs_dsp_remove() can
* change the list.
*/
lockdep_assert_not_held(&dsp->pwr_lock);
list_for_each_entry(cs_ctl, &dsp->ctl_list, list) {
if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
continue;
if (cs_ctl->priv)
continue;
hda_cs_dsp_control_add(cs_ctl, info);
}
} }
EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_add, SND_HDA_CS_DSP_CONTROLS); EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_add_controls, SND_HDA_CS_DSP_CONTROLS);
void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl)
{ {
...@@ -203,19 +214,18 @@ int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, ...@@ -203,19 +214,18 @@ int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
struct hda_cs_dsp_coeff_ctl *ctl; struct hda_cs_dsp_coeff_ctl *ctl;
int ret; int ret;
mutex_lock(&dsp->pwr_lock);
cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg); cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg);
if (!cs_ctl)
return -EINVAL;
ctl = cs_ctl->priv;
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len); ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
mutex_unlock(&dsp->pwr_lock);
if (ret) if (ret)
return ret; return ret;
if (cs_ctl->flags & WMFW_CTL_FLAG_SYS) if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
return 0; return 0;
ctl = cs_ctl->priv;
snd_ctl_notify(ctl->card, SNDRV_CTL_EVENT_MASK_VALUE, &ctl->kctl->id); snd_ctl_notify(ctl->card, SNDRV_CTL_EVENT_MASK_VALUE, &ctl->kctl->id);
return 0; return 0;
...@@ -225,13 +235,14 @@ EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, SND_HDA_CS_DSP_CONTROLS); ...@@ -225,13 +235,14 @@ EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_write_ctl, SND_HDA_CS_DSP_CONTROLS);
int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type, int hda_cs_dsp_read_ctl(struct cs_dsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len) unsigned int alg, void *buf, size_t len)
{ {
struct cs_dsp_coeff_ctl *cs_ctl; int ret;
cs_ctl = cs_dsp_get_ctl(dsp, name, type, alg); mutex_lock(&dsp->pwr_lock);
if (!cs_ctl) ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len);
return -EINVAL; mutex_unlock(&dsp->pwr_lock);
return ret;
return cs_dsp_coeff_read_ctrl(cs_ctl, 0, buf, len);
} }
EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS); EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_read_ctl, SND_HDA_CS_DSP_CONTROLS);
......
...@@ -29,7 +29,7 @@ struct hda_cs_dsp_ctl_info { ...@@ -29,7 +29,7 @@ struct hda_cs_dsp_ctl_info {
extern const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW]; extern const char * const hda_cs_dsp_fw_ids[HDA_CS_DSP_NUM_FW];
int hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, struct hda_cs_dsp_ctl_info *info); void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info);
void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl); void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl);
int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type, int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
unsigned int alg, const void *buf, size_t len); unsigned int alg, const void *buf, size_t len);
......
...@@ -4022,22 +4022,16 @@ static void alc5505_dsp_init(struct hda_codec *codec) ...@@ -4022,22 +4022,16 @@ static void alc5505_dsp_init(struct hda_codec *codec)
static int alc269_suspend(struct hda_codec *codec) static int alc269_suspend(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int i;
if (spec->has_alc5505_dsp) if (spec->has_alc5505_dsp)
alc5505_dsp_suspend(codec); alc5505_dsp_suspend(codec);
for (i = 0; i < HDA_MAX_COMPONENTS; i++)
if (spec->comps[i].suspend_hook)
spec->comps[i].suspend_hook(spec->comps[i].dev);
return alc_suspend(codec); return alc_suspend(codec);
} }
static int alc269_resume(struct hda_codec *codec) static int alc269_resume(struct hda_codec *codec)
{ {
struct alc_spec *spec = codec->spec; struct alc_spec *spec = codec->spec;
int i;
if (spec->codec_variant == ALC269_TYPE_ALC269VB) if (spec->codec_variant == ALC269_TYPE_ALC269VB)
alc269vb_toggle_power_output(codec, 0); alc269vb_toggle_power_output(codec, 0);
...@@ -4068,10 +4062,6 @@ static int alc269_resume(struct hda_codec *codec) ...@@ -4068,10 +4062,6 @@ static int alc269_resume(struct hda_codec *codec)
if (spec->has_alc5505_dsp) if (spec->has_alc5505_dsp)
alc5505_dsp_resume(codec); alc5505_dsp_resume(codec);
for (i = 0; i < HDA_MAX_COMPONENTS; i++)
if (spec->comps[i].resume_hook)
spec->comps[i].resume_hook(spec->comps[i].dev);
return 0; return 0;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
...@@ -6664,19 +6654,12 @@ static int comp_bind(struct device *dev) ...@@ -6664,19 +6654,12 @@ static int comp_bind(struct device *dev)
{ {
struct hda_codec *cdc = dev_to_hda_codec(dev); struct hda_codec *cdc = dev_to_hda_codec(dev);
struct alc_spec *spec = cdc->spec; struct alc_spec *spec = cdc->spec;
int ret, i; int ret;
ret = component_bind_all(dev, spec->comps); ret = component_bind_all(dev, spec->comps);
if (ret) if (ret)
return ret; return ret;
if (snd_hdac_is_power_on(&cdc->core)) {
codec_dbg(cdc, "Resuming after bind.\n");
for (i = 0; i < HDA_MAX_COMPONENTS; i++)
if (spec->comps[i].resume_hook)
spec->comps[i].resume_hook(spec->comps[i].dev);
}
return 0; return 0;
} }
...@@ -8449,11 +8432,13 @@ static const struct hda_fixup alc269_fixups[] = { ...@@ -8449,11 +8432,13 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC285_FIXUP_ASUS_G533Z_PINS] = { [ALC285_FIXUP_ASUS_G533Z_PINS] = {
.type = HDA_FIXUP_PINS, .type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) { .v.pins = (const struct hda_pintbl[]) {
{ 0x14, 0x90170120 }, { 0x14, 0x90170152 }, /* Speaker Surround Playback Switch */
{ 0x19, 0x03a19020 }, /* Mic Boost Volume */
{ 0x1a, 0x03a11c30 }, /* Mic Boost Volume */
{ 0x1e, 0x90170151 }, /* Rear jack, IN OUT EAPD Detect */
{ 0x21, 0x03211420 },
{ } { }
}, },
.chained = true,
.chain_id = ALC294_FIXUP_ASUS_G513_PINS,
}, },
[ALC294_FIXUP_ASUS_COEF_1B] = { [ALC294_FIXUP_ASUS_COEF_1B] = {
.type = HDA_FIXUP_VERBS, .type = HDA_FIXUP_VERBS,
...@@ -9198,7 +9183,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -9198,7 +9183,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC), SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC), SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB), SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
SND_PCI_QUIRK(0x1028, 0x087d, "Dell Precision 5530", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB), SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
...@@ -9422,6 +9406,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -9422,6 +9406,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401), SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
...@@ -9443,6 +9428,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { ...@@ -9443,6 +9428,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
......
...@@ -129,7 +129,8 @@ struct snd_usb_endpoint { ...@@ -129,7 +129,8 @@ struct snd_usb_endpoint {
in a stream */ in a stream */
bool implicit_fb_sync; /* syncs with implicit feedback */ bool implicit_fb_sync; /* syncs with implicit feedback */
bool lowlatency_playback; /* low-latency playback mode */ bool lowlatency_playback; /* low-latency playback mode */
bool need_setup; /* (re-)need for configure? */ bool need_setup; /* (re-)need for hw_params? */
bool need_prepare; /* (re-)need for prepare? */
/* for hw constraints */ /* for hw constraints */
const struct audioformat *cur_audiofmt; const struct audioformat *cur_audiofmt;
......
...@@ -32,6 +32,7 @@ struct snd_usb_iface_ref { ...@@ -32,6 +32,7 @@ struct snd_usb_iface_ref {
unsigned char iface; unsigned char iface;
bool need_setup; bool need_setup;
int opened; int opened;
int altset;
struct list_head list; struct list_head list;
}; };
...@@ -823,6 +824,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip, ...@@ -823,6 +824,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
ep->implicit_fb_sync = fp->implicit_fb; ep->implicit_fb_sync = fp->implicit_fb;
ep->need_setup = true; ep->need_setup = true;
ep->need_prepare = true;
usb_audio_dbg(chip, " channels=%d, rate=%d, format=%s, period_bytes=%d, periods=%d, implicit_fb=%d\n", usb_audio_dbg(chip, " channels=%d, rate=%d, format=%s, period_bytes=%d, periods=%d, implicit_fb=%d\n",
ep->cur_channels, ep->cur_rate, ep->cur_channels, ep->cur_rate,
...@@ -899,6 +901,9 @@ static int endpoint_set_interface(struct snd_usb_audio *chip, ...@@ -899,6 +901,9 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
int altset = set ? ep->altsetting : 0; int altset = set ? ep->altsetting : 0;
int err; int err;
if (ep->iface_ref->altset == altset)
return 0;
usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n", usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n",
ep->iface, altset, ep->ep_num); ep->iface, altset, ep->ep_num);
err = usb_set_interface(chip->dev, ep->iface, altset); err = usb_set_interface(chip->dev, ep->iface, altset);
...@@ -910,6 +915,7 @@ static int endpoint_set_interface(struct snd_usb_audio *chip, ...@@ -910,6 +915,7 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
if (chip->quirk_flags & QUIRK_FLAG_IFACE_DELAY) if (chip->quirk_flags & QUIRK_FLAG_IFACE_DELAY)
msleep(50); msleep(50);
ep->iface_ref->altset = altset;
return 0; return 0;
} }
...@@ -947,7 +953,7 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip, ...@@ -947,7 +953,7 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
/* Prepare for suspening EP, called from the main suspend handler */ /* Prepare for suspening EP, called from the main suspend handler */
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep) void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
{ {
ep->need_setup = true; ep->need_prepare = true;
if (ep->iface_ref) if (ep->iface_ref)
ep->iface_ref->need_setup = true; ep->iface_ref->need_setup = true;
if (ep->clock_ref) if (ep->clock_ref)
...@@ -1330,12 +1336,16 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, ...@@ -1330,12 +1336,16 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
struct snd_usb_endpoint *ep) struct snd_usb_endpoint *ep)
{ {
const struct audioformat *fmt = ep->cur_audiofmt; const struct audioformat *fmt = ep->cur_audiofmt;
int err; int err = 0;
mutex_lock(&chip->mutex);
if (!ep->need_setup)
goto unlock;
/* release old buffers, if any */ /* release old buffers, if any */
err = release_urbs(ep, false); err = release_urbs(ep, false);
if (err < 0) if (err < 0)
return err; goto unlock;
ep->datainterval = fmt->datainterval; ep->datainterval = fmt->datainterval;
ep->maxpacksize = fmt->maxpacksize; ep->maxpacksize = fmt->maxpacksize;
...@@ -1373,13 +1383,21 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip, ...@@ -1373,13 +1383,21 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
usb_audio_dbg(chip, "Set up %d URBS, ret=%d\n", ep->nurbs, err); usb_audio_dbg(chip, "Set up %d URBS, ret=%d\n", ep->nurbs, err);
if (err < 0) if (err < 0)
return err; goto unlock;
/* some unit conversions in runtime */ /* some unit conversions in runtime */
ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes; ep->maxframesize = ep->maxpacksize / ep->cur_frame_bytes;
ep->curframesize = ep->curpacksize / ep->cur_frame_bytes; ep->curframesize = ep->curpacksize / ep->cur_frame_bytes;
return update_clock_ref_rate(chip, ep); err = update_clock_ref_rate(chip, ep);
if (err >= 0) {
ep->need_setup = false;
err = 0;
}
unlock:
mutex_unlock(&chip->mutex);
return err;
} }
static int init_sample_rate(struct snd_usb_audio *chip, static int init_sample_rate(struct snd_usb_audio *chip,
...@@ -1426,7 +1444,7 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, ...@@ -1426,7 +1444,7 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip,
mutex_lock(&chip->mutex); mutex_lock(&chip->mutex);
if (WARN_ON(!ep->iface_ref)) if (WARN_ON(!ep->iface_ref))
goto unlock; goto unlock;
if (!ep->need_setup) if (!ep->need_prepare)
goto unlock; goto unlock;
/* If the interface has been already set up, just set EP parameters */ /* If the interface has been already set up, just set EP parameters */
...@@ -1480,7 +1498,7 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip, ...@@ -1480,7 +1498,7 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip,
ep->iface_ref->need_setup = false; ep->iface_ref->need_setup = false;
done: done:
ep->need_setup = false; ep->need_prepare = false;
err = 1; err = 1;
unlock: unlock:
......
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