aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/rawmidi.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-10-16 16:43:39 +0200
committerBen Hutchings <ben@decadent.org.uk>2012-11-16 16:46:50 +0000
commit38638f09259204fd9e6c6486867d8e2771ec5a4d (patch)
tree52ebf5e8fb2a6cc1e5c5b614dda0b6d6447e4a24 /sound/core/rawmidi.c
parent3b4a36722e5e518e4bdd3a215d8a1c5adc18e911 (diff)
downloadkernel_samsung_smdk4412-38638f09259204fd9e6c6486867d8e2771ec5a4d.zip
kernel_samsung_smdk4412-38638f09259204fd9e6c6486867d8e2771ec5a4d.tar.gz
kernel_samsung_smdk4412-38638f09259204fd9e6c6486867d8e2771ec5a4d.tar.bz2
ALSA: Avoid endless sleep after disconnect
commit 0914f7961babbf28aaa2f19b453951fb4841c03f upstream. When disconnect callback is called, each component should wake up sleepers and check card->shutdown flag for avoiding the endless sleep blocking the proper resource release. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'sound/core/rawmidi.c')
-rw-r--r--sound/core/rawmidi.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 7d4f62a..1bb95ae 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -424,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
mutex_unlock(&rmidi->open_mutex);
schedule();
mutex_lock(&rmidi->open_mutex);
+ if (rmidi->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
@@ -995,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
spin_unlock_irq(&runtime->lock);
schedule();
remove_wait_queue(&runtime->sleep, &wait);
+ if (rfile->rmidi->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return result > 0 ? result : -ERESTARTSYS;
if (!runtime->avail)
@@ -1238,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
spin_unlock_irq(&runtime->lock);
timeout = schedule_timeout(30 * HZ);
remove_wait_queue(&runtime->sleep, &wait);
+ if (rfile->rmidi->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return result > 0 ? result : -ERESTARTSYS;
if (!runtime->avail && !timeout)
@@ -1613,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
static int snd_rawmidi_dev_disconnect(struct snd_device *device)
{
struct snd_rawmidi *rmidi = device->device_data;
+ int dir;
mutex_lock(&register_mutex);
+ mutex_lock(&rmidi->open_mutex);
+ wake_up(&rmidi->open_wait);
list_del_init(&rmidi->list);
+ for (dir = 0; dir < 2; dir++) {
+ struct snd_rawmidi_substream *s;
+ list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
+ if (s->runtime)
+ wake_up(&s->runtime->sleep);
+ }
+ }
+
#ifdef CONFIG_SND_OSSEMUL
if (rmidi->ossreg) {
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
@@ -1630,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
}
#endif /* CONFIG_SND_OSSEMUL */
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+ mutex_unlock(&rmidi->open_mutex);
mutex_unlock(&register_mutex);
return 0;
}