summaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/hrtimer.c2
-rw-r--r--sound/core/hwdep.c2
-rw-r--r--sound/core/init.c32
-rw-r--r--sound/core/jack.c2
-rw-r--r--sound/core/pcm.c22
-rw-r--r--sound/core/pcm_lib.c6
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/core/seq/seq_clientmgr.c4
-rw-r--r--sound/core/seq/seq_timer.c2
-rw-r--r--sound/core/timer.c11
-rw-r--r--sound/core/timer_compat.c12
-rw-r--r--sound/core/vmaster.c6
12 files changed, 76 insertions, 27 deletions
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index 6e47b823bcaa..18cb6f476bf4 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -127,7 +127,7 @@ static int snd_hrtimer_stop(struct snd_timer *t)
return 0;
}
-static struct snd_timer_hardware hrtimer_hw = {
+static const struct snd_timer_hardware hrtimer_hw __initconst = {
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET,
.open = snd_hrtimer_open,
.close = snd_hrtimer_close,
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index a73baa1242be..8faae3d1455d 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -228,6 +228,8 @@ static int snd_hwdep_dsp_load(struct snd_hwdep *hw,
memset(&info, 0, sizeof(info));
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
+ if (info.index >= 32)
+ return -EINVAL;
/* check whether the dsp was already loaded */
if (hw->dsp_loaded & (1 << info.index))
return -EBUSY;
diff --git a/sound/core/init.c b/sound/core/init.c
index 32ebe2f6bc59..168ae03d3a1c 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -255,6 +255,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
#ifdef CONFIG_PM
init_waitqueue_head(&card->power_sleep);
#endif
+ init_waitqueue_head(&card->remove_sleep);
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
@@ -452,6 +453,35 @@ int snd_card_disconnect(struct snd_card *card)
}
EXPORT_SYMBOL(snd_card_disconnect);
+/**
+ * snd_card_disconnect_sync - disconnect card and wait until files get closed
+ * @card: card object to disconnect
+ *
+ * This calls snd_card_disconnect() for disconnecting all belonging components
+ * and waits until all pending files get closed.
+ * It assures that all accesses from user-space finished so that the driver
+ * can release its resources gracefully.
+ */
+void snd_card_disconnect_sync(struct snd_card *card)
+{
+ int err;
+
+ err = snd_card_disconnect(card);
+ if (err < 0) {
+ dev_err(card->dev,
+ "snd_card_disconnect error (%d), skipping sync\n",
+ err);
+ return;
+ }
+
+ spin_lock_irq(&card->files_lock);
+ wait_event_lock_irq(card->remove_sleep,
+ list_empty(&card->files_list),
+ card->files_lock);
+ spin_unlock_irq(&card->files_lock);
+}
+EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
+
static int snd_card_do_free(struct snd_card *card)
{
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
@@ -957,6 +987,8 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
break;
}
}
+ if (list_empty(&card->files_list))
+ wake_up_all(&card->remove_sleep);
spin_unlock(&card->files_lock);
if (!found) {
dev_err(card->dev, "card file remove problem (%p)\n", file);
diff --git a/sound/core/jack.c b/sound/core/jack.c
index f652e90efd7e..84c2a17c56ee 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -310,7 +310,7 @@ EXPORT_SYMBOL(snd_jack_set_parent);
* @type: Jack report type for this key
* @keytype: Input layer key type to be reported
*
- * Map a SND_JACK_BTN_ button type to an input layer key, allowing
+ * Map a SND_JACK_BTN_* button type to an input layer key, allowing
* reporting of keys on accessories via the jack abstraction. If no
* mapping is provided but keys are enabled in the jack type then
* BTN_n numeric buttons will be reported.
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 7eadb7fd8074..09ee8c6b9f75 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -153,7 +153,9 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
err = -ENXIO;
goto _error;
}
+ mutex_lock(&pcm->open_mutex);
err = snd_pcm_info_user(substream, info);
+ mutex_unlock(&pcm->open_mutex);
_error:
mutex_unlock(&register_mutex);
return err;
@@ -775,6 +777,9 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
};
+ static struct snd_device_ops internal_ops = {
+ .dev_free = snd_pcm_dev_free,
+ };
if (snd_BUG_ON(!card))
return -ENXIO;
@@ -801,7 +806,8 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
if (err < 0)
goto free_pcm;
- err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops);
+ err = snd_device_new(card, SNDRV_DEV_PCM, pcm,
+ internal ? &internal_ops : &ops);
if (err < 0)
goto free_pcm;
@@ -1099,8 +1105,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
if (snd_BUG_ON(!device || !device->device_data))
return -ENXIO;
pcm = device->device_data;
- if (pcm->internal)
- return 0;
mutex_lock(&register_mutex);
err = snd_pcm_add(pcm);
@@ -1152,6 +1156,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
snd_pcm_stream_lock_irq(substream);
if (substream->runtime) {
+ if (snd_pcm_running(substream))
+ snd_pcm_stop(substream,
+ SNDRV_PCM_STATE_DISCONNECTED);
+ /* to be sure, set the state unconditionally */
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
wake_up(&substream->runtime->sleep);
wake_up(&substream->runtime->tsleep);
@@ -1159,12 +1167,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
snd_pcm_stream_unlock_irq(substream);
}
}
- if (!pcm->internal) {
- pcm_call_notify(pcm, n_disconnect);
- }
+
+ pcm_call_notify(pcm, n_disconnect);
for (cidx = 0; cidx < 2; cidx++) {
- if (!pcm->internal)
- snd_unregister_device(&pcm->streams[cidx].dev);
+ snd_unregister_device(&pcm->streams[cidx].dev);
free_chmap(&pcm->streams[cidx]);
}
mutex_unlock(&pcm->open_mutex);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a93a4235a332..10e7ef7a8804 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -248,8 +248,10 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream,
runtime->rate);
*audio_tstamp = ns_to_timespec(audio_nsecs);
}
- runtime->status->audio_tstamp = *audio_tstamp;
- runtime->status->tstamp = *curr_tstamp;
+ if (!timespec_equal(&runtime->status->audio_tstamp, audio_tstamp)) {
+ runtime->status->audio_tstamp = *audio_tstamp;
+ runtime->status->tstamp = *curr_tstamp;
+ }
/*
* re-take a driver timestamp to let apps detect if the reference tstamp
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 2fec2feac387..a4d92e46c459 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -195,7 +195,6 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
{
- struct snd_pcm_runtime *runtime;
struct snd_pcm *pcm = substream->pcm;
struct snd_pcm_str *pstr = substream->pstr;
@@ -211,7 +210,6 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
info->subdevices_count = pstr->substream_count;
info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
strlcpy(info->subname, substream->name, sizeof(info->subname));
- runtime = substream->runtime;
return 0;
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index d10c780dfd54..6e22eea72654 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -802,6 +802,10 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
return -EMLINK;
}
+ if (snd_seq_ev_is_variable(event) &&
+ snd_BUG_ON(atomic && (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR)))
+ return -EINVAL;
+
if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS ||
event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)
result = deliver_to_subscribers(client, event, atomic, hop);
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 37d9cfbc29f9..b80985fbc334 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -355,7 +355,7 @@ static int initialize_timer(struct snd_seq_timer *tmr)
unsigned long freq;
t = tmr->timeri->timer;
- if (snd_BUG_ON(!t))
+ if (!t)
return -EINVAL;
freq = tmr->preferred_resolution;
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 15e82a656d96..ee09dace8bb1 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1069,15 +1069,17 @@ EXPORT_SYMBOL(snd_timer_global_register);
struct snd_timer_system_private {
struct timer_list tlist;
+ struct snd_timer *snd_timer;
unsigned long last_expires;
unsigned long last_jiffies;
unsigned long correction;
};
-static void snd_timer_s_function(unsigned long data)
+static void snd_timer_s_function(struct timer_list *t)
{
- struct snd_timer *timer = (struct snd_timer *)data;
- struct snd_timer_system_private *priv = timer->private_data;
+ struct snd_timer_system_private *priv = from_timer(priv, t,
+ tlist);
+ struct snd_timer *timer = priv->snd_timer;
unsigned long jiff = jiffies;
if (time_after(jiff, priv->last_expires))
priv->correction += (long)jiff - (long)priv->last_expires;
@@ -1159,7 +1161,8 @@ static int snd_timer_register_system(void)
snd_timer_free(timer);
return -ENOMEM;
}
- setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer);
+ priv->snd_timer = timer;
+ timer_setup(&priv->tlist, snd_timer_s_function, 0);
timer->private_data = priv;
timer->private_free = snd_timer_free_system;
return snd_timer_global_register(timer);
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 59127b6ef39e..e00f7e399e46 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -66,11 +66,11 @@ static int snd_timer_user_info_compat(struct file *file,
struct snd_timer *t;
tu = file->private_data;
- if (snd_BUG_ON(!tu->timeri))
- return -ENXIO;
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- if (snd_BUG_ON(!t))
- return -ENXIO;
+ if (!t)
+ return -EBADFD;
memset(&info, 0, sizeof(info));
info.card = t->card ? t->card->number : -1;
if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
@@ -99,8 +99,8 @@ static int snd_timer_user_status_compat(struct file *file,
struct snd_timer_status32 status;
tu = file->private_data;
- if (snd_BUG_ON(!tu->timeri))
- return -ENXIO;
+ if (!tu->timeri)
+ return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp.tv_sec = tu->tstamp.tv_sec;
status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index e43af18d4383..8632301489fa 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -495,7 +495,9 @@ EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
* Returns 0 if successful, or a negative error code.
*/
int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl,
- int (*func)(struct snd_kcontrol *, void *),
+ int (*func)(struct snd_kcontrol *vslave,
+ struct snd_kcontrol *slave,
+ void *arg),
void *arg)
{
struct link_master *master;
@@ -507,7 +509,7 @@ int snd_ctl_apply_vmaster_slaves(struct snd_kcontrol *kctl,
if (err < 0)
return err;
list_for_each_entry(slave, &master->slaves, list) {
- err = func(&slave->slave, arg);
+ err = func(slave->kctl, &slave->slave, arg);
if (err < 0)
return err;
}