forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/sound/firewire/tascam/tascam-stream.c
....@@ -1,9 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * tascam-stream.c - a part of driver for TASCAM FireWire series
34 *
45 * Copyright (c) 2015 Takashi Sakamoto
5
- *
6
- * Licensed under the terms of the GNU General Public License, version 2.
76 */
87
98 #include <linux/delay.h>
....@@ -180,7 +179,7 @@
180179 __be32 reg;
181180 int err;
182181
183
- /* Set an option for unknown purpose. */
182
+ // Set an option for unknown purpose.
184183 reg = cpu_to_be32(0x00200000);
185184 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
186185 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
....@@ -188,11 +187,7 @@
188187 if (err < 0)
189188 return err;
190189
191
- err = enable_data_channels(tscm);
192
- if (err < 0)
193
- return err;
194
-
195
- return set_clock(tscm, rate, INT_MAX);
190
+ return enable_data_channels(tscm);
196191 }
197192
198193 static void finish_session(struct snd_tscm *tscm)
....@@ -209,12 +204,49 @@
209204 TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_ON,
210205 &reg, sizeof(reg), 0);
211206
207
+ // Unregister channels.
208
+ reg = cpu_to_be32(0x00000000);
209
+ snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
210
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
211
+ &reg, sizeof(reg), 0);
212
+ reg = cpu_to_be32(0x00000000);
213
+ snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
214
+ TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
215
+ &reg, sizeof(reg), 0);
216
+ reg = cpu_to_be32(0x00000000);
217
+ snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
218
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
219
+ &reg, sizeof(reg), 0);
212220 }
213221
214222 static int begin_session(struct snd_tscm *tscm)
215223 {
216224 __be32 reg;
217225 int err;
226
+
227
+ // Register the isochronous channel for transmitting stream.
228
+ reg = cpu_to_be32(tscm->tx_resources.channel);
229
+ err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
230
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
231
+ &reg, sizeof(reg), 0);
232
+ if (err < 0)
233
+ return err;
234
+
235
+ // Unknown.
236
+ reg = cpu_to_be32(0x00000002);
237
+ err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
238
+ TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
239
+ &reg, sizeof(reg), 0);
240
+ if (err < 0)
241
+ return err;
242
+
243
+ // Register the isochronous channel for receiving stream.
244
+ reg = cpu_to_be32(tscm->rx_resources.channel);
245
+ err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
246
+ TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
247
+ &reg, sizeof(reg), 0);
248
+ if (err < 0)
249
+ return err;
218250
219251 reg = cpu_to_be32(0x00000001);
220252 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
....@@ -230,7 +262,7 @@
230262 if (err < 0)
231263 return err;
232264
233
- /* Set an option for unknown purpose. */
265
+ // Set an option for unknown purpose.
234266 reg = cpu_to_be32(0x00002000);
235267 err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
236268 TSCM_ADDR_BASE + TSCM_OFFSET_SET_OPTION,
....@@ -238,7 +270,7 @@
238270 if (err < 0)
239271 return err;
240272
241
- /* Start multiplexing PCM samples on packets. */
273
+ // Start multiplexing PCM samples on packets.
242274 reg = cpu_to_be32(0x00000001);
243275 return snd_fw_transaction(tscm->unit,
244276 TCODE_WRITE_QUADLET_REQUEST,
....@@ -246,169 +278,182 @@
246278 &reg, sizeof(reg), 0);
247279 }
248280
249
-static void release_resources(struct snd_tscm *tscm)
281
+static int keep_resources(struct snd_tscm *tscm, unsigned int rate,
282
+ struct amdtp_stream *stream)
250283 {
251
- __be32 reg;
252
-
253
- /* Unregister channels. */
254
- reg = cpu_to_be32(0x00000000);
255
- snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
256
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
257
- &reg, sizeof(reg), 0);
258
- reg = cpu_to_be32(0x00000000);
259
- snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
260
- TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
261
- &reg, sizeof(reg), 0);
262
- reg = cpu_to_be32(0x00000000);
263
- snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
264
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
265
- &reg, sizeof(reg), 0);
266
-
267
- /* Release isochronous resources. */
268
- fw_iso_resources_free(&tscm->tx_resources);
269
- fw_iso_resources_free(&tscm->rx_resources);
270
-}
271
-
272
-static int keep_resources(struct snd_tscm *tscm, unsigned int rate)
273
-{
274
- __be32 reg;
284
+ struct fw_iso_resources *resources;
275285 int err;
276286
277
- /* Keep resources for in-stream. */
278
- err = amdtp_tscm_set_parameters(&tscm->tx_stream, rate);
279
- if (err < 0)
280
- return err;
281
- err = fw_iso_resources_allocate(&tscm->tx_resources,
282
- amdtp_stream_get_max_payload(&tscm->tx_stream),
283
- fw_parent_device(tscm->unit)->max_speed);
284
- if (err < 0)
285
- goto error;
287
+ if (stream == &tscm->tx_stream)
288
+ resources = &tscm->tx_resources;
289
+ else
290
+ resources = &tscm->rx_resources;
286291
287
- /* Keep resources for out-stream. */
288
- err = amdtp_tscm_set_parameters(&tscm->rx_stream, rate);
289
- if (err < 0)
290
- return err;
291
- err = fw_iso_resources_allocate(&tscm->rx_resources,
292
- amdtp_stream_get_max_payload(&tscm->rx_stream),
293
- fw_parent_device(tscm->unit)->max_speed);
292
+ err = amdtp_tscm_set_parameters(stream, rate);
294293 if (err < 0)
295294 return err;
296295
297
- /* Register the isochronous channel for transmitting stream. */
298
- reg = cpu_to_be32(tscm->tx_resources.channel);
299
- err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
300
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_TX_CH,
301
- &reg, sizeof(reg), 0);
302
- if (err < 0)
303
- goto error;
296
+ return fw_iso_resources_allocate(resources,
297
+ amdtp_stream_get_max_payload(stream),
298
+ fw_parent_device(tscm->unit)->max_speed);
299
+}
304300
305
- /* Unknown */
306
- reg = cpu_to_be32(0x00000002);
307
- err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
308
- TSCM_ADDR_BASE + TSCM_OFFSET_UNKNOWN,
309
- &reg, sizeof(reg), 0);
310
- if (err < 0)
311
- goto error;
301
+static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s)
302
+{
303
+ struct fw_iso_resources *resources;
304
+ enum amdtp_stream_direction dir;
305
+ unsigned int pcm_channels;
306
+ int err;
312307
313
- /* Register the isochronous channel for receiving stream. */
314
- reg = cpu_to_be32(tscm->rx_resources.channel);
315
- err = snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST,
316
- TSCM_ADDR_BASE + TSCM_OFFSET_ISOC_RX_CH,
317
- &reg, sizeof(reg), 0);
318
- if (err < 0)
319
- goto error;
308
+ if (s == &tscm->tx_stream) {
309
+ resources = &tscm->tx_resources;
310
+ dir = AMDTP_IN_STREAM;
311
+ pcm_channels = tscm->spec->pcm_capture_analog_channels;
312
+ } else {
313
+ resources = &tscm->rx_resources;
314
+ dir = AMDTP_OUT_STREAM;
315
+ pcm_channels = tscm->spec->pcm_playback_analog_channels;
316
+ }
320317
321
- return 0;
322
-error:
323
- release_resources(tscm);
318
+ if (tscm->spec->has_adat)
319
+ pcm_channels += 8;
320
+ if (tscm->spec->has_spdif)
321
+ pcm_channels += 2;
322
+
323
+ err = fw_iso_resources_init(resources, tscm->unit);
324
+ if (err < 0)
325
+ return err;
326
+
327
+ err = amdtp_tscm_init(s, tscm->unit, dir, pcm_channels);
328
+ if (err < 0)
329
+ fw_iso_resources_free(resources);
330
+
324331 return err;
332
+}
333
+
334
+static void destroy_stream(struct snd_tscm *tscm, struct amdtp_stream *s)
335
+{
336
+ amdtp_stream_destroy(s);
337
+
338
+ if (s == &tscm->tx_stream)
339
+ fw_iso_resources_destroy(&tscm->tx_resources);
340
+ else
341
+ fw_iso_resources_destroy(&tscm->rx_resources);
325342 }
326343
327344 int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
328345 {
329
- unsigned int pcm_channels;
330346 int err;
331347
332
- /* For out-stream. */
333
- err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit);
334
- if (err < 0)
335
- return err;
336
- pcm_channels = tscm->spec->pcm_playback_analog_channels;
337
- if (tscm->spec->has_adat)
338
- pcm_channels += 8;
339
- if (tscm->spec->has_spdif)
340
- pcm_channels += 2;
341
- err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM,
342
- pcm_channels);
348
+ err = init_stream(tscm, &tscm->tx_stream);
343349 if (err < 0)
344350 return err;
345351
346
- /* For in-stream. */
347
- err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit);
348
- if (err < 0)
352
+ err = init_stream(tscm, &tscm->rx_stream);
353
+ if (err < 0) {
354
+ destroy_stream(tscm, &tscm->tx_stream);
349355 return err;
350
- pcm_channels = tscm->spec->pcm_capture_analog_channels;
351
- if (tscm->spec->has_adat)
352
- pcm_channels += 8;
353
- if (tscm->spec->has_spdif)
354
- pcm_channels += 2;
355
- err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM,
356
- pcm_channels);
357
- if (err < 0)
358
- amdtp_stream_destroy(&tscm->rx_stream);
356
+ }
357
+
358
+ err = amdtp_domain_init(&tscm->domain);
359
+ if (err < 0) {
360
+ destroy_stream(tscm, &tscm->tx_stream);
361
+ destroy_stream(tscm, &tscm->rx_stream);
362
+ }
359363
360364 return err;
361365 }
362366
363
-/* At bus reset, streaming is stopped and some registers are clear. */
367
+// At bus reset, streaming is stopped and some registers are clear.
364368 void snd_tscm_stream_update_duplex(struct snd_tscm *tscm)
365369 {
366
- amdtp_stream_pcm_abort(&tscm->tx_stream);
367
- amdtp_stream_stop(&tscm->tx_stream);
370
+ amdtp_domain_stop(&tscm->domain);
368371
372
+ amdtp_stream_pcm_abort(&tscm->tx_stream);
369373 amdtp_stream_pcm_abort(&tscm->rx_stream);
370
- amdtp_stream_stop(&tscm->rx_stream);
371374 }
372375
373
-/*
374
- * This function should be called before starting streams or after stopping
375
- * streams.
376
- */
376
+// This function should be called before starting streams or after stopping
377
+// streams.
377378 void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm)
378379 {
379
- amdtp_stream_destroy(&tscm->rx_stream);
380
- amdtp_stream_destroy(&tscm->tx_stream);
380
+ amdtp_domain_destroy(&tscm->domain);
381381
382
- fw_iso_resources_destroy(&tscm->rx_resources);
383
- fw_iso_resources_destroy(&tscm->tx_resources);
382
+ destroy_stream(tscm, &tscm->rx_stream);
383
+ destroy_stream(tscm, &tscm->tx_stream);
384
+}
385
+
386
+int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate,
387
+ unsigned int frames_per_period,
388
+ unsigned int frames_per_buffer)
389
+{
390
+ unsigned int curr_rate;
391
+ int err;
392
+
393
+ err = snd_tscm_stream_get_rate(tscm, &curr_rate);
394
+ if (err < 0)
395
+ return err;
396
+
397
+ if (tscm->substreams_counter == 0 || rate != curr_rate) {
398
+ amdtp_domain_stop(&tscm->domain);
399
+
400
+ finish_session(tscm);
401
+
402
+ fw_iso_resources_free(&tscm->tx_resources);
403
+ fw_iso_resources_free(&tscm->rx_resources);
404
+
405
+ err = set_clock(tscm, rate, INT_MAX);
406
+ if (err < 0)
407
+ return err;
408
+
409
+ err = keep_resources(tscm, rate, &tscm->tx_stream);
410
+ if (err < 0)
411
+ return err;
412
+
413
+ err = keep_resources(tscm, rate, &tscm->rx_stream);
414
+ if (err < 0) {
415
+ fw_iso_resources_free(&tscm->tx_resources);
416
+ return err;
417
+ }
418
+
419
+ err = amdtp_domain_set_events_per_period(&tscm->domain,
420
+ frames_per_period, frames_per_buffer);
421
+ if (err < 0) {
422
+ fw_iso_resources_free(&tscm->tx_resources);
423
+ fw_iso_resources_free(&tscm->rx_resources);
424
+ return err;
425
+ }
426
+ }
427
+
428
+ return 0;
384429 }
385430
386431 int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
387432 {
388
- unsigned int curr_rate;
433
+ unsigned int generation = tscm->rx_resources.generation;
389434 int err;
390435
391436 if (tscm->substreams_counter == 0)
392437 return 0;
393438
394
- err = snd_tscm_stream_get_rate(tscm, &curr_rate);
395
- if (err < 0)
396
- return err;
397
- if (curr_rate != rate ||
398
- amdtp_streaming_error(&tscm->rx_stream) ||
439
+ if (amdtp_streaming_error(&tscm->rx_stream) ||
399440 amdtp_streaming_error(&tscm->tx_stream)) {
441
+ amdtp_domain_stop(&tscm->domain);
400442 finish_session(tscm);
443
+ }
401444
402
- amdtp_stream_stop(&tscm->rx_stream);
403
- amdtp_stream_stop(&tscm->tx_stream);
445
+ if (generation != fw_parent_device(tscm->unit)->card->generation) {
446
+ err = fw_iso_resources_update(&tscm->tx_resources);
447
+ if (err < 0)
448
+ goto error;
404449
405
- release_resources(tscm);
450
+ err = fw_iso_resources_update(&tscm->rx_resources);
451
+ if (err < 0)
452
+ goto error;
406453 }
407454
408455 if (!amdtp_stream_running(&tscm->rx_stream)) {
409
- err = keep_resources(tscm, rate);
410
- if (err < 0)
411
- goto error;
456
+ int spd = fw_parent_device(tscm->unit)->max_speed;
412457
413458 err = set_stream_formats(tscm, rate);
414459 if (err < 0)
....@@ -418,27 +463,23 @@
418463 if (err < 0)
419464 goto error;
420465
421
- err = amdtp_stream_start(&tscm->rx_stream,
422
- tscm->rx_resources.channel,
423
- fw_parent_device(tscm->unit)->max_speed);
466
+ err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream,
467
+ tscm->rx_resources.channel, spd);
468
+ if (err < 0)
469
+ goto error;
470
+
471
+ err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream,
472
+ tscm->tx_resources.channel, spd);
473
+ if (err < 0)
474
+ goto error;
475
+
476
+ err = amdtp_domain_start(&tscm->domain, 0);
424477 if (err < 0)
425478 goto error;
426479
427480 if (!amdtp_stream_wait_callback(&tscm->rx_stream,
428
- CALLBACK_TIMEOUT)) {
429
- err = -ETIMEDOUT;
430
- goto error;
431
- }
432
- }
433
-
434
- if (!amdtp_stream_running(&tscm->tx_stream)) {
435
- err = amdtp_stream_start(&tscm->tx_stream,
436
- tscm->tx_resources.channel,
437
- fw_parent_device(tscm->unit)->max_speed);
438
- if (err < 0)
439
- goto error;
440
-
441
- if (!amdtp_stream_wait_callback(&tscm->tx_stream,
481
+ CALLBACK_TIMEOUT) ||
482
+ !amdtp_stream_wait_callback(&tscm->tx_stream,
442483 CALLBACK_TIMEOUT)) {
443484 err = -ETIMEDOUT;
444485 goto error;
....@@ -447,25 +488,21 @@
447488
448489 return 0;
449490 error:
450
- amdtp_stream_stop(&tscm->rx_stream);
451
- amdtp_stream_stop(&tscm->tx_stream);
452
-
491
+ amdtp_domain_stop(&tscm->domain);
453492 finish_session(tscm);
454
- release_resources(tscm);
455493
456494 return err;
457495 }
458496
459497 void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm)
460498 {
461
- if (tscm->substreams_counter > 0)
462
- return;
499
+ if (tscm->substreams_counter == 0) {
500
+ amdtp_domain_stop(&tscm->domain);
501
+ finish_session(tscm);
463502
464
- amdtp_stream_stop(&tscm->tx_stream);
465
- amdtp_stream_stop(&tscm->rx_stream);
466
-
467
- finish_session(tscm);
468
- release_resources(tscm);
503
+ fw_iso_resources_free(&tscm->tx_resources);
504
+ fw_iso_resources_free(&tscm->rx_resources);
505
+ }
469506 }
470507
471508 void snd_tscm_stream_lock_changed(struct snd_tscm *tscm)