Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/fireface/ff-midi.c
26470 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
unsigned long flags;
50
51
spin_lock_irqsave(&ff->lock, flags);
52
53
if (up)
54
WRITE_ONCE(ff->tx_midi_substreams[substream->number],
55
substream);
56
else
57
WRITE_ONCE(ff->tx_midi_substreams[substream->number], NULL);
58
59
spin_unlock_irqrestore(&ff->lock, flags);
60
}
61
62
static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
63
int up)
64
{
65
struct snd_ff *ff = substream->rmidi->private_data;
66
unsigned long flags;
67
68
spin_lock_irqsave(&ff->lock, flags);
69
70
if (up || !ff->rx_midi_error[substream->number])
71
schedule_work(&ff->rx_midi_work[substream->number]);
72
73
spin_unlock_irqrestore(&ff->lock, flags);
74
}
75
76
static void set_midi_substream_names(struct snd_rawmidi_str *stream,
77
const char *const name)
78
{
79
struct snd_rawmidi_substream *substream;
80
81
list_for_each_entry(substream, &stream->substreams, list) {
82
scnprintf(substream->name, sizeof(substream->name),
83
"%s MIDI %d", name, substream->number + 1);
84
}
85
}
86
87
int snd_ff_create_midi_devices(struct snd_ff *ff)
88
{
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,
93
};
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,
98
};
99
struct snd_rawmidi *rmidi;
100
struct snd_rawmidi_str *stream;
101
int err;
102
103
err = snd_rawmidi_new(ff->card, ff->card->driver, 0,
104
ff->spec->midi_out_ports, ff->spec->midi_in_ports,
105
&rmidi);
106
if (err < 0)
107
return err;
108
109
snprintf(rmidi->name, sizeof(rmidi->name),
110
"%s MIDI", ff->card->shortname);
111
rmidi->private_data = ff;
112
113
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
114
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
115
&midi_capture_ops);
116
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
117
set_midi_substream_names(stream, ff->card->shortname);
118
119
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
120
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
121
&midi_playback_ops);
122
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
123
set_midi_substream_names(stream, ff->card->shortname);
124
125
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
126
127
return 0;
128
}
129
130