sound fixes for 6.1-rc1

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmNJgcIOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE+WBxAAlwaJnvzqz2dxVqICM6MNlGiCssdNS2fW2lcm
 r2zEMiUt++tn2zem12MqROm+Zn9uwlV+fY8smjUlxNY7Wj07wCQWwH5LXfn9v82D
 +mRL4KOhYKGDQMDvo380WGrkuUjCMJkXtVMJDWR1HSMFRZmWu0YdCE0dFd90Hrus
 HW+/+fyP4CNhpk0m5jrffqB7FQI6ylB3j4qmhbxwP9AlA3ik2QvslA+fK6cVltay
 A+hljqNRa1M3/730UvDTNN6PykYBunuvT/EzUFdY/Y0lNtz5RgAAVDBQEZ3T6URE
 6AMgYyCv+gyRH5bcO2Arp3X0JY9ZQKp3/gbTrKfY0G2JQlKVALW1vjExUTlQaWBi
 5Q8/rWo+ZsRsis8NOrJJ9fdHyc6rFXRKX9t/U8svjIW/JxW/4ge2UWxKnISzcQZ6
 1ktFGpoImi8+fXMspKxiePVgJSPxdk5GjRHjdQJ0LYQeceEipljFIXswLPk84KmM
 QPBFMBDxCm3C4E7ZRfk2Rnt0ypf3eRlfQmuWDRtvYsjpgpx08ZKElBhgNMejPtcX
 usXugOMYDB6LK+qlNQhE4iS9V+Xh/6XQL2lblPosPyRY1Ui367s6FHuAty4Yjxcg
 QkggiMuLWSypVIJVUG/uUcgZYHSZbnWPXvfPmt0PM2EbYKLr3zmdkLgKDUfdRvD5
 Hy5HNdU=
 =6PA4
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2022-10-14 13:22:14 -07:00
commit dca45efbe3
10 changed files with 246 additions and 124 deletions

View File

@ -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) \

View File

@ -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]);

View File

@ -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;
}

View File

