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