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