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