1
2
3
4
5
6
7
8#include "./bebob.h"
9
10#define CALLBACK_TIMEOUT 2500
11#define FW_ISO_RESOURCE_DELAY 1000
12
13
14
15
16
17
18
19
20
21
22
23#define FORMAT_MAXIMUM_LENGTH 128
24
25const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES] = {
26 [0] = 32000,
27 [1] = 44100,
28 [2] = 48000,
29 [3] = 88200,
30 [4] = 96000,
31 [5] = 176400,
32 [6] = 192000,
33};
34
35
36
37
38
39static const unsigned int bridgeco_freq_table[] = {
40 [0] = 0x02,
41 [1] = 0x03,
42 [2] = 0x04,
43 [3] = 0x0a,
44 [4] = 0x05,
45 [5] = 0x06,
46 [6] = 0x07,
47};
48
49static int
50get_formation_index(unsigned int rate, unsigned int *index)
51{
52 unsigned int i;
53
54 for (i = 0; i < ARRAY_SIZE(snd_bebob_rate_table); i++) {
55 if (snd_bebob_rate_table[i] == rate) {
56 *index = i;
57 return 0;
58 }
59 }
60 return -EINVAL;
61}
62
63int
64snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate)
65{
66 unsigned int tx_rate, rx_rate, trials;
67 int err;
68
69 trials = 0;
70 do {
71 err = avc_general_get_sig_fmt(bebob->unit, &tx_rate,
72 AVC_GENERAL_PLUG_DIR_OUT, 0);
73 } while (err == -EAGAIN && ++trials < 3);
74 if (err < 0)
75 goto end;
76
77 trials = 0;
78 do {
79 err = avc_general_get_sig_fmt(bebob->unit, &rx_rate,
80 AVC_GENERAL_PLUG_DIR_IN, 0);
81 } while (err == -EAGAIN && ++trials < 3);
82 if (err < 0)
83 goto end;
84
85 *curr_rate = rx_rate;
86 if (rx_rate == tx_rate)
87 goto end;
88
89
90 err = avc_general_set_sig_fmt(bebob->unit, rx_rate,
91 AVC_GENERAL_PLUG_DIR_IN, 0);
92end:
93 return err;
94}
95
96int
97snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate)
98{
99 int err;
100
101 err = avc_general_set_sig_fmt(bebob->unit, rate,
102 AVC_GENERAL_PLUG_DIR_OUT, 0);
103 if (err < 0)
104 goto end;
105
106 err = avc_general_set_sig_fmt(bebob->unit, rate,
107 AVC_GENERAL_PLUG_DIR_IN, 0);
108 if (err < 0)
109 goto end;
110
111
112
113
114
115 msleep(300);
116end:
117 return err;
118}
119
120int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
121 enum snd_bebob_clock_type *src)
122{
123 const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
124 u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
125 unsigned int id;
126 enum avc_bridgeco_plug_type type;
127 int err = 0;
128
129
130 if (clk_spec) {
131 err = clk_spec->get(bebob, &id);
132 if (err < 0) {
133 dev_err(&bebob->unit->device,
134 "fail to get clock source: %d\n", err);
135 goto end;
136 }
137
138 if (id >= clk_spec->num) {
139 dev_err(&bebob->unit->device,
140 "clock source %d out of range 0..%d\n",
141 id, clk_spec->num - 1);
142 err = -EIO;
143 goto end;
144 }
145
146 *src = clk_spec->types[id];
147 goto end;
148 }
149
150
151
152
153
154 if (bebob->sync_input_plug < 0) {
155 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
156 goto end;
157 }
158
159
160
161
162
163 avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
164 bebob->sync_input_plug);
165 err = avc_bridgeco_get_plug_input(bebob->unit, addr, input);
166 if (err < 0) {
167 dev_err(&bebob->unit->device,
168 "fail to get an input for MSU in plug %d: %d\n",
169 bebob->sync_input_plug, err);
170 goto end;
171 }
172
173
174
175
176
177 if (input[0] == 0xff) {
178 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
179 goto end;
180 }
181
182
183 if (input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) {
184
185
186
187
188
189 if (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT &&
190 input[2] == 0x0c) {
191 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
192 goto end;
193 }
194
195 } else if (input[1] == AVC_BRIDGECO_PLUG_MODE_UNIT) {
196 if (input[2] == AVC_BRIDGECO_PLUG_UNIT_ISOC) {
197 if (input[3] == 0x00) {
198
199
200
201
202
203
204
205 *src = SND_BEBOB_CLOCK_TYPE_SYT;
206 goto end;
207 } else {
208
209
210
211
212
213 *src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
214 goto end;
215 }
216 } else if (input[2] == AVC_BRIDGECO_PLUG_UNIT_EXT) {
217
218 avc_bridgeco_fill_unit_addr(addr,
219 AVC_BRIDGECO_PLUG_DIR_IN,
220 AVC_BRIDGECO_PLUG_UNIT_EXT,
221 input[3]);
222 err = avc_bridgeco_get_plug_type(bebob->unit, addr,
223 &type);
224 if (err < 0)
225 goto end;
226
227 if (type == AVC_BRIDGECO_PLUG_TYPE_DIG) {
228
229
230
231
232 *src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
233 goto end;
234 } else if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
235
236 *src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
237 goto end;
238 } else if (type == AVC_BRIDGECO_PLUG_TYPE_ADDITION) {
239
240
241
242
243 *src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
244 goto end;
245 }
246 }
247 }
248
249
250 err = -EIO;
251end:
252 return err;
253}
254
255static int map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s)
256{
257 unsigned int sec, sections, ch, channels;
258 unsigned int pcm, midi, location;
259 unsigned int stm_pos, sec_loc, pos;
260 u8 *buf, addr[AVC_BRIDGECO_ADDR_BYTES], type;
261 enum avc_bridgeco_plug_dir dir;
262 int err;
263
264
265
266
267
268 buf = kzalloc(256, GFP_KERNEL);
269 if (buf == NULL)
270 return -ENOMEM;
271
272 if (s == &bebob->tx_stream)
273 dir = AVC_BRIDGECO_PLUG_DIR_OUT;
274 else
275 dir = AVC_BRIDGECO_PLUG_DIR_IN;
276
277 avc_bridgeco_fill_unit_addr(addr, dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
278 err = avc_bridgeco_get_plug_ch_pos(bebob->unit, addr, buf, 256);
279 if (err < 0) {
280 dev_err(&bebob->unit->device,
281 "fail to get channel position for isoc %s plug 0: %d\n",
282 (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : "out",
283 err);
284 goto end;
285 }
286 pos = 0;
287
288
289 pcm = 0;
290 midi = 0;
291
292
293 sections = buf[pos++];
294
295 for (sec = 0; sec < sections; sec++) {
296
297 avc_bridgeco_fill_unit_addr(addr, dir,
298 AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
299 err = avc_bridgeco_get_plug_section_type(bebob->unit, addr,
300 sec, &type);
301 if (err < 0) {
302 dev_err(&bebob->unit->device,
303 "fail to get section type for isoc %s plug 0: %d\n",
304 (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" :
305 "out",
306 err);
307 goto end;
308 }
309
310 if (type == 0xff) {
311 err = -ENOSYS;
312 goto end;
313 }
314
315
316 channels = buf[pos++];
317
318 for (ch = 0; ch < channels; ch++) {
319
320 stm_pos = buf[pos++] - 1;
321
322 sec_loc = buf[pos++] - 1;
323
324
325
326
327
328
329
330 if (sec_loc >= channels)
331 sec_loc = ch;
332
333 switch (type) {
334
335 case 0x0a:
336
337 if ((midi > 0) && (stm_pos != midi)) {
338 err = -ENOSYS;
339 goto end;
340 }
341 amdtp_am824_set_midi_position(s, stm_pos);
342 midi = stm_pos;
343 break;
344
345 case 0x01:
346 case 0x02:
347 case 0x03:
348 case 0x04:
349 case 0x05:
350 case 0x06:
351 case 0x07:
352
353 case 0x08:
354 case 0x09:
355 default:
356 location = pcm + sec_loc;
357 if (location >= AM824_MAX_CHANNELS_FOR_PCM) {
358 err = -ENOSYS;
359 goto end;
360 }
361 amdtp_am824_set_pcm_position(s, location,
362 stm_pos);
363 break;
364 }
365 }
366
367 if (type != 0x0a)
368 pcm += channels;
369 else
370 midi += channels;
371 }
372end:
373 kfree(buf);
374 return err;
375}
376
377static int
378check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s)
379{
380 struct cmp_connection *conn;
381 bool used;
382 int err;
383
384 if (s == &bebob->tx_stream)
385 conn = &bebob->out_conn;
386 else
387 conn = &bebob->in_conn;
388
389 err = cmp_connection_check_used(conn, &used);
390 if ((err >= 0) && used && !amdtp_stream_running(s)) {
391 dev_err(&bebob->unit->device,
392 "Connection established by others: %cPCR[%d]\n",
393 (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
394 conn->pcr_index);
395 err = -EBUSY;
396 }
397
398 return err;
399}
400
401static void break_both_connections(struct snd_bebob *bebob)
402{
403 cmp_connection_break(&bebob->in_conn);
404 cmp_connection_break(&bebob->out_conn);
405
406
407
408
409 if (bebob->version < 2)
410 msleep(600);
411}
412
413static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
414{
415 struct cmp_connection *conn;
416 int err = 0;
417
418 if (stream == &bebob->rx_stream)
419 conn = &bebob->in_conn;
420 else
421 conn = &bebob->out_conn;
422
423
424 if (bebob->maudio_special_quirk == NULL) {
425 err = map_data_channels(bebob, stream);
426 if (err < 0)
427 return err;
428 }
429
430 err = cmp_connection_establish(conn);
431 if (err < 0)
432 return err;
433
434 return amdtp_domain_add_stream(&bebob->domain, stream,
435 conn->resources.channel, conn->speed);
436}
437
438static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
439{
440 enum amdtp_stream_direction dir_stream;
441 struct cmp_connection *conn;
442 enum cmp_direction dir_conn;
443 int err;
444
445 if (stream == &bebob->tx_stream) {
446 dir_stream = AMDTP_IN_STREAM;
447 conn = &bebob->out_conn;
448 dir_conn = CMP_OUTPUT;
449 } else {
450 dir_stream = AMDTP_OUT_STREAM;
451 conn = &bebob->in_conn;
452 dir_conn = CMP_INPUT;
453 }
454
455 err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
456 if (err < 0)
457 return err;
458
459 err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING);
460 if (err < 0) {
461 cmp_connection_destroy(conn);
462 return err;
463 }
464
465 if (stream == &bebob->tx_stream) {
466
467
468
469
470 if (bebob->version > 2)
471 bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
472 CIP_SKIP_DBC_ZERO_CHECK;
473
474
475
476
477 if (bebob->maudio_special_quirk)
478 bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
479 }
480
481 return 0;
482}
483
484static void destroy_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
485{
486 amdtp_stream_destroy(stream);
487
488 if (stream == &bebob->tx_stream)
489 cmp_connection_destroy(&bebob->out_conn);
490 else
491 cmp_connection_destroy(&bebob->in_conn);
492}
493
494int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
495{
496 int err;
497
498 err = init_stream(bebob, &bebob->tx_stream);
499 if (err < 0)
500 return err;
501
502 err = init_stream(bebob, &bebob->rx_stream);
503 if (err < 0) {
504 destroy_stream(bebob, &bebob->tx_stream);
505 return err;
506 }
507
508 err = amdtp_domain_init(&bebob->domain);
509 if (err < 0) {
510 destroy_stream(bebob, &bebob->tx_stream);
511 destroy_stream(bebob, &bebob->rx_stream);
512 }
513
514 return err;
515}
516
517static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
518 unsigned int rate, unsigned int index)
519{
520 struct snd_bebob_stream_formation *formation;
521 struct cmp_connection *conn;
522 int err;
523
524 if (stream == &bebob->tx_stream) {
525 formation = bebob->tx_stream_formations + index;
526 conn = &bebob->out_conn;
527 } else {
528 formation = bebob->rx_stream_formations + index;
529 conn = &bebob->in_conn;
530 }
531
532 err = amdtp_am824_set_parameters(stream, rate, formation->pcm,
533 formation->midi, false);
534 if (err < 0)
535 return err;
536
537 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
538}
539
540int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate,
541 unsigned int frames_per_period,
542 unsigned int frames_per_buffer)
543{
544 unsigned int curr_rate;
545 int err;
546
547
548
549 err = check_connection_used_by_others(bebob, &bebob->rx_stream);
550 if (err < 0)
551 return err;
552
553 err = bebob->spec->rate->get(bebob, &curr_rate);
554 if (err < 0)
555 return err;
556 if (rate == 0)
557 rate = curr_rate;
558 if (curr_rate != rate) {
559 amdtp_domain_stop(&bebob->domain);
560 break_both_connections(bebob);
561
562 cmp_connection_release(&bebob->out_conn);
563 cmp_connection_release(&bebob->in_conn);
564 }
565
566 if (bebob->substreams_counter == 0 || curr_rate != rate) {
567 unsigned int index;
568
569
570
571
572
573
574 err = bebob->spec->rate->set(bebob, rate);
575 if (err < 0) {
576 dev_err(&bebob->unit->device,
577 "fail to set sampling rate: %d\n",
578 err);
579 return err;
580 }
581
582 err = get_formation_index(rate, &index);
583 if (err < 0)
584 return err;
585
586 err = keep_resources(bebob, &bebob->tx_stream, rate, index);
587 if (err < 0)
588 return err;
589
590 err = keep_resources(bebob, &bebob->rx_stream, rate, index);
591 if (err < 0) {
592 cmp_connection_release(&bebob->out_conn);
593 return err;
594 }
595
596 err = amdtp_domain_set_events_per_period(&bebob->domain,
597 frames_per_period, frames_per_buffer);
598 if (err < 0) {
599 cmp_connection_release(&bebob->out_conn);
600 cmp_connection_release(&bebob->in_conn);
601 return err;
602 }
603 }
604
605 return 0;
606}
607
608int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
609{
610 int err;
611
612
613 if (bebob->substreams_counter == 0)
614 return -EIO;
615
616
617 if (amdtp_streaming_error(&bebob->rx_stream) ||
618 amdtp_streaming_error(&bebob->tx_stream)) {
619 amdtp_domain_stop(&bebob->domain);
620 break_both_connections(bebob);
621 }
622
623 if (!amdtp_stream_running(&bebob->rx_stream)) {
624 enum snd_bebob_clock_type src;
625 struct amdtp_stream *master, *slave;
626 unsigned int curr_rate;
627 unsigned int ir_delay_cycle;
628
629 if (bebob->maudio_special_quirk) {
630 err = bebob->spec->rate->get(bebob, &curr_rate);
631 if (err < 0)
632 return err;
633 }
634
635 err = snd_bebob_stream_get_clock_src(bebob, &src);
636 if (err < 0)
637 return err;
638
639 if (src != SND_BEBOB_CLOCK_TYPE_SYT) {
640 master = &bebob->tx_stream;
641 slave = &bebob->rx_stream;
642 } else {
643 master = &bebob->rx_stream;
644 slave = &bebob->tx_stream;
645 }
646
647 err = start_stream(bebob, master);
648 if (err < 0)
649 goto error;
650
651 err = start_stream(bebob, slave);
652 if (err < 0)
653 goto error;
654
655
656
657
658
659
660
661
662
663
664 if (bebob->version < 2)
665 ir_delay_cycle = 3200;
666 else
667 ir_delay_cycle = 16000;
668 err = amdtp_domain_start(&bebob->domain, ir_delay_cycle);
669 if (err < 0)
670 goto error;
671
672
673
674
675 if (bebob->maudio_special_quirk) {
676 err = bebob->spec->rate->set(bebob, curr_rate);
677 if (err < 0) {
678 dev_err(&bebob->unit->device,
679 "fail to ensure sampling rate: %d\n",
680 err);
681 goto error;
682 }
683 }
684
685 if (!amdtp_stream_wait_callback(&bebob->rx_stream,
686 CALLBACK_TIMEOUT) ||
687 !amdtp_stream_wait_callback(&bebob->tx_stream,
688 CALLBACK_TIMEOUT)) {
689 err = -ETIMEDOUT;
690 goto error;
691 }
692 }
693
694 return 0;
695error:
696 amdtp_domain_stop(&bebob->domain);
697 break_both_connections(bebob);
698 return err;
699}
700
701void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
702{
703 if (bebob->substreams_counter == 0) {
704 amdtp_domain_stop(&bebob->domain);
705 break_both_connections(bebob);
706
707 cmp_connection_release(&bebob->out_conn);
708 cmp_connection_release(&bebob->in_conn);
709 }
710}
711
712
713
714
715
716void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
717{
718 amdtp_domain_destroy(&bebob->domain);
719
720 destroy_stream(bebob, &bebob->tx_stream);
721 destroy_stream(bebob, &bebob->rx_stream);
722}
723
724
725
726
727
728
729static int
730parse_stream_formation(u8 *buf, unsigned int len,
731 struct snd_bebob_stream_formation *formation)
732{
733 unsigned int i, e, channels, format;
734
735
736
737
738
739
740 if ((buf[0] != 0x90) || (buf[1] != 0x40))
741 return -ENOSYS;
742
743
744 for (i = 0; i < ARRAY_SIZE(bridgeco_freq_table); i++) {
745 if (buf[2] == bridgeco_freq_table[i])
746 break;
747 }
748 if (i == ARRAY_SIZE(bridgeco_freq_table))
749 return -ENOSYS;
750
751
752 memset(&formation[i], 0, sizeof(struct snd_bebob_stream_formation));
753
754 for (e = 0; e < buf[4]; e++) {
755 channels = buf[5 + e * 2];
756 format = buf[6 + e * 2];
757
758 switch (format) {
759
760 case 0x00:
761
762 case 0x06:
763 formation[i].pcm += channels;
764 break;
765
766 case 0x0d:
767 formation[i].midi += channels;
768 break;
769
770 case 0x01:
771 case 0x02:
772 case 0x03:
773 case 0x04:
774 case 0x05:
775
776 case 0x07:
777 case 0x0c:
778
779 case 0x08:
780 case 0x09:
781 case 0x0a:
782 case 0x0b:
783
784 case 0x40:
785
786 case 0xff:
787 default:
788 return -ENOSYS;
789 }
790 }
791
792 if (formation[i].pcm > AM824_MAX_CHANNELS_FOR_PCM ||
793 formation[i].midi > AM824_MAX_CHANNELS_FOR_MIDI)
794 return -ENOSYS;
795
796 return 0;
797}
798
799static int
800fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir,
801 unsigned short pid)
802{
803 u8 *buf;
804 struct snd_bebob_stream_formation *formations;
805 unsigned int len, eid;
806 u8 addr[AVC_BRIDGECO_ADDR_BYTES];
807 int err;
808
809 buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL);
810 if (buf == NULL)
811 return -ENOMEM;
812
813 if (dir == AVC_BRIDGECO_PLUG_DIR_IN)
814 formations = bebob->rx_stream_formations;
815 else
816 formations = bebob->tx_stream_formations;
817
818 for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) {
819 len = FORMAT_MAXIMUM_LENGTH;
820 avc_bridgeco_fill_unit_addr(addr, dir,
821 AVC_BRIDGECO_PLUG_UNIT_ISOC, pid);
822 err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf,
823 &len, eid);
824
825 if (err == -EINVAL && eid > 0) {
826 err = 0;
827 break;
828 } else if (err < 0) {
829 dev_err(&bebob->unit->device,
830 "fail to get stream format %d for isoc %s plug %d:%d\n",
831 eid,
832 (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" :
833 "out",
834 pid, err);
835 break;
836 }
837
838 err = parse_stream_formation(buf, len, formations);
839 if (err < 0)
840 break;
841 }
842
843 kfree(buf);
844 return err;
845}
846
847static int
848seek_msu_sync_input_plug(struct snd_bebob *bebob)
849{
850 u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
851 unsigned int i;
852 enum avc_bridgeco_plug_type type;
853 int err;
854
855
856 err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs);
857 if (err < 0) {
858 dev_err(&bebob->unit->device,
859 "fail to get info for MSU in/out plugs: %d\n",
860 err);
861 goto end;
862 }
863
864
865 bebob->sync_input_plug = -1;
866 for (i = 0; i < plugs[0]; i++) {
867 avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i);
868 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
869 if (err < 0) {
870 dev_err(&bebob->unit->device,
871 "fail to get type for MSU in plug %d: %d\n",
872 i, err);
873 goto end;
874 }
875
876 if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
877 bebob->sync_input_plug = i;
878 break;
879 }
880 }
881end:
882 return err;
883}
884
885int snd_bebob_stream_discover(struct snd_bebob *bebob)
886{
887 const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
888 u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
889 enum avc_bridgeco_plug_type type;
890 unsigned int i;
891 int err;
892
893
894 err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs);
895 if (err < 0) {
896 dev_err(&bebob->unit->device,
897 "fail to get info for isoc/external in/out plugs: %d\n",
898 err);
899 goto end;
900 }
901
902
903
904
905
906 if ((plugs[0] == 0) || (plugs[1] == 0)) {
907 err = -ENOSYS;
908 goto end;
909 }
910
911 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
912 AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
913 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
914 if (err < 0) {
915 dev_err(&bebob->unit->device,
916 "fail to get type for isoc in plug 0: %d\n", err);
917 goto end;
918 } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
919 err = -ENOSYS;
920 goto end;
921 }
922 err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0);
923 if (err < 0)
924 goto end;
925
926 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
927 AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
928 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
929 if (err < 0) {
930 dev_err(&bebob->unit->device,
931 "fail to get type for isoc out plug 0: %d\n", err);
932 goto end;
933 } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
934 err = -ENOSYS;
935 goto end;
936 }
937 err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0);
938 if (err < 0)
939 goto end;
940
941
942 bebob->midi_input_ports = 0;
943 for (i = 0; i < plugs[2]; i++) {
944 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
945 AVC_BRIDGECO_PLUG_UNIT_EXT, i);
946 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
947 if (err < 0) {
948 dev_err(&bebob->unit->device,
949 "fail to get type for external in plug %d: %d\n",
950 i, err);
951 goto end;
952 } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
953 bebob->midi_input_ports++;
954 }
955 }
956
957
958 bebob->midi_output_ports = 0;
959 for (i = 0; i < plugs[3]; i++) {
960 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
961 AVC_BRIDGECO_PLUG_UNIT_EXT, i);
962 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
963 if (err < 0) {
964 dev_err(&bebob->unit->device,
965 "fail to get type for external out plug %d: %d\n",
966 i, err);
967 goto end;
968 } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
969 bebob->midi_output_ports++;
970 }
971 }
972
973
974 if (!clk_spec)
975 err = seek_msu_sync_input_plug(bebob);
976end:
977 return err;
978}
979
980void snd_bebob_stream_lock_changed(struct snd_bebob *bebob)
981{
982 bebob->dev_lock_changed = true;
983 wake_up(&bebob->hwdep_wait);
984}
985
986int snd_bebob_stream_lock_try(struct snd_bebob *bebob)
987{
988 int err;
989
990 spin_lock_irq(&bebob->lock);
991
992
993 if (bebob->dev_lock_count < 0) {
994 err = -EBUSY;
995 goto end;
996 }
997
998
999 if (bebob->dev_lock_count++ == 0)
1000 snd_bebob_stream_lock_changed(bebob);
1001 err = 0;
1002end:
1003 spin_unlock_irq(&bebob->lock);
1004 return err;
1005}
1006
1007void snd_bebob_stream_lock_release(struct snd_bebob *bebob)
1008{
1009 spin_lock_irq(&bebob->lock);
1010
1011 if (WARN_ON(bebob->dev_lock_count <= 0))
1012 goto end;
1013 if (--bebob->dev_lock_count == 0)
1014 snd_bebob_stream_lock_changed(bebob);
1015end:
1016 spin_unlock_irq(&bebob->lock);
1017}
1018