mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 09:12:07 +00:00
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:
commit
dca45efbe3
@ -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(®ister_mutex);
|
||||
if (rmidi->ops && rmidi->ops->dev_unregister)
|
||||
rmidi->ops->dev_unregister(rmidi);
|
||||
mutex_unlock(®ister_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;
|
||||
}
|
||||
|
@ -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 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user