diff options
author | Takashi Iwai <tiwai@suse.de> | 2018-08-12 08:55:01 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2018-08-12 08:55:10 +0200 |
commit | 73b383141d296c55bfbc0ce336a4a946627e7780 (patch) | |
tree | df0840c4ea4bbd5aa453931a594936bd9adab61d /sound/core/seq/seq_virmidi.c | |
parent | 627661ced8246c8e833f3bc3817070e934cd79ba (diff) | |
parent | 91c6e15efc1756b068dc6e945c1626397e60a119 (diff) | |
download | blackbird-op-linux-73b383141d296c55bfbc0ce336a4a946627e7780.tar.gz blackbird-op-linux-73b383141d296c55bfbc0ce336a4a946627e7780.zip |
Merge branch 'for-next' into for-linus
Preparation for 4.19 merge material.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/seq/seq_virmidi.c')
-rw-r--r-- | sound/core/seq/seq_virmidi.c | 143 |
1 files changed, 49 insertions, 94 deletions
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 8ebbca554e99..a2f1c6b58693 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -89,7 +89,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, else down_read(&rdev->filelist_sem); list_for_each_entry(vmidi, &rdev->filelist, list) { - if (!vmidi->trigger) + if (!READ_ONCE(vmidi->trigger)) continue; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) @@ -110,23 +110,6 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, } /* - * receive an event from the remote virmidi port - * - * for rawmidi inputs, you can call this function from the event - * handler of a remote port which is attached to the virmidi via - * SNDRV_VIRMIDI_SEQ_ATTACH. - */ -#if 0 -int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev) -{ - struct snd_virmidi_dev *rdev; - - rdev = rmidi->private_data; - return snd_virmidi_dev_receive_event(rdev, ev, true); -} -#endif /* 0 */ - -/* * event handler of virmidi port */ static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct, @@ -147,78 +130,62 @@ static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, i { struct snd_virmidi *vmidi = substream->runtime->private_data; - if (up) { - vmidi->trigger = 1; - } else { - vmidi->trigger = 0; - } + WRITE_ONCE(vmidi->trigger, !!up); } -/* - * trigger rawmidi stream for output +/* process rawmidi bytes and send events; + * we need no lock here for vmidi->event since it's handled only in this work */ -static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) +static void snd_vmidi_output_work(struct work_struct *work) { - struct snd_virmidi *vmidi = substream->runtime->private_data; - int count, res; - unsigned char buf[32], *pbuf; - unsigned long flags; - bool check_resched = !in_atomic(); - - if (up) { - vmidi->trigger = 1; - if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && - !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - while (snd_rawmidi_transmit(substream, buf, - sizeof(buf)) > 0) { - /* ignored */ - } - return; - } - spin_lock_irqsave(&substream->runtime->lock, flags); + struct snd_virmidi *vmidi; + struct snd_rawmidi_substream *substream; + unsigned char input; + int ret; + + vmidi = container_of(work, struct snd_virmidi, output_work); + substream = vmidi->substream; + + /* discard the outputs in dispatch mode unless subscribed */ + if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && + !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { + while (!snd_rawmidi_transmit_empty(substream)) + snd_rawmidi_transmit_ack(substream, 1); + return; + } + + while (READ_ONCE(vmidi->trigger)) { + if (snd_rawmidi_transmit(substream, &input, 1) != 1) + break; + if (!snd_midi_event_encode_byte(vmidi->parser, input, + &vmidi->event)) + continue; if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - goto out; + ret = snd_seq_kernel_client_dispatch(vmidi->client, + &vmidi->event, + false, 0); vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - } - while (1) { - count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf)); - if (count <= 0) + if (ret < 0) break; - pbuf = buf; - while (count > 0) { - res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event); - if (res < 0) { - snd_midi_event_reset_encode(vmidi->parser); - continue; - } - __snd_rawmidi_transmit_ack(substream, res); - pbuf += res; - count -= res; - if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) { - if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0) - goto out; - vmidi->event.type = SNDRV_SEQ_EVENT_NONE; - } - } - if (!check_resched) - continue; - /* do temporary unlock & cond_resched() for avoiding - * CPU soft lockup, which may happen via a write from - * a huge rawmidi buffer - */ - spin_unlock_irqrestore(&substream->runtime->lock, flags); - cond_resched(); - spin_lock_irqsave(&substream->runtime->lock, flags); } - out: - spin_unlock_irqrestore(&substream->runtime->lock, flags); - } else { - vmidi->trigger = 0; + /* rawmidi input might be huge, allow to have a break */ + cond_resched(); } } /* + * trigger rawmidi stream for output + */ +static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up) +{ + struct snd_virmidi *vmidi = substream->runtime->private_data; + + WRITE_ONCE(vmidi->trigger, !!up); + if (up) + queue_work(system_highpri_wq, &vmidi->output_work); +} + +/* * open rawmidi handle for input */ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) @@ -270,6 +237,7 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream) vmidi->port = rdev->port; snd_virmidi_init_event(vmidi, &vmidi->event); vmidi->rdev = rdev; + INIT_WORK(&vmidi->output_work, snd_vmidi_output_work); runtime->private_data = vmidi; return 0; } @@ -299,6 +267,9 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream) { struct snd_virmidi *vmidi = substream->runtime->private_data; + + WRITE_ONCE(vmidi->trigger, false); /* to be sure */ + cancel_work_sync(&vmidi->output_work); snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); @@ -556,19 +527,3 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi return 0; } EXPORT_SYMBOL(snd_virmidi_new); - -/* - * ENTRY functions - */ - -static int __init alsa_virmidi_init(void) -{ - return 0; -} - -static void __exit alsa_virmidi_exit(void) -{ -} - -module_init(alsa_virmidi_init) -module_exit(alsa_virmidi_exit) |