Commit e2c15aff authored by Linus Torvalds's avatar Linus Torvalds

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
parents 667058ae db45dc95
...@@ -9925,6 +9925,13 @@ F: Documentation/ABI/stable/sysfs-bus-nvmem ...@@ -9925,6 +9925,13 @@ F: Documentation/ABI/stable/sysfs-bus-nvmem
F: include/linux/nvmem-consumer.h F: include/linux/nvmem-consumer.h
F: include/linux/nvmem-provider.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 NXP TDA998X DRM DRIVER
M: Russell King <linux@armlinux.org.uk> M: Russell King <linux@armlinux.org.uk>
S: Supported S: Supported
...@@ -12107,6 +12114,7 @@ M: Sylwester Nawrocki <s.nawrocki@samsung.com> ...@@ -12107,6 +12114,7 @@ M: Sylwester Nawrocki <s.nawrocki@samsung.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported S: Supported
F: sound/soc/samsung/ F: sound/soc/samsung/
F: Documentation/devicetree/bindings/sound/samsung*
SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
M: Krzysztof Kozlowski <krzk@kernel.org> 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) ...@@ -1762,10 +1762,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
return -ENOMEM; return -ENOMEM;
_snd_pcm_hw_params_any(params); _snd_pcm_hw_params_any(params);
err = snd_pcm_hw_refine(substream, 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) 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) { for (fmt = 0; fmt < 32; ++fmt) {
if (snd_mask_test(format_mask, fmt)) { if (snd_mask_test(format_mask, fmt)) {
int f = snd_pcm_oss_format_to(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) ...@@ -1773,7 +1772,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
formats |= f; 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) 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) ...@@ -255,12 +255,12 @@ static int seq_free_client1(struct snd_seq_client *client)
if (!client) if (!client)
return 0; return 0;
snd_seq_delete_all_ports(client);
snd_seq_queue_client_leave(client->number);
spin_lock_irqsave(&clients_lock, flags); spin_lock_irqsave(&clients_lock, flags);
clienttablock[client->number] = 1; clienttablock[client->number] = 1;
clienttab[client->number] = NULL; clienttab[client->number] = NULL;
spin_unlock_irqrestore(&clients_lock, flags); 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_use_lock_sync(&client->use_lock);
snd_seq_queue_client_termination(client->number); snd_seq_queue_client_termination(client->number);
if (client->pool) if (client->pool)
......
...@@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo) ...@@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
if (f->cells > 0) { if (f->cells > 0) {
/* drain prioQ */ /* drain prioQ */
while (f->cells > 0) 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); kfree(f);
...@@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, ...@@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
return 0; 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 */ /* 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; struct snd_seq_event_cell *cell;
unsigned long flags; unsigned long flags;
...@@ -227,6 +237,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f) ...@@ -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); spin_lock_irqsave(&f->lock, flags);
cell = f->head; cell = f->head;
if (cell && current_time && !event_is_ready(&cell->event, current_time))
cell = NULL;
if (cell) { if (cell) {
f->head = cell->next; f->head = cell->next;
...@@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f) ...@@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
return f->cells; 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, static inline int prioq_match(struct snd_seq_event_cell *cell,
int client, int timestamp) int client, int timestamp)
{ {
......
...@@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo); ...@@ -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); int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);
/* dequeue cell from prioq */ /* 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 */ /* return number of events available in prioq */
int snd_seq_prioq_avail(struct snd_seq_prioq *f); 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 */ /* client left queue */
void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp); 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) ...@@ -277,30 +277,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
__again: __again:
/* Process tick queue... */ /* Process tick queue... */
while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) { for (;;) {
if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick, cell = snd_seq_prioq_cell_out(q->tickq,
&cell->event.time.tick)) { &q->timer->tick.cur_tick);
cell = snd_seq_prioq_cell_out(q->tickq); if (!cell)
if (cell)
snd_seq_dispatch_event(cell, atomic, hop);
} else {
/* event remains in the queue */
break; break;
} snd_seq_dispatch_event(cell, atomic, hop);
} }
/* Process time queue... */ /* Process time queue... */
while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) { for (;;) {
if (snd_seq_compare_real_time(&q->timer->cur_time, cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time);
&cell->event.time.time)) { if (!cell)
cell = snd_seq_prioq_cell_out(q->timeq);
if (cell)
snd_seq_dispatch_event(cell, atomic, hop);
} else {
/* event remains in the queue */
break; break;
} snd_seq_dispatch_event(cell, atomic, hop);
} }
/* free lock */ /* free lock */
......
...@@ -181,11 +181,15 @@ static const struct kernel_param_ops param_ops_xint = { ...@@ -181,11 +181,15 @@ static const struct kernel_param_ops param_ops_xint = {
}; };
#define param_check_xint param_check_int #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_param(power_save, xint, 0644);
MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
"(in second, 0 = disable)."); "(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. /* reset the HD-audio controller in power save mode.
* this may give more power-saving, but will take longer time to * this may give more power-saving, but will take longer time to
* wake up. * wake up.
...@@ -2300,10 +2304,9 @@ static int azx_probe_continue(struct azx *chip) ...@@ -2300,10 +2304,9 @@ static int azx_probe_continue(struct azx *chip)
val = power_save; val = power_save;
#ifdef CONFIG_PM #ifdef CONFIG_PM
if (val == -1) { if (pm_blacklist) {
const struct snd_pci_quirk *q; const struct snd_pci_quirk *q;
val = CONFIG_SND_HDA_POWER_SAVE_DEFAULT;
q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist); q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
if (q && val) { if (q && val) {
dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n", 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) ...@@ -579,13 +579,6 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)
for (bank = 1; bank < 48; bank++) for (bank = 1; bank < 48; bank++)
acp_set_sram_bank_state(acp_mmio, bank, false); 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; return 0;
} }
...@@ -774,6 +767,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, ...@@ -774,6 +767,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
{ {
int status; int status;
uint64_t size; uint64_t size;
u32 val = 0;
struct page *pg; struct page *pg;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd; struct audio_substream_data *rtd;
...@@ -786,6 +780,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream, ...@@ -786,6 +780,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
if (WARN_ON(!rtd)) if (WARN_ON(!rtd))
return -EINVAL; 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); size = params_buffer_bytes(params);
status = snd_pcm_lib_malloc_pages(substream, size); status = snd_pcm_lib_malloc_pages(substream, size);
if (status < 0) if (status < 0)
......
...@@ -70,6 +70,8 @@ ...@@ -70,6 +70,8 @@
#define CAPTURE_END_DMA_DESCR_CH15 7 #define CAPTURE_END_DMA_DESCR_CH15 7
#define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209 #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 { enum acp_dma_priority_level {
/* 0x0 Specifies the DMA channel is given normal priority */ /* 0x0 Specifies the DMA channel is given normal priority */
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0, ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
......
...@@ -798,12 +798,7 @@ static int hdmi_codec_probe(struct platform_device *pdev) ...@@ -798,12 +798,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
static int hdmi_codec_remove(struct platform_device *pdev) static int hdmi_codec_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; snd_soc_unregister_codec(&pdev->dev);
struct hdmi_codec_priv *hcp;
hcp = dev_get_drvdata(dev);
kfree(hcp->chmap_info);
snd_soc_unregister_codec(dev);
return 0; return 0;
} }
......
...@@ -1722,6 +1722,7 @@ static const struct regmap_config rt5651_regmap = { ...@@ -1722,6 +1722,7 @@ static const struct regmap_config rt5651_regmap = {
.num_reg_defaults = ARRAY_SIZE(rt5651_reg), .num_reg_defaults = ARRAY_SIZE(rt5651_reg),
.ranges = rt5651_ranges, .ranges = rt5651_ranges,
.num_ranges = ARRAY_SIZE(rt5651_ranges), .num_ranges = ARRAY_SIZE(rt5651_ranges),
.use_single_rw = true,
}; };
#if defined(CONFIG_OF) #if defined(CONFIG_OF)
......
...@@ -529,10 +529,15 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { ...@@ -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) static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
{ {
struct snd_soc_codec *codec = codec_dai->codec; 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; return 0;
} }
...@@ -871,15 +876,26 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -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, static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct sgtl5000_priv *sgtl = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
case SND_SOC_BIAS_STANDBY: 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, snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_REFTOP_POWERUP, SGTL5000_REFTOP_POWERUP,
SGTL5000_REFTOP_POWERUP); SGTL5000_REFTOP_POWERUP);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
regcache_cache_only(sgtl->regmap, true);
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_REFTOP_POWERUP, 0); SGTL5000_REFTOP_POWERUP, 0);
break; break;
...@@ -1237,6 +1253,10 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) ...@@ -1237,6 +1253,10 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
*/ */
snd_soc_write(codec, SGTL5000_DAP_CTRL, 0); 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; return 0;
err: err:
......
...@@ -1204,12 +1204,14 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) ...@@ -1204,12 +1204,14 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
kcontrol->put = wm_coeff_put_acked; kcontrol->put = wm_coeff_put_acked;
break; break;
default: default:
kcontrol->get = wm_coeff_get; if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
kcontrol->put = wm_coeff_put; ctl->bytes_ext.max = ctl->len;
ctl->bytes_ext.get = wm_coeff_tlv_get;
ctl->bytes_ext.max = ctl->len; ctl->bytes_ext.put = wm_coeff_tlv_put;
ctl->bytes_ext.get = wm_coeff_tlv_get; } else {
ctl->bytes_ext.put = wm_coeff_tlv_put; kcontrol->get = wm_coeff_get;
kcontrol->put = wm_coeff_put;
}
break; break;
} }
......
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
#define SUN8I_I2S_CHAN_CFG_REG 0x30 #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_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_MASK GENMASK(2, 0)
#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1) #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1)
......
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