Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/digi00x/digi00x-midi.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
4
*
5
* Copyright (c) 2014-2015 Takashi Sakamoto
6
*/
7
8
#include "digi00x.h"
9
10
static int midi_open(struct snd_rawmidi_substream *substream)
11
{
12
struct snd_dg00x *dg00x = substream->rmidi->private_data;
13
int err;
14
15
err = snd_dg00x_stream_lock_try(dg00x);
16
if (err < 0)
17
return err;
18
19
mutex_lock(&dg00x->mutex);
20
err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0, 0);
21
if (err >= 0) {
22
++dg00x->substreams_counter;
23
err = snd_dg00x_stream_start_duplex(dg00x);
24
if (err < 0)
25
--dg00x->substreams_counter;
26
}
27
mutex_unlock(&dg00x->mutex);
28
if (err < 0)
29
snd_dg00x_stream_lock_release(dg00x);
30
31
return err;
32
}
33
34
static int midi_close(struct snd_rawmidi_substream *substream)
35
{
36
struct snd_dg00x *dg00x = substream->rmidi->private_data;
37
38
mutex_lock(&dg00x->mutex);
39
--dg00x->substreams_counter;
40
snd_dg00x_stream_stop_duplex(dg00x);
41
mutex_unlock(&dg00x->mutex);
42
43
snd_dg00x_stream_lock_release(dg00x);
44
return 0;
45
}
46
47
static void midi_capture_trigger(struct snd_rawmidi_substream *substream,
48
int up)
49
{
50
struct snd_dg00x *dg00x = substream->rmidi->private_data;
51
unsigned int port;
52
unsigned long flags;
53
54
if (substream->rmidi->device == 0)
55
port = substream->number;
56
else
57
port = 2;
58
59
spin_lock_irqsave(&dg00x->lock, flags);
60
61
if (up)
62
amdtp_dot_midi_trigger(&dg00x->tx_stream, port, substream);
63
else
64
amdtp_dot_midi_trigger(&dg00x->tx_stream, port, NULL);
65
66
spin_unlock_irqrestore(&dg00x->lock, flags);
67
}
68
69
static void midi_playback_trigger(struct snd_rawmidi_substream *substream,
70
int up)
71
{
72
struct snd_dg00x *dg00x = substream->rmidi->private_data;
73
unsigned int port;
74
unsigned long flags;
75
76
if (substream->rmidi->device == 0)
77
port = substream->number;
78
else
79
port = 2;
80
81
spin_lock_irqsave(&dg00x->lock, flags);
82
83
if (up)
84
amdtp_dot_midi_trigger(&dg00x->rx_stream, port, substream);
85
else
86
amdtp_dot_midi_trigger(&dg00x->rx_stream, port, NULL);
87
88
spin_unlock_irqrestore(&dg00x->lock, flags);
89
}
90
91
static void set_substream_names(struct snd_dg00x *dg00x,
92
struct snd_rawmidi *rmidi, bool is_console)
93
{
94
struct snd_rawmidi_substream *subs;
95
struct snd_rawmidi_str *str;
96
int i;
97
98
for (i = 0; i < 2; ++i) {
99
str = &rmidi->streams[i];
100
101
list_for_each_entry(subs, &str->substreams, list) {
102
if (!is_console) {
103
scnprintf(subs->name, sizeof(subs->name),
104
"%s MIDI %d",
105
dg00x->card->shortname,
106
subs->number + 1);
107
} else {
108
scnprintf(subs->name, sizeof(subs->name),
109
"%s control",
110
dg00x->card->shortname);
111
}
112
}
113
}
114
}
115
116
static int add_substream_pair(struct snd_dg00x *dg00x, unsigned int out_ports,
117
unsigned int in_ports, bool is_console)
118
{
119
static const struct snd_rawmidi_ops capture_ops = {
120
.open = midi_open,
121
.close = midi_close,
122
.trigger = midi_capture_trigger,
123
};
124
static const struct snd_rawmidi_ops playback_ops = {
125
.open = midi_open,
126
.close = midi_close,
127
.trigger = midi_playback_trigger,
128
};
129
const char *label;
130
struct snd_rawmidi *rmidi;
131
int err;
132
133
/* Add physical midi ports. */
134
err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, is_console,
135
out_ports, in_ports, &rmidi);
136
if (err < 0)
137
return err;
138
rmidi->private_data = dg00x;
139
140
if (!is_console)
141
label = "%s control";
142
else
143
label = "%s MIDI";
144
snprintf(rmidi->name, sizeof(rmidi->name), label,
145
dg00x->card->shortname);
146
147
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &playback_ops);
148
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &capture_ops);
149
150
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT |
151
SNDRV_RAWMIDI_INFO_OUTPUT |
152
SNDRV_RAWMIDI_INFO_DUPLEX;
153
154
set_substream_names(dg00x, rmidi, is_console);
155
156
return 0;
157
}
158
159
int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
160
{
161
int err;
162
163
/* Add physical midi ports. */
164
err = add_substream_pair(dg00x, DOT_MIDI_OUT_PORTS, DOT_MIDI_IN_PORTS,
165
false);
166
if (err < 0)
167
return err;
168
169
if (dg00x->is_console)
170
err = add_substream_pair(dg00x, 1, 1, true);
171
172
return err;
173
}
174
175