xref: /openbmc/linux/sound/firewire/fireface/ff-midi.c (revision 2af5acbaa74c91266457fa1494685729d6f9e540)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ff2c293eSTakashi Sakamoto /*
3ff2c293eSTakashi Sakamoto  * ff-midi.c - a part of driver for RME Fireface series
4ff2c293eSTakashi Sakamoto  *
5ff2c293eSTakashi Sakamoto  * Copyright (c) 2015-2017 Takashi Sakamoto
6ff2c293eSTakashi Sakamoto  */
7ff2c293eSTakashi Sakamoto 
8ff2c293eSTakashi Sakamoto #include "ff.h"
9ff2c293eSTakashi Sakamoto 
midi_capture_open(struct snd_rawmidi_substream * substream)10ff2c293eSTakashi Sakamoto static int midi_capture_open(struct snd_rawmidi_substream *substream)
11ff2c293eSTakashi Sakamoto {
12ff2c293eSTakashi Sakamoto 	/* Do nothing. */
13ff2c293eSTakashi Sakamoto 	return 0;
14ff2c293eSTakashi Sakamoto }
15ff2c293eSTakashi Sakamoto 
midi_playback_open(struct snd_rawmidi_substream * substream)16ff2c293eSTakashi Sakamoto static int midi_playback_open(struct snd_rawmidi_substream *substream)
17ff2c293eSTakashi Sakamoto {
18ff2c293eSTakashi Sakamoto 	struct snd_ff *ff = substream->rmidi->private_data;
19ff2c293eSTakashi Sakamoto 
20ff2c293eSTakashi Sakamoto 	/* Initialize internal status. */
21f0f9f497STakashi Sakamoto 	ff->on_sysex[substream->number] = 0;
22ff2c293eSTakashi Sakamoto 	ff->rx_midi_error[substream->number] = false;
23ff2c293eSTakashi Sakamoto 
246aa7de05SMark Rutland 	WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream);
25ff2c293eSTakashi Sakamoto 
26ff2c293eSTakashi Sakamoto 	return 0;
27ff2c293eSTakashi Sakamoto }
28ff2c293eSTakashi Sakamoto 
midi_capture_close(struct snd_rawmidi_substream * substream)29ff2c293eSTakashi Sakamoto static int midi_capture_close(struct snd_rawmidi_substream *substream)
30ff2c293eSTakashi Sakamoto {
31ff2c293eSTakashi Sakamoto 	/* Do nothing. */
32ff2c293eSTakashi Sakamoto 	return 0;
33ff2c293eSTakashi Sakamoto }
34ff2c293eSTakashi Sakamoto 
midi_playback_close(struct snd_rawmidi_substream * substream)35ff2c293eSTakashi Sakamoto static int midi_playback_close(struct snd_rawmidi_substream *substream)
36ff2c293eSTakashi Sakamoto {
37ff2c293eSTakashi Sakamoto 	struct snd_ff *ff = substream->rmidi->private_data;
38ff2c293eSTakashi Sakamoto 
39ff2c293eSTakashi Sakamoto 	cancel_work_sync(&ff->rx_midi_work[substream->number]);
406aa7de05SMark Rutland 	WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL);
41ff2c293eSTakashi Sakamoto 
42ff2c293eSTakashi Sakamoto 	return 0;
43ff2c293eSTakashi Sakamoto }
44ff2c293eSTakashi Sakamoto 
midi_capture_trigger(struct snd_rawmidi_substream * substream,int up)45ff2c293eSTakashi Sakamoto static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
46ff2c293eSTakashi Sakamoto 				 int up)
47ff2c293eSTakashi Sakamoto {
48ff2c293eSTakashi Sakamoto 	struct snd_ff *ff = substream->rmidi->private_data;
49ff2c293eSTakashi Sakamoto 	unsigned long flags;
50ff2c293eSTakashi Sakamoto 
51ff2c293eSTakashi Sakamoto 	spin_lock_irqsave(&ff->lock, flags);
52ff2c293eSTakashi Sakamoto 
53ff2c293eSTakashi Sakamoto 	if (up)
546aa7de05SMark Rutland 		WRITE_ONCE(ff->tx_midi_substreams[substream->number],
556aa7de05SMark Rutland 			   substream);
56ff2c293eSTakashi Sakamoto 	else
576aa7de05SMark Rutland 		WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
58ff2c293eSTakashi Sakamoto 
59ff2c293eSTakashi Sakamoto 	spin_unlock_irqrestore(&ff->lock, flags);
60ff2c293eSTakashi Sakamoto }
61ff2c293eSTakashi Sakamoto 
midi_playback_trigger(struct snd_rawmidi_substream * substream,int up)62ff2c293eSTakashi Sakamoto static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
63ff2c293eSTakashi Sakamoto 				  int up)
64ff2c293eSTakashi Sakamoto {
65ff2c293eSTakashi Sakamoto 	struct snd_ff *ff = substream->rmidi->private_data;
66ff2c293eSTakashi Sakamoto 	unsigned long flags;
67ff2c293eSTakashi Sakamoto 
68ff2c293eSTakashi Sakamoto 	spin_lock_irqsave(&ff->lock, flags);
69ff2c293eSTakashi Sakamoto 
70ff2c293eSTakashi Sakamoto 	if (up || !ff->rx_midi_error[substream->number])
71ff2c293eSTakashi Sakamoto 		schedule_work(&ff->rx_midi_work[substream->number]);
72ff2c293eSTakashi Sakamoto 
73ff2c293eSTakashi Sakamoto 	spin_unlock_irqrestore(&ff->lock, flags);
74ff2c293eSTakashi Sakamoto }
75ff2c293eSTakashi Sakamoto 
set_midi_substream_names(struct snd_rawmidi_str * stream,const char * const name)76ff2c293eSTakashi Sakamoto static void set_midi_substream_names(struct snd_rawmidi_str *stream,
77ff2c293eSTakashi Sakamoto 				     const char *const name)
78ff2c293eSTakashi Sakamoto {
79ff2c293eSTakashi Sakamoto 	struct snd_rawmidi_substream *substream;
80ff2c293eSTakashi Sakamoto 
81ff2c293eSTakashi Sakamoto 	list_for_each_entry(substream, &stream->substreams, list) {
82*ea77850eSTakashi Iwai 		scnprintf(substream->name, sizeof(substream->name),
83ff2c293eSTakashi Sakamoto 			  "%s MIDI %d", name, substream->number + 1);
84ff2c293eSTakashi Sakamoto 	}
85ff2c293eSTakashi Sakamoto }
86ff2c293eSTakashi Sakamoto 
snd_ff_create_midi_devices(struct snd_ff * ff)87ff2c293eSTakashi Sakamoto int snd_ff_create_midi_devices(struct snd_ff *ff)
88ff2c293eSTakashi Sakamoto {
89d2dc2a96STakashi Sakamoto 	static const struct snd_rawmidi_ops midi_capture_ops = {
90d2dc2a96STakashi Sakamoto 		.open		= midi_capture_open,
91d2dc2a96STakashi Sakamoto 		.close		= midi_capture_close,
92d2dc2a96STakashi Sakamoto 		.trigger	= midi_capture_trigger,
93d2dc2a96STakashi Sakamoto 	};
94d2dc2a96STakashi Sakamoto 	static const struct snd_rawmidi_ops midi_playback_ops = {
95d2dc2a96STakashi Sakamoto 		.open		= midi_playback_open,
96d2dc2a96STakashi Sakamoto 		.close		= midi_playback_close,
97d2dc2a96STakashi Sakamoto 		.trigger	= midi_playback_trigger,
98d2dc2a96STakashi Sakamoto 	};
99ff2c293eSTakashi Sakamoto 	struct snd_rawmidi *rmidi;
100ff2c293eSTakashi Sakamoto 	struct snd_rawmidi_str *stream;
101ff2c293eSTakashi Sakamoto 	int err;
102ff2c293eSTakashi Sakamoto 
103ff2c293eSTakashi Sakamoto 	err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
104ff2c293eSTakashi Sakamoto 			      ff->spec->midi_out_ports, ff->spec->midi_in_ports,
105ff2c293eSTakashi Sakamoto 			      &rmidi);
106ff2c293eSTakashi Sakamoto 	if (err < 0)
107ff2c293eSTakashi Sakamoto 		return err;
108ff2c293eSTakashi Sakamoto 
109ff2c293eSTakashi Sakamoto 	snprintf(rmidi->name, sizeof(rmidi->name),
110ff2c293eSTakashi Sakamoto 		 "%s MIDI", ff->card->shortname);
111ff2c293eSTakashi Sakamoto 	rmidi->private_data = ff;
112ff2c293eSTakashi Sakamoto 
113ff2c293eSTakashi Sakamoto 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
114ff2c293eSTakashi Sakamoto 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
115ff2c293eSTakashi Sakamoto 			    &midi_capture_ops);
116ff2c293eSTakashi Sakamoto 	stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
117ff2c293eSTakashi Sakamoto 	set_midi_substream_names(stream, ff->card->shortname);
118ff2c293eSTakashi Sakamoto 
119ff2c293eSTakashi Sakamoto 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
120ff2c293eSTakashi Sakamoto 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
121ff2c293eSTakashi Sakamoto 			    &midi_playback_ops);
122ff2c293eSTakashi Sakamoto 	stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
123ff2c293eSTakashi Sakamoto 	set_midi_substream_names(stream, ff->card->shortname);
124ff2c293eSTakashi Sakamoto 
125ff2c293eSTakashi Sakamoto 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
126ff2c293eSTakashi Sakamoto 
127ff2c293eSTakashi Sakamoto 	return 0;
128ff2c293eSTakashi Sakamoto }
129