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