Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/oxfw/oxfw-midi.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* oxfw_midi.c - a part of driver for OXFW970/971 based devices
4
*
5
* Copyright (c) 2014 Takashi Sakamoto
6
*/
7
8
#include "oxfw.h"
9
10
static int midi_capture_open(struct snd_rawmidi_substream *substream)
11
{
12
struct snd_oxfw *oxfw = substream->rmidi->private_data;
13
int err;
14
15
err = snd_oxfw_stream_lock_try(oxfw);
16
if (err < 0)
17
return err;
18
19
scoped_guard(mutex, &oxfw->mutex) {
20
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0, 0);
21
if (err >= 0) {
22
++oxfw->substreams_count;
23
err = snd_oxfw_stream_start_duplex(oxfw);
24
if (err < 0)
25
--oxfw->substreams_count;
26
}
27
}
28
29
if (err < 0)
30
snd_oxfw_stream_lock_release(oxfw);
31
32
return err;
33
}
34
35
static int midi_playback_open(struct snd_rawmidi_substream *substream)
36
{
37
struct snd_oxfw *oxfw = substream->rmidi->private_data;
38
int err;
39
40
err = snd_oxfw_stream_lock_try(oxfw);
41
if (err < 0)
42
return err;
43
44
scoped_guard(mutex, &oxfw->mutex) {
45
err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0, 0);
46
if (err >= 0) {
47
++oxfw->substreams_count;
48
err = snd_oxfw_stream_start_duplex(oxfw);
49
}
50
}
51
52
if (err < 0)
53
snd_oxfw_stream_lock_release(oxfw);
54
55
return err;
56
}
57
58
static int midi_capture_close(struct snd_rawmidi_substream *substream)
59
{
60
struct snd_oxfw *oxfw = substream->rmidi->private_data;
61
62
scoped_guard(mutex, &oxfw->mutex) {
63
--oxfw->substreams_count;
64
snd_oxfw_stream_stop_duplex(oxfw);
65
}
66
67
snd_oxfw_stream_lock_release(oxfw);
68
return 0;
69
}
70
71
static int midi_playback_close(struct snd_rawmidi_substream *substream)
72
{
73
struct snd_oxfw *oxfw = substream->rmidi->private_data;
74
75
scoped_guard(mutex, &oxfw->mutex) {
76
--oxfw->substreams_count;
77
snd_oxfw_stream_stop_duplex(oxfw);
78
}
79
80
snd_oxfw_stream_lock_release(oxfw);
81
return 0;
82
}
83
84
static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
85
{
86
struct snd_oxfw *oxfw = substrm->rmidi->private_data;
87
88
guard(spinlock_irqsave)(&oxfw->lock);
89
90
if (up)
91
amdtp_am824_midi_trigger(&oxfw->tx_stream,
92
substrm->number, substrm);
93
else
94
amdtp_am824_midi_trigger(&oxfw->tx_stream,
95
substrm->number, NULL);
96
}
97
98
static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
99
{
100
struct snd_oxfw *oxfw = substrm->rmidi->private_data;
101
102
guard(spinlock_irqsave)(&oxfw->lock);
103
104
if (up)
105
amdtp_am824_midi_trigger(&oxfw->rx_stream,
106
substrm->number, substrm);
107
else
108
amdtp_am824_midi_trigger(&oxfw->rx_stream,
109
substrm->number, NULL);
110
}
111
112
static void set_midi_substream_names(struct snd_oxfw *oxfw,
113
struct snd_rawmidi_str *str)
114
{
115
struct snd_rawmidi_substream *subs;
116
117
list_for_each_entry(subs, &str->substreams, list) {
118
scnprintf(subs->name, sizeof(subs->name),
119
"%s MIDI %d",
120
oxfw->card->shortname, subs->number + 1);
121
}
122
}
123
124
int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
125
{
126
static const struct snd_rawmidi_ops capture_ops = {
127
.open = midi_capture_open,
128
.close = midi_capture_close,
129
.trigger = midi_capture_trigger,
130
};
131
static const struct snd_rawmidi_ops playback_ops = {
132
.open = midi_playback_open,
133
.close = midi_playback_close,
134
.trigger = midi_playback_trigger,
135
};
136
struct snd_rawmidi *rmidi;
137
struct snd_rawmidi_str *str;
138
int err;
139
140
if (oxfw->midi_input_ports == 0 && oxfw->midi_output_ports == 0)
141
return 0;
142
143
/* create midi ports */
144
err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
145
oxfw->midi_output_ports, oxfw->midi_input_ports,
146
&rmidi);
147
if (err < 0)
148
return err;
149
150
snprintf(rmidi->name, sizeof(rmidi->name),
151
"%s MIDI", oxfw->card->shortname);
152
rmidi->private_data = oxfw;
153
154
if (oxfw->midi_input_ports > 0) {
155
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
156
157
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
158
&capture_ops);
159
160
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
161
162
set_midi_substream_names(oxfw, str);
163
}
164
165
if (oxfw->midi_output_ports > 0) {
166
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
167
168
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
169
&playback_ops);
170
171
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
172
173
set_midi_substream_names(oxfw, str);
174
}
175
176
if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
177
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
178
179
return 0;
180
}
181
182