Commit | Line | Data |
---|---|---|
da607e19 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
9e796e7d TS |
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> | |
9e796e7d TS |
6 | */ |
7 | #include "motu.h" | |
8 | ||
f6341db6 | 9 | static int midi_open(struct snd_rawmidi_substream *substream) |
9e796e7d TS |
10 | { |
11 | struct snd_motu *motu = substream->rmidi->private_data; | |
12 | int err; | |
13 | ||
71c37977 TS |
14 | err = snd_motu_stream_lock_try(motu); |
15 | if (err < 0) | |
16 | return err; | |
17 | ||
9e796e7d TS |
18 | mutex_lock(&motu->mutex); |
19 | ||
0f5482e7 | 20 | err = snd_motu_stream_reserve_duplex(motu, 0, 0, 0); |
8edc56ec TS |
21 | if (err >= 0) { |
22 | ++motu->substreams_counter; | |
23 | err = snd_motu_stream_start_duplex(motu); | |
ba18ca2b TS |
24 | if (err < 0) |
25 | --motu->substreams_counter; | |
8edc56ec | 26 | } |
9e796e7d TS |
27 | |
28 | mutex_unlock(&motu->mutex); | |
29 | ||
71c37977 TS |
30 | if (err < 0) |
31 | snd_motu_stream_lock_release(motu); | |
32 | ||
9e796e7d TS |
33 | return err; |
34 | } | |
35 | ||
f6341db6 | 36 | static int midi_close(struct snd_rawmidi_substream *substream) |
9e796e7d TS |
37 | { |
38 | struct snd_motu *motu = substream->rmidi->private_data; | |
39 | ||
40 | mutex_lock(&motu->mutex); | |
41 | ||
8edc56ec | 42 | --motu->substreams_counter; |
9e796e7d TS |
43 | snd_motu_stream_stop_duplex(motu); |
44 | ||
45 | mutex_unlock(&motu->mutex); | |
46 | ||
71c37977 | 47 | snd_motu_stream_lock_release(motu); |
9e796e7d TS |
48 | return 0; |
49 | } | |
50 | ||
51 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | |
52 | { | |
53 | struct snd_motu *motu = substrm->rmidi->private_data; | |
54 | unsigned long flags; | |
55 | ||
56 | spin_lock_irqsave(&motu->lock, flags); | |
57 | ||
58 | if (up) | |
59 | amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, | |
60 | substrm); | |
61 | else | |
62 | amdtp_motu_midi_trigger(&motu->tx_stream, substrm->number, | |
63 | NULL); | |
64 | ||
65 | spin_unlock_irqrestore(&motu->lock, flags); | |
66 | } | |
67 | ||
68 | static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) | |
69 | { | |
70 | struct snd_motu *motu = substrm->rmidi->private_data; | |
71 | unsigned long flags; | |
72 | ||
73 | spin_lock_irqsave(&motu->lock, flags); | |
74 | ||
75 | if (up) | |
76 | amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, | |
77 | substrm); | |
78 | else | |
79 | amdtp_motu_midi_trigger(&motu->rx_stream, substrm->number, | |
80 | NULL); | |
81 | ||
82 | spin_unlock_irqrestore(&motu->lock, flags); | |
83 | } | |
84 | ||
85 | static void set_midi_substream_names(struct snd_motu *motu, | |
86 | struct snd_rawmidi_str *str) | |
87 | { | |
88 | struct snd_rawmidi_substream *subs; | |
89 | ||
90 | list_for_each_entry(subs, &str->substreams, list) { | |
ea77850e TI |
91 | scnprintf(subs->name, sizeof(subs->name), |
92 | "%s MIDI %d", motu->card->shortname, subs->number + 1); | |
9e796e7d TS |
93 | } |
94 | } | |
95 | ||
96 | int snd_motu_create_midi_devices(struct snd_motu *motu) | |
97 | { | |
eb2c1830 | 98 | static const struct snd_rawmidi_ops capture_ops = { |
f6341db6 TS |
99 | .open = midi_open, |
100 | .close = midi_close, | |
9e796e7d TS |
101 | .trigger = midi_capture_trigger, |
102 | }; | |
eb2c1830 | 103 | static const struct snd_rawmidi_ops playback_ops = { |
f6341db6 TS |
104 | .open = midi_open, |
105 | .close = midi_close, | |
9e796e7d TS |
106 | .trigger = midi_playback_trigger, |
107 | }; | |
108 | struct snd_rawmidi *rmidi; | |
109 | struct snd_rawmidi_str *str; | |
110 | int err; | |
111 | ||
112 | /* create midi ports */ | |
113 | err = snd_rawmidi_new(motu->card, motu->card->driver, 0, 1, 1, &rmidi); | |
114 | if (err < 0) | |
115 | return err; | |
116 | ||
117 | snprintf(rmidi->name, sizeof(rmidi->name), | |
118 | "%s MIDI", motu->card->shortname); | |
119 | rmidi->private_data = motu; | |
120 | ||
121 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT | | |
122 | SNDRV_RAWMIDI_INFO_OUTPUT | | |
123 | SNDRV_RAWMIDI_INFO_DUPLEX; | |
124 | ||
125 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | |
126 | &capture_ops); | |
127 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | |
128 | set_midi_substream_names(motu, str); | |
129 | ||
130 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | |
131 | &playback_ops); | |
132 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | |
133 | set_midi_substream_names(motu, str); | |
134 | ||
135 | return 0; | |
136 | } |