@ -91,20 +91,18 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
};
static int cs35l41_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
static void cs35l41_add_controls(struct cs35l41_hda *cs35l41)
{
struct cs35l41_hda *cs35l41 = container_of(cs_ctl->dsp, struct cs35l41_hda, cs_dsp);
struct hda_cs_dsp_ctl_info info;
info.device_name = cs35l41->amp_name;
info.fw_type = cs35l41->firmware_type;
info.card = cs35l41->codec->card;
return hda_cs_dsp_control_add(cs_ctl, &info);
hda_cs_dsp_add_controls(&cs35l41->cs_dsp, &info);
}
static const struct cs_dsp_client_ops client_ops = {
.control_add = cs35l41_control_add,
.control_remove = hda_cs_dsp_control_remove,
};
@ -435,6 +433,8 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
if (ret)
goto err_release;
cs35l41_add_controls(cs35l41);
ret = cs35l41_save_calibration(cs35l41);
err_release:
@ -461,9 +461,12 @@ static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
struct cs_dsp *dsp = &cs35l41->cs_dsp;
cancel_work_sync(&cs35l41->fw_load_work);
mutex_lock(&cs35l41->fw_mutex);
cs35l41_shutdown_dsp(cs35l41);
cs_dsp_remove(dsp);
cs35l41->halo_initialized = false;
mutex_unlock(&cs35l41->fw_mutex);
}
/* Protection release cycle to get the speaker out of Safe-Mode */
@ -487,10 +490,10 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
struct regmap *reg = cs35l41->regmap;
int ret = 0;
mutex_lock(&cs35l41->fw_mutex);
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
pm_runtime_get_sync(dev);
mutex_lock(&cs35l41->fw_mutex);
cs35l41->playback_started = true;
if (cs35l41->firmware_running) {
regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
@ -508,15 +511,21 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
mutex_unlock(&cs35l41->fw_mutex);
break;
case HDA_GEN_PCM_ACT_PREPARE:
mutex_lock(&cs35l41->fw_mutex);
ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1);
mutex_unlock(&cs35l41->fw_mutex);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
mutex_lock(&cs35l41->fw_mutex);
regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0);
mutex_unlock(&cs35l41->fw_mutex);
break;
case HDA_GEN_PCM_ACT_CLOSE:
mutex_lock(&cs35l41->fw_mutex);
ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
@ -530,14 +539,16 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
}
cs35l41_irq_release(cs35l41);
cs35l41->playback_started = false;
mutex_unlock(&cs35l41->fw_mutex);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
break;
default:
dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
break;
}
mutex_unlock(&cs35l41->fw_mutex);
if (ret)
dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret);
}
@ -562,45 +573,148 @@ static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsi
rx_slot);
}
static void cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
{
mutex_lock(&cs35l41->fw_mutex);
if (cs35l41->firmware_running) {
regcache_cache_only(cs35l41->regmap, false);
cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
cs35l41_shutdown_dsp(cs35l41);
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
regcache_cache_only(cs35l41->regmap, true);
regcache_mark_dirty(cs35l41->regmap);
}
mutex_unlock(&cs35l41->fw_mutex);
}
static int cs35l41_system_suspend(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
int ret;
dev_dbg(cs35l41->dev, "System Suspend\n");
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
dev_err(cs35l41->dev, "System Suspend not supported\n");
return -EINVAL;
}
ret = pm_runtime_force_suspend(dev);
if (ret)
return ret;
/* Shutdown DSP before system suspend */
cs35l41_ready_for_reset(cs35l41);
/*
* Reset GPIO may be shared, so cannot reset here.
* However beyond this point, amps may be powered down.
*/
return 0;
}
static int cs35l41_system_resume(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
int ret;
dev_dbg(cs35l41->dev, "System Resume\n");
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
dev_err(cs35l41->dev, "System Resume not supported\n");
return -EINVAL;
}
if (cs35l41->reset_gpio) {
usleep_range(2000, 2100);
gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
}
usleep_range(2000, 2100);
ret = pm_runtime_force_resume(dev);
mutex_lock(&cs35l41->fw_mutex);
if (!ret && cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
cs35l41->fw_request_ongoing = true;
schedule_work(&cs35l41->fw_load_work);
}
mutex_unlock(&cs35l41->fw_mutex);
return ret;
}
static int cs35l41_runtime_suspend(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
int ret = 0;
dev_dbg(cs35l41->dev, "Suspend\n");
dev_dbg(cs35l41->dev, "Runtime Suspend\n");
if (!cs35l41->firmware_running)
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
dev_dbg(cs35l41->dev, "Runtime Suspend not supported\n");
return 0;
}
if (cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type) < 0)
return 0;
mutex_lock(&cs35l41->fw_mutex);
if (cs35l41->playback_started) {
regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute,
ARRAY_SIZE(cs35l41_hda_mute));
cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0);
regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
regmap_write(cs35l41->regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
cs35l41->playback_started = false;
}
if (cs35l41->firmware_running) {
ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap,
cs35l41->hw_cfg.bst_type);
if (ret)
goto err;
} else {
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
}
regcache_cache_only(cs35l41->regmap, true);
regcache_mark_dirty(cs35l41->regmap);
return 0;
err:
mutex_unlock(&cs35l41->fw_mutex);
return ret;
}
static int cs35l41_runtime_resume(struct device *dev)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
int ret;
int ret = 0;
dev_dbg(cs35l41->dev, "Resume.\n");
dev_dbg(cs35l41->dev, "Runtime Resume\n");
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
dev_dbg(cs35l41->dev, "System does not support Resume\n");
dev_dbg(cs35l41->dev, "Runtime Resume not supported\n");
return 0;
}
if (!cs35l41->firmware_running)
return 0;
mutex_lock(&cs35l41->fw_mutex);
regcache_cache_only(cs35l41->regmap, false);
ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
if (ret) {
regcache_cache_only(cs35l41->regmap, true);
return ret;
if (cs35l41->firmware_running) {
ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
if (ret) {
dev_warn(cs35l41->dev, "Unable to exit Hibernate.");
goto err;
}
}
/* Test key needs to be unlocked to allow the OTP settings to re-apply */
@ -609,26 +723,16 @@ static int cs35l41_runtime_resume(struct device *dev)
cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
if (ret) {
dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
return ret;
goto err;
}
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
return 0;
}
err:
mutex_unlock(&cs35l41->fw_mutex);
static int cs35l41_hda_suspend_hook(struct device *dev)
{
dev_dbg(dev, "Request Suspend\n");
pm_runtime_mark_last_busy(dev);
return pm_runtime_put_autosuspend(dev);
}
static int cs35l41_hda_resume_hook(struct device *dev)
{
dev_dbg(dev, "Request Resume\n");
return pm_runtime_get_sync(dev);
return ret;
}
static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
@ -678,8 +782,6 @@ clean_dsp:
static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
{
pm_runtime_get_sync(cs35l41->dev);
if (cs35l41->firmware_running && !load) {
dev_dbg(cs35l41->dev, "Unloading Firmware\n");
cs35l41_shutdown_dsp(cs35l41);
@ -689,9 +791,6 @@ static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
} else {
dev_dbg(cs35l41->dev, "Unable to Load firmware.\n");
}
pm_runtime_mark_last_busy(cs35l41->dev);
pm_runtime_put_autosuspend(cs35l41->dev);
}
static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol,
@ -707,16 +806,21 @@ static void cs35l41_fw_load_work(struct work_struct *work)
{
struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work);
pm_runtime_get_sync(cs35l41->dev);
mutex_lock(&cs35l41->fw_mutex);
/* Recheck if playback is ongoing, mutex will block playback during firmware loading */
if (cs35l41->playback_started)
dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n");
else
cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
cs35l41->fw_request_ongoing = false;
mutex_unlock(&cs35l41->fw_mutex);
pm_runtime_mark_last_busy(cs35l41->dev);
pm_runtime_put_autosuspend(cs35l41->dev);
}
static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol,
@ -840,6 +944,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
pm_runtime_get_sync(dev);
mutex_lock(&cs35l41->fw_mutex);
comps->dev = dev;
if (!cs35l41->acpi_subsystem_id)
cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x",
@ -852,10 +958,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
if (firmware_autostart) {
dev_dbg(cs35l41->dev, "Firmware Autostart.\n");
cs35l41->request_fw_load = true;
mutex_lock(&cs35l41->fw_mutex);
if (cs35l41_smart_amp(cs35l41) < 0)
dev_warn(cs35l41->dev, "Cannot Run Firmware, reverting to dsp bypass...\n");
mutex_unlock(&cs35l41->fw_mutex);
} else {
dev_dbg(cs35l41->dev, "Firmware Autostart is disabled.\n");
}
@ -863,8 +967,8 @@ static int cs35l41_hda_bind(struct device *dev, struct device *master, void *mas
ret = cs35l41_create_controls(cs35l41);
comps->playback_hook = cs35l41_hda_playback_hook;
comps->suspend_hook = cs35l41_hda_suspend_hook;
comps->resume_hook = cs35l41_hda_resume_hook;
mutex_unlock(&cs35l41->fw_mutex);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@ -1433,6 +1537,7 @@ EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);
const struct dev_pm_ops cs35l41_hda_pm_ops = {
RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
};
EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, SND_HDA_SCODEC_CS35L41);

View File

@ -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);
};

View File

@ -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;
}
return 0;
hda_cs_dsp_add_kcontrol(ctl, name);
}
EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_add, SND_HDA_CS_DSP_CONTROLS);
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_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);

View File

@ -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);

View File

@ -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),

View File

@ -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;

View File

@ -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: