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 amdtp_stream_stop(&dice->tx_stream[i]);
158
159 snd_dice_transaction_write_tx(dice,
160 params->size * i + TX_ISOCHRONOUS,
161 ®, sizeof(reg));
162 } else {
163 amdtp_stream_stop(&dice->rx_stream[i]);
164
165 snd_dice_transaction_write_rx(dice,
166 params->size * i + RX_ISOCHRONOUS,
167 ®, sizeof(reg));
168 }
169 }
170}
171
172static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream,
173 struct fw_iso_resources *resources, unsigned int rate,
174 unsigned int pcm_chs, unsigned int midi_ports)
175{
176 bool double_pcm_frames;
177 unsigned int i;
178 int err;
179
180
181
182
183
184
185
186
187
188 double_pcm_frames = rate > 96000;
189 if (double_pcm_frames) {
190 rate /= 2;
191 pcm_chs *= 2;
192 }
193
194 err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
195 double_pcm_frames);
196 if (err < 0)
197 return err;
198
199 if (double_pcm_frames) {
200 pcm_chs /= 2;
201
202 for (i = 0; i < pcm_chs; i++) {
203 amdtp_am824_set_pcm_position(stream, i, i * 2);
204 amdtp_am824_set_pcm_position(stream, i + pcm_chs,
205 i * 2 + 1);
206 }
207 }
208
209 return fw_iso_resources_allocate(resources,
210 amdtp_stream_get_max_payload(stream),
211 fw_parent_device(dice->unit)->max_speed);
212}
213
214static int keep_dual_resources(struct snd_dice *dice, unsigned int rate,
215 enum amdtp_stream_direction dir,
216 struct reg_params *params)
217{
218 enum snd_dice_rate_mode mode;
219 int i;
220 int err;
221
222 err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
223 if (err < 0)
224 return err;
225
226 for (i = 0; i < params->count; ++i) {
227 __be32 reg[2];
228 struct amdtp_stream *stream;
229 struct fw_iso_resources *resources;
230 unsigned int pcm_cache;
231 unsigned int midi_cache;
232 unsigned int pcm_chs;
233 unsigned int midi_ports;
234
235 if (dir == AMDTP_IN_STREAM) {
236 stream = &dice->tx_stream[i];
237 resources = &dice->tx_resources[i];
238
239 pcm_cache = dice->tx_pcm_chs[i][mode];
240 midi_cache = dice->tx_midi_ports[i];
241 err = snd_dice_transaction_read_tx(dice,
242 params->size * i + TX_NUMBER_AUDIO,
243 reg, sizeof(reg));
244 } else {
245 stream = &dice->rx_stream[i];
246 resources = &dice->rx_resources[i];
247
248 pcm_cache = dice->rx_pcm_chs[i][mode];
249 midi_cache = dice->rx_midi_ports[i];
250 err = snd_dice_transaction_read_rx(dice,
251 params->size * i + RX_NUMBER_AUDIO,
252 reg, sizeof(reg));
253 }
254 if (err < 0)
255 return err;
256 pcm_chs = be32_to_cpu(reg[0]);
257 midi_ports = be32_to_cpu(reg[1]);
258
259
260 if (pcm_chs != pcm_cache || midi_ports != midi_cache) {
261 dev_info(&dice->unit->device,
262 "cache mismatch: pcm: %u:%u, midi: %u:%u\n",
263 pcm_chs, pcm_cache, midi_ports, midi_cache);
264 return -EPROTO;
265 }
266
267 err = keep_resources(dice, stream, resources, rate, pcm_chs,
268 midi_ports);
269 if (err < 0)
270 return err;
271 }
272
273 return 0;
274}
275
276static void finish_session(struct snd_dice *dice, struct reg_params *tx_params,
277 struct reg_params *rx_params)
278{
279 stop_streams(dice, AMDTP_IN_STREAM, tx_params);
280 stop_streams(dice, AMDTP_OUT_STREAM, rx_params);
281
282 snd_dice_transaction_clear_enable(dice);
283}
284
285int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate)
286{
287 unsigned int curr_rate;
288 int err;
289
290
291 err = snd_dice_transaction_get_rate(dice, &curr_rate);
292 if (err < 0)
293 return err;
294 if (rate == 0)
295 rate = curr_rate;
296
297 if (dice->substreams_counter == 0 || curr_rate != rate) {
298 struct reg_params tx_params, rx_params;
299
300 err = get_register_params(dice, &tx_params, &rx_params);
301 if (err < 0)
302 return err;
303
304 finish_session(dice, &tx_params, &rx_params);
305
306 release_resources(dice);
307
308
309
310
311 err = ensure_phase_lock(dice, rate);
312 if (err < 0)
313 return err;
314
315
316
317 err = get_register_params(dice, &tx_params, &rx_params);
318 if (err < 0)
319 return err;
320
321 err = keep_dual_resources(dice, rate, AMDTP_IN_STREAM,
322 &tx_params);
323 if (err < 0)
324 goto error;
325
326 err = keep_dual_resources(dice, rate, AMDTP_OUT_STREAM,
327 &rx_params);
328 if (err < 0)
329 goto error;
330 }
331
332 return 0;
333error:
334 release_resources(dice);
335 return err;
336}
337
338static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
339 unsigned int rate, struct reg_params *params)
340{
341 unsigned int max_speed = fw_parent_device(dice->unit)->max_speed;
342 int i;
343 int err;
344
345 for (i = 0; i < params->count; i++) {
346 struct amdtp_stream *stream;
347 struct fw_iso_resources *resources;
348 __be32 reg;
349
350 if (dir == AMDTP_IN_STREAM) {
351 stream = dice->tx_stream + i;
352 resources = dice->tx_resources + i;
353 } else {
354 stream = dice->rx_stream + i;
355 resources = dice->rx_resources + i;
356 }
357
358 reg = cpu_to_be32(resources->channel);
359 if (dir == AMDTP_IN_STREAM) {
360 err = snd_dice_transaction_write_tx(dice,
361 params->size * i + TX_ISOCHRONOUS,
362 ®, sizeof(reg));
363 } else {
364 err = snd_dice_transaction_write_rx(dice,
365 params->size * i + RX_ISOCHRONOUS,
366 ®, sizeof(reg));
367 }
368 if (err < 0)
369 return err;
370
371 if (dir == AMDTP_IN_STREAM) {
372 reg = cpu_to_be32(max_speed);
373 err = snd_dice_transaction_write_tx(dice,
374 params->size * i + TX_SPEED,
375 ®, sizeof(reg));
376 if (err < 0)
377 return err;
378 }
379
380 err = amdtp_stream_start(stream, resources->channel, max_speed);
381 if (err < 0)
382 return err;
383 }
384
385 return 0;
386}
387
388
389
390
391
392
393int snd_dice_stream_start_duplex(struct snd_dice *dice)
394{
395 unsigned int generation = dice->rx_resources[0].generation;
396 struct reg_params tx_params, rx_params;
397 unsigned int i;
398 unsigned int rate;
399 enum snd_dice_rate_mode mode;
400 int err;
401
402 if (dice->substreams_counter == 0)
403 return -EIO;
404
405 err = get_register_params(dice, &tx_params, &rx_params);
406 if (err < 0)
407 return err;
408
409
410 for (i = 0; i < MAX_STREAMS; ++i) {
411 if (amdtp_streaming_error(&dice->tx_stream[i]) ||
412 amdtp_streaming_error(&dice->rx_stream[i])) {
413 finish_session(dice, &tx_params, &rx_params);
414 break;
415 }
416 }
417
418 if (generation != fw_parent_device(dice->unit)->card->generation) {
419 for (i = 0; i < MAX_STREAMS; ++i) {
420 if (i < tx_params.count)
421 fw_iso_resources_update(dice->tx_resources + i);
422 if (i < rx_params.count)
423 fw_iso_resources_update(dice->rx_resources + i);
424 }
425 }
426
427
428 err = snd_dice_transaction_get_rate(dice, &rate);
429 if (err < 0)
430 return err;
431 err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
432 if (err < 0)
433 return err;
434 for (i = 0; i < MAX_STREAMS; ++i) {
435 if (dice->tx_pcm_chs[i][mode] > 0 &&
436 !amdtp_stream_running(&dice->tx_stream[i]))
437 break;
438 if (dice->rx_pcm_chs[i][mode] > 0 &&
439 !amdtp_stream_running(&dice->rx_stream[i]))
440 break;
441 }
442 if (i < MAX_STREAMS) {
443
444 err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params);
445 if (err < 0)
446 goto error;
447
448 err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params);
449 if (err < 0)
450 goto error;
451
452 err = snd_dice_transaction_set_enable(dice);
453 if (err < 0) {
454 dev_err(&dice->unit->device,
455 "fail to enable interface\n");
456 goto error;
457 }
458
459 for (i = 0; i < MAX_STREAMS; i++) {
460 if ((i < tx_params.count &&
461 !amdtp_stream_wait_callback(&dice->tx_stream[i],
462 CALLBACK_TIMEOUT)) ||
463 (i < rx_params.count &&
464 !amdtp_stream_wait_callback(&dice->rx_stream[i],
465 CALLBACK_TIMEOUT))) {
466 err = -ETIMEDOUT;
467 goto error;
468 }
469 }
470 }
471
472 return 0;
473error:
474 finish_session(dice, &tx_params, &rx_params);
475 return err;
476}
477
478
479
480
481
482
483void snd_dice_stream_stop_duplex(struct snd_dice *dice)
484{
485 struct reg_params tx_params, rx_params;
486
487 if (dice->substreams_counter == 0) {
488 if (get_register_params(dice, &tx_params, &rx_params) >= 0)
489 finish_session(dice, &tx_params, &rx_params);
490
491 release_resources(dice);
492 }
493}
494
495static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
496 unsigned int index)
497{
498 struct amdtp_stream *stream;
499 struct fw_iso_resources *resources;
500 int err;
501
502 if (dir == AMDTP_IN_STREAM) {
503 stream = &dice->tx_stream[index];
504 resources = &dice->tx_resources[index];
505 } else {
506 stream = &dice->rx_stream[index];
507 resources = &dice->rx_resources[index];
508 }
509
510 err = fw_iso_resources_init(resources, dice->unit);
511 if (err < 0)
512 goto end;
513 resources->channels_mask = 0x00000000ffffffffuLL;
514
515 err = amdtp_am824_init(stream, dice->unit, dir, CIP_BLOCKING);
516 if (err < 0) {
517 amdtp_stream_destroy(stream);
518 fw_iso_resources_destroy(resources);
519 }
520end:
521 return err;
522}
523
524
525
526
527
528static void destroy_stream(struct snd_dice *dice,
529 enum amdtp_stream_direction dir,
530 unsigned int index)
531{
532 struct amdtp_stream *stream;
533 struct fw_iso_resources *resources;
534
535 if (dir == AMDTP_IN_STREAM) {
536 stream = &dice->tx_stream[index];
537 resources = &dice->tx_resources[index];
538 } else {
539 stream = &dice->rx_stream[index];
540 resources = &dice->rx_resources[index];
541 }
542
543 amdtp_stream_destroy(stream);
544 fw_iso_resources_destroy(resources);
545}
546
547int snd_dice_stream_init_duplex(struct snd_dice *dice)
548{
549 int i, err;
550
551 for (i = 0; i < MAX_STREAMS; i++) {
552 err = init_stream(dice, AMDTP_IN_STREAM, i);
553 if (err < 0) {
554 for (; i >= 0; i--)
555 destroy_stream(dice, AMDTP_IN_STREAM, i);
556 goto end;
557 }
558 }
559
560 for (i = 0; i < MAX_STREAMS; i++) {
561 err = init_stream(dice, AMDTP_OUT_STREAM, i);
562 if (err < 0) {
563 for (; i >= 0; i--)
564 destroy_stream(dice, AMDTP_OUT_STREAM, i);
565 for (i = 0; i < MAX_STREAMS; i++)
566 destroy_stream(dice, AMDTP_IN_STREAM, i);
567 break;
568 }
569 }
570end:
571 return err;
572}
573
574void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
575{
576 unsigned int i;
577
578 for (i = 0; i < MAX_STREAMS; i++) {
579 destroy_stream(dice, AMDTP_IN_STREAM, i);
580 destroy_stream(dice, AMDTP_OUT_STREAM, i);
581 }
582}
583
584void snd_dice_stream_update_duplex(struct snd_dice *dice)
585{
586 struct reg_params tx_params, rx_params;
587
588
589
590
591
592
593
594
595
596 dice->global_enabled = false;
597
598 if (get_register_params(dice, &tx_params, &rx_params) == 0) {
599 stop_streams(dice, AMDTP_IN_STREAM, &tx_params);
600 stop_streams(dice, AMDTP_OUT_STREAM, &rx_params);
601 }
602}
603
604int snd_dice_stream_detect_current_formats(struct snd_dice *dice)
605{
606 unsigned int rate;
607 enum snd_dice_rate_mode mode;
608 __be32 reg[2];
609 struct reg_params tx_params, rx_params;
610 int i;
611 int err;
612
613
614 err = snd_dice_detect_extension_formats(dice);
615 if (err >= 0)
616 return err;
617
618
619
620
621
622 err = snd_dice_transaction_get_rate(dice, &rate);
623 if (err < 0)
624 return err;
625
626 err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
627 if (err < 0)
628 return err;
629
630
631
632
633
634
635 err = ensure_phase_lock(dice, rate);
636 if (err < 0)
637 return err;
638
639 err = get_register_params(dice, &tx_params, &rx_params);
640 if (err < 0)
641 return err;
642
643 for (i = 0; i < tx_params.count; ++i) {
644 err = snd_dice_transaction_read_tx(dice,
645 tx_params.size * i + TX_NUMBER_AUDIO,
646 reg, sizeof(reg));
647 if (err < 0)
648 return err;
649 dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
650 dice->tx_midi_ports[i] = max_t(unsigned int,
651 be32_to_cpu(reg[1]), dice->tx_midi_ports[i]);
652 }
653 for (i = 0; i < rx_params.count; ++i) {
654 err = snd_dice_transaction_read_rx(dice,
655 rx_params.size * i + RX_NUMBER_AUDIO,
656 reg, sizeof(reg));
657 if (err < 0)
658 return err;
659 dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]);
660 dice->rx_midi_ports[i] = max_t(unsigned int,
661 be32_to_cpu(reg[1]), dice->rx_midi_ports[i]);
662 }
663
664 return 0;
665}
666
667static void dice_lock_changed(struct snd_dice *dice)
668{
669 dice->dev_lock_changed = true;
670 wake_up(&dice->hwdep_wait);
671}
672
673int snd_dice_stream_lock_try(struct snd_dice *dice)
674{
675 int err;
676
677 spin_lock_irq(&dice->lock);
678
679 if (dice->dev_lock_count < 0) {
680 err = -EBUSY;
681 goto out;
682 }
683
684 if (dice->dev_lock_count++ == 0)
685 dice_lock_changed(dice);
686 err = 0;
687out:
688 spin_unlock_irq(&dice->lock);
689 return err;
690}
691
692void snd_dice_stream_lock_release(struct snd_dice *dice)
693{
694 spin_lock_irq(&dice->lock);
695
696 if (WARN_ON(dice->dev_lock_count <= 0))
697 goto out;
698
699 if (--dice->dev_lock_count == 0)
700 dice_lock_changed(dice);
701out:
702 spin_unlock_irq(&dice->lock);
703}
704