]> asedeno.scripts.mit.edu Git - linux.git/blob - sound/firewire/digi00x/digi00x-stream.c
Merge tag 'mtd/for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
[linux.git] / sound / firewire / digi00x / digi00x-stream.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * digi00x-stream.c - a part of driver for Digidesign Digi 002/003 family
4  *
5  * Copyright (c) 2014-2015 Takashi Sakamoto
6  */
7
8 #include "digi00x.h"
9
10 #define CALLBACK_TIMEOUT 500
11
12 const unsigned int snd_dg00x_stream_rates[SND_DG00X_RATE_COUNT] = {
13         [SND_DG00X_RATE_44100] = 44100,
14         [SND_DG00X_RATE_48000] = 48000,
15         [SND_DG00X_RATE_88200] = 88200,
16         [SND_DG00X_RATE_96000] = 96000,
17 };
18
19 /* Multi Bit Linear Audio data channels for each sampling transfer frequency. */
20 const unsigned int
21 snd_dg00x_stream_pcm_channels[SND_DG00X_RATE_COUNT] = {
22         /* Analog/ADAT/SPDIF */
23         [SND_DG00X_RATE_44100] = (8 + 8 + 2),
24         [SND_DG00X_RATE_48000] = (8 + 8 + 2),
25         /* Analog/SPDIF */
26         [SND_DG00X_RATE_88200] = (8 + 2),
27         [SND_DG00X_RATE_96000] = (8 + 2),
28 };
29
30 int snd_dg00x_stream_get_local_rate(struct snd_dg00x *dg00x, unsigned int *rate)
31 {
32         u32 data;
33         __be32 reg;
34         int err;
35
36         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
37                                  DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
38                                  &reg, sizeof(reg), 0);
39         if (err < 0)
40                 return err;
41
42         data = be32_to_cpu(reg) & 0x0f;
43         if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
44                 *rate = snd_dg00x_stream_rates[data];
45         else
46                 err = -EIO;
47
48         return err;
49 }
50
51 int snd_dg00x_stream_set_local_rate(struct snd_dg00x *dg00x, unsigned int rate)
52 {
53         __be32 reg;
54         unsigned int i;
55
56         for (i = 0; i < ARRAY_SIZE(snd_dg00x_stream_rates); i++) {
57                 if (rate == snd_dg00x_stream_rates[i])
58                         break;
59         }
60         if (i == ARRAY_SIZE(snd_dg00x_stream_rates))
61                 return -EINVAL;
62
63         reg = cpu_to_be32(i);
64         return snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
65                                   DG00X_ADDR_BASE + DG00X_OFFSET_LOCAL_RATE,
66                                   &reg, sizeof(reg), 0);
67 }
68
69 int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
70                                enum snd_dg00x_clock *clock)
71 {
72         __be32 reg;
73         int err;
74
75         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
76                                  DG00X_ADDR_BASE + DG00X_OFFSET_CLOCK_SOURCE,
77                                  &reg, sizeof(reg), 0);
78         if (err < 0)
79                 return err;
80
81         *clock = be32_to_cpu(reg) & 0x0f;
82         if (*clock >= SND_DG00X_CLOCK_COUNT)
83                 err = -EIO;
84
85         return err;
86 }
87
88 int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect)
89 {
90         __be32 reg;
91         int err;
92
93         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
94                                  DG00X_ADDR_BASE + DG00X_OFFSET_DETECT_EXTERNAL,
95                                  &reg, sizeof(reg), 0);
96         if (err >= 0)
97                 *detect = be32_to_cpu(reg) > 0;
98
99         return err;
100 }
101
102 int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
103                                        unsigned int *rate)
104 {
105         u32 data;
106         __be32 reg;
107         int err;
108
109         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
110                                  DG00X_ADDR_BASE + DG00X_OFFSET_EXTERNAL_RATE,
111                                  &reg, sizeof(reg), 0);
112         if (err < 0)
113                 return err;
114
115         data = be32_to_cpu(reg) & 0x0f;
116         if (data < ARRAY_SIZE(snd_dg00x_stream_rates))
117                 *rate = snd_dg00x_stream_rates[data];
118         /* This means desync. */
119         else
120                 err = -EBUSY;
121
122         return err;
123 }
124
125 static void finish_session(struct snd_dg00x *dg00x)
126 {
127         __be32 data;
128
129         amdtp_stream_stop(&dg00x->tx_stream);
130         amdtp_stream_stop(&dg00x->rx_stream);
131
132         data = cpu_to_be32(0x00000003);
133         snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
134                            DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
135                            &data, sizeof(data), 0);
136
137         // Unregister isochronous channels for both direction.
138         data = 0;
139         snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
140                            DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
141                            &data, sizeof(data), 0);
142
143         // Just after finishing the session, the device may lost transmitting
144         // functionality for a short time.
145         msleep(50);
146 }
147
148 static int begin_session(struct snd_dg00x *dg00x)
149 {
150         __be32 data;
151         u32 curr;
152         int err;
153
154         // Register isochronous channels for both direction.
155         data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
156                            dg00x->rx_resources.channel);
157         err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
158                                  DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
159                                  &data, sizeof(data), 0);
160         if (err < 0)
161                 return err;
162
163         err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
164                                  DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
165                                  &data, sizeof(data), 0);
166         if (err < 0)
167                 return err;
168         curr = be32_to_cpu(data);
169
170         if (curr == 0)
171                 curr = 2;
172
173         curr--;
174         while (curr > 0) {
175                 data = cpu_to_be32(curr);
176                 err = snd_fw_transaction(dg00x->unit,
177                                          TCODE_WRITE_QUADLET_REQUEST,
178                                          DG00X_ADDR_BASE +
179                                          DG00X_OFFSET_STREAMING_SET,
180                                          &data, sizeof(data), 0);
181                 if (err < 0)
182                         break;
183
184                 msleep(20);
185                 curr--;
186         }
187
188         return err;
189 }
190
191 static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
192                           unsigned int rate)
193 {
194         struct fw_iso_resources *resources;
195         int i;
196         int err;
197
198         // Check sampling rate.
199         for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
200                 if (snd_dg00x_stream_rates[i] == rate)
201                         break;
202         }
203         if (i == SND_DG00X_RATE_COUNT)
204                 return -EINVAL;
205
206         if (stream == &dg00x->tx_stream)
207                 resources = &dg00x->tx_resources;
208         else
209                 resources = &dg00x->rx_resources;
210
211         err = amdtp_dot_set_parameters(stream, rate,
212                                        snd_dg00x_stream_pcm_channels[i]);
213         if (err < 0)
214                 return err;
215
216         return fw_iso_resources_allocate(resources,
217                                 amdtp_stream_get_max_payload(stream),
218                                 fw_parent_device(dg00x->unit)->max_speed);
219 }
220
221 int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
222 {
223         int err;
224
225         /* For out-stream. */
226         err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit);
227         if (err < 0)
228                 goto error;
229         err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM);
230         if (err < 0)
231                 goto error;
232
233         /* For in-stream. */
234         err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit);
235         if (err < 0)
236                 goto error;
237         err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM);
238         if (err < 0)
239                 goto error;
240
241         return 0;
242 error:
243         snd_dg00x_stream_destroy_duplex(dg00x);
244         return err;
245 }
246
247 /*
248  * This function should be called before starting streams or after stopping
249  * streams.
250  */
251 void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
252 {
253         amdtp_stream_destroy(&dg00x->rx_stream);
254         fw_iso_resources_destroy(&dg00x->rx_resources);
255
256         amdtp_stream_destroy(&dg00x->tx_stream);
257         fw_iso_resources_destroy(&dg00x->tx_resources);
258 }
259
260 int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
261 {
262         unsigned int curr_rate;
263         int err;
264
265         err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
266         if (err < 0)
267                 return err;
268         if (rate == 0)
269                 rate = curr_rate;
270
271         if (dg00x->substreams_counter == 0 || curr_rate != rate) {
272                 finish_session(dg00x);
273
274                 fw_iso_resources_free(&dg00x->tx_resources);
275                 fw_iso_resources_free(&dg00x->rx_resources);
276
277                 err = snd_dg00x_stream_set_local_rate(dg00x, rate);
278                 if (err < 0)
279                         return err;
280
281                 err = keep_resources(dg00x, &dg00x->rx_stream, rate);
282                 if (err < 0)
283                         return err;
284
285                 err = keep_resources(dg00x, &dg00x->tx_stream, rate);
286                 if (err < 0) {
287                         fw_iso_resources_free(&dg00x->rx_resources);
288                         return err;
289                 }
290         }
291
292         return 0;
293 }
294
295 int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
296 {
297         unsigned int generation = dg00x->rx_resources.generation;
298         int err = 0;
299
300         if (dg00x->substreams_counter == 0)
301                 return 0;
302
303         if (amdtp_streaming_error(&dg00x->tx_stream) ||
304             amdtp_streaming_error(&dg00x->rx_stream))
305                 finish_session(dg00x);
306
307         if (generation != fw_parent_device(dg00x->unit)->card->generation) {
308                 err = fw_iso_resources_update(&dg00x->tx_resources);
309                 if (err < 0)
310                         goto error;
311
312                 err = fw_iso_resources_update(&dg00x->rx_resources);
313                 if (err < 0)
314                         goto error;
315         }
316
317         /*
318          * No packets are transmitted without receiving packets, reagardless of
319          * which source of clock is used.
320          */
321         if (!amdtp_stream_running(&dg00x->rx_stream)) {
322                 err = begin_session(dg00x);
323                 if (err < 0)
324                         goto error;
325
326                 err = amdtp_stream_start(&dg00x->rx_stream,
327                                 dg00x->rx_resources.channel,
328                                 fw_parent_device(dg00x->unit)->max_speed);
329                 if (err < 0)
330                         goto error;
331
332                 if (!amdtp_stream_wait_callback(&dg00x->rx_stream,
333                                               CALLBACK_TIMEOUT)) {
334                         err = -ETIMEDOUT;
335                         goto error;
336                 }
337         }
338
339         /*
340          * The value of SYT field in transmitted packets is always 0x0000. Thus,
341          * duplex streams with timestamp synchronization cannot be built.
342          */
343         if (!amdtp_stream_running(&dg00x->tx_stream)) {
344                 err = amdtp_stream_start(&dg00x->tx_stream,
345                                 dg00x->tx_resources.channel,
346                                 fw_parent_device(dg00x->unit)->max_speed);
347                 if (err < 0)
348                         goto error;
349
350                 if (!amdtp_stream_wait_callback(&dg00x->tx_stream,
351                                               CALLBACK_TIMEOUT)) {
352                         err = -ETIMEDOUT;
353                         goto error;
354                 }
355         }
356
357         return 0;
358 error:
359         finish_session(dg00x);
360
361         return err;
362 }
363
364 void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
365 {
366         if (dg00x->substreams_counter == 0) {
367                 finish_session(dg00x);
368
369                 fw_iso_resources_free(&dg00x->tx_resources);
370                 fw_iso_resources_free(&dg00x->rx_resources);
371         }
372 }
373
374 void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
375 {
376         fw_iso_resources_update(&dg00x->tx_resources);
377         fw_iso_resources_update(&dg00x->rx_resources);
378
379         amdtp_stream_update(&dg00x->tx_stream);
380         amdtp_stream_update(&dg00x->rx_stream);
381 }
382
383 void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
384 {
385         dg00x->dev_lock_changed = true;
386         wake_up(&dg00x->hwdep_wait);
387 }
388
389 int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
390 {
391         int err;
392
393         spin_lock_irq(&dg00x->lock);
394
395         /* user land lock this */
396         if (dg00x->dev_lock_count < 0) {
397                 err = -EBUSY;
398                 goto end;
399         }
400
401         /* this is the first time */
402         if (dg00x->dev_lock_count++ == 0)
403                 snd_dg00x_stream_lock_changed(dg00x);
404         err = 0;
405 end:
406         spin_unlock_irq(&dg00x->lock);
407         return err;
408 }
409
410 void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
411 {
412         spin_lock_irq(&dg00x->lock);
413
414         if (WARN_ON(dg00x->dev_lock_count <= 0))
415                 goto end;
416         if (--dg00x->dev_lock_count == 0)
417                 snd_dg00x_stream_lock_changed(dg00x);
418 end:
419         spin_unlock_irq(&dg00x->lock);
420 }