Commit | Line | Data |
---|---|---|
eb7b3a05 TS |
1 | /* |
2 | * bebob_stream.c - a part of driver for BeBoB based devices | |
3 | * | |
4 | * Copyright (c) 2013-2014 Takashi Sakamoto | |
5 | * | |
6 | * Licensed under the terms of the GNU General Public License, version 2. | |
7 | */ | |
8 | ||
9 | #include "./bebob.h" | |
10 | ||
11 | #define CALLBACK_TIMEOUT 1000 | |
12 | ||
13 | /* | |
14 | * NOTE; | |
15 | * For BeBoB streams, Both of input and output CMP connection are important. | |
16 | * | |
17 | * For most devices, each CMP connection starts to transmit/receive a | |
18 | * corresponding stream. But for a few devices, both of CMP connection needs | |
19 | * to start transmitting stream. An example is 'M-Audio Firewire 410'. | |
20 | */ | |
21 | ||
22 | /* 128 is an arbitrary length but it seems to be enough */ | |
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 | * See: Table 51: Extended Stream Format Info ‘Sampling Frequency’ | |
37 | * in Additional AVC commands (Nov 2003, BridgeCo) | |
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 unsigned int | |
50 | get_formation_index(unsigned int rate) | |
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 | return i; | |
57 | } | |
58 | return -EINVAL; | |
59 | } | |
60 | ||
61 | int | |
62 | snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *curr_rate) | |
63 | { | |
64 | unsigned int tx_rate, rx_rate, trials; | |
65 | int err; | |
66 | ||
67 | trials = 0; | |
68 | do { | |
69 | err = avc_general_get_sig_fmt(bebob->unit, &tx_rate, | |
70 | AVC_GENERAL_PLUG_DIR_OUT, 0); | |
71 | } while (err == -EAGAIN && ++trials < 3); | |
72 | if (err < 0) | |
73 | goto end; | |
74 | ||
75 | trials = 0; | |
76 | do { | |
77 | err = avc_general_get_sig_fmt(bebob->unit, &rx_rate, | |
78 | AVC_GENERAL_PLUG_DIR_IN, 0); | |
79 | } while (err == -EAGAIN && ++trials < 3); | |
80 | if (err < 0) | |
81 | goto end; | |
82 | ||
83 | *curr_rate = rx_rate; | |
84 | if (rx_rate == tx_rate) | |
85 | goto end; | |
86 | ||
87 | /* synchronize receive stream rate to transmit stream rate */ | |
88 | err = avc_general_set_sig_fmt(bebob->unit, rx_rate, | |
89 | AVC_GENERAL_PLUG_DIR_IN, 0); | |
90 | end: | |
91 | return err; | |
92 | } | |
93 | ||
94 | int | |
95 | snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate) | |
96 | { | |
97 | int err; | |
98 | ||
99 | err = avc_general_set_sig_fmt(bebob->unit, rate, | |
100 | AVC_GENERAL_PLUG_DIR_OUT, 0); | |
101 | if (err < 0) | |
102 | goto end; | |
103 | ||
104 | err = avc_general_set_sig_fmt(bebob->unit, rate, | |
105 | AVC_GENERAL_PLUG_DIR_IN, 0); | |
106 | if (err < 0) | |
107 | goto end; | |
108 | ||
109 | /* | |
110 | * Some devices need a bit time for transition. | |
111 | * 300msec is got by some experiments. | |
112 | */ | |
113 | msleep(300); | |
114 | end: | |
115 | return err; | |
116 | } | |
117 | ||
118 | int | |
119 | snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal) | |
120 | { | |
121 | u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7]; | |
122 | int err = 0; | |
123 | ||
124 | *internal = false; | |
125 | ||
126 | /* | |
127 | * 1.The device don't support to switch source of clock then assumed | |
128 | * to use internal clock always | |
129 | */ | |
130 | if (bebob->sync_input_plug < 0) { | |
131 | *internal = true; | |
132 | goto end; | |
133 | } | |
134 | ||
135 | /* | |
136 | * 2.The device supports to switch source of clock by an usual way. | |
137 | * Let's check input for 'Music Sub Unit Sync Input' plug. | |
138 | */ | |
139 | avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, | |
140 | bebob->sync_input_plug); | |
141 | err = avc_bridgeco_get_plug_input(bebob->unit, addr, input); | |
142 | if (err < 0) { | |
143 | dev_err(&bebob->unit->device, | |
144 | "fail to get an input for MSU in plug %d: %d\n", | |
145 | bebob->sync_input_plug, err); | |
146 | goto end; | |
147 | } | |
148 | ||
149 | /* | |
150 | * If there are no input plugs, all of fields are 0xff. | |
151 | * Here check the first field. This field is used for direction. | |
152 | */ | |
153 | if (input[0] == 0xff) { | |
154 | *internal = true; | |
155 | goto end; | |
156 | } | |
157 | ||
158 | /* | |
159 | * If source of clock is internal CSR, Music Sub Unit Sync Input is | |
160 | * a destination of Music Sub Unit Sync Output. | |
161 | */ | |
162 | *internal = ((input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) && | |
163 | (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT) && | |
164 | (input[2] == 0x0c) && | |
165 | (input[3] == 0x00)); | |
166 | end: | |
167 | return err; | |
168 | } | |
169 | ||
170 | static unsigned int | |
171 | map_data_channels(struct snd_bebob *bebob, struct amdtp_stream *s) | |
172 | { | |
173 | unsigned int sec, sections, ch, channels; | |
174 | unsigned int pcm, midi, location; | |
175 | unsigned int stm_pos, sec_loc, pos; | |
176 | u8 *buf, addr[AVC_BRIDGECO_ADDR_BYTES], type; | |
177 | enum avc_bridgeco_plug_dir dir; | |
178 | int err; | |
179 | ||
180 | /* | |
181 | * The length of return value of this command cannot be expected. Here | |
182 | * use the maximum length of FCP. | |
183 | */ | |
184 | buf = kzalloc(256, GFP_KERNEL); | |
185 | if (buf == NULL) | |
186 | return -ENOMEM; | |
187 | ||
188 | if (s == &bebob->tx_stream) | |
189 | dir = AVC_BRIDGECO_PLUG_DIR_OUT; | |
190 | else | |
191 | dir = AVC_BRIDGECO_PLUG_DIR_IN; | |
192 | ||
193 | avc_bridgeco_fill_unit_addr(addr, dir, AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | |
194 | err = avc_bridgeco_get_plug_ch_pos(bebob->unit, addr, buf, 256); | |
195 | if (err < 0) { | |
196 | dev_err(&bebob->unit->device, | |
197 | "fail to get channel position for isoc %s plug 0: %d\n", | |
198 | (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : "out", | |
199 | err); | |
200 | goto end; | |
201 | } | |
202 | pos = 0; | |
203 | ||
204 | /* positions in I/O buffer */ | |
205 | pcm = 0; | |
206 | midi = 0; | |
207 | ||
208 | /* the number of sections in AMDTP packet */ | |
209 | sections = buf[pos++]; | |
210 | ||
211 | for (sec = 0; sec < sections; sec++) { | |
212 | /* type of this section */ | |
213 | avc_bridgeco_fill_unit_addr(addr, dir, | |
214 | AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | |
215 | err = avc_bridgeco_get_plug_section_type(bebob->unit, addr, | |
216 | sec, &type); | |
217 | if (err < 0) { | |
218 | dev_err(&bebob->unit->device, | |
219 | "fail to get section type for isoc %s plug 0: %d\n", | |
220 | (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : | |
221 | "out", | |
222 | err); | |
223 | goto end; | |
224 | } | |
225 | /* NoType */ | |
226 | if (type == 0xff) { | |
227 | err = -ENOSYS; | |
228 | goto end; | |
229 | } | |
230 | ||
231 | /* the number of channels in this section */ | |
232 | channels = buf[pos++]; | |
233 | ||
234 | for (ch = 0; ch < channels; ch++) { | |
235 | /* position of this channel in AMDTP packet */ | |
236 | stm_pos = buf[pos++] - 1; | |
237 | /* location of this channel in this section */ | |
238 | sec_loc = buf[pos++] - 1; | |
239 | ||
240 | switch (type) { | |
241 | /* for MIDI conformant data channel */ | |
242 | case 0x0a: | |
243 | /* AMDTP_MAX_CHANNELS_FOR_MIDI is 1. */ | |
244 | if ((midi > 0) && (stm_pos != midi)) { | |
245 | err = -ENOSYS; | |
246 | goto end; | |
247 | } | |
248 | s->midi_position = stm_pos; | |
249 | midi = stm_pos; | |
250 | break; | |
251 | /* for PCM data channel */ | |
252 | case 0x01: /* Headphone */ | |
253 | case 0x02: /* Microphone */ | |
254 | case 0x03: /* Line */ | |
255 | case 0x04: /* SPDIF */ | |
256 | case 0x05: /* ADAT */ | |
257 | case 0x06: /* TDIF */ | |
258 | case 0x07: /* MADI */ | |
259 | /* for undefined/changeable signal */ | |
260 | case 0x08: /* Analog */ | |
261 | case 0x09: /* Digital */ | |
262 | default: | |
263 | location = pcm + sec_loc; | |
264 | if (location >= AMDTP_MAX_CHANNELS_FOR_PCM) { | |
265 | err = -ENOSYS; | |
266 | goto end; | |
267 | } | |
268 | s->pcm_positions[location] = stm_pos; | |
269 | break; | |
270 | } | |
271 | } | |
272 | ||
273 | if (type != 0x0a) | |
274 | pcm += channels; | |
275 | else | |
276 | midi += channels; | |
277 | } | |
278 | end: | |
279 | kfree(buf); | |
280 | return err; | |
281 | } | |
282 | ||
283 | static int | |
284 | init_both_connections(struct snd_bebob *bebob) | |
285 | { | |
286 | int err; | |
287 | ||
288 | err = cmp_connection_init(&bebob->in_conn, | |
289 | bebob->unit, CMP_INPUT, 0); | |
290 | if (err < 0) | |
291 | goto end; | |
292 | ||
293 | err = cmp_connection_init(&bebob->out_conn, | |
294 | bebob->unit, CMP_OUTPUT, 0); | |
295 | if (err < 0) | |
296 | cmp_connection_destroy(&bebob->in_conn); | |
297 | end: | |
298 | return err; | |
299 | } | |
300 | ||
301 | static int | |
302 | check_connection_used_by_others(struct snd_bebob *bebob, struct amdtp_stream *s) | |
303 | { | |
304 | struct cmp_connection *conn; | |
305 | bool used; | |
306 | int err; | |
307 | ||
308 | if (s == &bebob->tx_stream) | |
309 | conn = &bebob->out_conn; | |
310 | else | |
311 | conn = &bebob->in_conn; | |
312 | ||
313 | err = cmp_connection_check_used(conn, &used); | |
314 | if ((err >= 0) && used && !amdtp_stream_running(s)) { | |
315 | dev_err(&bebob->unit->device, | |
316 | "Connection established by others: %cPCR[%d]\n", | |
317 | (conn->direction == CMP_OUTPUT) ? 'o' : 'i', | |
318 | conn->pcr_index); | |
319 | err = -EBUSY; | |
320 | } | |
321 | ||
322 | return err; | |
323 | } | |
324 | ||
325 | static int | |
326 | make_both_connections(struct snd_bebob *bebob, unsigned int rate) | |
327 | { | |
328 | int index, pcm_channels, midi_channels, err; | |
329 | ||
330 | /* confirm params for both streams */ | |
331 | index = get_formation_index(rate); | |
332 | pcm_channels = bebob->tx_stream_formations[index].pcm; | |
333 | midi_channels = bebob->tx_stream_formations[index].midi; | |
334 | amdtp_stream_set_parameters(&bebob->tx_stream, | |
335 | rate, pcm_channels, midi_channels * 8); | |
336 | pcm_channels = bebob->rx_stream_formations[index].pcm; | |
337 | midi_channels = bebob->rx_stream_formations[index].midi; | |
338 | amdtp_stream_set_parameters(&bebob->rx_stream, | |
339 | rate, pcm_channels, midi_channels * 8); | |
340 | ||
341 | /* establish connections for both streams */ | |
342 | err = cmp_connection_establish(&bebob->out_conn, | |
343 | amdtp_stream_get_max_payload(&bebob->tx_stream)); | |
344 | if (err < 0) | |
345 | goto end; | |
346 | err = cmp_connection_establish(&bebob->in_conn, | |
347 | amdtp_stream_get_max_payload(&bebob->rx_stream)); | |
348 | if (err < 0) | |
349 | cmp_connection_break(&bebob->out_conn); | |
350 | end: | |
351 | return err; | |
352 | } | |
353 | ||
354 | static void | |
355 | break_both_connections(struct snd_bebob *bebob) | |
356 | { | |
357 | cmp_connection_break(&bebob->in_conn); | |
358 | cmp_connection_break(&bebob->out_conn); | |
359 | } | |
360 | ||
361 | static void | |
362 | destroy_both_connections(struct snd_bebob *bebob) | |
363 | { | |
364 | break_both_connections(bebob); | |
365 | ||
366 | cmp_connection_destroy(&bebob->in_conn); | |
367 | cmp_connection_destroy(&bebob->out_conn); | |
368 | } | |
369 | ||
370 | static int | |
371 | get_sync_mode(struct snd_bebob *bebob, enum cip_flags *sync_mode) | |
372 | { | |
373 | /* currently this module doesn't support SYT-Match mode */ | |
374 | *sync_mode = CIP_SYNC_TO_DEVICE; | |
375 | return 0; | |
376 | } | |
377 | ||
378 | static int | |
379 | start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream, | |
380 | unsigned int rate) | |
381 | { | |
382 | struct cmp_connection *conn; | |
383 | int err = 0; | |
384 | ||
385 | if (stream == &bebob->rx_stream) | |
386 | conn = &bebob->in_conn; | |
387 | else | |
388 | conn = &bebob->out_conn; | |
389 | ||
390 | /* channel mapping */ | |
391 | err = map_data_channels(bebob, stream); | |
392 | if (err < 0) | |
393 | goto end; | |
394 | ||
395 | /* start amdtp stream */ | |
396 | err = amdtp_stream_start(stream, | |
397 | conn->resources.channel, | |
398 | conn->speed); | |
399 | end: | |
400 | return err; | |
401 | } | |
402 | ||
403 | int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) | |
404 | { | |
405 | int err; | |
406 | ||
407 | err = init_both_connections(bebob); | |
408 | if (err < 0) | |
409 | goto end; | |
410 | ||
411 | err = amdtp_stream_init(&bebob->tx_stream, bebob->unit, | |
412 | AMDTP_IN_STREAM, CIP_BLOCKING); | |
413 | if (err < 0) { | |
414 | amdtp_stream_destroy(&bebob->tx_stream); | |
415 | destroy_both_connections(bebob); | |
416 | goto end; | |
417 | } | |
418 | ||
419 | err = amdtp_stream_init(&bebob->rx_stream, bebob->unit, | |
420 | AMDTP_OUT_STREAM, CIP_BLOCKING); | |
421 | if (err < 0) { | |
422 | amdtp_stream_destroy(&bebob->tx_stream); | |
423 | amdtp_stream_destroy(&bebob->rx_stream); | |
424 | destroy_both_connections(bebob); | |
425 | } | |
426 | end: | |
427 | return err; | |
428 | } | |
429 | ||
430 | int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, int rate) | |
431 | { | |
432 | struct amdtp_stream *master, *slave; | |
433 | atomic_t *slave_substreams; | |
434 | enum cip_flags sync_mode; | |
435 | unsigned int curr_rate; | |
436 | int err = 0; | |
437 | ||
438 | mutex_lock(&bebob->mutex); | |
439 | ||
440 | /* Need no substreams */ | |
441 | if (atomic_read(&bebob->playback_substreams) == 0 && | |
442 | atomic_read(&bebob->capture_substreams) == 0) | |
443 | goto end; | |
444 | ||
445 | err = get_sync_mode(bebob, &sync_mode); | |
446 | if (err < 0) | |
447 | goto end; | |
448 | if (sync_mode == CIP_SYNC_TO_DEVICE) { | |
449 | master = &bebob->tx_stream; | |
450 | slave = &bebob->rx_stream; | |
451 | slave_substreams = &bebob->playback_substreams; | |
452 | } else { | |
453 | master = &bebob->rx_stream; | |
454 | slave = &bebob->tx_stream; | |
455 | slave_substreams = &bebob->capture_substreams; | |
456 | } | |
457 | ||
458 | /* | |
459 | * Considering JACK/FFADO streaming: | |
460 | * TODO: This can be removed hwdep functionality becomes popular. | |
461 | */ | |
462 | err = check_connection_used_by_others(bebob, master); | |
463 | if (err < 0) | |
464 | goto end; | |
465 | ||
466 | /* packet queueing error */ | |
467 | if (amdtp_streaming_error(master)) { | |
468 | amdtp_stream_stop(master); | |
469 | amdtp_stream_stop(slave); | |
470 | } | |
471 | if (amdtp_streaming_error(slave)) | |
472 | amdtp_stream_stop(slave); | |
473 | ||
474 | /* stop streams if rate is different */ | |
475 | err = snd_bebob_stream_get_rate(bebob, &curr_rate); | |
476 | if (err < 0) { | |
477 | dev_err(&bebob->unit->device, | |
478 | "fail to get sampling rate: %d\n", err); | |
479 | goto end; | |
480 | } | |
481 | if (rate == 0) | |
482 | rate = curr_rate; | |
483 | if (rate != curr_rate) { | |
484 | amdtp_stream_stop(master); | |
485 | amdtp_stream_stop(slave); | |
486 | break_both_connections(bebob); | |
487 | } | |
488 | ||
489 | /* master should be always running */ | |
490 | if (!amdtp_stream_running(master)) { | |
491 | amdtp_stream_set_sync(sync_mode, master, slave); | |
492 | bebob->master = master; | |
493 | ||
494 | /* | |
495 | * NOTE: | |
496 | * If establishing connections at first, Yamaha GO46 | |
497 | * (and maybe Terratec X24) don't generate sound. | |
498 | */ | |
499 | err = snd_bebob_stream_set_rate(bebob, rate); | |
500 | if (err < 0) { | |
501 | dev_err(&bebob->unit->device, | |
502 | "fail to set sampling rate: %d\n", | |
503 | err); | |
504 | goto end; | |
505 | } | |
506 | ||
507 | err = make_both_connections(bebob, rate); | |
508 | if (err < 0) | |
509 | goto end; | |
510 | ||
511 | err = start_stream(bebob, master, rate); | |
512 | if (err < 0) { | |
513 | dev_err(&bebob->unit->device, | |
514 | "fail to run AMDTP master stream:%d\n", err); | |
515 | break_both_connections(bebob); | |
516 | goto end; | |
517 | } | |
518 | ||
519 | /* wait first callback */ | |
520 | if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT)) { | |
521 | amdtp_stream_stop(master); | |
522 | break_both_connections(bebob); | |
523 | err = -ETIMEDOUT; | |
524 | goto end; | |
525 | } | |
526 | } | |
527 | ||
528 | /* start slave if needed */ | |
529 | if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { | |
530 | err = start_stream(bebob, slave, rate); | |
531 | if (err < 0) { | |
532 | dev_err(&bebob->unit->device, | |
533 | "fail to run AMDTP slave stream:%d\n", err); | |
534 | amdtp_stream_stop(master); | |
535 | break_both_connections(bebob); | |
536 | goto end; | |
537 | } | |
538 | ||
539 | /* wait first callback */ | |
540 | if (!amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) { | |
541 | amdtp_stream_stop(slave); | |
542 | amdtp_stream_stop(master); | |
543 | break_both_connections(bebob); | |
544 | err = -ETIMEDOUT; | |
545 | } | |
546 | } | |
547 | end: | |
548 | mutex_unlock(&bebob->mutex); | |
549 | return err; | |
550 | } | |
551 | ||
552 | void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) | |
553 | { | |
554 | struct amdtp_stream *master, *slave; | |
555 | atomic_t *master_substreams, *slave_substreams; | |
556 | ||
557 | mutex_lock(&bebob->mutex); | |
558 | ||
559 | if (bebob->master == &bebob->rx_stream) { | |
560 | slave = &bebob->tx_stream; | |
561 | master = &bebob->rx_stream; | |
562 | slave_substreams = &bebob->capture_substreams; | |
563 | master_substreams = &bebob->playback_substreams; | |
564 | } else { | |
565 | slave = &bebob->rx_stream; | |
566 | master = &bebob->tx_stream; | |
567 | slave_substreams = &bebob->playback_substreams; | |
568 | master_substreams = &bebob->capture_substreams; | |
569 | } | |
570 | ||
571 | if (atomic_read(slave_substreams) == 0) { | |
572 | amdtp_stream_pcm_abort(slave); | |
573 | amdtp_stream_stop(slave); | |
574 | ||
575 | if (atomic_read(master_substreams) == 0) { | |
576 | amdtp_stream_pcm_abort(master); | |
577 | amdtp_stream_stop(master); | |
578 | break_both_connections(bebob); | |
579 | } | |
580 | } | |
581 | ||
582 | mutex_unlock(&bebob->mutex); | |
583 | } | |
584 | ||
585 | void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) | |
586 | { | |
587 | /* vs. XRUN recovery due to discontinuity at bus reset */ | |
588 | mutex_lock(&bebob->mutex); | |
589 | ||
590 | if ((cmp_connection_update(&bebob->in_conn) < 0) || | |
591 | (cmp_connection_update(&bebob->out_conn) < 0)) { | |
592 | amdtp_stream_pcm_abort(&bebob->rx_stream); | |
593 | amdtp_stream_pcm_abort(&bebob->tx_stream); | |
594 | amdtp_stream_stop(&bebob->rx_stream); | |
595 | amdtp_stream_stop(&bebob->tx_stream); | |
596 | break_both_connections(bebob); | |
597 | } else { | |
598 | amdtp_stream_update(&bebob->rx_stream); | |
599 | amdtp_stream_update(&bebob->tx_stream); | |
600 | } | |
601 | ||
602 | mutex_unlock(&bebob->mutex); | |
603 | } | |
604 | ||
605 | void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) | |
606 | { | |
607 | mutex_lock(&bebob->mutex); | |
608 | ||
609 | amdtp_stream_pcm_abort(&bebob->rx_stream); | |
610 | amdtp_stream_pcm_abort(&bebob->tx_stream); | |
611 | ||
612 | amdtp_stream_stop(&bebob->rx_stream); | |
613 | amdtp_stream_stop(&bebob->tx_stream); | |
614 | ||
615 | amdtp_stream_destroy(&bebob->rx_stream); | |
616 | amdtp_stream_destroy(&bebob->tx_stream); | |
617 | ||
618 | destroy_both_connections(bebob); | |
619 | ||
620 | mutex_unlock(&bebob->mutex); | |
621 | } | |
622 | ||
623 | /* | |
624 | * See: Table 50: Extended Stream Format Info Format Hierarchy Level 2’ | |
625 | * in Additional AVC commands (Nov 2003, BridgeCo) | |
626 | * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005 | |
627 | */ | |
628 | static int | |
629 | parse_stream_formation(u8 *buf, unsigned int len, | |
630 | struct snd_bebob_stream_formation *formation) | |
631 | { | |
632 | unsigned int i, e, channels, format; | |
633 | ||
634 | /* | |
635 | * this module can support a hierarchy combination that: | |
636 | * Root: Audio and Music (0x90) | |
637 | * Level 1: AM824 Compound (0x40) | |
638 | */ | |
639 | if ((buf[0] != 0x90) || (buf[1] != 0x40)) | |
640 | return -ENOSYS; | |
641 | ||
642 | /* check sampling rate */ | |
643 | for (i = 0; i < ARRAY_SIZE(bridgeco_freq_table); i++) { | |
644 | if (buf[2] == bridgeco_freq_table[i]) | |
645 | break; | |
646 | } | |
647 | if (i == sizeof(bridgeco_freq_table)) | |
648 | return -ENOSYS; | |
649 | ||
650 | /* Avoid double count by different entries for the same rate. */ | |
651 | memset(&formation[i], 0, sizeof(struct snd_bebob_stream_formation)); | |
652 | ||
653 | for (e = 0; e < buf[4]; e++) { | |
654 | channels = buf[5 + e * 2]; | |
655 | format = buf[6 + e * 2]; | |
656 | ||
657 | switch (format) { | |
658 | /* IEC 60958-3, currently handle as MBLA */ | |
659 | case 0x00: | |
660 | /* Multi bit linear audio */ | |
661 | case 0x06: /* Raw */ | |
662 | formation[i].pcm += channels; | |
663 | break; | |
664 | /* MIDI Conformant */ | |
665 | case 0x0d: | |
666 | formation[i].midi += channels; | |
667 | break; | |
668 | /* IEC 61937-3 to 7 */ | |
669 | case 0x01: | |
670 | case 0x02: | |
671 | case 0x03: | |
672 | case 0x04: | |
673 | case 0x05: | |
674 | /* Multi bit linear audio */ | |
675 | case 0x07: /* DVD-Audio */ | |
676 | case 0x0c: /* High Precision */ | |
677 | /* One Bit Audio */ | |
678 | case 0x08: /* (Plain) Raw */ | |
679 | case 0x09: /* (Plain) SACD */ | |
680 | case 0x0a: /* (Encoded) Raw */ | |
681 | case 0x0b: /* (Encoded) SACD */ | |
682 | /* Synchronization Stream (Stereo Raw audio) */ | |
683 | case 0x40: | |
684 | /* Don't care */ | |
685 | case 0xff: | |
686 | default: | |
687 | return -ENOSYS; /* not supported */ | |
688 | } | |
689 | } | |
690 | ||
691 | if (formation[i].pcm > AMDTP_MAX_CHANNELS_FOR_PCM || | |
692 | formation[i].midi > AMDTP_MAX_CHANNELS_FOR_MIDI) | |
693 | return -ENOSYS; | |
694 | ||
695 | return 0; | |
696 | } | |
697 | ||
698 | static int | |
699 | fill_stream_formations(struct snd_bebob *bebob, enum avc_bridgeco_plug_dir dir, | |
700 | unsigned short pid) | |
701 | { | |
702 | u8 *buf; | |
703 | struct snd_bebob_stream_formation *formations; | |
704 | unsigned int len, eid; | |
705 | u8 addr[AVC_BRIDGECO_ADDR_BYTES]; | |
706 | int err; | |
707 | ||
708 | buf = kmalloc(FORMAT_MAXIMUM_LENGTH, GFP_KERNEL); | |
709 | if (buf == NULL) | |
710 | return -ENOMEM; | |
711 | ||
712 | if (dir == AVC_BRIDGECO_PLUG_DIR_IN) | |
713 | formations = bebob->rx_stream_formations; | |
714 | else | |
715 | formations = bebob->tx_stream_formations; | |
716 | ||
717 | for (eid = 0; eid < SND_BEBOB_STRM_FMT_ENTRIES; eid++) { | |
718 | len = FORMAT_MAXIMUM_LENGTH; | |
719 | avc_bridgeco_fill_unit_addr(addr, dir, | |
720 | AVC_BRIDGECO_PLUG_UNIT_ISOC, pid); | |
721 | err = avc_bridgeco_get_plug_strm_fmt(bebob->unit, addr, buf, | |
722 | &len, eid); | |
723 | /* No entries remained. */ | |
724 | if (err == -EINVAL && eid > 0) { | |
725 | err = 0; | |
726 | break; | |
727 | } else if (err < 0) { | |
728 | dev_err(&bebob->unit->device, | |
729 | "fail to get stream format %d for isoc %s plug %d:%d\n", | |
730 | eid, | |
731 | (dir == AVC_BRIDGECO_PLUG_DIR_IN) ? "in" : | |
732 | "out", | |
733 | pid, err); | |
734 | break; | |
735 | } | |
736 | ||
737 | err = parse_stream_formation(buf, len, formations); | |
738 | if (err < 0) | |
739 | break; | |
740 | } | |
741 | ||
742 | kfree(buf); | |
743 | return err; | |
744 | } | |
745 | ||
746 | static int | |
747 | seek_msu_sync_input_plug(struct snd_bebob *bebob) | |
748 | { | |
749 | u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; | |
750 | unsigned int i, type; | |
751 | int err; | |
752 | ||
753 | /* Get the number of Music Sub Unit for both direction. */ | |
754 | err = avc_general_get_plug_info(bebob->unit, 0x0c, 0x00, 0x00, plugs); | |
755 | if (err < 0) { | |
756 | dev_err(&bebob->unit->device, | |
757 | "fail to get info for MSU in/out plugs: %d\n", | |
758 | err); | |
759 | goto end; | |
760 | } | |
761 | ||
762 | /* seek destination plugs for 'MSU sync input' */ | |
763 | bebob->sync_input_plug = -1; | |
764 | for (i = 0; i < plugs[0]; i++) { | |
765 | avc_bridgeco_fill_msu_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, i); | |
766 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | |
767 | if (err < 0) { | |
768 | dev_err(&bebob->unit->device, | |
769 | "fail to get type for MSU in plug %d: %d\n", | |
770 | i, err); | |
771 | goto end; | |
772 | } | |
773 | ||
774 | if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) { | |
775 | bebob->sync_input_plug = i; | |
776 | break; | |
777 | } | |
778 | } | |
779 | end: | |
780 | return err; | |
781 | } | |
782 | ||
783 | int snd_bebob_stream_discover(struct snd_bebob *bebob) | |
784 | { | |
785 | u8 plugs[AVC_PLUG_INFO_BUF_BYTES], addr[AVC_BRIDGECO_ADDR_BYTES]; | |
786 | enum avc_bridgeco_plug_type type; | |
787 | unsigned int i; | |
788 | int err; | |
789 | ||
790 | /* the number of plugs for isoc in/out, ext in/out */ | |
791 | err = avc_general_get_plug_info(bebob->unit, 0x1f, 0x07, 0x00, plugs); | |
792 | if (err < 0) { | |
793 | dev_err(&bebob->unit->device, | |
794 | "fail to get info for isoc/external in/out plugs: %d\n", | |
795 | err); | |
796 | goto end; | |
797 | } | |
798 | ||
799 | /* | |
800 | * This module supports at least one isoc input plug and one isoc | |
801 | * output plug. | |
802 | */ | |
803 | if ((plugs[0] == 0) || (plugs[1] == 0)) { | |
804 | err = -ENOSYS; | |
805 | goto end; | |
806 | } | |
807 | ||
808 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, | |
809 | AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | |
810 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | |
811 | if (err < 0) { | |
812 | dev_err(&bebob->unit->device, | |
813 | "fail to get type for isoc in plug 0: %d\n", err); | |
814 | goto end; | |
815 | } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { | |
816 | err = -ENOSYS; | |
817 | goto end; | |
818 | } | |
819 | err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_IN, 0); | |
820 | if (err < 0) | |
821 | goto end; | |
822 | ||
823 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, | |
824 | AVC_BRIDGECO_PLUG_UNIT_ISOC, 0); | |
825 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | |
826 | if (err < 0) { | |
827 | dev_err(&bebob->unit->device, | |
828 | "fail to get type for isoc out plug 0: %d\n", err); | |
829 | goto end; | |
830 | } else if (type != AVC_BRIDGECO_PLUG_TYPE_ISOC) { | |
831 | err = -ENOSYS; | |
832 | goto end; | |
833 | } | |
834 | err = fill_stream_formations(bebob, AVC_BRIDGECO_PLUG_DIR_OUT, 0); | |
835 | if (err < 0) | |
836 | goto end; | |
837 | ||
838 | /* count external input plugs for MIDI */ | |
839 | bebob->midi_input_ports = 0; | |
840 | for (i = 0; i < plugs[2]; i++) { | |
841 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_IN, | |
842 | AVC_BRIDGECO_PLUG_UNIT_EXT, i); | |
843 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | |
844 | if (err < 0) { | |
845 | dev_err(&bebob->unit->device, | |
846 | "fail to get type for external in plug %d: %d\n", | |
847 | i, err); | |
848 | goto end; | |
849 | } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { | |
850 | bebob->midi_input_ports++; | |
851 | } | |
852 | } | |
853 | ||
854 | /* count external output plugs for MIDI */ | |
855 | bebob->midi_output_ports = 0; | |
856 | for (i = 0; i < plugs[3]; i++) { | |
857 | avc_bridgeco_fill_unit_addr(addr, AVC_BRIDGECO_PLUG_DIR_OUT, | |
858 | AVC_BRIDGECO_PLUG_UNIT_EXT, i); | |
859 | err = avc_bridgeco_get_plug_type(bebob->unit, addr, &type); | |
860 | if (err < 0) { | |
861 | dev_err(&bebob->unit->device, | |
862 | "fail to get type for external out plug %d: %d\n", | |
863 | i, err); | |
864 | goto end; | |
865 | } else if (type == AVC_BRIDGECO_PLUG_TYPE_MIDI) { | |
866 | bebob->midi_output_ports++; | |
867 | } | |
868 | } | |
869 | ||
870 | /* for check source of clock later */ | |
871 | err = seek_msu_sync_input_plug(bebob); | |
872 | end: | |
873 | return err; | |
874 | } |