diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 4154035af414..d812f70725bd 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -86,6 +86,7 @@ struct snd_rawmidi_substream { bool opened; /* open flag */ bool append; /* append flag (merge more streams) */ bool active_sensing; /* send active sensing when close */ + bool disconnected; /* already disconnected */ unsigned int framing; /* whether to frame input data */ unsigned int clock_type; /* clock source to use for input framing */ int use_count; /* use counter (for output) */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 34b4c7d6dbe6..2e582688923d 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -208,14 +208,14 @@ static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream) static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) { - if (!substream->opened) + if (!substream->opened || substream->disconnected) return; substream->ops->trigger(substream, up); } static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, int up) { - if (!substream->opened) + if (!substream->opened || substream->disconnected) return; substream->ops->trigger(substream, up); if (!up) @@ -254,7 +254,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) scoped_guard(spinlock_irq, &substream->lock) { runtime = substream->runtime; - if (!substream->opened || !runtime || !runtime->buffer) + if (!substream->opened || !runtime || !runtime->buffer || + substream->disconnected) return -EINVAL; snd_rawmidi_buffer_ref(runtime); runtime->drain = 1; @@ -537,7 +538,7 @@ static void close_substream(struct snd_rawmidi *rmidi, if (--substream->use_count) return; - if (cleanup) { + if (cleanup && !substream->disconnected) { if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT) snd_rawmidi_input_trigger(substream, 0); else { @@ -1151,7 +1152,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, struct snd_rawmidi_runtime *runtime; guard(spinlock_irqsave)(&substream->lock); - if (!substream->opened) + if (!substream->opened || substream->disconnected) return -EBADFD; runtime = substream->runtime; if (!runtime || !runtime->buffer) { @@ -2063,8 +2064,13 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) struct snd_rawmidi_substream *s; list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { - if (s->runtime) + scoped_guard(spinlock_irq, &s->lock) + s->disconnected = true; + if (s->runtime) { + s->ops->trigger(s, 0); + cancel_work_sync(&s->runtime->event_work); wake_up(&s->runtime->sleep); + } } }