This source file includes following definitions.
- get_formation_index
- snd_bebob_stream_get_rate
- snd_bebob_stream_set_rate
- snd_bebob_stream_get_clock_src
- map_data_channels
- check_connection_used_by_others
- make_both_connections
- break_both_connections
- start_stream
- init_stream
- destroy_stream
- snd_bebob_stream_init_duplex
- keep_resources
- snd_bebob_stream_reserve_duplex
- snd_bebob_stream_start_duplex
- snd_bebob_stream_stop_duplex
- snd_bebob_stream_destroy_duplex
- parse_stream_formation
- fill_stream_formations
- seek_msu_sync_input_plug
- snd_bebob_stream_discover
- snd_bebob_stream_lock_changed
- snd_bebob_stream_lock_try
- snd_bebob_stream_lock_release
1
2
3
4
5
6
7
8 #include "./bebob.h"
9
10 #define CALLBACK_TIMEOUT 2000
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
25 const 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
39 static 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
49 static int
50 get_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
63 int
64 snd_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);
92 end:
93 return err;
94 }
95
96 int
97 snd_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);
116 end:
117 return err;
118 }
119
120 int 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;
251 end:
252 return err;
253 }
254
255 static 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 }
372 end:
373 kfree(buf);
374 return err;
375 }
376
377 static int
378 check_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
401 static int make_both_connections(struct snd_bebob *bebob)
402 {
403 int err = 0;
404
405 err = cmp_connection_establish(&bebob->out_conn);
406 if (err < 0)
407 return err;
408
409 err = cmp_connection_establish(&bebob->in_conn);
410 if (err < 0) {
411 cmp_connection_break(&bebob->out_conn);
412 return err;
413 }
414
415 return 0;
416 }
417
418 static void break_both_connections(struct snd_bebob *bebob)
419 {
420 cmp_connection_break(&bebob->in_conn);
421 cmp_connection_break(&bebob->out_conn);
422
423
424
425
426 if (bebob->version < 2)
427 msleep(600);
428 }
429
430 static int
431 start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
432 {
433 struct cmp_connection *conn;
434 int err = 0;
435
436 if (stream == &bebob->rx_stream)
437 conn = &bebob->in_conn;
438 else
439 conn = &bebob->out_conn;
440
441
442 if (bebob->maudio_special_quirk == NULL) {
443 err = map_data_channels(bebob, stream);
444 if (err < 0)
445 goto end;
446 }
447
448
449 err = amdtp_domain_add_stream(&bebob->domain, stream,
450 conn->resources.channel, conn->speed);
451 end:
452 return err;
453 }
454
455 static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
456 {
457 enum amdtp_stream_direction dir_stream;
458 struct cmp_connection *conn;
459 enum cmp_direction dir_conn;
460 int err;
461
462 if (stream == &bebob->tx_stream) {
463 dir_stream = AMDTP_IN_STREAM;
464 conn = &bebob->out_conn;
465 dir_conn = CMP_OUTPUT;
466 } else {
467 dir_stream = AMDTP_OUT_STREAM;
468 conn = &bebob->in_conn;
469 dir_conn = CMP_INPUT;
470 }
471
472 err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
473 if (err < 0)
474 return err;
475
476 err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING);
477 if (err < 0) {
478 cmp_connection_destroy(conn);
479 return err;
480 }
481
482 if (stream == &bebob->tx_stream) {
483
484
485
486
487 if (bebob->version > 2)
488 bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
489 CIP_SKIP_DBC_ZERO_CHECK;
490
491
492
493
494 if (bebob->maudio_special_quirk)
495 bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
496 }
497
498 return 0;
499 }
500
501 static void destroy_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
502 {
503 amdtp_stream_destroy(stream);
504
505 if (stream == &bebob->tx_stream)
506 cmp_connection_destroy(&bebob->out_conn);
507 else
508 cmp_connection_destroy(&bebob->in_conn);
509 }
510
511 int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
512 {
513 int err;
514
515 err = init_stream(bebob, &bebob->tx_stream);
516 if (err < 0)
517 return err;
518
519 err = init_stream(bebob, &bebob->rx_stream);
520 if (err < 0) {
521 destroy_stream(bebob, &bebob->tx_stream);
522 return err;
523 }
524
525 err = amdtp_domain_init(&bebob->domain);
526 if (err < 0) {
527 destroy_stream(bebob, &bebob->tx_stream);
528 destroy_stream(bebob, &bebob->rx_stream);
529 }
530
531 return err;
532 }
533
534 static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream,
535 unsigned int rate, unsigned int index)
536 {
537 struct snd_bebob_stream_formation *formation;
538 struct cmp_connection *conn;
539 int err;
540
541 if (stream == &bebob->tx_stream) {
542 formation = bebob->tx_stream_formations + index;
543 conn = &bebob->out_conn;
544 } else {
545 formation = bebob->rx_stream_formations + index;
546 conn = &bebob->in_conn;
547 }
548
549 err = amdtp_am824_set_parameters(stream, rate, formation->pcm,
550 formation->midi, false);
551 if (err < 0)
552 return err;
553
554 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
555 }
556
557 int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate)
558 {
559 unsigned int curr_rate;
560 int err;
561
562
563
564 err = check_connection_used_by_others(bebob, &bebob->rx_stream);
565 if (err < 0)
566 return err;
567
568 err = bebob->spec->rate->get(bebob, &curr_rate);
569 if (err < 0)
570 return err;
571 if (rate == 0)
572 rate = curr_rate;
573 if (curr_rate != rate) {
574 amdtp_domain_stop(&bebob->domain);
575 break_both_connections(bebob);
576
577 cmp_connection_release(&bebob->out_conn);
578 cmp_connection_release(&bebob->in_conn);
579 }
580
581 if (bebob->substreams_counter == 0 || curr_rate != rate) {
582 unsigned int index;
583
584
585
586
587
588
589 err = bebob->spec->rate->set(bebob, rate);
590 if (err < 0) {
591 dev_err(&bebob->unit->device,
592 "fail to set sampling rate: %d\n",
593 err);
594 return err;
595 }
596
597 err = get_formation_index(rate, &index);
598 if (err < 0)
599 return err;
600
601 err = keep_resources(bebob, &bebob->tx_stream, rate, index);
602 if (err < 0)
603 return err;
604
605 err = keep_resources(bebob, &bebob->rx_stream, rate, index);
606 if (err < 0) {
607 cmp_connection_release(&bebob->out_conn);
608 return err;
609 }
610 }
611
612 return 0;
613 }
614
615 int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
616 {
617 int err;
618
619
620 if (bebob->substreams_counter == 0)
621 return -EIO;
622
623
624 if (amdtp_streaming_error(&bebob->rx_stream) ||
625 amdtp_streaming_error(&bebob->tx_stream)) {
626 amdtp_domain_stop(&bebob->domain);
627 break_both_connections(bebob);
628 }
629
630 if (!amdtp_stream_running(&bebob->rx_stream)) {
631 unsigned int curr_rate;
632
633 if (bebob->maudio_special_quirk) {
634 err = bebob->spec->rate->get(bebob, &curr_rate);
635 if (err < 0)
636 return err;
637 }
638
639 err = make_both_connections(bebob);
640 if (err < 0)
641 return err;
642
643 err = start_stream(bebob, &bebob->rx_stream);
644 if (err < 0)
645 goto error;
646
647 err = start_stream(bebob, &bebob->tx_stream);
648 if (err < 0)
649 goto error;
650
651 err = amdtp_domain_start(&bebob->domain);
652 if (err < 0)
653 goto error;
654
655
656
657
658 if (bebob->maudio_special_quirk) {
659 err = bebob->spec->rate->set(bebob, curr_rate);
660 if (err < 0) {
661 dev_err(&bebob->unit->device,
662 "fail to ensure sampling rate: %d\n",
663 err);
664 goto error;
665 }
666 }
667
668 if (!amdtp_stream_wait_callback(&bebob->rx_stream,
669 CALLBACK_TIMEOUT) ||
670 !amdtp_stream_wait_callback(&bebob->tx_stream,
671 CALLBACK_TIMEOUT)) {
672 err = -ETIMEDOUT;
673 goto error;
674 }
675 }
676
677 return 0;
678 error:
679 amdtp_domain_stop(&bebob->domain);
680 break_both_connections(bebob);
681 return err;
682 }
683
684 void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
685 {
686 if (bebob->substreams_counter == 0) {
687 amdtp_domain_stop(&bebob->domain);
688 break_both_connections(bebob);
689
690 cmp_connection_release(&bebob->out_conn);
691 cmp_connection_release(&bebob->in_conn);
692 }
693 }
694
695
696
697
698
699 void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
700 {
701 amdtp_domain_destroy(&bebob->domain);
702
703 destroy_stream(bebob, &bebob->tx_stream);
704 destroy_stream(bebob, &bebob->rx_stream);
705 }
706
707
708
709
710
711
712 static int
713 parse_stream_formation(u8 *buf, unsigned int len,
714 struct snd_bebob_stream_formation *formation)
715 {
716 unsigned int i, e, channels, format;
717
718
719
720
721
722
723 if ((buf[0] != 0x90) || (buf[1] != 0x40))
724 return -ENOSYS;
725
726
727 for (i = 0; i < ARRAY_SIZE(bridgeco_freq_table); i++) {
728 if (buf[2] == bridgeco_freq_table[i])
729 break;
730 }
731 if (i == ARRAY_SIZE(bridgeco_freq_table))
732 return -ENOSYS;
733
734
735 memset(&formation[i], 0, sizeof(struct snd_bebob_stream_formation));
736
737 for (e = 0; e < buf[4]; e++) {
738 channels = buf[5 + e * 2];
739 format = buf[6 + e * 2];
740
741 switch (format) {
742
743 case 0x00:
744
745 case 0x06:
746 formation[i].pcm += channels;
747 break;
748
749 case 0x0d:
750 formation[i].midi += channels;
751 break;
752
753 case 0x01:
754 case 0x02:
755 case 0x03:
756 case 0x04:
757 case 0x05:
758
759 case 0x07:
760 case 0x0c:
761
762 case 0x08:
763 case 0x09:
764 case 0x0a:
765 case 0x0b:
766
767 case 0x40:
768
769 case 0xff:
770 default:
771 return -ENOSYS;
772 }
773 }
774
775 if (formation[i].pcm > AM824_MAX_CHANNELS_FOR_PCM ||
776 formation[i].midi > AM824_MAX_CHANNELS_FOR_MIDI)
777 return -ENOSYS;
778
779 return 0;
780 }
781
782 static int
783 fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir,
784 unsigned short pid)
785 {
786 u8 *buf;
787 struct snd_bebob_stream_formation *formations;
788 unsigned int len, eid;
789 u8 addr[AVC_BRIDGECO_ADDR_BYTES];
790 int err;
791
792 buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL);
793 if (buf == NULL)
794 return -ENOMEM;
795
796 if (dir == AVC_BRIDGECO_PLUG_DIR_IN)
797 formations = bebob->rx_stream_formations;
798 else
799 formations = bebob->tx_stream_formations;
800
801 for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) {
802 len = FORMAT_MAXIMUM_LENGTH;
803 avc_bridgeco_fill_unit_addr(addr, dir,
804 AVC_BRIDGECO_PLUG_UNIT_ISOC, pid);
805 err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf,
806 &len, eid);
807
808 if (err == -EINVAL && eid > 0) {
809 err = 0;
810 break;
811 } else if (err < 0) {
812 dev_err(&bebob->unit->device,
813 "fail to get stream format %d for isoc %s plug %d:%d\n",
814 eid,
815 (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" :
816 "out",
817 pid, err);
818 break;
819 }
820
821 err = parse_stream_formation(buf, len, formations);
822 if (err < 0)
823 break;
824 }
825
826 kfree(buf);
827 return err;
828 }
829
830 static int
831 seek_msu_sync_input_plug(struct snd_bebob *bebob)
832 {
833 u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
834 unsigned int i;
835 enum avc_bridgeco_plug_type type;
836 int err;
837
838
839 err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs);
840 if (err < 0) {
841 dev_err(&bebob->unit->device,
842 "fail to get info for MSU in/out plugs: %d\n",
843 err);
844 goto end;
845 }
846
847
848 bebob->sync_input_plug = -1;
849 for (i = 0; i < plugs[0]; i++) {
850 avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i);
851 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
852 if (err < 0) {
853 dev_err(&bebob->unit->device,
854 "fail to get type for MSU in plug %d: %d\n",
855 i, err);
856 goto end;
857 }
858
859 if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
860 bebob->sync_input_plug = i;
861 break;
862 }
863 }
864 end:
865 return err;
866 }
867
868 int snd_bebob_stream_discover(struct snd_bebob *bebob)
869 {
870 const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
871 u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES];
872 enum avc_bridgeco_plug_type type;
873 unsigned int i;
874 int err;
875
876
877 err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs);
878 if (err < 0) {
879 dev_err(&bebob->unit->device,
880 "fail to get info for isoc/external in/out plugs: %d\n",
881 err);
882 goto end;
883 }
884
885
886
887
888
889 if ((plugs[0] == 0) || (plugs[1] == 0)) {
890 err = -ENOSYS;
891 goto end;
892 }
893
894 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
895 AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
896 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
897 if (err < 0) {
898 dev_err(&bebob->unit->device,
899 "fail to get type for isoc in plug 0: %d\n", err);
900 goto end;
901 } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
902 err = -ENOSYS;
903 goto end;
904 }
905 err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0);
906 if (err < 0)
907 goto end;
908
909 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
910 AVC_BRIDGECO_PLUG_UNIT_ISOC, 0);
911 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
912 if (err < 0) {
913 dev_err(&bebob->unit->device,
914 "fail to get type for isoc out plug 0: %d\n", err);
915 goto end;
916 } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) {
917 err = -ENOSYS;
918 goto end;
919 }
920 err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0);
921 if (err < 0)
922 goto end;
923
924
925 bebob->midi_input_ports = 0;
926 for (i = 0; i < plugs[2]; i++) {
927 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN,
928 AVC_BRIDGECO_PLUG_UNIT_EXT, i);
929 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
930 if (err < 0) {
931 dev_err(&bebob->unit->device,
932 "fail to get type for external in plug %d: %d\n",
933 i, err);
934 goto end;
935 } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
936 bebob->midi_input_ports++;
937 }
938 }
939
940
941 bebob->midi_output_ports = 0;
942 for (i = 0; i < plugs[3]; i++) {
943 avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT,
944 AVC_BRIDGECO_PLUG_UNIT_EXT, i);
945 err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type);
946 if (err < 0) {
947 dev_err(&bebob->unit->device,
948 "fail to get type for external out plug %d: %d\n",
949 i, err);
950 goto end;
951 } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) {
952 bebob->midi_output_ports++;
953 }
954 }
955
956
957 if (!clk_spec)
958 err = seek_msu_sync_input_plug(bebob);
959 end:
960 return err;
961 }
962
963 void snd_bebob_stream_lock_changed(struct snd_bebob *bebob)
964 {
965 bebob->dev_lock_changed = true;
966 wake_up(&bebob->hwdep_wait);
967 }
968
969 int snd_bebob_stream_lock_try(struct snd_bebob *bebob)
970 {
971 int err;
972
973 spin_lock_irq(&bebob->lock);
974
975
976 if (bebob->dev_lock_count < 0) {
977 err = -EBUSY;
978 goto end;
979 }
980
981
982 if (bebob->dev_lock_count++ == 0)
983 snd_bebob_stream_lock_changed(bebob);
984 err = 0;
985 end:
986 spin_unlock_irq(&bebob->lock);
987 return err;
988 }
989
990 void snd_bebob_stream_lock_release(struct snd_bebob *bebob)
991 {
992 spin_lock_irq(&bebob->lock);
993
994 if (WARN_ON(bebob->dev_lock_count <= 0))
995 goto end;
996 if (--bebob->dev_lock_count == 0)
997 snd_bebob_stream_lock_changed(bebob);
998 end:
999 spin_unlock_irq(&bebob->lock);
1000 }