summaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/compress_offload.c5
-rw-r--r--sound/core/control.c12
-rw-r--r--sound/core/control_compat.c14
-rw-r--r--sound/core/control_led.c2
-rw-r--r--sound/core/init.c4
-rw-r--r--sound/core/oss/pcm_plugin.h16
-rw-r--r--sound/core/pcm_drm_eld.c73
-rw-r--r--sound/core/pcm_native.c4
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c35
-rw-r--r--sound/core/timer.c18
10 files changed, 137 insertions, 46 deletions
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 243acad89fd3..30f73097447b 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -589,7 +589,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
struct snd_compr_params *params;
int retval;
- if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+ if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) {
/*
* we should allow parameter change only when stream has been
* opened not in other cases
@@ -612,6 +612,9 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
if (retval)
goto out;
+ if (stream->next_track)
+ goto out;
+
stream->metadata_set = false;
stream->next_track = false;
diff --git a/sound/core/control.c b/sound/core/control.c
index 82aa1af1d1d8..8386b53acdcd 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -730,12 +730,20 @@ EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
* Finds the control with the old id from the card, and replaces the
* id with the new one.
*
+ * The function tries to keep the already assigned numid while replacing
+ * the rest.
+ *
+ * Note that this function should be used only in the card initialization
+ * phase. Calling after the card instantiation may cause issues with
+ * user-space expecting persistent numids.
+ *
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
struct snd_ctl_elem_id *dst_id)
{
struct snd_kcontrol *kctl;
+ int saved_numid;
down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, src_id);
@@ -743,10 +751,10 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
up_write(&card->controls_rwsem);
return -ENOENT;
}
+ saved_numid = kctl->id.numid;
remove_hash_entries(card, kctl);
kctl->id = *dst_id;
- kctl->id.numid = card->last_numid + 1;
- card->last_numid += kctl->count;
+ kctl->id.numid = saved_numid;
add_hash_entries(card, kctl);
up_write(&card->controls_rwsem);
return 0;
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index d8a86d1a99d6..9cae5d74335c 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -197,7 +197,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
return err;
}
-static int get_elem_size(int type, int count)
+static int get_elem_size(snd_ctl_elem_type_t type, int count)
{
switch (type) {
case SNDRV_CTL_ELEM_TYPE_INTEGER64:
@@ -234,8 +234,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
if (type < 0)
return type;
- if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -244,7 +244,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
data->value.integer.value[i] = val;
}
} else {
- size = get_elem_size(type, count);
+ size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
if (size < 0) {
dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
@@ -267,8 +267,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
struct snd_ctl_elem_value32 __user *data32 = userdata;
int i, size;
- if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -277,7 +277,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
return -EFAULT;
}
} else {
- size = get_elem_size(type, count);
+ size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
if (copy_to_user(valuep, data->value.bytes.data, size))
return -EFAULT;
}
diff --git a/sound/core/control_led.c b/sound/core/control_led.c
index 3cadd40100f3..ee77547bf8dc 100644
--- a/sound/core/control_led.c
+++ b/sound/core/control_led.c
@@ -737,7 +737,7 @@ static int __init snd_ctl_led_init(void)
unsigned int group;
device_initialize(&snd_ctl_led_dev);
- snd_ctl_led_dev.class = sound_class;
+ snd_ctl_led_dev.class = &sound_class;
snd_ctl_led_dev.release = snd_ctl_led_dev_release;
dev_set_name(&snd_ctl_led_dev, "ctl-led");
if (device_add(&snd_ctl_led_dev)) {
diff --git a/sound/core/init.c b/sound/core/init.c
index df0c22480375..baef2688d0cf 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -129,7 +129,7 @@ void snd_device_initialize(struct device *dev, struct snd_card *card)
device_initialize(dev);
if (card)
dev->parent = &card->card_dev;
- dev->class = sound_class;
+ dev->class = &sound_class;
dev->release = default_release;
}
EXPORT_SYMBOL_GPL(snd_device_initialize);
@@ -331,7 +331,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
- card->card_dev.class = sound_class;
+ card->card_dev.class = &sound_class;
card->card_dev.release = release_card_device;
card->card_dev.groups = card->dev_groups;
card->dev_groups[0] = &card_dev_attr_group;
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index 46e273bd4a78..50a6b50f5db4 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -141,6 +141,14 @@ int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_channel,
void *snd_pcm_plug_buf_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t size);
void snd_pcm_plug_buf_unlock(struct snd_pcm_substream *plug, void *ptr);
+#else
+
+static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
+static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
+static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; }
+
+#endif
+
snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream,
const char *ptr, snd_pcm_uframes_t size,
int in_kernel);
@@ -151,14 +159,6 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream,
snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream,
void **bufs, snd_pcm_uframes_t frames);
-#else
-
-static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
-static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
-static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; }
-
-#endif
-
#ifdef PLUGIN_DEBUG
#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args)
#else
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
index 4b5faae5d16e..07075071972d 100644
--- a/sound/core/pcm_drm_eld.c
+++ b/sound/core/pcm_drm_eld.c
@@ -2,11 +2,25 @@
/*
* PCM DRM helpers
*/
+#include <linux/bitfield.h>
#include <linux/export.h>
+#include <linux/hdmi.h>
#include <drm/drm_edid.h>
#include <sound/pcm.h>
#include <sound/pcm_drm_eld.h>
+#define SAD0_CHANNELS_MASK GENMASK(2, 0) /* max number of channels - 1 */
+#define SAD0_FORMAT_MASK GENMASK(6, 3) /* audio format */
+
+#define SAD1_RATE_MASK GENMASK(6, 0) /* bitfield of supported rates */
+#define SAD1_RATE_32000_MASK BIT(0)
+#define SAD1_RATE_44100_MASK BIT(1)
+#define SAD1_RATE_48000_MASK BIT(2)
+#define SAD1_RATE_88200_MASK BIT(3)
+#define SAD1_RATE_96000_MASK BIT(4)
+#define SAD1_RATE_176400_MASK BIT(5)
+#define SAD1_RATE_192000_MASK BIT(6)
+
static const unsigned int eld_rates[] = {
32000,
44100,
@@ -17,9 +31,62 @@ static const unsigned int eld_rates[] = {
192000,
};
+static unsigned int map_rate_families(const u8 *sad,
+ unsigned int mask_32000,
+ unsigned int mask_44100,
+ unsigned int mask_48000)
+{
+ unsigned int rate_mask = 0;
+
+ if (sad[1] & SAD1_RATE_32000_MASK)
+ rate_mask |= mask_32000;
+ if (sad[1] & (SAD1_RATE_44100_MASK | SAD1_RATE_88200_MASK | SAD1_RATE_176400_MASK))
+ rate_mask |= mask_44100;
+ if (sad[1] & (SAD1_RATE_48000_MASK | SAD1_RATE_96000_MASK | SAD1_RATE_192000_MASK))
+ rate_mask |= mask_48000;
+ return rate_mask;
+}
+
+static unsigned int sad_rate_mask(const u8 *sad)
+{
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return sad[1] & SAD1_RATE_MASK;
+ case HDMI_AUDIO_CODING_TYPE_AC3:
+ case HDMI_AUDIO_CODING_TYPE_DTS:
+ return map_rate_families(sad,
+ SAD1_RATE_32000_MASK,
+ SAD1_RATE_44100_MASK,
+ SAD1_RATE_48000_MASK);
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
+ case HDMI_AUDIO_CODING_TYPE_MLP:
+ return map_rate_families(sad,
+ 0,
+ SAD1_RATE_176400_MASK,
+ SAD1_RATE_192000_MASK);
+ default:
+ /* TODO adjust for other compressed formats as well */
+ return sad[1] & SAD1_RATE_MASK;
+ }
+}
+
static unsigned int sad_max_channels(const u8 *sad)
{
- return 1 + (sad[0] & 7);
+ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) {
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
+ case HDMI_AUDIO_CODING_TYPE_AC3:
+ case HDMI_AUDIO_CODING_TYPE_DTS:
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
+ return 2;
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
+ case HDMI_AUDIO_CODING_TYPE_MLP:
+ return 8;
+ default:
+ /* TODO adjust for other compressed formats as well */
+ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
+ }
}
static int eld_limit_rates(struct snd_pcm_hw_params *params,
@@ -42,7 +109,7 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
* requested number of channels.
*/
if (c->min <= max_channels)
- rate_mask |= sad[1];
+ rate_mask |= sad_rate_mask(sad);
}
}
@@ -70,7 +137,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
rate_mask |= BIT(i);
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
- if (rate_mask & sad[1])
+ if (rate_mask & sad_rate_mask(sad))
t.max = max(t.max, sad_max_channels(sad));
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 39a65d1415ab..95fc56e403b1 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1605,10 +1605,6 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream,
{
if (substream->runtime->trigger_master != substream)
return 0;
- /* some drivers might use hw_ptr to recover from the pause -
- update the hw_ptr now */
- if (pause_pushed(state))
- snd_pcm_update_hw_ptr(substream);
/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
* a delta between the current jiffies, this gives a large enough
* delta, effectively to skip the check once.
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 07efb38f58ac..f2940b29595f 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -37,6 +37,7 @@ struct seq_oss_midi {
struct snd_midi_event *coder; /* MIDI event coder */
struct seq_oss_devinfo *devinfo; /* assigned OSSseq device */
snd_use_lock_t use_lock;
+ struct mutex open_mutex;
};
@@ -172,6 +173,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
mdev->flags = pinfo->capability;
mdev->opened = 0;
snd_use_lock_init(&mdev->use_lock);
+ mutex_init(&mdev->open_mutex);
/* copy and truncate the name of synth device */
strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
@@ -322,15 +324,17 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
int perm;
struct seq_oss_midi *mdev;
struct snd_seq_port_subscribe subs;
+ int err;
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
+ mutex_lock(&mdev->open_mutex);
/* already used? */
if (mdev->opened && mdev->devinfo != dp) {
- snd_use_lock_free(&mdev->use_lock);
- return -EBUSY;
+ err = -EBUSY;
+ goto unlock;
}
perm = 0;
@@ -340,14 +344,14 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
perm |= PERM_READ;
perm &= mdev->flags;
if (perm == 0) {
- snd_use_lock_free(&mdev->use_lock);
- return -ENXIO;
+ err = -ENXIO;
+ goto unlock;
}
/* already opened? */
if ((mdev->opened & perm) == perm) {
- snd_use_lock_free(&mdev->use_lock);
- return 0;
+ err = 0;
+ goto unlock;
}
perm &= ~mdev->opened;
@@ -372,13 +376,17 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
}
if (! mdev->opened) {
- snd_use_lock_free(&mdev->use_lock);
- return -ENXIO;
+ err = -ENXIO;
+ goto unlock;
}
mdev->devinfo = dp;
+ err = 0;
+
+ unlock:
+ mutex_unlock(&mdev->open_mutex);
snd_use_lock_free(&mdev->use_lock);
- return 0;
+ return err;
}
/*
@@ -393,10 +401,9 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
- if (! mdev->opened || mdev->devinfo != dp) {
- snd_use_lock_free(&mdev->use_lock);
- return 0;
- }
+ mutex_lock(&mdev->open_mutex);
+ if (!mdev->opened || mdev->devinfo != dp)
+ goto unlock;
memset(&subs, 0, sizeof(subs));
if (mdev->opened & PERM_WRITE) {
@@ -415,6 +422,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
mdev->opened = 0;
mdev->devinfo = NULL;
+ unlock:
+ mutex_unlock(&mdev->open_mutex);
snd_use_lock_free(&mdev->use_lock);
return 0;
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index e08a37c23add..9d0d2a5c2e15 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1246,6 +1246,7 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
{
struct snd_timer *timer;
struct snd_timer_instance *ti;
+ unsigned long resolution;
mutex_lock(&register_mutex);
list_for_each_entry(timer, &snd_timer_list, device_list) {
@@ -1269,10 +1270,13 @@ static void snd_timer_proc_read(struct snd_info_entry *entry,
timer->tmr_device, timer->tmr_subdevice);
}
snd_iprintf(buffer, "%s :", timer->name);
- if (timer->hw.resolution)
+ spin_lock_irq(&timer->lock);
+ resolution = snd_timer_hw_resolution(timer);
+ spin_unlock_irq(&timer->lock);
+ if (resolution)
snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
- timer->hw.resolution / 1000,
- timer->hw.resolution % 1000,
+ resolution / 1000,
+ resolution % 1000,
timer->hw.ticks);
if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
snd_iprintf(buffer, " SLAVE");
@@ -1662,7 +1666,9 @@ static int snd_timer_user_ginfo(struct file *file,
ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
strscpy(ginfo->id, t->id, sizeof(ginfo->id));
strscpy(ginfo->name, t->name, sizeof(ginfo->name));
- ginfo->resolution = t->hw.resolution;
+ spin_lock_irq(&t->lock);
+ ginfo->resolution = snd_timer_hw_resolution(t);
+ spin_unlock_irq(&t->lock);
if (t->hw.resolution_min > 0) {
ginfo->resolution_min = t->hw.resolution_min;
ginfo->resolution_max = t->hw.resolution_max;
@@ -1817,7 +1823,9 @@ static int snd_timer_user_info(struct file *file,
info->flags |= SNDRV_TIMER_FLG_SLAVE;
strscpy(info->id, t->id, sizeof(info->id));
strscpy(info->name, t->name, sizeof(info->name));
- info->resolution = t->hw.resolution;
+ spin_lock_irq(&t->lock);
+ info->resolution = snd_timer_hw_resolution(t);
+ spin_unlock_irq(&t->lock);
if (copy_to_user(_info, info, sizeof(*_info)))
err = -EFAULT;
kfree(info);