xref: /openbmc/linux/sound/firewire/motu/motu-midi.c (revision 4e95bc26)
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 
9 static int midi_capture_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 	motu->capture_substreams++;
21 	err = snd_motu_stream_start_duplex(motu, 0);
22 
23 	mutex_unlock(&motu->mutex);
24 
25 	if (err < 0)
26 		snd_motu_stream_lock_release(motu);
27 
28 	return err;
29 }
30 
31 static int midi_playback_open(struct snd_rawmidi_substream *substream)
32 {
33 	struct snd_motu *motu = substream->rmidi->private_data;
34 	int err;
35 
36 	err = snd_motu_stream_lock_try(motu);
37 	if (err < 0)
38 		return err;
39 
40 	mutex_lock(&motu->mutex);
41 
42 	motu->playback_substreams++;
43 	err = snd_motu_stream_start_duplex(motu, 0);
44 
45 	mutex_unlock(&motu->mutex);
46 
47 	if (err < 0)
48 		snd_motu_stream_lock_release(motu);
49 
50 	return err;
51 }
52 
53 static int midi_capture_close(struct snd_rawmidi_substream *substream)
54 {
55 	struct snd_motu *motu = substream->rmidi->private_data;
56 
57 	mutex_lock(&motu->mutex);
58 
59 	motu->capture_substreams--;
60 	snd_motu_stream_stop_duplex(motu);
61 
62 	mutex_unlock(&motu->mutex);
63 
64 	snd_motu_stream_lock_release(motu);
65 	return 0;
66 }
67 
68 static int midi_playback_close(struct snd_rawmidi_substream *substream)
69 {
70 	struct snd_motu *motu = substream->rmidi->private_data;
71 
72 	mutex_lock(&motu->mutex);
73 
74 	motu->playback_substreams--;
75 	snd_motu_stream_stop_duplex(motu);
76 
77 	mutex_unlock(&motu->mutex);
78 
79 	snd_motu_stream_lock_release(motu);
80 	return 0;
81 }
82 
83 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
84 {
85 	struct snd_motu *motu = substrm->rmidi->private_data;
86 	unsigned long flags;
87 
88 	spin_lock_irqsave(&motu->lock, flags);
89 
90 	if (up)
91 		amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
92 					substrm);
93 	else
94 		amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
95 					NULL);
96 
97 	spin_unlock_irqrestore(&motu->lock, flags);
98 }
99 
100 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
101 {
102 	struct snd_motu *motu = substrm->rmidi->private_data;
103 	unsigned long flags;
104 
105 	spin_lock_irqsave(&motu->lock, flags);
106 
107 	if (up)
108 		amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
109 					substrm);
110 	else
111 		amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
112 					NULL);
113 
114 	spin_unlock_irqrestore(&motu->lock, flags);
115 }
116 
117 static void set_midi_substream_names(struct snd_motu *motu,
118 				     struct snd_rawmidi_str *str)
119 {
120 	struct snd_rawmidi_substream *subs;
121 
122 	list_for_each_entry(subs, &str->substreams, list) {
123 		snprintf(subs->name, sizeof(subs->name),
124 			 "%s MIDI %d", motu->card->shortname, subs->number + 1);
125 	}
126 }
127 
128 int snd_motu_create_midi_devices(struct snd_motu *motu)
129 {
130 	static const struct snd_rawmidi_ops capture_ops = {
131 		.open		= midi_capture_open,
132 		.close		= midi_capture_close,
133 		.trigger	= midi_capture_trigger,
134 	};
135 	static const struct snd_rawmidi_ops playback_ops = {
136 		.open		= midi_playback_open,
137 		.close		= midi_playback_close,
138 		.trigger	= midi_playback_trigger,
139 	};
140 	struct snd_rawmidi *rmidi;
141 	struct snd_rawmidi_str *str;
142 	int err;
143 
144 	/* create midi ports */
145 	err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi);
146 	if (err < 0)
147 		return err;
148 
149 	snprintf(rmidi->name, sizeof(rmidi->name),
150 		 "%s MIDI", motu->card->shortname);
151 	rmidi->private_data = motu;
152 
153 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
154 			     SNDRV_RAWMIDI_INFO_OUTPUT |
155 			     SNDRV_RAWMIDI_INFO_DUPLEX;
156 
157 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
158 			    &capture_ops);
159 	str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
160 	set_midi_substream_names(motu, str);
161 
162 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
163 			    &playback_ops);
164 	str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
165 	set_midi_substream_names(motu, str);
166 
167 	return 0;
168 }
169