blob: 483a8771d5020abe68a5ea688446782ce37685a8 [file] [log] [blame]
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +09001/*
2 * motu-stream.c - a part of driver for MOTU FireWire series
3 *
4 * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
5 *
6 * Licensed under the terms of the GNU General Public License, version 2.
7 */
8
9#include "motu.h"
10
11#define CALLBACK_TIMEOUT 200
12
13#define ISOC_COMM_CONTROL_OFFSET 0x0b00
14#define ISOC_COMM_CONTROL_MASK 0xffff0000
15#define CHANGE_RX_ISOC_COMM_STATE 0x80000000
16#define RX_ISOC_COMM_IS_ACTIVATED 0x40000000
17#define RX_ISOC_COMM_CHANNEL_MASK 0x3f000000
18#define RX_ISOC_COMM_CHANNEL_SHIFT 24
19#define CHANGE_TX_ISOC_COMM_STATE 0x00800000
20#define TX_ISOC_COMM_IS_ACTIVATED 0x00400000
21#define TX_ISOC_COMM_CHANNEL_MASK 0x003f0000
22#define TX_ISOC_COMM_CHANNEL_SHIFT 16
23
24#define PACKET_FORMAT_OFFSET 0x0b10
25#define TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000080
26#define RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS 0x00000040
27#define TX_PACKET_TRANSMISSION_SPEED_MASK 0x0000000f
28
29static int start_both_streams(struct snd_motu *motu, unsigned int rate)
30{
Takashi Sakamoto9e796e72017-03-22 21:30:23 +090031 unsigned int midi_ports = 0;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090032 __be32 reg;
33 u32 data;
34 int err;
35
Takashi Sakamoto8b460c72017-08-20 21:25:03 +090036 if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
37 (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
Takashi Sakamoto9e796e72017-03-22 21:30:23 +090038 midi_ports = 1;
39
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090040 /* Set packet formation to our packet streaming engine. */
Takashi Sakamoto9e796e72017-03-22 21:30:23 +090041 err = amdtp_motu_set_parameters(&motu->rx_stream, rate, midi_ports,
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090042 &motu->rx_packet_formats);
43 if (err < 0)
44 return err;
45
Takashi Sakamoto8b460c72017-08-20 21:25:03 +090046 if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
47 (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
48 midi_ports = 1;
49 else
50 midi_ports = 0;
51
Takashi Sakamoto9e796e72017-03-22 21:30:23 +090052 err = amdtp_motu_set_parameters(&motu->tx_stream, rate, midi_ports,
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090053 &motu->tx_packet_formats);
54 if (err < 0)
55 return err;
56
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090057 /* Get isochronous resources on the bus. */
58 err = fw_iso_resources_allocate(&motu->rx_resources,
59 amdtp_stream_get_max_payload(&motu->rx_stream),
60 fw_parent_device(motu->unit)->max_speed);
61 if (err < 0)
62 return err;
63
64 err = fw_iso_resources_allocate(&motu->tx_resources,
65 amdtp_stream_get_max_payload(&motu->tx_stream),
66 fw_parent_device(motu->unit)->max_speed);
67 if (err < 0)
68 return err;
69
70 /* Configure the unit to start isochronous communication. */
71 err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
72 sizeof(reg));
73 if (err < 0)
74 return err;
75 data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
76
77 data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
78 (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
79 CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
80 (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
81
82 reg = cpu_to_be32(data);
83 return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
84 sizeof(reg));
85}
86
87static void stop_both_streams(struct snd_motu *motu)
88{
89 __be32 reg;
90 u32 data;
91 int err;
92
93 err = motu->spec->protocol->switch_fetching_mode(motu, false);
94 if (err < 0)
95 return;
96
97 err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
98 sizeof(reg));
99 if (err < 0)
100 return;
101 data = be32_to_cpu(reg);
102
103 data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
104 data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
105
106 reg = cpu_to_be32(data);
107 snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
108 sizeof(reg));
109
110 fw_iso_resources_free(&motu->tx_resources);
111 fw_iso_resources_free(&motu->rx_resources);
112}
113
114static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
115{
116 struct fw_iso_resources *resources;
117 int err;
118
119 if (stream == &motu->rx_stream)
120 resources = &motu->rx_resources;
121 else
122 resources = &motu->tx_resources;
123
124 err = amdtp_stream_start(stream, resources->channel,
125 fw_parent_device(motu->unit)->max_speed);
126 if (err < 0)
127 return err;
128
129 if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
130 amdtp_stream_stop(stream);
131 fw_iso_resources_free(resources);
132 return -ETIMEDOUT;
133 }
134
135 return 0;
136}
137
138static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
139{
140 struct fw_iso_resources *resources;
141
142 if (stream == &motu->rx_stream)
143 resources = &motu->rx_resources;
144 else
145 resources = &motu->tx_resources;
146
147 amdtp_stream_stop(stream);
148 fw_iso_resources_free(resources);
149}
150
Takashi Sakamoto8b460c72017-08-20 21:25:03 +0900151int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
152{
153 int err;
154
155 err = motu->spec->protocol->cache_packet_formats(motu);
156 if (err < 0)
157 return err;
158
159 if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) {
160 motu->tx_packet_formats.midi_flag_offset = 4;
161 motu->tx_packet_formats.midi_byte_offset = 6;
162 } else if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q) {
163 motu->tx_packet_formats.midi_flag_offset = 8;
164 motu->tx_packet_formats.midi_byte_offset = 7;
165 }
166
167 if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) {
168 motu->rx_packet_formats.midi_flag_offset = 4;
169 motu->rx_packet_formats.midi_byte_offset = 6;
170 } else if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) {
171 motu->rx_packet_formats.midi_flag_offset = 8;
172 motu->rx_packet_formats.midi_byte_offset = 7;
173 }
174
175 return 0;
176}
177
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900178static int ensure_packet_formats(struct snd_motu *motu)
179{
180 __be32 reg;
181 u32 data;
182 int err;
183
184 err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, &reg,
185 sizeof(reg));
186 if (err < 0)
187 return err;
188 data = be32_to_cpu(reg);
189
190 data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
191 RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
192 TX_PACKET_TRANSMISSION_SPEED_MASK);
193 if (motu->tx_packet_formats.differed_part_pcm_chunks[0] == 0)
194 data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
195 if (motu->rx_packet_formats.differed_part_pcm_chunks[0] == 0)
196 data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
197 data |= fw_parent_device(motu->unit)->max_speed;
198
199 reg = cpu_to_be32(data);
200 return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, &reg,
201 sizeof(reg));
202}
203
204int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
205{
206 const struct snd_motu_protocol *protocol = motu->spec->protocol;
207 unsigned int curr_rate;
208 int err = 0;
209
210 if (motu->capture_substreams == 0 && motu->playback_substreams == 0)
211 return 0;
212
213 /* Some packet queueing errors. */
214 if (amdtp_streaming_error(&motu->rx_stream) ||
215 amdtp_streaming_error(&motu->tx_stream)) {
216 amdtp_stream_stop(&motu->rx_stream);
217 amdtp_stream_stop(&motu->tx_stream);
218 stop_both_streams(motu);
219 }
220
Takashi Sakamoto8b460c72017-08-20 21:25:03 +0900221 err = snd_motu_stream_cache_packet_formats(motu);
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900222 if (err < 0)
223 return err;
224
225 /* Stop stream if rate is different. */
226 err = protocol->get_clock_rate(motu, &curr_rate);
227 if (err < 0) {
228 dev_err(&motu->unit->device,
229 "fail to get sampling rate: %d\n", err);
230 return err;
231 }
232 if (rate == 0)
233 rate = curr_rate;
234 if (rate != curr_rate) {
235 amdtp_stream_stop(&motu->rx_stream);
236 amdtp_stream_stop(&motu->tx_stream);
237 stop_both_streams(motu);
238 }
239
240 if (!amdtp_stream_running(&motu->rx_stream)) {
241 err = protocol->set_clock_rate(motu, rate);
242 if (err < 0) {
243 dev_err(&motu->unit->device,
244 "fail to set sampling rate: %d\n", err);
245 return err;
246 }
247
248 err = ensure_packet_formats(motu);
249 if (err < 0)
250 return err;
251
252 err = start_both_streams(motu, rate);
253 if (err < 0) {
254 dev_err(&motu->unit->device,
255 "fail to start isochronous comm: %d\n", err);
Markus Elfringf16e6662017-09-06 13:30:14 +0200256 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900257 }
258
259 err = start_isoc_ctx(motu, &motu->rx_stream);
260 if (err < 0) {
261 dev_err(&motu->unit->device,
262 "fail to start IT context: %d\n", err);
Markus Elfringf16e6662017-09-06 13:30:14 +0200263 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900264 }
265
266 err = protocol->switch_fetching_mode(motu, true);
267 if (err < 0) {
268 dev_err(&motu->unit->device,
269 "fail to enable frame fetching: %d\n", err);
Markus Elfringf16e6662017-09-06 13:30:14 +0200270 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900271 }
272 }
273
274 if (!amdtp_stream_running(&motu->tx_stream) &&
275 motu->capture_substreams > 0) {
276 err = start_isoc_ctx(motu, &motu->tx_stream);
277 if (err < 0) {
278 dev_err(&motu->unit->device,
279 "fail to start IR context: %d", err);
280 amdtp_stream_stop(&motu->rx_stream);
Markus Elfringf16e6662017-09-06 13:30:14 +0200281 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900282 }
283 }
284
285 return 0;
Markus Elfringf16e6662017-09-06 13:30:14 +0200286
287stop_streams:
288 stop_both_streams(motu);
289 return err;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900290}
291
292void snd_motu_stream_stop_duplex(struct snd_motu *motu)
293{
294 if (motu->capture_substreams == 0) {
295 if (amdtp_stream_running(&motu->tx_stream))
296 stop_isoc_ctx(motu, &motu->tx_stream);
297
298 if (motu->playback_substreams == 0) {
299 if (amdtp_stream_running(&motu->rx_stream))
300 stop_isoc_ctx(motu, &motu->rx_stream);
301 stop_both_streams(motu);
302 }
303 }
304}
305
306static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir)
307{
308 int err;
309 struct amdtp_stream *stream;
310 struct fw_iso_resources *resources;
311
312 if (dir == AMDTP_IN_STREAM) {
313 stream = &motu->tx_stream;
314 resources = &motu->tx_resources;
315 } else {
316 stream = &motu->rx_stream;
317 resources = &motu->rx_resources;
318 }
319
320 err = fw_iso_resources_init(resources, motu->unit);
321 if (err < 0)
322 return err;
323
324 err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol);
325 if (err < 0) {
326 amdtp_stream_destroy(stream);
327 fw_iso_resources_destroy(resources);
328 }
329
330 return err;
331}
332
333static void destroy_stream(struct snd_motu *motu,
334 enum amdtp_stream_direction dir)
335{
336 struct amdtp_stream *stream;
337 struct fw_iso_resources *resources;
338
339 if (dir == AMDTP_IN_STREAM) {
340 stream = &motu->tx_stream;
341 resources = &motu->tx_resources;
342 } else {
343 stream = &motu->rx_stream;
344 resources = &motu->rx_resources;
345 }
346
347 amdtp_stream_destroy(stream);
Takashi Sakamotoe2127972019-06-01 12:08:01 +0900348 fw_iso_resources_destroy(resources);
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900349}
350
351int snd_motu_stream_init_duplex(struct snd_motu *motu)
352{
353 int err;
354
355 err = init_stream(motu, AMDTP_IN_STREAM);
356 if (err < 0)
357 return err;
358
359 err = init_stream(motu, AMDTP_OUT_STREAM);
360 if (err < 0)
361 destroy_stream(motu, AMDTP_IN_STREAM);
362
363 return err;
364}
365
366/*
367 * This function should be called before starting streams or after stopping
368 * streams.
369 */
370void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
371{
372 destroy_stream(motu, AMDTP_IN_STREAM);
373 destroy_stream(motu, AMDTP_OUT_STREAM);
374
375 motu->playback_substreams = 0;
376 motu->capture_substreams = 0;
377}
Takashi Sakamoto71c37972017-03-22 21:30:24 +0900378
379static void motu_lock_changed(struct snd_motu *motu)
380{
381 motu->dev_lock_changed = true;
382 wake_up(&motu->hwdep_wait);
383}
384
385int snd_motu_stream_lock_try(struct snd_motu *motu)
386{
387 int err;
388
389 spin_lock_irq(&motu->lock);
390
391 if (motu->dev_lock_count < 0) {
392 err = -EBUSY;
393 goto out;
394 }
395
396 if (motu->dev_lock_count++ == 0)
397 motu_lock_changed(motu);
398 err = 0;
399out:
400 spin_unlock_irq(&motu->lock);
401 return err;
402}
403
404void snd_motu_stream_lock_release(struct snd_motu *motu)
405{
406 spin_lock_irq(&motu->lock);
407
408 if (WARN_ON(motu->dev_lock_count <= 0))
409 goto out;
410
411 if (--motu->dev_lock_count == 0)
412 motu_lock_changed(motu);
413out:
414 spin_unlock_irq(&motu->lock);
415}