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