xref: /openbmc/linux/sound/firewire/oxfw/oxfw-midi.c (revision 3fc41476)
1 /*
2  * oxfw_midi.c - a part of driver for OXFW970/971 based devices
3  *
4  * Copyright (c) 2014 Takashi Sakamoto
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 
9 #include "oxfw.h"
10 
11 static int midi_capture_open(struct snd_rawmidi_substream *substream)
12 {
13 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
14 	int err;
15 
16 	err = snd_oxfw_stream_lock_try(oxfw);
17 	if (err < 0)
18 		return err;
19 
20 	mutex_lock(&oxfw->mutex);
21 
22 	err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0);
23 	if (err >= 0) {
24 		++oxfw->substreams_count;
25 		err = snd_oxfw_stream_start_duplex(oxfw);
26 	}
27 
28 	mutex_unlock(&oxfw->mutex);
29 
30 	if (err < 0)
31 		snd_oxfw_stream_lock_release(oxfw);
32 
33 	return err;
34 }
35 
36 static int midi_playback_open(struct snd_rawmidi_substream *substream)
37 {
38 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
39 	int err;
40 
41 	err = snd_oxfw_stream_lock_try(oxfw);
42 	if (err < 0)
43 		return err;
44 
45 	mutex_lock(&oxfw->mutex);
46 
47 	err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0);
48 	if (err >= 0) {
49 		++oxfw->substreams_count;
50 		err = snd_oxfw_stream_start_duplex(oxfw);
51 	}
52 
53 	mutex_unlock(&oxfw->mutex);
54 
55 	if (err < 0)
56 		snd_oxfw_stream_lock_release(oxfw);
57 
58 	return err;
59 }
60 
61 static int midi_capture_close(struct snd_rawmidi_substream *substream)
62 {
63 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
64 
65 	mutex_lock(&oxfw->mutex);
66 
67 	--oxfw->substreams_count;
68 	snd_oxfw_stream_stop_duplex(oxfw);
69 
70 	mutex_unlock(&oxfw->mutex);
71 
72 	snd_oxfw_stream_lock_release(oxfw);
73 	return 0;
74 }
75 
76 static int midi_playback_close(struct snd_rawmidi_substream *substream)
77 {
78 	struct snd_oxfw *oxfw = substream->rmidi->private_data;
79 
80 	mutex_lock(&oxfw->mutex);
81 
82 	--oxfw->substreams_count;
83 	snd_oxfw_stream_stop_duplex(oxfw);
84 
85 	mutex_unlock(&oxfw->mutex);
86 
87 	snd_oxfw_stream_lock_release(oxfw);
88 	return 0;
89 }
90 
91 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
92 {
93 	struct snd_oxfw *oxfw = substrm->rmidi->private_data;
94 	unsigned long flags;
95 
96 	spin_lock_irqsave(&oxfw->lock, flags);
97 
98 	if (up)
99 		amdtp_am824_midi_trigger(&oxfw->tx_stream,
100 					 substrm->number, substrm);
101 	else
102 		amdtp_am824_midi_trigger(&oxfw->tx_stream,
103 					 substrm->number, NULL);
104 
105 	spin_unlock_irqrestore(&oxfw->lock, flags);
106 }
107 
108 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
109 {
110 	struct snd_oxfw *oxfw = substrm->rmidi->private_data;
111 	unsigned long flags;
112 
113 	spin_lock_irqsave(&oxfw->lock, flags);
114 
115 	if (up)
116 		amdtp_am824_midi_trigger(&oxfw->rx_stream,
117 					 substrm->number, substrm);
118 	else
119 		amdtp_am824_midi_trigger(&oxfw->rx_stream,
120 					 substrm->number, NULL);
121 
122 	spin_unlock_irqrestore(&oxfw->lock, flags);
123 }
124 
125 static void set_midi_substream_names(struct snd_oxfw *oxfw,
126 				     struct snd_rawmidi_str *str)
127 {
128 	struct snd_rawmidi_substream *subs;
129 
130 	list_for_each_entry(subs, &str->substreams, list) {
131 		snprintf(subs->name, sizeof(subs->name),
132 			 "%s MIDI %d",
133 			 oxfw->card->shortname, subs->number + 1);
134 	}
135 }
136 
137 int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
138 {
139 	static const struct snd_rawmidi_ops capture_ops = {
140 		.open		= midi_capture_open,
141 		.close		= midi_capture_close,
142 		.trigger	= midi_capture_trigger,
143 	};
144 	static const struct snd_rawmidi_ops playback_ops = {
145 		.open		= midi_playback_open,
146 		.close		= midi_playback_close,
147 		.trigger	= midi_playback_trigger,
148 	};
149 	struct snd_rawmidi *rmidi;
150 	struct snd_rawmidi_str *str;
151 	int err;
152 
153 	if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0)
154 		return 0;
155 
156 	/* create midi ports */
157 	err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
158 			      oxfw->midi_output_ports, oxfw->midi_input_ports,
159 			      &rmidi);
160 	if (err < 0)
161 		return err;
162 
163 	snprintf(rmidi->name, sizeof(rmidi->name),
164 		 "%s MIDI", oxfw->card->shortname);
165 	rmidi->private_data = oxfw;
166 
167 	if (oxfw->midi_input_ports > 0) {
168 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
169 
170 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
171 				    &capture_ops);
172 
173 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
174 
175 		set_midi_substream_names(oxfw, str);
176 	}
177 
178 	if (oxfw->midi_output_ports > 0) {
179 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
180 
181 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
182 				    &playback_ops);
183 
184 		str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
185 
186 		set_midi_substream_names(oxfw, str);
187 	}
188 
189 	if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
190 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
191 
192 	return 0;
193 }
194