Linux Audio

Check our new training course

Loading...
  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
 10static 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
 37static 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
 62static 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
 77static 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
 92static 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
109static 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
126static 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		scnprintf(subs->name, sizeof(subs->name),
133			  "%s MIDI %d",
134			  oxfw->card->shortname, subs->number + 1);
135	}
136}
137
138int 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}