blob: 5630a8f1f2f1b6a0c03fe45cf43ecc6d1a1239ff [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
Takashi Sakamoto83501322019-06-17 17:15:03 +090029static int keep_resources(struct snd_motu *motu, unsigned int rate,
30 struct amdtp_stream *stream)
31{
32 struct fw_iso_resources *resources;
33 struct snd_motu_packet_format *packet_format;
34 unsigned int midi_ports = 0;
35 int err;
36
37 if (stream == &motu->rx_stream) {
38 resources = &motu->rx_resources;
39 packet_format = &motu->rx_packet_formats;
40
41 if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) ||
42 (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q))
43 midi_ports = 1;
44 } else {
45 resources = &motu->tx_resources;
46 packet_format = &motu->tx_packet_formats;
47
48 if ((motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) ||
49 (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q))
50 midi_ports = 1;
51 }
52
53 err = amdtp_motu_set_parameters(stream, rate, midi_ports,
54 packet_format);
55 if (err < 0)
56 return err;
57
58 return fw_iso_resources_allocate(resources,
59 amdtp_stream_get_max_payload(stream),
60 fw_parent_device(motu->unit)->max_speed);
61}
62
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +090063static int begin_session(struct snd_motu *motu)
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090064{
65 __be32 reg;
66 u32 data;
67 int err;
68
Takashi Sakamoto83501322019-06-17 17:15:03 +090069 // Configure the unit to start isochronous communication.
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090070 err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
71 sizeof(reg));
72 if (err < 0)
73 return err;
74 data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
75
76 data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
77 (motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
78 CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
79 (motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
80
81 reg = cpu_to_be32(data);
82 return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
83 sizeof(reg));
84}
85
Takashi Sakamotob66ab142019-06-17 17:15:05 +090086static void finish_session(struct snd_motu *motu)
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090087{
88 __be32 reg;
89 u32 data;
90 int err;
91
92 err = motu->spec->protocol->switch_fetching_mode(motu, false);
93 if (err < 0)
94 return;
95
Takashi Sakamotoec694fb2019-06-17 17:15:07 +090096 amdtp_stream_stop(&motu->tx_stream);
97 amdtp_stream_stop(&motu->rx_stream);
98
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +090099 err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
100 sizeof(reg));
101 if (err < 0)
102 return;
103 data = be32_to_cpu(reg);
104
105 data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
106 data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
107
108 reg = cpu_to_be32(data);
109 snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
110 sizeof(reg));
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900111}
112
113static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
114{
115 struct fw_iso_resources *resources;
116 int err;
117
118 if (stream == &motu->rx_stream)
119 resources = &motu->rx_resources;
120 else
121 resources = &motu->tx_resources;
122
123 err = amdtp_stream_start(stream, resources->channel,
124 fw_parent_device(motu->unit)->max_speed);
125 if (err < 0)
126 return err;
127
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +0900128 if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT))
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900129 return -ETIMEDOUT;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900130
131 return 0;
132}
133
Takashi Sakamoto8b460c72017-08-20 21:25:03 +0900134int snd_motu_stream_cache_packet_formats(struct snd_motu *motu)
135{
136 int err;
137
138 err = motu->spec->protocol->cache_packet_formats(motu);
139 if (err < 0)
140 return err;
141
142 if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) {
143 motu->tx_packet_formats.midi_flag_offset = 4;
144 motu->tx_packet_formats.midi_byte_offset = 6;
145 } else if (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q) {
146 motu->tx_packet_formats.midi_flag_offset = 8;
147 motu->tx_packet_formats.midi_byte_offset = 7;
148 }
149
150 if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) {
151 motu->rx_packet_formats.midi_flag_offset = 4;
152 motu->rx_packet_formats.midi_byte_offset = 6;
153 } else if (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) {
154 motu->rx_packet_formats.midi_flag_offset = 8;
155 motu->rx_packet_formats.midi_byte_offset = 7;
156 }
157
158 return 0;
159}
160
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +0900161int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate)
162{
163 unsigned int curr_rate;
164 int err;
165
166 err = motu->spec->protocol->get_clock_rate(motu, &curr_rate);
167 if (err < 0)
168 return err;
169 if (rate == 0)
170 rate = curr_rate;
171
172 if (motu->substreams_counter == 0 || curr_rate != rate) {
173 finish_session(motu);
174
175 fw_iso_resources_free(&motu->tx_resources);
176 fw_iso_resources_free(&motu->rx_resources);
177
178 err = motu->spec->protocol->set_clock_rate(motu, rate);
179 if (err < 0) {
180 dev_err(&motu->unit->device,
181 "fail to set sampling rate: %d\n", err);
182 return err;
183 }
184
185 err = snd_motu_stream_cache_packet_formats(motu);
186 if (err < 0)
187 return err;
188
189 err = keep_resources(motu, rate, &motu->tx_stream);
190 if (err < 0)
191 return err;
192
193 err = keep_resources(motu, rate, &motu->rx_stream);
194 if (err < 0) {
195 fw_iso_resources_free(&motu->tx_resources);
196 return err;
197 }
198 }
199
200 return 0;
201}
202
203void snd_motu_stream_release_duplex(struct snd_motu *motu)
204{
205 if (motu->substreams_counter == 0) {
206 fw_iso_resources_free(&motu->tx_resources);
207 fw_iso_resources_free(&motu->rx_resources);
208 }
209}
210
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900211static int ensure_packet_formats(struct snd_motu *motu)
212{
213 __be32 reg;
214 u32 data;
215 int err;
216
217 err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, &reg,
218 sizeof(reg));
219 if (err < 0)
220 return err;
221 data = be32_to_cpu(reg);
222
223 data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
224 RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
225 TX_PACKET_TRANSMISSION_SPEED_MASK);
226 if (motu->tx_packet_formats.differed_part_pcm_chunks[0] == 0)
227 data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
228 if (motu->rx_packet_formats.differed_part_pcm_chunks[0] == 0)
229 data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
230 data |= fw_parent_device(motu->unit)->max_speed;
231
232 reg = cpu_to_be32(data);
233 return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, &reg,
234 sizeof(reg));
235}
236
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +0900237int snd_motu_stream_start_duplex(struct snd_motu *motu)
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900238{
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900239 int err = 0;
240
Takashi Sakamoto18f26032019-06-17 17:15:01 +0900241 if (motu->substreams_counter == 0)
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900242 return 0;
243
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +0900244 if (amdtp_streaming_error(&motu->rx_stream) ||
Takashi Sakamotoec694fb2019-06-17 17:15:07 +0900245 amdtp_streaming_error(&motu->tx_stream))
Takashi Sakamotob66ab142019-06-17 17:15:05 +0900246 finish_session(motu);
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900247
248 if (!amdtp_stream_running(&motu->rx_stream)) {
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900249 err = ensure_packet_formats(motu);
250 if (err < 0)
251 return err;
252
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +0900253 err = begin_session(motu);
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900254 if (err < 0) {
255 dev_err(&motu->unit->device,
256 "fail to start isochronous comm: %d\n", err);
Markus Elfringf16e6662017-09-06 13:30:14 +0200257 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900258 }
259
260 err = start_isoc_ctx(motu, &motu->rx_stream);
261 if (err < 0) {
262 dev_err(&motu->unit->device,
263 "fail to start IT context: %d\n", err);
Markus Elfringf16e6662017-09-06 13:30:14 +0200264 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900265 }
266
Takashi Sakamoto8edc56e2019-06-17 17:15:08 +0900267 err = motu->spec->protocol->switch_fetching_mode(motu, true);
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900268 if (err < 0) {
269 dev_err(&motu->unit->device,
270 "fail to enable frame fetching: %d\n", err);
Markus Elfringf16e6662017-09-06 13:30:14 +0200271 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900272 }
273 }
274
Takashi Sakamoto18f26032019-06-17 17:15:01 +0900275 if (!amdtp_stream_running(&motu->tx_stream)) {
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900276 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);
Markus Elfringf16e6662017-09-06 13:30:14 +0200280 goto stop_streams;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900281 }
282 }
283
284 return 0;
Markus Elfringf16e6662017-09-06 13:30:14 +0200285
286stop_streams:
Takashi Sakamotob66ab142019-06-17 17:15:05 +0900287 finish_session(motu);
Markus Elfringf16e6662017-09-06 13:30:14 +0200288 return err;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900289}
290
291void snd_motu_stream_stop_duplex(struct snd_motu *motu)
292{
Takashi Sakamotoec694fb2019-06-17 17:15:07 +0900293 if (motu->substreams_counter == 0)
294 finish_session(motu);
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900295}
296
297static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir)
298{
299 int err;
300 struct amdtp_stream *stream;
301 struct fw_iso_resources *resources;
302
303 if (dir == AMDTP_IN_STREAM) {
304 stream = &motu->tx_stream;
305 resources = &motu->tx_resources;
306 } else {
307 stream = &motu->rx_stream;
308 resources = &motu->rx_resources;
309 }
310
311 err = fw_iso_resources_init(resources, motu->unit);
312 if (err < 0)
313 return err;
314
315 err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol);
316 if (err < 0) {
317 amdtp_stream_destroy(stream);
318 fw_iso_resources_destroy(resources);
319 }
320
321 return err;
322}
323
324static void destroy_stream(struct snd_motu *motu,
325 enum amdtp_stream_direction dir)
326{
327 struct amdtp_stream *stream;
328 struct fw_iso_resources *resources;
329
330 if (dir == AMDTP_IN_STREAM) {
331 stream = &motu->tx_stream;
332 resources = &motu->tx_resources;
333 } else {
334 stream = &motu->rx_stream;
335 resources = &motu->rx_resources;
336 }
337
338 amdtp_stream_destroy(stream);
339 fw_iso_resources_free(resources);
340}
341
342int snd_motu_stream_init_duplex(struct snd_motu *motu)
343{
344 int err;
345
346 err = init_stream(motu, AMDTP_IN_STREAM);
347 if (err < 0)
348 return err;
349
350 err = init_stream(motu, AMDTP_OUT_STREAM);
351 if (err < 0)
352 destroy_stream(motu, AMDTP_IN_STREAM);
353
354 return err;
355}
356
357/*
358 * This function should be called before starting streams or after stopping
359 * streams.
360 */
361void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
362{
363 destroy_stream(motu, AMDTP_IN_STREAM);
364 destroy_stream(motu, AMDTP_OUT_STREAM);
365
Takashi Sakamoto18f26032019-06-17 17:15:01 +0900366 motu->substreams_counter = 0;
Takashi Sakamoto9b2bb4f2017-03-22 21:30:20 +0900367}
Takashi Sakamoto71c37972017-03-22 21:30:24 +0900368
369static void motu_lock_changed(struct snd_motu *motu)
370{
371 motu->dev_lock_changed = true;
372 wake_up(&motu->hwdep_wait);
373}
374
375int snd_motu_stream_lock_try(struct snd_motu *motu)
376{
377 int err;
378
379 spin_lock_irq(&motu->lock);
380
381 if (motu->dev_lock_count < 0) {
382 err = -EBUSY;
383 goto out;
384 }
385
386 if (motu->dev_lock_count++ == 0)
387 motu_lock_changed(motu);
388 err = 0;
389out:
390 spin_unlock_irq(&motu->lock);
391 return err;
392}
393
394void snd_motu_stream_lock_release(struct snd_motu *motu)
395{
396 spin_lock_irq(&motu->lock);
397
398 if (WARN_ON(motu->dev_lock_count <= 0))
399 goto out;
400
401 if (--motu->dev_lock_count == 0)
402 motu_lock_changed(motu);
403out:
404 spin_unlock_irq(&motu->lock);
405}