1
2
3
4
5
6
7
8
9#include "dice.h"
10
11#define CALLBACK_TIMEOUT 200
12#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC)
13
14struct reg_params {
15 unsigned int count;
16 unsigned int size;
17};
18
19const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
20
21 [0] = 32000,
22 [1] = 44100,
23 [2] = 48000,
24
25 [3] = 88200,
26 [4] = 96000,
27
28 [5] = 176400,
29 [6] = 192000,
30};
31
32int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
33 enum snd_dice_rate_mode *mode)
34{
35
36 static const enum snd_dice_rate_mode modes[] = {
37 [0] = SND_DICE_RATE_MODE_LOW,
38 [1] = SND_DICE_RATE_MODE_LOW,
39 [2] = SND_DICE_RATE_MODE_LOW,
40 [3] = SND_DICE_RATE_MODE_MIDDLE,
41 [4] = SND_DICE_RATE_MODE_MIDDLE,
42 [5] = SND_DICE_RATE_MODE_HIGH,
43 [6] = SND_DICE_RATE_MODE_HIGH,
44 };
45 int i;
46
47 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
48 if (!(dice->clock_caps & BIT(i)))
49 continue;
50 if (snd_dice_rates[i] != rate)
51 continue;
52
53 *mode = modes[i];
54 return 0;
55 }
56
57 return -EINVAL;
58}
59
60
61
62
63
64static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate)
65{
66 __be32 reg, nominal;
67 u32 data;
68 int i;
69 int err;
70
71 err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
72 ®, sizeof(reg));
73 if (err < 0)
74 return err;
75
76 data = be32_to_cpu(reg);
77
78 data &= ~CLOCK_RATE_MASK;
79 for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
80 if (snd_dice_rates[i] == rate)
81 break;
82 }
83 if (i == ARRAY_SIZE(snd_dice_rates))
84 return -EINVAL;
85 data |= i << CLOCK_RATE_SHIFT;
86
87 if (completion_done(&dice->clock_accepted))
88 reinit_completion(&dice->clock_accepted);
89
90 reg = cpu_to_be32(data);
91 err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
92 ®, sizeof(reg));
93 if (err < 0)
94 return err;
95
96 if (wait_for_completion_timeout(&dice->clock_accepted,
97 msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
98
99
100
101
102
103 err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS,
104 &nominal, sizeof(nominal));
105 if (err < 0)
106 return err;
107 if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED))
108 return -ETIMEDOUT;
109 }
110
111 return 0;
112}
113
114static int get_register_params(struct snd_dice *dice,
115 struct reg_params *tx_params,
116 struct reg_params *rx_params)
117{
118 __be32 reg[2];
119 int err;
120
121 err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
122 if (err < 0)
123 return err;
124 tx_params->count =
125 min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
126 tx_params->size = be32_to_cpu(reg[1]) * 4;
127
128 err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
129 if (err < 0)
130 return err;
131 rx_params->count =
132 min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
133 rx_params->size = be32_to_cpu(reg[1]) * 4;
134
135 return 0;
136}
137
138static void release_resources(struct snd_dice *dice)
139{
140 int i;
141
142 for (i = 0; i < MAX_STREAMS; ++i) {
143 fw_iso_resources_free(&dice->tx_resources[i]);
144 fw_iso_resources_free(&dice->rx_resources[i]);
145 }
146}
147
148static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
149 struct reg_params *params)
150{
151 __be32 reg;
152 unsigned int i;
153
154 for (i = 0; i < params->count; i++) {
155 reg = cpu_to_be32((u32)-1);
156 if (dir == AMDTP_IN_STREAM) {
157 snd_dice_transaction_write_tx(dice,
158 params->size * i + TX_ISOCHRONOUS,
159 ®, sizeof(reg));
160 } else {
161 snd_dice_transaction_write_rx(dice,
162 params->size * i + RX_ISOCHRONOUS,
163 ®, sizeof(reg));
164 }
165 }
166}
167
168static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
169 struct fw_iso_resources *resources, unsigned int rate,
170 unsigned int pcm_chs, unsigned int midi_ports)
171{
172 bool double_pcm_frames;
173 unsigned int i;
174 int err;
175
176
177
178
179
180
181
182
183
184 double_pcm_frames = rate > 96000;
185 if (double_pcm_frames) {
186 rate /= 2;
187 pcm_chs *= 2;
188 }
189
190 err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
191 double_pcm_frames);
192 if (err < 0)
193 return err;
194
195 if (double_pcm_frames) {
196 pcm_chs /= 2;
197
198 for (i = 0; i < pcm_chs; i++) {
199 amdtp_am824_set_pcm_position(stream, i, i * 2);
200 amdtp_am824_set_pcm_position(stream, i + pcm_chs,
201 i * 2 + 1);
202 }
203 }
204
205 return fw_iso_resources_allocate(resources,
206 amdtp_stream_get_max_payload(stream),
207 fw_parent_device(dice->unit)->max_speed);
208}
209
210static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
211 enum amdtp_stream_direction dir,
212 struct reg_params *params)
213{
214 enum snd_dice_rate_mode mode;
215 int i;
216 int err;
217
218 err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
219 if (err < 0)
220 return err;
221
222 for (i = 0; i < params->count; ++i) {
223 __be32 reg[2];
224 struct amdtp_stream *stream;
225 struct fw_iso_resources *resources;
226 unsigned int pcm_cache;
227 unsigned int pcm_chs;
228 unsigned int midi_ports;
229
230 if (dir == AMDTP_IN_STREAM) {
231 stream = &dice->tx_stream[i];
232 resources = &dice->tx_resources[i];
233
234 pcm_cache = dice->tx_pcm_chs[i][mode];
235 err = snd_dice_transaction_read_tx(dice,
236 params->size * i + TX_NUMBER_AUDIO,
237 reg, sizeof(reg));
238 } else {
239 stream = &dice->rx_stream[i];
240 resources = &dice->rx_resources[i];
241
242 pcm_cache = dice->rx_pcm_chs[i][mode];
243 err = snd_dice_transaction_read_rx(dice,
244 params->size * i + RX_NUMBER_AUDIO,
245 reg, sizeof(reg));
246 }
247 if (err < 0)
248 return err;
249 pcm_chs = be32_to_cpu(reg[0]);
250 midi_ports = be32_to_cpu(reg[1]);
251
252
253 if (pcm_chs != pcm_cache) {
254 dev_info(&dice->unit->device,
255 "cache mismatch: pcm: %u:%u, midi: %u\n",
256 pcm_chs, pcm_cache, midi_ports);
257 return -EPROTO;
258 }
259
260 err = keep_resources(dice, stream, resources, rate, pcm_chs,
261 midi_ports);
262 if (err < 0)
263 return err;
264 }
265
266 return 0;
267}
268
269static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
270 struct reg_params *rx_params)
271{
272 stop_streams(dice, AMDTP_IN_STREAM, tx_params);
273 stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
274
275 snd_dice_transaction_clear_enable(dice);
276}
277
278int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate,
279 unsigned int events_per_period,
280 unsigned int events_per_buffer)
281{
282 unsigned int curr_rate;
283 int err;
284
285
286 err = snd_dice_transaction_get_rate(dice, &curr_rate);
287 if (err < 0)
288 return err;
289 if (rate == 0)
290 rate = curr_rate;
291
292 if (dice->substreams_counter == 0 || curr_rate != rate) {
293 struct reg_params tx_params, rx_params;
294
295 amdtp_domain_stop(&dice->domain);
296
297 err = get_register_params(dice, &tx_params, &rx_params);
298 if (err < 0)
299 return err;
300 finish_session(dice, &tx_params, &rx_params);
301
302 release_resources(dice);
303
304
305
306
307 err = ensure_phase_lock(dice, rate);
308 if (err < 0)
309 return err;
310
311
312
313 err = get_register_params(dice, &tx_params, &rx_params);
314 if (err < 0)
315 return err;
316
317 err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
318 &tx_params);
319 if (err < 0)
320 goto error;
321
322 err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
323 &rx_params);
324 if (err < 0)
325 goto error;
326
327 err = amdtp_domain_set_events_per_period(&dice->domain,
328 events_per_period, events_per_buffer);
329 if (err < 0)
330 goto error;
331 }
332
333 return 0;
334error:
335 release_resources(dice);
336 return err;
337}
338
339static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
340 unsigned int rate, struct reg_params *params)
341{
342 unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
343 int i;
344 int err;
345
346 for (i = 0; i < params->count; i++) {
347 struct amdtp_stream *stream;
348 struct fw_iso_resources *resources;
349 __be32 reg;
350
351 if (dir == AMDTP_IN_STREAM) {
352 stream = dice->tx_stream + i;
353 resources = dice->tx_resources + i;
354 } else {
355 stream = dice->rx_stream + i;
356 resources = dice->rx_resources + i;
357 }
358
359 reg = cpu_to_be32(resources->channel);
360 if (dir == AMDTP_IN_STREAM) {
361 err = snd_dice_transaction_write_tx(dice,
362 params->size * i + TX_ISOCHRONOUS,
363 ®, sizeof(reg));
364 } else {
365 err = snd_dice_transaction_write_rx(dice,
366 params->size * i + RX_ISOCHRONOUS,
367 ®, sizeof(reg));
368 }
369 if (err < 0)
370 return err;
371
372 if (dir == AMDTP_IN_STREAM) {
373 reg = cpu_to_be32(max_speed);
374 err = snd_dice_transaction_write_tx(dice,
375 params->size * i + TX_SPEED,
376 ®, sizeof(reg));
377 if (err < 0)
378 return err;
379 }
380
381 err = amdtp_domain_add_stream(&dice->domain, stream,
382 resources->channel, max_speed);
383 if (err < 0)
384 return err;
385 }
386
387 return 0;
388}
389
390
391
392
393
394
395int snd_dice_stream_start_duplex(struct snd_dice *dice)
396{
397 unsigned int generation = dice->rx_resources[0].generation;
398 struct reg_params tx_params, rx_params;
399 unsigned int i;
400 unsigned int rate;
401 enum snd_dice_rate_mode mode;
402 int err;
403
404 if (dice->substreams_counter == 0)
405 return -EIO;
406
407 err = get_register_params(dice, &tx_params, &rx_params);
408 if (err < 0)
409 return err;
410
411
412 for (i = 0; i < MAX_STREAMS; ++i) {
413 if (amdtp_streaming_error(&dice->tx_stream[i]) ||
414 amdtp_streaming_error(&dice->rx_stream[i])) {
415 amdtp_domain_stop(&dice->domain);
416 finish_session(dice, &tx_params, &rx_params);
417 break;
418 }
419 }
420
421 if (generation != fw_parent_device(dice->unit)->card->generation) {
422 for (i = 0; i < MAX_STREAMS; ++i) {
423 if (i < tx_params.count)
424 fw_iso_resources_update(dice->tx_resources + i);
425 if (i < rx_params.count)
426 fw_iso_resources_update(dice->rx_resources + i);
427 }
428 }
429
430
431 err = snd_dice_transaction_get_rate(dice, &rate);
432 if (err < 0)
433 return err;
434 err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
435 if (err < 0)
436 return err;
437 for (i = 0; i < MAX_STREAMS; ++i) {
438 if (dice->tx_pcm_chs[i][mode] > 0 &&
439 !amdtp_stream_running(&dice->tx_stream[i]))
440 break;
441 if (dice->rx_pcm_chs[i][mode] > 0 &&
442 !amdtp_stream_running(&dice->rx_stream[i]))
443 break;
444 }
445 if (i < MAX_STREAMS) {
446
447 err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
448 if (err < 0)
449 goto error;
450
451 err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
452 if (err < 0)
453 goto error;
454
455 err = snd_dice_transaction_set_enable(dice);
456 if (err < 0) {
457 dev_err(&dice->unit->device,
458 "fail to enable interface\n");
459 goto error;
460 }
461
462 err = amdtp_domain_start(&dice->domain, 0);
463 if (err < 0)
464 goto error;
465
466 for (i = 0; i < MAX_STREAMS; i++) {
467 if ((i < tx_params.count &&
468 !amdtp_stream_wait_callback(&dice->tx_stream[i],
469 CALLBACK_TIMEOUT)) ||
470 (i < rx_params.count &&
471 !amdtp_stream_wait_callback(&dice->rx_stream[i],
472 CALLBACK_TIMEOUT))) {
473 err = -ETIMEDOUT;
474 goto error;
475 }
476 }
477 }
478
479 return 0;
480error:
481 amdtp_domain_stop(&dice->domain);
482 finish_session(dice, &tx_params, &rx_params);
483 return err;
484}
485
486
487
488
489
490
491void snd_dice_stream_stop_duplex(struct snd_dice *dice)
492{
493 struct reg_params tx_params, rx_params;
494
495 if (dice->substreams_counter == 0) {
496 if (get_register_params(dice, &tx_params, &rx_params) >= 0) {
497 amdtp_domain_stop(&dice->domain);
498 finish_session(dice, &tx_params, &rx_params);
499 }
500
501 release_resources(dice);
502 }
503}
504
505static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
506 unsigned int index)
507{
508 struct amdtp_stream *stream;
509 struct fw_iso_resources *resources;
510 int err;
511
512 if (dir == AMDTP_IN_STREAM) {
513 stream = &dice->tx_stream[index];
514 resources = &dice->tx_resources[index];
515 } else {
516 stream = &dice->rx_stream[index];
517 resources = &dice->rx_resources[index];
518 }
519
520 err = fw_iso_resources_init(resources, dice->unit);
521 if (err < 0)
522 goto end;
523 resources->channels_mask = 0x00000000ffffffffuLL;
524
525 err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
526 if (err < 0) {
527 amdtp_stream_destroy(stream);
528 fw_iso_resources_destroy(resources);
529 }
530end:
531 return err;
532}
533
534
535
536
537
538static void destroy_stream(struct snd_dice *dice,
539 enum amdtp_stream_direction dir,
540 unsigned int index)
541{
542 struct amdtp_stream *stream;
543 struct fw_iso_resources *resources;
544
545 if (dir == AMDTP_IN_STREAM) {
546 stream = &dice->tx_stream[index];
547 resources = &dice->tx_resources[index];
548 } else {
549 stream = &dice->rx_stream[index];
550 resources = &dice->rx_resources[index];
551 }
552
553 amdtp_stream_destroy(stream);
554 fw_iso_resources_destroy(resources);
555}
556
557int snd_dice_stream_init_duplex(struct snd_dice *dice)
558{
559 int i, err;
560
561 for (i = 0; i < MAX_STREAMS; i++) {
562 err = init_stream(dice, AMDTP_IN_STREAM, i);
563 if (err < 0) {
564 for (; i >= 0; i--)
565 destroy_stream(dice, AMDTP_IN_STREAM, i);
566 goto end;
567 }
568 }
569
570 for (i = 0; i < MAX_STREAMS; i++) {
571 err = init_stream(dice, AMDTP_OUT_STREAM, i);
572 if (err < 0) {
573 for (; i >= 0; i--)
574 destroy_stream(dice, AMDTP_OUT_STREAM, i);
575 for (i = 0; i < MAX_STREAMS; i++)
576 destroy_stream(dice, AMDTP_IN_STREAM, i);
577 goto end;
578 }
579 }
580
581 err = amdtp_domain_init(&dice->domain);
582 if (err < 0) {
583 for (i = 0; i < MAX_STREAMS; ++i) {
584 destroy_stream(dice, AMDTP_OUT_STREAM, i);
585 destroy_stream(dice, AMDTP_IN_STREAM, i);
586 }
587 }
588end:
589 return err;
590}
591
592void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
593{
594 unsigned int i;
595
596 for (i = 0; i < MAX_STREAMS; i++) {
597 destroy_stream(dice, AMDTP_IN_STREAM, i);
598 destroy_stream(dice, AMDTP_OUT_STREAM, i);
599 }
600
601 amdtp_domain_destroy(&dice->domain);
602}
603
604void snd_dice_stream_update_duplex(struct snd_dice *dice)
605{
606 struct reg_params tx_params, rx_params;
607
608
609
610
611
612
613
614
615
616 dice->global_enabled = false;
617
618 if (get_register_params(dice, &tx_params, &rx_params) == 0) {
619 amdtp_domain_stop(&dice->domain);
620
621 stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
622 stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
623 }
624}
625
626int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
627{
628 unsigned int rate;
629 enum snd_dice_rate_mode mode;
630 __be32 reg[2];
631 struct reg_params tx_params, rx_params;
632 int i;
633 int err;
634
635
636 err = snd_dice_detect_extension_formats(dice);
637 if (err >= 0)
638 return err;
639
640
641
642
643
644 err = snd_dice_transaction_get_rate(dice, &rate);
645 if (err < 0)
646 return err;
647
648 err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
649 if (err < 0)
650 return err;
651
652
653
654
655
656
657 err = ensure_phase_lock(dice, rate);
658 if (err < 0)
659 return err;
660
661 err = get_register_params(dice, &tx_params, &rx_params);
662 if (err < 0)
663 return err;
664
665 for (i = 0; i < tx_params.count; ++i) {
666 err = snd_dice_transaction_read_tx(dice,
667 tx_params.size * i + TX_NUMBER_AUDIO,
668 reg, sizeof(reg));
669 if (err < 0)
670 return err;
671 dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
672 dice->tx_midi_ports[i] = max_t(unsigned int,
673 be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
674 }
675 for (i = 0; i < rx_params.count; ++i) {
676 err = snd_dice_transaction_read_rx(dice,
677 rx_params.size * i + RX_NUMBER_AUDIO,
678 reg, sizeof(reg));
679 if (err < 0)
680 return err;
681 dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
682 dice->rx_midi_ports[i] = max_t(unsigned int,
683 be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
684 }
685
686 return 0;
687}
688
689static void dice_lock_changed(struct snd_dice *dice)
690{
691 dice->dev_lock_changed = true;
692 wake_up(&dice->hwdep_wait);
693}
694
695int snd_dice_stream_lock_try(struct snd_dice *dice)
696{
697 int err;
698
699 spin_lock_irq(&dice->lock);
700
701 if (dice->dev_lock_count < 0) {
702 err = -EBUSY;
703 goto out;
704 }
705
706 if (dice->dev_lock_count++ == 0)
707 dice_lock_changed(dice);
708 err = 0;
709out:
710 spin_unlock_irq(&dice->lock);
711 return err;
712}
713
714void snd_dice_stream_lock_release(struct snd_dice *dice)
715{
716 spin_lock_irq(&dice->lock);
717
718 if (WARN_ON(dice->dev_lock_count <= 0))
719 goto out;
720
721 if (--dice->dev_lock_count == 0)
722 dice_lock_changed(dice);
723out:
724 spin_unlock_irq(&dice->lock);
725}
726