blob: 1d649e3975a0ef226b6216cab6b9db4b149753d9 [file] [log] [blame]
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +09001/*
2 * digi00x-midi.h - a part of driver for Digidesign Digi 002/003 family
3 *
4 * Copyright (c) 2014-2015 Takashi Sakamoto
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include "digi00x.h"
10
Takashi Sakamoto5918f962015-10-31 02:43:14 +090011static int midi_phys_open(struct snd_rawmidi_substream *substream)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090012{
13 struct snd_dg00x *dg00x = substream->rmidi->private_data;
14 int err;
15
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090016 /* This port is for asynchronous transaction. */
17 if (substream->number == 0)
18 return 0;
19
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090020 err = snd_dg00x_stream_lock_try(dg00x);
21 if (err < 0)
22 return err;
23
24 mutex_lock(&dg00x->mutex);
25 dg00x->substreams_counter++;
26 err = snd_dg00x_stream_start_duplex(dg00x, 0);
27 mutex_unlock(&dg00x->mutex);
28 if (err < 0)
29 snd_dg00x_stream_lock_release(dg00x);
30
31 return err;
32}
33
Takashi Sakamoto5918f962015-10-31 02:43:14 +090034static int midi_phys_close(struct snd_rawmidi_substream *substream)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090035{
36 struct snd_dg00x *dg00x = substream->rmidi->private_data;
37
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090038 /* This port is for asynchronous transaction. */
39 if (substream->number == 0)
40 return 0;
41
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090042 mutex_lock(&dg00x->mutex);
43 dg00x->substreams_counter--;
44 snd_dg00x_stream_stop_duplex(dg00x);
45 mutex_unlock(&dg00x->mutex);
46
47 snd_dg00x_stream_lock_release(dg00x);
48 return 0;
49}
50
Takashi Sakamoto5918f962015-10-31 02:43:14 +090051static void midi_phys_capture_trigger(struct snd_rawmidi_substream *substream,
52 int up)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090053{
Takashi Sakamoto5918f962015-10-31 02:43:14 +090054 struct snd_dg00x *dg00x = substream->rmidi->private_data;
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090055 unsigned long flags;
56
57 spin_lock_irqsave(&dg00x->lock, flags);
58
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090059 /* This port is for asynchronous transaction. */
Takashi Sakamoto5918f962015-10-31 02:43:14 +090060 if (substream->number == 0) {
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090061 if (up)
Takashi Sakamoto5918f962015-10-31 02:43:14 +090062 dg00x->in_control = substream;
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090063 else
64 dg00x->in_control = NULL;
65 } else {
66 if (up)
67 amdtp_dot_midi_trigger(&dg00x->tx_stream,
Takashi Sakamoto5918f962015-10-31 02:43:14 +090068 substream->number - 1,
69 substream);
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090070 else
71 amdtp_dot_midi_trigger(&dg00x->tx_stream,
Takashi Sakamoto5918f962015-10-31 02:43:14 +090072 substream->number - 1, NULL);
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090073 }
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090074
75 spin_unlock_irqrestore(&dg00x->lock, flags);
76}
77
Takashi Sakamoto5918f962015-10-31 02:43:14 +090078static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
79 int up)
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090080{
Takashi Sakamoto5918f962015-10-31 02:43:14 +090081 struct snd_dg00x *dg00x = substream->rmidi->private_data;
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +090082 unsigned long flags;
83
84 spin_lock_irqsave(&dg00x->lock, flags);
85
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090086 /* This port is for asynchronous transaction. */
Takashi Sakamoto5918f962015-10-31 02:43:14 +090087 if (substream->number == 0) {
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090088 if (up)
89 snd_fw_async_midi_port_run(&dg00x->out_control,
Takashi Sakamoto5918f962015-10-31 02:43:14 +090090 substream);
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090091 } else {
92 if (up)
93 amdtp_dot_midi_trigger(&dg00x->rx_stream,
Takashi Sakamoto5918f962015-10-31 02:43:14 +090094 substream->number - 1,
95 substream);
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090096 else
97 amdtp_dot_midi_trigger(&dg00x->rx_stream,
Takashi Sakamoto5918f962015-10-31 02:43:14 +090098 substream->number - 1, NULL);
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +090099 }
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900100
101 spin_unlock_irqrestore(&dg00x->lock, flags);
102}
103
Takashi Sakamoto5918f962015-10-31 02:43:14 +0900104static struct snd_rawmidi_ops midi_phys_capture_ops = {
105 .open = midi_phys_open,
106 .close = midi_phys_close,
107 .trigger = midi_phys_capture_trigger,
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900108};
109
Takashi Sakamoto5918f962015-10-31 02:43:14 +0900110static struct snd_rawmidi_ops midi_phys_playback_ops = {
111 .open = midi_phys_open,
112 .close = midi_phys_close,
113 .trigger = midi_phys_playback_trigger,
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900114};
115
116static void set_midi_substream_names(struct snd_dg00x *dg00x,
117 struct snd_rawmidi_str *str)
118{
119 struct snd_rawmidi_substream *subs;
120
121 list_for_each_entry(subs, &str->substreams, list) {
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +0900122 if (subs->number > 0)
123 snprintf(subs->name, sizeof(subs->name),
124 "%s MIDI %d",
125 dg00x->card->shortname, subs->number);
126 else
127 /* This port is for asynchronous transaction. */
128 snprintf(subs->name, sizeof(subs->name),
129 "%s control",
130 dg00x->card->shortname);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900131 }
132}
133
134int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
135{
136 struct snd_rawmidi *rmidi;
137 struct snd_rawmidi_str *str;
138 int err;
139
140 err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 0,
Takashi Sakamotoe8bd5772015-10-11 12:30:19 +0900141 DOT_MIDI_OUT_PORTS + 1, DOT_MIDI_IN_PORTS + 1, &rmidi);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900142 if (err < 0)
143 return err;
144
145 snprintf(rmidi->name, sizeof(rmidi->name),
146 "%s MIDI", dg00x->card->shortname);
147 rmidi->private_data = dg00x;
148
149 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
150 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
Takashi Sakamoto5918f962015-10-31 02:43:14 +0900151 &midi_phys_capture_ops);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900152 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
153 set_midi_substream_names(dg00x, str);
154
155 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
156 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
Takashi Sakamoto5918f962015-10-31 02:43:14 +0900157 &midi_phys_playback_ops);
Takashi Sakamoto9fbfd382015-10-11 12:30:16 +0900158 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
159 set_midi_substream_names(dg00x, str);
160
161 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
162
163 return 0;
164}