Commit | Line | Data |
---|---|---|
ff2c293e TS |
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 | ||
6aa7de05 | 25 | WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream); |
ff2c293e TS |
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]); | |
6aa7de05 | 41 | WRITE_ONCE(ff->rx_midi_substreams[substream->number], NULL); |
ff2c293e TS |
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) | |
6aa7de05 MR |
55 | WRITE_ONCE(ff->tx_midi_substreams[substream->number], |
56 | substream); | |
ff2c293e | 57 | else |
6aa7de05 | 58 | WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL); |
ff2c293e TS |
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 | ||
ff2c293e TS |
77 | static void set_midi_substream_names(struct snd_rawmidi_str *stream, |
78 | const char *const name) | |
79 | { | |
80 | struct snd_rawmidi_substream *substream; | |
81 | ||
82 | list_for_each_entry(substream, &stream->substreams, list) { | |
83 | snprintf(substream->name, sizeof(substream->name), | |
84 | "%s MIDI %d", name, substream->number + 1); | |
85 | } | |
86 | } | |
87 | ||
88 | int snd_ff_create_midi_devices(struct snd_ff *ff) | |
89 | { | |
d2dc2a96 TS |
90 | static const struct snd_rawmidi_ops midi_capture_ops = { |
91 | .open = midi_capture_open, | |
92 | .close = midi_capture_close, | |
93 | .trigger = midi_capture_trigger, | |
94 | }; | |
95 | static const struct snd_rawmidi_ops midi_playback_ops = { | |
96 | .open = midi_playback_open, | |
97 | .close = midi_playback_close, | |
98 | .trigger = midi_playback_trigger, | |
99 | }; | |
ff2c293e TS |
100 | struct snd_rawmidi *rmidi; |
101 | struct snd_rawmidi_str *stream; | |
102 | int err; | |
103 | ||
104 | err = snd_rawmidi_new(ff->card, ff->card->driver, 0, | |
105 | ff->spec->midi_out_ports, ff->spec->midi_in_ports, | |
106 | &rmidi); | |
107 | if (err < 0) | |
108 | return err; | |
109 | ||
110 | snprintf(rmidi->name, sizeof(rmidi->name), | |
111 | "%s MIDI", ff->card->shortname); | |
112 | rmidi->private_data = ff; | |
113 | ||
114 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | |
115 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | |
116 | &midi_capture_ops); | |
117 | stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | |
118 | set_midi_substream_names(stream, ff->card->shortname); | |
119 | ||
120 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | |
121 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | |
122 | &midi_playback_ops); | |
123 | stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | |
124 | set_midi_substream_names(stream, ff->card->shortname); | |
125 | ||
126 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | |
127 | ||
128 | return 0; | |
129 | } |