Commit b3c705aa authored by Takashi Iwai's avatar Takashi Iwai

ALSA: rawmidi - Use workq for event handling

Kill tasklet usage in rawmidi core code.  Use workq for the event callback
instead of tasklet (which is used only in core/seq/seq_midi.c).
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 30bdee02
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/workqueue.h>
#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
#include "seq_device.h" #include "seq_device.h"
...@@ -63,6 +64,7 @@ struct snd_rawmidi_global_ops { ...@@ -63,6 +64,7 @@ struct snd_rawmidi_global_ops {
}; };
struct snd_rawmidi_runtime { struct snd_rawmidi_runtime {
struct snd_rawmidi_substream *substream;
unsigned int drain: 1, /* drain stage */ unsigned int drain: 1, /* drain stage */
oss: 1; /* OSS compatible mode */ oss: 1; /* OSS compatible mode */
/* midi stream buffer */ /* midi stream buffer */
...@@ -79,7 +81,7 @@ struct snd_rawmidi_runtime { ...@@ -79,7 +81,7 @@ struct snd_rawmidi_runtime {
/* event handler (new bytes, input only) */ /* event handler (new bytes, input only) */
void (*event)(struct snd_rawmidi_substream *substream); void (*event)(struct snd_rawmidi_substream *substream);
/* defers calls to event [input] or ops->trigger [output] */ /* defers calls to event [input] or ops->trigger [output] */
struct tasklet_struct tasklet; struct work_struct event_work;
/* private data */ /* private data */
void *private_data; void *private_data;
void (*private_free)(struct snd_rawmidi_substream *substream); void (*private_free)(struct snd_rawmidi_substream *substream);
......
...@@ -92,16 +92,12 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre ...@@ -92,16 +92,12 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre
(!substream->append || runtime->avail >= count); (!substream->append || runtime->avail >= count);
} }
static void snd_rawmidi_input_event_tasklet(unsigned long data) static void snd_rawmidi_input_event_work(struct work_struct *work)
{ {
struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data; struct snd_rawmidi_runtime *runtime =
substream->runtime->event(substream); container_of(work, struct snd_rawmidi_runtime, event_work);
} if (runtime->event)
runtime->event(runtime->substream);
static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
{
struct snd_rawmidi_substream *substream = (struct snd_rawmidi_substream *)data;
substream->ops->trigger(substream, 1);
} }
static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
...@@ -110,16 +106,10 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) ...@@ -110,16 +106,10 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
runtime->substream = substream;
spin_lock_init(&runtime->lock); spin_lock_init(&runtime->lock);
init_waitqueue_head(&runtime->sleep); init_waitqueue_head(&runtime->sleep);
if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) INIT_WORK(&runtime->event_work, snd_rawmidi_input_event_work);
tasklet_init(&runtime->tasklet,
snd_rawmidi_input_event_tasklet,
(unsigned long)substream);
else
tasklet_init(&runtime->tasklet,
snd_rawmidi_output_trigger_tasklet,
(unsigned long)substream);
runtime->event = NULL; runtime->event = NULL;
runtime->buffer_size = PAGE_SIZE; runtime->buffer_size = PAGE_SIZE;
runtime->avail_min = 1; runtime->avail_min = 1;
...@@ -150,12 +140,7 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs ...@@ -150,12 +140,7 @@ static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *subs
{ {
if (!substream->opened) if (!substream->opened)
return; return;
if (up) { substream->ops->trigger(substream, up);
tasklet_schedule(&substream->runtime->tasklet);
} else {
tasklet_kill(&substream->runtime->tasklet);
substream->ops->trigger(substream, 0);
}
} }
static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
...@@ -163,8 +148,8 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i ...@@ -163,8 +148,8 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i
if (!substream->opened) if (!substream->opened)
return; return;
substream->ops->trigger(substream, up); substream->ops->trigger(substream, up);
if (!up && substream->runtime->event) if (!up)
tasklet_kill(&substream->runtime->tasklet); cancel_work_sync(&substream->runtime->event_work);
} }
int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
...@@ -926,7 +911,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, ...@@ -926,7 +911,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
} }
if (result > 0) { if (result > 0) {
if (runtime->event) if (runtime->event)
tasklet_schedule(&runtime->tasklet); schedule_work(&runtime->event_work);
else if (snd_rawmidi_ready(substream)) else if (snd_rawmidi_ready(substream))
wake_up(&runtime->sleep); wake_up(&runtime->sleep);
} }
......
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