aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-12-08 10:10:48 -0500
committerTakashi Iwai <tiwai@suse.de>2014-12-10 04:49:33 -0500
commit05588d340a128ff5c7b768c517150e31842a78aa (patch)
tree60a509a34e46e8ff91fae1e2da6f821adfa0d8e6
parent216e256f7bf974ba402309d0ceb24f3500dc65c4 (diff)
ALSA: oxfw: Add support for capture/playback MIDI messages
This commit adds MIDI functionality with an assumption of 'if the device has MIDI comformant data channels in its stream formation, the device has one MIDI port'. When no streams have already started, MIDI functionality starts stream with current sampling rate. When MIDI functionality has already starts some streams and PCM functionality is going to start streams at different sampling rate, this driver stops streams once and changes sampling rate, then restarts streams for both PCM/MIDI substreams. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Acked-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/firewire/oxfw/Makefile2
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c191
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c4
-rw-r--r--sound/firewire/oxfw/oxfw.c5
-rw-r--r--sound/firewire/oxfw/oxfw.h7
5 files changed, 208 insertions, 1 deletions
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
index e9297c638aa1..3904a302d48e 100644
--- a/sound/firewire/oxfw/Makefile
+++ b/sound/firewire/oxfw/Makefile
@@ -1,3 +1,3 @@
1snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \ 1snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \
2 oxfw-proc.o oxfw.o 2 oxfw-proc.o oxfw-midi.o oxfw.o
3obj-m += snd-oxfw.o 3obj-m += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
new file mode 100644
index 000000000000..334b11d1a422
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -0,0 +1,191 @@
1/*
2 * oxfw_midi.c - a part of driver for OXFW970/971 based devices
3 *
4 * Copyright (c) 2014 Takashi Sakamoto
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include "oxfw.h"
10
11static int midi_capture_open(struct snd_rawmidi_substream *substream)
12{
13 struct snd_oxfw *oxfw = substream->rmidi->private_data;
14 int err;
15
16 mutex_lock(&oxfw->mutex);
17
18 oxfw->capture_substreams++;
19 err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 0, 0);
20
21 mutex_unlock(&oxfw->mutex);
22
23 return err;
24}
25
26static int midi_playback_open(struct snd_rawmidi_substream *substream)
27{
28 struct snd_oxfw *oxfw = substream->rmidi->private_data;
29 int err;
30
31 mutex_lock(&oxfw->mutex);
32
33 oxfw->playback_substreams++;
34 err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 0, 0);
35
36 mutex_unlock(&oxfw->mutex);
37
38 return err;
39}
40
41static int midi_capture_close(struct snd_rawmidi_substream *substream)
42{
43 struct snd_oxfw *oxfw = substream->rmidi->private_data;
44
45 mutex_lock(&oxfw->mutex);
46
47 oxfw->capture_substreams--;
48 snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
49
50 mutex_unlock(&oxfw->mutex);
51
52 return 0;
53}
54
55static int midi_playback_close(struct snd_rawmidi_substream *substream)
56{
57 struct snd_oxfw *oxfw = substream->rmidi->private_data;
58
59 mutex_lock(&oxfw->mutex);
60
61 oxfw->playback_substreams--;
62 snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
63
64 mutex_unlock(&oxfw->mutex);
65
66 return 0;
67}
68
69static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
70{
71 struct snd_oxfw *oxfw = substrm->rmidi->private_data;
72 unsigned long flags;
73
74 spin_lock_irqsave(&oxfw->lock, flags);
75
76 if (up)
77 amdtp_stream_midi_trigger(&oxfw->tx_stream,
78 substrm->number, substrm);
79 else
80 amdtp_stream_midi_trigger(&oxfw->tx_stream,
81 substrm->number, NULL);
82
83 spin_unlock_irqrestore(&oxfw->lock, flags);
84}
85
86static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
87{
88 struct snd_oxfw *oxfw = substrm->rmidi->private_data;
89 unsigned long flags;
90
91 spin_lock_irqsave(&oxfw->lock, flags);
92
93 if (up)
94 amdtp_stream_midi_trigger(&oxfw->rx_stream,
95 substrm->number, substrm);
96 else
97 amdtp_stream_midi_trigger(&oxfw->rx_stream,
98 substrm->number, NULL);
99
100 spin_unlock_irqrestore(&oxfw->lock, flags);
101}
102
103static struct snd_rawmidi_ops midi_capture_ops = {
104 .open = midi_capture_open,
105 .close = midi_capture_close,
106 .trigger = midi_capture_trigger,
107};
108
109static struct snd_rawmidi_ops midi_playback_ops = {
110 .open = midi_playback_open,
111 .close = midi_playback_close,
112 .trigger = midi_playback_trigger,
113};
114
115static void set_midi_substream_names(struct snd_oxfw *oxfw,
116 struct snd_rawmidi_str *str)
117{
118 struct snd_rawmidi_substream *subs;
119
120 list_for_each_entry(subs, &str->substreams, list) {
121 snprintf(subs->name, sizeof(subs->name),
122 "%s MIDI %d",
123 oxfw->card->shortname, subs->number + 1);
124 }
125}
126
127int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
128{
129 struct snd_oxfw_stream_formation formation;
130 struct snd_rawmidi *rmidi;
131 struct snd_rawmidi_str *str;
132 u8 *format;
133 int i, err;
134
135 /* If its stream has MIDI conformant data channel, add one MIDI port */
136 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
137 format = oxfw->tx_stream_formats[i];
138 if (format != NULL) {
139 err = snd_oxfw_stream_parse_format(format, &formation);
140 if (err >= 0 && formation.midi > 0)
141 oxfw->midi_input_ports = 1;
142 }
143
144 format = oxfw->rx_stream_formats[i];
145 if (format != NULL) {
146 err = snd_oxfw_stream_parse_format(format, &formation);
147 if (err >= 0 && formation.midi > 0)
148 oxfw->midi_output_ports = 1;
149 }
150 }
151 if ((oxfw->midi_input_ports == 0) && (oxfw->midi_output_ports == 0))
152 return 0;
153
154 /* create midi ports */
155 err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
156 oxfw->midi_output_ports, oxfw->midi_input_ports,
157 &rmidi);
158 if (err < 0)
159 return err;
160
161 snprintf(rmidi->name, sizeof(rmidi->name),
162 "%s MIDI", oxfw->card->shortname);
163 rmidi->private_data = oxfw;
164
165 if (oxfw->midi_input_ports > 0) {
166 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
167
168 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
169 &midi_capture_ops);
170
171 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
172
173 set_midi_substream_names(oxfw, str);
174 }
175
176 if (oxfw->midi_output_ports > 0) {
177 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
178
179 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
180 &midi_playback_ops);
181
182 str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
183
184 set_midi_substream_names(oxfw, str);
185 }
186
187 if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
188 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
189
190 return 0;
191}
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 1d154284873e..a38b3c36faca 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -282,6 +282,10 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
282 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); 282 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
283 if (err < 0) 283 if (err < 0)
284 goto end; 284 goto end;
285 if (rate == 0)
286 rate = formation.rate;
287 if (pcm_channels == 0)
288 pcm_channels = formation.pcm;
285 289
286 if ((formation.rate != rate) || (formation.pcm != pcm_channels)) { 290 if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
287 if (opposite != NULL) { 291 if (opposite != NULL) {
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 23c00a2bb7d3..9cfbfb168dac 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -138,6 +138,7 @@ static int oxfw_probe(struct fw_unit *unit,
138 mutex_init(&oxfw->mutex); 138 mutex_init(&oxfw->mutex);
139 oxfw->unit = unit; 139 oxfw->unit = unit;
140 oxfw->device_info = (const struct device_info *)id->driver_data; 140 oxfw->device_info = (const struct device_info *)id->driver_data;
141 spin_lock_init(&oxfw->lock);
141 142
142 err = snd_oxfw_stream_discover(oxfw); 143 err = snd_oxfw_stream_discover(oxfw);
143 if (err < 0) 144 if (err < 0)
@@ -159,6 +160,10 @@ static int oxfw_probe(struct fw_unit *unit,
159 160
160 snd_oxfw_proc_init(oxfw); 161 snd_oxfw_proc_init(oxfw);
161 162
163 err = snd_oxfw_create_midi(oxfw);
164 if (err < 0)
165 goto error;
166
162 err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream); 167 err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream);
163 if (err < 0) 168 if (err < 0)
164 goto error; 169 goto error;
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 2211d11a79e1..83a54fc73a11 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -19,6 +19,7 @@
19#include <sound/pcm.h> 19#include <sound/pcm.h>
20#include <sound/pcm_params.h> 20#include <sound/pcm_params.h>
21#include <sound/info.h> 21#include <sound/info.h>
22#include <sound/rawmidi.h>
22 23
23#include "../lib.h" 24#include "../lib.h"
24#include "../fcp.h" 25#include "../fcp.h"
@@ -43,6 +44,7 @@ struct snd_oxfw {
43 struct fw_unit *unit; 44 struct fw_unit *unit;
44 const struct device_info *device_info; 45 const struct device_info *device_info;
45 struct mutex mutex; 46 struct mutex mutex;
47 spinlock_t lock;
46 48
47 bool has_output; 49 bool has_output;
48 u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES]; 50 u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
@@ -55,6 +57,9 @@ struct snd_oxfw {
55 unsigned int capture_substreams; 57 unsigned int capture_substreams;
56 unsigned int playback_substreams; 58 unsigned int playback_substreams;
57 59
60 unsigned int midi_input_ports;
61 unsigned int midi_output_ports;
62
58 bool mute; 63 bool mute;
59 s16 volume[6]; 64 s16 volume[6];
60 s16 volume_min; 65 s16 volume_min;
@@ -124,3 +129,5 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);
124int snd_oxfw_create_mixer(struct snd_oxfw *oxfw); 129int snd_oxfw_create_mixer(struct snd_oxfw *oxfw);
125 130
126void snd_oxfw_proc_init(struct snd_oxfw *oxfw); 131void snd_oxfw_proc_init(struct snd_oxfw *oxfw);
132
133int snd_oxfw_create_midi(struct snd_oxfw *oxfw);