xref: /linux/sound/firewire/motu/motu-midi.c (revision 55a42f78ffd386e01a5404419f8c5ded7db70a21)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * motu-midi.h - a part of driver for MOTU FireWire series
4  *
5  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
6  */
7 #include "motu.h"
8 
9 static int midi_open(struct snd_rawmidi_substream *substream)
10 {
11 	struct snd_motu *motu = substream->rmidi->private_data;
12 	int err;
13 
14 	err = snd_motu_stream_lock_try(motu);
15 	if (err < 0)
16 		return err;
17 
18 	scoped_guard(mutex, &motu->mutex) {
19 		err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0);
20 		if (err >= 0) {
21 			++motu->substreams_counter;
22 			err = snd_motu_stream_start_duplex(motu);
23 			if (err < 0)
24 				--motu->substreams_counter;
25 		}
26 	}
27 
28 	if (err < 0)
29 		snd_motu_stream_lock_release(motu);
30 
31 	return err;
32 }
33 
34 static int midi_close(struct snd_rawmidi_substream *substream)
35 {
36 	struct snd_motu *motu = substream->rmidi->private_data;
37 
38 	scoped_guard(mutex, &motu->mutex) {
39 		--motu->substreams_counter;
40 		snd_motu_stream_stop_duplex(motu);
41 	}
42 
43 	snd_motu_stream_lock_release(motu);
44 	return 0;
45 }
46 
47 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
48 {
49 	struct snd_motu *motu = substrm->rmidi->private_data;
50 
51 	guard(spinlock_irqsave)(&motu->lock);
52 
53 	if (up)
54 		amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
55 					substrm);
56 	else
57 		amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
58 					NULL);
59 }
60 
61 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
62 {
63 	struct snd_motu *motu = substrm->rmidi->private_data;
64 
65 	guard(spinlock_irqsave)(&motu->lock);
66 
67 	if (up)
68 		amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
69 					substrm);
70 	else
71 		amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
72 					NULL);
73 }
74 
75 static void set_midi_substream_names(struct snd_motu *motu,
76 				     struct snd_rawmidi_str *str)
77 {
78 	struct snd_rawmidi_substream *subs;
79 
80 	list_for_each_entry(subs, &str->substreams, list) {
81 		scnprintf(subs->name, sizeof(subs->name),
82 			  "%s MIDI %d", motu->card->shortname, subs->number + 1);
83 	}
84 }
85 
86 int snd_motu_create_midi_devices(struct snd_motu *motu)
87 {
88 	static const struct snd_rawmidi_ops capture_ops = {
89 		.open		= midi_open,
90 		.close		= midi_close,
91 		.trigger	= midi_capture_trigger,
92 	};
93 	static const struct snd_rawmidi_ops playback_ops = {
94 		.open		= midi_open,
95 		.close		= midi_close,
96 		.trigger	= midi_playback_trigger,
97 	};
98 	struct snd_rawmidi *rmidi;
99 	struct snd_rawmidi_str *str;
100 	int err;
101 
102 	/* create midi ports */
103 	err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi);
104 	if (err < 0)
105 		return err;
106 
107 	snprintf(rmidi->name, sizeof(rmidi->name),
108 		 "%s MIDI", motu->card->shortname);
109 	rmidi->private_data = motu;
110 
111 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
112 			     SNDRV_RAWMIDI_INFO_OUTPUT |
113 			     SNDRV_RAWMIDI_INFO_DUPLEX;
114 
115 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
116 			    &capture_ops);
117 	str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
118 	set_midi_substream_names(motu, str);
119 
120 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
121 			    &playback_ops);
122 	str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
123 	set_midi_substream_names(motu, str);
124 
125 	return 0;
126 }
127