GNU Linux-libre 4.14.290-gnu1
[releases.git] / sound / firewire / motu / motu-midi.c
1 /*
2  * motu-midi.h - a part of driver for MOTU FireWire series
3  *
4  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
5  *
6  * Licensed under the terms of the GNU General Public License, version 2.
7  */
8 #include "motu.h"
9
10 static int midi_capture_open(struct snd_rawmidi_substream *substream)
11 {
12         struct snd_motu *motu = substream->rmidi->private_data;
13         int err;
14
15         err = snd_motu_stream_lock_try(motu);
16         if (err < 0)
17                 return err;
18
19         mutex_lock(&motu->mutex);
20
21         motu->capture_substreams++;
22         err = snd_motu_stream_start_duplex(motu, 0);
23
24         mutex_unlock(&motu->mutex);
25
26         if (err < 0)
27                 snd_motu_stream_lock_release(motu);
28
29         return err;
30 }
31
32 static int midi_playback_open(struct snd_rawmidi_substream *substream)
33 {
34         struct snd_motu *motu = substream->rmidi->private_data;
35         int err;
36
37         err = snd_motu_stream_lock_try(motu);
38         if (err < 0)
39                 return err;
40
41         mutex_lock(&motu->mutex);
42
43         motu->playback_substreams++;
44         err = snd_motu_stream_start_duplex(motu, 0);
45
46         mutex_unlock(&motu->mutex);
47
48         if (err < 0)
49                 snd_motu_stream_lock_release(motu);
50
51         return err;
52 }
53
54 static int midi_capture_close(struct snd_rawmidi_substream *substream)
55 {
56         struct snd_motu *motu = substream->rmidi->private_data;
57
58         mutex_lock(&motu->mutex);
59
60         motu->capture_substreams--;
61         snd_motu_stream_stop_duplex(motu);
62
63         mutex_unlock(&motu->mutex);
64
65         snd_motu_stream_lock_release(motu);
66         return 0;
67 }
68
69 static int midi_playback_close(struct snd_rawmidi_substream *substream)
70 {
71         struct snd_motu *motu = substream->rmidi->private_data;
72
73         mutex_lock(&motu->mutex);
74
75         motu->playback_substreams--;
76         snd_motu_stream_stop_duplex(motu);
77
78         mutex_unlock(&motu->mutex);
79
80         snd_motu_stream_lock_release(motu);
81         return 0;
82 }
83
84 static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
85 {
86         struct snd_motu *motu = substrm->rmidi->private_data;
87         unsigned long flags;
88
89         spin_lock_irqsave(&motu->lock, flags);
90
91         if (up)
92                 amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
93                                         substrm);
94         else
95                 amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number,
96                                         NULL);
97
98         spin_unlock_irqrestore(&motu->lock, flags);
99 }
100
101 static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
102 {
103         struct snd_motu *motu = substrm->rmidi->private_data;
104         unsigned long flags;
105
106         spin_lock_irqsave(&motu->lock, flags);
107
108         if (up)
109                 amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
110                                         substrm);
111         else
112                 amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number,
113                                         NULL);
114
115         spin_unlock_irqrestore(&motu->lock, flags);
116 }
117
118 static void set_midi_substream_names(struct snd_motu *motu,
119                                      struct snd_rawmidi_str *str)
120 {
121         struct snd_rawmidi_substream *subs;
122
123         list_for_each_entry(subs, &str->substreams, list) {
124                 snprintf(subs->name, sizeof(subs->name),
125                          "%s MIDI %d", motu->card->shortname, subs->number + 1);
126         }
127 }
128
129 int snd_motu_create_midi_devices(struct snd_motu *motu)
130 {
131         static const struct snd_rawmidi_ops capture_ops = {
132                 .open           = midi_capture_open,
133                 .close          = midi_capture_close,
134                 .trigger        = midi_capture_trigger,
135         };
136         static const struct snd_rawmidi_ops playback_ops = {
137                 .open           = midi_playback_open,
138                 .close          = midi_playback_close,
139                 .trigger        = midi_playback_trigger,
140         };
141         struct snd_rawmidi *rmidi;
142         struct snd_rawmidi_str *str;
143         int err;
144
145         /* create midi ports */
146         err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi);
147         if (err < 0)
148                 return err;
149
150         snprintf(rmidi->name, sizeof(rmidi->name),
151                  "%s MIDI", motu->card->shortname);
152         rmidi->private_data = motu;
153
154         rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
155                              SNDRV_RAWMIDI_INFO_OUTPUT |
156                              SNDRV_RAWMIDI_INFO_DUPLEX;
157
158         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
159                             &capture_ops);
160         str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
161         set_midi_substream_names(motu, str);
162
163         snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
164                             &playback_ops);
165         str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
166         set_midi_substream_names(motu, str);
167
168         return 0;
169 }