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,
#define snd_hdac_stream_readb(dev, 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) \
readb_poll_timeout((dev)->sd_addr + AZX_REG_ ## reg, val, cond, \
delay_us, timeout_us)
read_poll_timeout_atomic(snd_hdac_reg_readb, val, cond, 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) \
readl_poll_timeout((dev)->sd_addr + AZX_REG_ ## reg, val, cond, \
delay_us, timeout_us)
read_poll_timeout_atomic(snd_hdac_reg_readl, val, cond, delay_us, timeout_us, \
false, (dev)->bus, (dev)->sd_addr + AZX_REG_ ## reg)
/* update a register, pass without AZX_REG_ prefix */
#define snd_hdac_stream_updatel(dev, reg, mask, val) \
......
......@@ -1899,10 +1899,8 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
snd_info_free_entry(rmidi->proc_entry);
rmidi->proc_entry = NULL;
mutex_lock(&register_mutex);
if (rmidi->ops && rmidi->ops->dev_unregister)
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_OUTPUT]);
......
......@@ -162,7 +162,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
mutex_unlock(&sound_oss_mutex);
return -ENOENT;
}
unregister_sound_special(minor);
switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
case SNDRV_MINOR_OSS_PCM:
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)
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break;
}
if (track2 >= 0) {
unregister_sound_special(track2);
if (track2 >= 0)
snd_oss_minors[track2] = NULL;
}
snd_oss_minors[minor] = NULL;
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);
return 0;
}
......
This diff is collapsed.
......@@ -16,6 +16,4 @@ struct hda_component {
char name[HDA_MAX_NAME_SIZE];
struct hda_codec *codec;
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)
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 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
if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) {
dev_err(cs_ctl->dsp->dev, "KControl %s: length %zu exceeds maximum %d\n", name,
cs_ctl->len, ADSP_MAX_STD_CTRL_SIZE);
return -EINVAL;
return;
}
kcontrol.name = name;
......@@ -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,
* and will be freed when cs_dsp removes the control */
kctl = snd_ctl_new1(&kcontrol, (void *)ctl);
if (!kctl) {
ret = -ENOMEM;
return ret;
}
if (!kctl)
return;
ret = snd_ctl_add(ctl->card, kctl);
if (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);
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;
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
const char *region_name;
int ret;
if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
return 0;
region_name = cs_dsp_mem_region_name(cs_ctl->alg_region.type);
if (!region_name) {
dev_err(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type);
return -EINVAL;
dev_warn(cs_dsp->dev, "Unknown region type: %d\n", cs_ctl->alg_region.type);
return;
}
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
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
if (!ctl)
return -ENOMEM;
return;
ctl->cs_ctl = cs_ctl;
ctl->card = info->card;
cs_ctl->priv = ctl;
ret = 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;
}
hda_cs_dsp_add_kcontrol(ctl, name);
}
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)
{
......@@ -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;
int ret;
mutex_lock(&dsp->pwr_lock);
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);
mutex_unlock(&dsp->pwr_lock);
if (ret)
return ret;
if (cs_ctl->flags & WMFW_CTL_FLAG_SYS)
return 0;
ctl = cs_ctl->priv;
snd_ctl_notify(ctl->card, SNDRV_CTL_EVENT_MASK_VALUE, &ctl->kctl->id);
return 0;
......@@ -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,
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);
if (!cs_ctl)
return -EINVAL;
mutex_lock(&dsp->pwr_lock);
ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len);
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);
......
......@@ -29,7 +29,7 @@ struct hda_cs_dsp_ctl_info {
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);
int hda_cs_dsp_write_ctl(struct cs_dsp *dsp, const char *name, int type,
unsigned int alg, const void *buf, size_t len);
......
......@@ -4022,22 +4022,16 @@ static void alc5505_dsp_init(struct hda_codec *codec)
static int alc269_suspend(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int i;
if (spec->has_alc5505_dsp)
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);
}
static int alc269_resume(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
int i;
if (spec->codec_variant == ALC269_TYPE_ALC269VB)
alc269vb_toggle_power_output(codec, 0);
......@@ -4068,10 +4062,6 @@ static int alc269_resume(struct hda_codec *codec)
if (spec->has_alc5505_dsp)
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;
}
#endif /* CONFIG_PM */
......@@ -6664,19 +6654,12 @@ static int comp_bind(struct device *dev)
{
struct hda_codec *cdc = dev_to_hda_codec(dev);
struct alc_spec *spec = cdc->spec;
int ret, i;
int ret;
ret = component_bind_all(dev, spec->comps);
if (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;
}
......@@ -8449,11 +8432,13 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC285_FIXUP_ASUS_G533Z_PINS] = {
.type = HDA_FIXUP_PINS,
.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] = {
.type = HDA_FIXUP_VERBS,
......@@ -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, 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, 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, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
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[] = {
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, 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, 0x831a, "ASUS P901", 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[] = {
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, 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, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
......
......@@ -129,7 +129,8 @@ struct snd_usb_endpoint {
in a stream */
bool implicit_fb_sync; /* syncs with implicit feedback */
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 */
const struct audioformat *cur_audiofmt;
......
......@@ -32,6 +32,7 @@ struct snd_usb_iface_ref {
unsigned char iface;
bool need_setup;
int opened;
int altset;
struct list_head list;
};
......@@ -823,6 +824,7 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
ep->implicit_fb_sync = fp->implicit_fb;
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",
ep->cur_channels, ep->cur_rate,
......@@ -899,6 +901,9 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
int altset = set ? ep->altsetting : 0;
int err;
if (ep->iface_ref->altset == altset)
return 0;
usb_audio_dbg(chip, "Setting usb interface %d:%d for EP 0x%x\n",
ep->iface, altset, ep->ep_num);
err = usb_set_interface(chip->dev, ep->iface, altset);
......@@ -910,6 +915,7 @@ static int endpoint_set_interface(struct snd_usb_audio *chip,
if (chip->quirk_flags & QUIRK_FLAG_IFACE_DELAY)
msleep(50);
ep->iface_ref->altset = altset;
return 0;
}
......@@ -947,7 +953,7 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
/* Prepare for suspening EP, called from the main suspend handler */
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
{
ep->need_setup = true;
ep->need_prepare = true;
if (ep->iface_ref)
ep->iface_ref->need_setup = true;
if (ep->clock_ref)
......@@ -1330,12 +1336,16 @@ int snd_usb_endpoint_set_params(struct snd_usb_audio *chip,
struct snd_usb_endpoint *ep)
{
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 */
err = release_urbs(ep, false);
if (err < 0)
return err;
goto unlock;
ep->datainterval = fmt->datainterval;
ep->maxpacksize = fmt->maxpacksize;
......@@ -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);
if (err < 0)
return err;
goto unlock;
/* some unit conversions in runtime */
ep->maxframesize = ep->maxpacksize / 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,
......@@ -1426,7 +1444,7 @@ int snd_usb_endpoint_prepare(struct snd_usb_audio *chip,
mutex_lock(&chip->mutex);
if (WARN_ON(!ep->iface_ref))
goto unlock;
if (!ep->need_setup)
if (!ep->need_prepare)
goto unlock;
/* 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,
ep->iface_ref->need_setup = false;
done:
ep->need_setup = false;
ep->need_prepare = false;
err = 1;
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