Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * motu-midi.h - a part of driver for MOTU FireWire series
  4 *
  5 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
  6 */
  7#include "motu.h"
  8
  9static int midi_open(struct snd_rawmidi_substream *substream)
 10{
 11	struct snd_motu *motu = substream->rmidi->private_data;
 12	int err;
 13
 14	err = snd_motu_stream_lock_try(motu);
 15	if (err < 0)
 16		return err;
 17
 18	mutex_lock(&motu->mutex);
 19
 20	err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0);
 21	if (err >= 0) {
 22		++motu->substreams_counter;
 23		err = snd_motu_stream_start_duplex(motu);
 24		if (err < 0)
 25			--motu->substreams_counter;
 26	}
 27
 28	mutex_unlock(&motu->mutex);
 29
 30	if (err < 0)
 31		snd_motu_stream_lock_release(motu);
 32
 33	return err;
 34}
 35
 36static int midi_close(struct snd_rawmidi_substream *substream)
 37{
 38	struct snd_motu *motu = substream->rmidi->private_data;
 39
 40	mutex_lock(&motu->mutex);
 41
 42	--motu->substreams_counter;
 43	snd_motu_stream_stop_duplex(motu);
 44
 45	mutex_unlock(&motu->mutex);
 46
 47	snd_motu_stream_lock_release(motu);
 48	return 0;
 49}
 50
 51static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
 52{
 53	struct snd_motu *motu = substrm->rmidi->private_data;
 54	unsigned long flags;
 55
 56	spin_lock_irqsave(&motu->lock, flags);
 57
 58	if (up)
 59		amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
 60					substrm);
 61	else
 62		amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
 63					NULL);
 64
 65	spin_unlock_irqrestore(&motu->lock, flags);
 66}
 67
 68static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
 69{
 70	struct snd_motu *motu = substrm->rmidi->private_data;
 71	unsigned long flags;
 72
 73	spin_lock_irqsave(&motu->lock, flags);
 74
 75	if (up)
 76		amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
 77					substrm);
 78	else
 79		amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
 80					NULL);
 81
 82	spin_unlock_irqrestore(&motu->lock, flags);
 83}
 84
 85static void set_midi_substream_names(struct snd_motu *motu,
 86				     struct snd_rawmidi_str *str)
 87{
 88	struct snd_rawmidi_substream *subs;
 89
 90	list_for_each_entry(subs, &str->substreams, list) {
 91		scnprintf(subs->name, sizeof(subs->name),
 92			  "%s MIDI %d", motu->card->shortname, subs->number + 1);
 93	}
 94}
 95
 96int snd_motu_create_midi_devices(struct snd_motu *motu)
 97{
 98	static const struct snd_rawmidi_ops capture_ops = {
 99		.open		= midi_open,
100		.close		= midi_close,
101		.trigger	= midi_capture_trigger,
102	};
103	static const struct snd_rawmidi_ops playback_ops = {
104		.open		= midi_open,
105		.close		= midi_close,
106		.trigger	= midi_playback_trigger,
107	};
108	struct snd_rawmidi *rmidi;
109	struct snd_rawmidi_str *str;
110	int err;
111
112	/* create midi ports */
113	err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi);
114	if (err < 0)
115		return err;
116
117	snprintf(rmidi->name, sizeof(rmidi->name),
118		 "%s MIDI", motu->card->shortname);
119	rmidi->private_data = motu;
120
121	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
122			     SNDRV_RAWMIDI_INFO_OUTPUT |
123			     SNDRV_RAWMIDI_INFO_DUPLEX;
124
125	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
126			    &capture_ops);
127	str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
128	set_midi_substream_names(motu, str);
129
130	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
131			    &playback_ops);
132	str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
133	set_midi_substream_names(motu, str);
134
135	return 0;
136}