File Index
Files and directories
Sign in
FILE

oxfw-midi.c

File preview with syntax highlighting.

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