1 // SPDX-License-Identifier: GPL-2.0-only
3 * ff-midi.c - a part of driver for RME Fireface series
5 * Copyright (c) 2015-2017 Takashi Sakamoto
10 static int midi_capture_open(struct snd_rawmidi_substream
*substream
)
16 static int midi_playback_open(struct snd_rawmidi_substream
*substream
)
18 struct snd_ff
*ff
= substream
->rmidi
->private_data
;
20 /* Initialize internal status. */
21 ff
->on_sysex
[substream
->number
] = 0;
22 ff
->rx_midi_error
[substream
->number
] = false;
24 WRITE_ONCE(ff
->rx_midi_substreams
[substream
->number
], substream
);
29 static int midi_capture_close(struct snd_rawmidi_substream
*substream
)
35 static int midi_playback_close(struct snd_rawmidi_substream
*substream
)
37 struct snd_ff
*ff
= substream
->rmidi
->private_data
;
39 cancel_work_sync(&ff
->rx_midi_work
[substream
->number
]);
40 WRITE_ONCE(ff
->rx_midi_substreams
[substream
->number
], NULL
);
45 static void midi_capture_trigger(struct snd_rawmidi_substream
*substream
,
48 struct snd_ff
*ff
= substream
->rmidi
->private_data
;
51 spin_lock_irqsave(&ff
->lock
, flags
);
54 WRITE_ONCE(ff
->tx_midi_substreams
[substream
->number
],
57 WRITE_ONCE(ff
->tx_midi_substreams
[substream
->number
], NULL
);
59 spin_unlock_irqrestore(&ff
->lock
, flags
);
62 static void midi_playback_trigger(struct snd_rawmidi_substream
*substream
,
65 struct snd_ff
*ff
= substream
->rmidi
->private_data
;
68 spin_lock_irqsave(&ff
->lock
, flags
);
70 if (up
|| !ff
->rx_midi_error
[substream
->number
])
71 schedule_work(&ff
->rx_midi_work
[substream
->number
]);
73 spin_unlock_irqrestore(&ff
->lock
, flags
);
76 static void set_midi_substream_names(struct snd_rawmidi_str
*stream
,
77 const char *const name
)
79 struct snd_rawmidi_substream
*substream
;
81 list_for_each_entry(substream
, &stream
->substreams
, list
) {
82 snprintf(substream
->name
, sizeof(substream
->name
),
83 "%s MIDI %d", name
, substream
->number
+ 1);
87 int snd_ff_create_midi_devices(struct snd_ff
*ff
)
89 static const struct snd_rawmidi_ops midi_capture_ops
= {
90 .open
= midi_capture_open
,
91 .close
= midi_capture_close
,
92 .trigger
= midi_capture_trigger
,
94 static const struct snd_rawmidi_ops midi_playback_ops
= {
95 .open
= midi_playback_open
,
96 .close
= midi_playback_close
,
97 .trigger
= midi_playback_trigger
,
99 struct snd_rawmidi
*rmidi
;
100 struct snd_rawmidi_str
*stream
;
103 err
= snd_rawmidi_new(ff
->card
, ff
->card
->driver
, 0,
104 ff
->spec
->midi_out_ports
, ff
->spec
->midi_in_ports
,
109 snprintf(rmidi
->name
, sizeof(rmidi
->name
),
110 "%s MIDI", ff
->card
->shortname
);
111 rmidi
->private_data
= ff
;
113 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_INPUT
;
114 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_INPUT
,
116 stream
= &rmidi
->streams
[SNDRV_RAWMIDI_STREAM_INPUT
];
117 set_midi_substream_names(stream
, ff
->card
->shortname
);
119 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_OUTPUT
;
120 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_OUTPUT
,
122 stream
= &rmidi
->streams
[SNDRV_RAWMIDI_STREAM_OUTPUT
];
123 set_midi_substream_names(stream
, ff
->card
->shortname
);
125 rmidi
->info_flags
|= SNDRV_RAWMIDI_INFO_DUPLEX
;