sound fixes for 4.16-rc6
A series of small fixes in ASoC, HD-audio and core stuff: - A UAF fix in ALSA PCM core - Yet more hardening for ALSA sequencer - A regression fix for the previous HD-audio power_save option change - Various ASoC codec fixes (sgtl5000, rt5651, hdmi-codec, wm_adsp) - Minor ASoC platform fixes (AMD ACP, sun4i) -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAlqqprkOHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE+Fow//b3ud9UpNKYArnADF+jt5rhXHKPZdQf4W9Thy RVCv4twJzB2kT7gxw/x5dghMBYYWbHtOMqHtanwqIu9YehQ6XiKyRsAQrD5PFAzM 27h+bNNBIEAJ+jSuJS8pp2T6mQ8KTyMt8lCpsA5yhuBIWahraTJ76tk3CmkXrKwe Stk0RxSDjH4TVbPSHbBc064freBuJcLvDNXSKMxxYc/0mJ2qatvdcKevDeISjvwB yQkDiyHdfpOugYxMVx0H8T1bIM1esUg19+CF9E8/JuKKibKRkOPHPCLjPI8sXVSV zYpfbH5SZT69H7VQRlX1y9rqQycTeMyZyDZBQlTx2KoDh+KnQJ6JKH9NoKg9l5o0 GPr6zMBaIxCI4mAJd5VMOfMCQVGa1pU6KD7dnRbBtFDlSsO93IGf1EMi9L+Yh2KC GV6EJxo82h7JPZotYTQEh9C4OvStIKxdm8kmy3Yd1N7MOAy0TpemC41rYp3KAaET W2GrT39c1uyPMRU27GVb08X64itDIpAFGvA3sEaT7TGoO3mAv30tfN4SUu8Ls3n/ 0dCnKN68yAGISogz6fbrvSz2tQoZQf1ACz548zony753tOvmxndtvgPIvGDDa/j3 z/FYfoCMTF/KijQhEKK7pOu5lwEaOd66VC3XZgyYgCON0SZbzcStqQF33kGuIlhT BcmjHOI= =mCc/ -----END PGP SIGNATURE----- Merge tag 'sound-4.16-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound fixes from Takashi Iwai: "A series of small fixes in ASoC, HD-audio and core stuff: - a UAF fix in ALSA PCM core - yet more hardening for ALSA sequencer - a regression fix for the previous HD-audio power_save option change - various ASoC codec fixes (sgtl5000, rt5651, hdmi-codec, wm_adsp) - minor ASoC platform fixes (AMD ACP, sun4i)" * tag 'sound-4.16-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: ALSA: hda - Revert power_save option default value ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats() ALSA: seq: Clear client entry before deleting else at closing ALSA: seq: Fix possible UAF in snd_seq_check_queue() ASoC: amd: 16bit resolution support for i2s sp instance ASoC: wm_adsp: For TLV controls only register TLV get/set ASoC: sun4i-i2s: Fix RX slot number of SUN8I ASoC: hdmi-codec: Fix module unloading caused kernel crash ASoC: rt5651: Fix regcache sync errors on resume ASoC: sgtl5000: Fix suspend/resume MAINTAINERS: Add myself as sgtl5000 maintainer ASoC: samsung: Add the DT binding files entry to MAINTAINERS sgtl5000: change digital_mute policy
This commit is contained in:
commit
e2c15aff5f
@ -9925,6 +9925,13 @@ F: Documentation/ABI/stable/sysfs-bus-nvmem
|
||||
F: include/linux/nvmem-consumer.h
|
||||
F: include/linux/nvmem-provider.h
|
||||
|
||||
NXP SGTL5000 DRIVER
|
||||
M: Fabio Estevam <fabio.estevam@nxp.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/sound/sgtl5000.txt
|
||||
F: sound/soc/codecs/sgtl5000*
|
||||
|
||||
NXP TDA998X DRM DRIVER
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
S: Supported
|
||||
@ -12107,6 +12114,7 @@ M: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: sound/soc/samsung/
|
||||
F: Documentation/devicetree/bindings/sound/samsung*
|
||||
|
||||
SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
|
||||
M: Krzysztof Kozlowski <krzk@kernel.org>
|
||||
|
@ -1762,10 +1762,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
return -ENOMEM;
|
||||
_snd_pcm_hw_params_any(params);
|
||||
err = snd_pcm_hw_refine(substream, params);
|
||||
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
kfree(params);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto error;
|
||||
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
for (fmt = 0; fmt < 32; ++fmt) {
|
||||
if (snd_mask_test(format_mask, fmt)) {
|
||||
int f = snd_pcm_oss_format_to(fmt);
|
||||
@ -1773,7 +1772,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
|
||||
formats |= f;
|
||||
}
|
||||
}
|
||||
return formats;
|
||||
|
||||
error:
|
||||
kfree(params);
|
||||
return err < 0 ? err : formats;
|
||||
}
|
||||
|
||||
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
|
||||
|
@ -255,12 +255,12 @@ static int seq_free_client1(struct snd_seq_client *client)
|
||||
|
||||
if (!client)
|
||||
return 0;
|
||||
snd_seq_delete_all_ports(client);
|
||||
snd_seq_queue_client_leave(client->number);
|
||||
spin_lock_irqsave(&clients_lock, flags);
|
||||
clienttablock[client->number] = 1;
|
||||
clienttab[client->number] = NULL;
|
||||
spin_unlock_irqrestore(&clients_lock, flags);
|
||||
snd_seq_delete_all_ports(client);
|
||||
snd_seq_queue_client_leave(client->number);
|
||||
snd_use_lock_sync(&client->use_lock);
|
||||
snd_seq_queue_client_termination(client->number);
|
||||
if (client->pool)
|
||||
|
@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
|
||||
if (f->cells > 0) {
|
||||
/* drain prioQ */
|
||||
while (f->cells > 0)
|
||||
snd_seq_cell_free(snd_seq_prioq_cell_out(f));
|
||||
snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL));
|
||||
}
|
||||
|
||||
kfree(f);
|
||||
@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return 1 if the current time >= event timestamp */
|
||||
static int event_is_ready(struct snd_seq_event *ev, void *current_time)
|
||||
{
|
||||
if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK)
|
||||
return snd_seq_compare_tick_time(current_time, &ev->time.tick);
|
||||
else
|
||||
return snd_seq_compare_real_time(current_time, &ev->time.time);
|
||||
}
|
||||
|
||||
/* dequeue cell from prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
|
||||
void *current_time)
|
||||
{
|
||||
struct snd_seq_event_cell *cell;
|
||||
unsigned long flags;
|
||||
@ -227,6 +237,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
|
||||
spin_lock_irqsave(&f->lock, flags);
|
||||
|
||||
cell = f->head;
|
||||
if (cell && current_time && !event_is_ready(&cell->event, current_time))
|
||||
cell = NULL;
|
||||
if (cell) {
|
||||
f->head = cell->next;
|
||||
|
||||
@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
|
||||
return f->cells;
|
||||
}
|
||||
|
||||
|
||||
/* peek at cell at the head of the prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
|
||||
{
|
||||
if (f == NULL) {
|
||||
pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
|
||||
return NULL;
|
||||
}
|
||||
return f->head;
|
||||
}
|
||||
|
||||
|
||||
static inline int prioq_match(struct snd_seq_event_cell *cell,
|
||||
int client, int timestamp)
|
||||
{
|
||||
|
@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo);
|
||||
int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);
|
||||
|
||||
/* dequeue cell from prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f);
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
|
||||
void *current_time);
|
||||
|
||||
/* return number of events available in prioq */
|
||||
int snd_seq_prioq_avail(struct snd_seq_prioq *f);
|
||||
|
||||
/* peek at cell at the head of the prioq */
|
||||
struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f);
|
||||
|
||||
/* client left queue */
|
||||
void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp);
|
||||
|
||||
|
@ -277,30 +277,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
|
||||
|
||||
__again:
|
||||
/* Process tick queue... */
|
||||
while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) {
|
||||
if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick,
|
||||
&cell->event.time.tick)) {
|
||||
cell = snd_seq_prioq_cell_out(q->tickq);
|
||||
if (cell)
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
} else {
|
||||
/* event remains in the queue */
|
||||
for (;;) {
|
||||
cell = snd_seq_prioq_cell_out(q->tickq,
|
||||
&q->timer->tick.cur_tick);
|
||||
if (!cell)
|
||||
break;
|
||||
}
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
}
|
||||
|
||||
|
||||
/* Process time queue... */
|
||||
while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) {
|
||||
if (snd_seq_compare_real_time(&q->timer->cur_time,
|
||||
&cell->event.time.time)) {
|
||||
cell = snd_seq_prioq_cell_out(q->timeq);
|
||||
if (cell)
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
} else {
|
||||
/* event remains in the queue */
|
||||
for (;;) {
|
||||
cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time);
|
||||
if (!cell)
|
||||
break;
|
||||
}
|
||||
snd_seq_dispatch_event(cell, atomic, hop);
|
||||
}
|
||||
|
||||
/* free lock */
|
||||
|
@ -181,11 +181,15 @@ static const struct kernel_param_ops param_ops_xint = {
|
||||
};
|
||||
#define param_check_xint param_check_int
|
||||
|
||||
static int power_save = -1;
|
||||
static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||
module_param(power_save, xint, 0644);
|
||||
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
|
||||
"(in second, 0 = disable).");
|
||||
|
||||
static bool pm_blacklist = true;
|
||||
module_param(pm_blacklist, bool, 0644);
|
||||
MODULE_PARM_DESC(pm_blacklist, "Enable power-management blacklist");
|
||||
|
||||
/* reset the HD-audio controller in power save mode.
|
||||
* this may give more power-saving, but will take longer time to
|
||||
* wake up.
|
||||
@ -2300,10 +2304,9 @@ static int azx_probe_continue(struct azx *chip)
|
||||
|
||||
val = power_save;
|
||||
#ifdef CONFIG_PM
|
||||
if (val == -1) {
|
||||
if (pm_blacklist) {
|
||||
const struct snd_pci_quirk *q;
|
||||
|
||||
val = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
|
||||
q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
|
||||
if (q && val) {
|
||||
dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n",
|
||||
|
@ -579,13 +579,6 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)
|
||||
for (bank = 1; bank < 48; bank++)
|
||||
acp_set_sram_bank_state(acp_mmio, bank, false);
|
||||
}
|
||||
|
||||
/* Stoney supports 16bit resolution */
|
||||
if (asic_type == CHIP_STONEY) {
|
||||
val = acp_reg_read(acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
|
||||
val |= 0x03;
|
||||
acp_reg_write(val, acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -774,6 +767,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
int status;
|
||||
uint64_t size;
|
||||
u32 val = 0;
|
||||
struct page *pg;
|
||||
struct snd_pcm_runtime *runtime;
|
||||
struct audio_substream_data *rtd;
|
||||
@ -786,6 +780,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
if (WARN_ON(!rtd))
|
||||
return -EINVAL;
|
||||
|
||||
if (adata->asic_type == CHIP_STONEY) {
|
||||
val = acp_reg_read(adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
val |= ACP_I2S_SP_16BIT_RESOLUTION_EN;
|
||||
else
|
||||
val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN;
|
||||
acp_reg_write(val, adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
|
||||
}
|
||||
size = params_buffer_bytes(params);
|
||||
status = snd_pcm_lib_malloc_pages(substream, size);
|
||||
if (status < 0)
|
||||
|
@ -70,6 +70,8 @@
|
||||
#define CAPTURE_END_DMA_DESCR_CH15 7
|
||||
|
||||
#define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209
|
||||
#define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01
|
||||
#define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02
|
||||
enum acp_dma_priority_level {
|
||||
/* 0x0 Specifies the DMA channel is given normal priority */
|
||||
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
|
||||
|
@ -798,12 +798,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
|
||||
|
||||
static int hdmi_codec_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct hdmi_codec_priv *hcp;
|
||||
|
||||
hcp = dev_get_drvdata(dev);
|
||||
kfree(hcp->chmap_info);
|
||||
snd_soc_unregister_codec(dev);
|
||||
snd_soc_unregister_codec(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1722,6 +1722,7 @@ static const struct regmap_config rt5651_regmap = {
|
||||
.num_reg_defaults = ARRAY_SIZE(rt5651_reg),
|
||||
.ranges = rt5651_ranges,
|
||||
.num_ranges = ARRAY_SIZE(rt5651_ranges),
|
||||
.use_single_rw = true,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
|
@ -529,10 +529,15 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
|
||||
static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
u16 adcdac_ctrl = SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT;
|
||||
u16 i2s_pwr = SGTL5000_I2S_IN_POWERUP;
|
||||
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL,
|
||||
adcdac_ctrl, mute ? adcdac_ctrl : 0);
|
||||
/*
|
||||
* During 'digital mute' do not mute DAC
|
||||
* because LINE_IN would be muted aswell. We want to mute
|
||||
* only I2S block - this can be done by powering it off
|
||||
*/
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_DIG_POWER,
|
||||
i2s_pwr, mute ? 0 : i2s_pwr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -871,15 +876,26 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct sgtl5000_priv *sgtl = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
regcache_cache_only(sgtl->regmap, false);
|
||||
ret = regcache_sync(sgtl->regmap);
|
||||
if (ret) {
|
||||
regcache_cache_only(sgtl->regmap, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_REFTOP_POWERUP,
|
||||
SGTL5000_REFTOP_POWERUP);
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
regcache_cache_only(sgtl->regmap, true);
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
|
||||
SGTL5000_REFTOP_POWERUP, 0);
|
||||
break;
|
||||
@ -1237,6 +1253,10 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
|
||||
*/
|
||||
snd_soc_write(codec, SGTL5000_DAP_CTRL, 0);
|
||||
|
||||
/* Unmute DAC after start */
|
||||
snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL,
|
||||
SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
@ -1204,12 +1204,14 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
|
||||
kcontrol->put = wm_coeff_put_acked;
|
||||
break;
|
||||
default:
|
||||
kcontrol->get = wm_coeff_get;
|
||||
kcontrol->put = wm_coeff_put;
|
||||
|
||||
ctl->bytes_ext.max = ctl->len;
|
||||
ctl->bytes_ext.get = wm_coeff_tlv_get;
|
||||
ctl->bytes_ext.put = wm_coeff_tlv_put;
|
||||
if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
|
||||
ctl->bytes_ext.max = ctl->len;
|
||||
ctl->bytes_ext.get = wm_coeff_tlv_get;
|
||||
ctl->bytes_ext.put = wm_coeff_tlv_put;
|
||||
} else {
|
||||
kcontrol->get = wm_coeff_get;
|
||||
kcontrol->put = wm_coeff_put;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@
|
||||
|
||||
#define SUN8I_I2S_CHAN_CFG_REG 0x30
|
||||
#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(6, 4)
|
||||
#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) (chan - 1)
|
||||
#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) ((chan - 1) << 4)
|
||||
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(2, 0)
|
||||
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user