]>
Commit | Line | Data |
---|---|---|
e2786ca6 TS |
1 | /* |
2 | * oxfw_stream.c - a part of driver for OXFW970/971 based devices | |
3 | * | |
4 | * Copyright (c) 2014 Takashi Sakamoto | |
5 | * | |
6 | * Licensed under the terms of the GNU General Public License, version 2. | |
7 | */ | |
8 | ||
9 | #include "oxfw.h" | |
f3699e2c | 10 | #include <linux/delay.h> |
e2786ca6 | 11 | |
5cd1d3f4 | 12 | #define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512 |
f3699e2c | 13 | #define CALLBACK_TIMEOUT 200 |
5cd1d3f4 TS |
14 | |
15 | /* | |
16 | * According to datasheet of Oxford Semiconductor: | |
17 | * OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O | |
18 | * OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O | |
19 | */ | |
20 | static const unsigned int oxfw_rate_table[] = { | |
21 | [0] = 32000, | |
22 | [1] = 44100, | |
23 | [2] = 48000, | |
24 | [3] = 88200, | |
25 | [4] = 96000, | |
26 | [5] = 192000, | |
27 | }; | |
28 | ||
29 | /* | |
30 | * See Table 5.7 – Sampling frequency for Multi-bit Audio | |
31 | * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA) | |
32 | */ | |
33 | static const unsigned int avc_stream_rate_table[] = { | |
34 | [0] = 0x02, | |
35 | [1] = 0x03, | |
36 | [2] = 0x04, | |
37 | [3] = 0x0a, | |
38 | [4] = 0x05, | |
39 | [5] = 0x07, | |
40 | }; | |
41 | ||
b0ac0009 TS |
42 | static int set_rate(struct snd_oxfw *oxfw, unsigned int rate) |
43 | { | |
44 | int err; | |
45 | ||
46 | err = avc_general_set_sig_fmt(oxfw->unit, rate, | |
47 | AVC_GENERAL_PLUG_DIR_IN, 0); | |
48 | if (err < 0) | |
49 | goto end; | |
50 | ||
51 | if (oxfw->has_output) | |
52 | err = avc_general_set_sig_fmt(oxfw->unit, rate, | |
53 | AVC_GENERAL_PLUG_DIR_OUT, 0); | |
54 | end: | |
55 | return err; | |
56 | } | |
57 | ||
f3699e2c TS |
58 | static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s, |
59 | unsigned int rate, unsigned int pcm_channels) | |
60 | { | |
61 | u8 **formats; | |
62 | struct snd_oxfw_stream_formation formation; | |
63 | enum avc_general_plug_dir dir; | |
5580ba7b DC |
64 | unsigned int len; |
65 | int i, err; | |
f3699e2c | 66 | |
b0ac0009 TS |
67 | if (s == &oxfw->tx_stream) { |
68 | formats = oxfw->tx_stream_formats; | |
69 | dir = AVC_GENERAL_PLUG_DIR_OUT; | |
70 | } else { | |
71 | formats = oxfw->rx_stream_formats; | |
72 | dir = AVC_GENERAL_PLUG_DIR_IN; | |
73 | } | |
f3699e2c TS |
74 | |
75 | /* Seek stream format for requirements. */ | |
76 | for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { | |
77 | err = snd_oxfw_stream_parse_format(formats[i], &formation); | |
78 | if (err < 0) | |
79 | return err; | |
80 | ||
81 | if ((formation.rate == rate) && (formation.pcm == pcm_channels)) | |
82 | break; | |
83 | } | |
84 | if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) | |
85 | return -EINVAL; | |
86 | ||
87 | /* If assumed, just change rate. */ | |
88 | if (oxfw->assumed) | |
b0ac0009 | 89 | return set_rate(oxfw, rate); |
f3699e2c TS |
90 | |
91 | /* Calculate format length. */ | |
92 | len = 5 + formats[i][4] * 2; | |
93 | ||
94 | err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len); | |
95 | if (err < 0) | |
96 | return err; | |
97 | ||
98 | /* Some requests just after changing format causes freezing. */ | |
99 | msleep(100); | |
100 | ||
101 | return 0; | |
102 | } | |
103 | ||
b0ac0009 | 104 | static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) |
e2786ca6 | 105 | { |
b0ac0009 TS |
106 | amdtp_stream_pcm_abort(stream); |
107 | amdtp_stream_stop(stream); | |
e2786ca6 | 108 | |
b0ac0009 TS |
109 | if (stream == &oxfw->tx_stream) |
110 | cmp_connection_break(&oxfw->out_conn); | |
111 | else | |
112 | cmp_connection_break(&oxfw->in_conn); | |
e2786ca6 TS |
113 | } |
114 | ||
b0ac0009 TS |
115 | static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream, |
116 | unsigned int rate, unsigned int pcm_channels) | |
e2786ca6 | 117 | { |
f3699e2c TS |
118 | u8 **formats; |
119 | struct cmp_connection *conn; | |
120 | struct snd_oxfw_stream_formation formation; | |
121 | unsigned int i, midi_ports; | |
f3699e2c | 122 | int err; |
e2786ca6 | 123 | |
b0ac0009 TS |
124 | if (stream == &oxfw->rx_stream) { |
125 | formats = oxfw->rx_stream_formats; | |
126 | conn = &oxfw->in_conn; | |
127 | } else { | |
128 | formats = oxfw->tx_stream_formats; | |
129 | conn = &oxfw->out_conn; | |
130 | } | |
f3699e2c | 131 | |
b0ac0009 | 132 | /* Get stream format */ |
f3699e2c TS |
133 | for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { |
134 | if (formats[i] == NULL) | |
135 | break; | |
136 | ||
137 | err = snd_oxfw_stream_parse_format(formats[i], &formation); | |
138 | if (err < 0) | |
139 | goto end; | |
140 | if (rate != formation.rate) | |
141 | continue; | |
142 | if (pcm_channels == 0 || pcm_channels == formation.pcm) | |
143 | break; | |
144 | } | |
145 | if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) { | |
146 | err = -EINVAL; | |
147 | goto end; | |
148 | } | |
149 | ||
150 | pcm_channels = formation.pcm; | |
151 | midi_ports = DIV_ROUND_UP(formation.midi, 8); | |
e2786ca6 | 152 | |
f3699e2c TS |
153 | /* The stream should have one pcm channels at least */ |
154 | if (pcm_channels == 0) { | |
155 | err = -EINVAL; | |
e2786ca6 | 156 | goto end; |
f3699e2c TS |
157 | } |
158 | amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports); | |
e2786ca6 | 159 | |
f3699e2c TS |
160 | err = cmp_connection_establish(conn, |
161 | amdtp_stream_get_max_payload(stream)); | |
e2786ca6 TS |
162 | if (err < 0) |
163 | goto end; | |
164 | ||
f3699e2c TS |
165 | err = amdtp_stream_start(stream, |
166 | conn->resources.channel, | |
167 | conn->speed); | |
168 | if (err < 0) { | |
169 | cmp_connection_break(conn); | |
170 | goto end; | |
171 | } | |
172 | ||
173 | /* Wait first packet */ | |
174 | err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT); | |
175 | if (err < 0) | |
b0ac0009 | 176 | stop_stream(oxfw, stream); |
f3699e2c TS |
177 | end: |
178 | return err; | |
179 | } | |
180 | ||
b0ac0009 TS |
181 | static int check_connection_used_by_others(struct snd_oxfw *oxfw, |
182 | struct amdtp_stream *stream) | |
f3699e2c | 183 | { |
b0ac0009 TS |
184 | struct cmp_connection *conn; |
185 | bool used; | |
186 | int err; | |
187 | ||
188 | if (stream == &oxfw->tx_stream) | |
189 | conn = &oxfw->out_conn; | |
190 | else | |
191 | conn = &oxfw->in_conn; | |
192 | ||
193 | err = cmp_connection_check_used(conn, &used); | |
194 | if ((err >= 0) && used && !amdtp_stream_running(stream)) { | |
195 | dev_err(&oxfw->unit->device, | |
196 | "Connection established by others: %cPCR[%d]\n", | |
197 | (conn->direction == CMP_OUTPUT) ? 'o' : 'i', | |
198 | conn->pcr_index); | |
199 | err = -EBUSY; | |
200 | } | |
201 | ||
202 | return err; | |
203 | } | |
204 | ||
205 | int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw, | |
206 | struct amdtp_stream *stream) | |
207 | { | |
208 | struct cmp_connection *conn; | |
209 | enum cmp_direction c_dir; | |
210 | enum amdtp_stream_direction s_dir; | |
211 | int err; | |
212 | ||
213 | if (stream == &oxfw->tx_stream) { | |
214 | conn = &oxfw->out_conn; | |
215 | c_dir = CMP_OUTPUT; | |
216 | s_dir = AMDTP_IN_STREAM; | |
217 | } else { | |
218 | conn = &oxfw->in_conn; | |
219 | c_dir = CMP_INPUT; | |
220 | s_dir = AMDTP_OUT_STREAM; | |
221 | } | |
222 | ||
223 | err = cmp_connection_init(conn, oxfw->unit, c_dir, 0); | |
224 | if (err < 0) | |
225 | goto end; | |
226 | ||
227 | err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING); | |
228 | if (err < 0) { | |
229 | amdtp_stream_destroy(stream); | |
230 | cmp_connection_destroy(conn); | |
231 | goto end; | |
232 | } | |
233 | ||
234 | /* OXFW starts to transmit packets with non-zero dbc. */ | |
235 | if (stream == &oxfw->tx_stream) | |
236 | oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK; | |
237 | end: | |
238 | return err; | |
239 | } | |
240 | ||
241 | int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, | |
242 | struct amdtp_stream *stream, | |
243 | unsigned int rate, unsigned int pcm_channels) | |
244 | { | |
245 | struct amdtp_stream *opposite; | |
f3699e2c | 246 | struct snd_oxfw_stream_formation formation; |
b0ac0009 TS |
247 | enum avc_general_plug_dir dir; |
248 | unsigned int substreams, opposite_substreams; | |
f3699e2c TS |
249 | int err = 0; |
250 | ||
b0ac0009 TS |
251 | if (stream == &oxfw->tx_stream) { |
252 | substreams = oxfw->capture_substreams; | |
253 | opposite = &oxfw->rx_stream; | |
254 | opposite_substreams = oxfw->playback_substreams; | |
255 | dir = AVC_GENERAL_PLUG_DIR_OUT; | |
256 | } else { | |
257 | substreams = oxfw->playback_substreams; | |
258 | opposite_substreams = oxfw->capture_substreams; | |
259 | ||
260 | if (oxfw->has_output) | |
261 | opposite = &oxfw->rx_stream; | |
262 | else | |
263 | opposite = NULL; | |
264 | ||
265 | dir = AVC_GENERAL_PLUG_DIR_IN; | |
266 | } | |
267 | ||
268 | if (substreams == 0) | |
269 | goto end; | |
270 | ||
271 | /* | |
272 | * Considering JACK/FFADO streaming: | |
273 | * TODO: This can be removed hwdep functionality becomes popular. | |
274 | */ | |
275 | err = check_connection_used_by_others(oxfw, stream); | |
276 | if (err < 0) | |
277 | goto end; | |
278 | ||
f3699e2c | 279 | /* packet queueing error */ |
b0ac0009 TS |
280 | if (amdtp_streaming_error(stream)) |
281 | stop_stream(oxfw, stream); | |
f3699e2c | 282 | |
b0ac0009 | 283 | err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); |
e2786ca6 | 284 | if (err < 0) |
f3699e2c | 285 | goto end; |
05588d34 TS |
286 | if (rate == 0) |
287 | rate = formation.rate; | |
288 | if (pcm_channels == 0) | |
289 | pcm_channels = formation.pcm; | |
f3699e2c TS |
290 | |
291 | if ((formation.rate != rate) || (formation.pcm != pcm_channels)) { | |
b0ac0009 TS |
292 | if (opposite != NULL) { |
293 | err = check_connection_used_by_others(oxfw, opposite); | |
294 | if (err < 0) | |
295 | goto end; | |
296 | stop_stream(oxfw, opposite); | |
297 | } | |
298 | stop_stream(oxfw, stream); | |
f3699e2c | 299 | |
b0ac0009 | 300 | err = set_stream_format(oxfw, stream, rate, pcm_channels); |
f3699e2c TS |
301 | if (err < 0) { |
302 | dev_err(&oxfw->unit->device, | |
303 | "fail to set stream format: %d\n", err); | |
304 | goto end; | |
305 | } | |
b0ac0009 TS |
306 | |
307 | /* Start opposite stream if needed. */ | |
308 | if (opposite && !amdtp_stream_running(opposite) && | |
309 | (opposite_substreams > 0)) { | |
310 | err = start_stream(oxfw, opposite, rate, 0); | |
311 | if (err < 0) { | |
312 | dev_err(&oxfw->unit->device, | |
313 | "fail to restart stream: %d\n", err); | |
314 | goto end; | |
315 | } | |
316 | } | |
f3699e2c TS |
317 | } |
318 | ||
b0ac0009 TS |
319 | /* Start requested stream. */ |
320 | if (!amdtp_stream_running(stream)) { | |
321 | err = start_stream(oxfw, stream, rate, pcm_channels); | |
322 | if (err < 0) | |
323 | dev_err(&oxfw->unit->device, | |
324 | "fail to start stream: %d\n", err); | |
325 | } | |
e2786ca6 TS |
326 | end: |
327 | return err; | |
328 | } | |
329 | ||
b0ac0009 TS |
330 | void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, |
331 | struct amdtp_stream *stream) | |
e2786ca6 | 332 | { |
b0ac0009 TS |
333 | if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) || |
334 | ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0))) | |
335 | return; | |
336 | ||
337 | stop_stream(oxfw, stream); | |
e2786ca6 TS |
338 | } |
339 | ||
d23c2cc4 TS |
340 | /* |
341 | * This function should be called before starting the stream or after stopping | |
342 | * the streams. | |
343 | */ | |
b0ac0009 TS |
344 | void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, |
345 | struct amdtp_stream *stream) | |
e2786ca6 | 346 | { |
b0ac0009 TS |
347 | struct cmp_connection *conn; |
348 | ||
349 | if (stream == &oxfw->tx_stream) | |
350 | conn = &oxfw->out_conn; | |
351 | else | |
352 | conn = &oxfw->in_conn; | |
e2786ca6 | 353 | |
b0ac0009 TS |
354 | amdtp_stream_destroy(stream); |
355 | cmp_connection_destroy(conn); | |
e2786ca6 TS |
356 | } |
357 | ||
b0ac0009 TS |
358 | void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw, |
359 | struct amdtp_stream *stream) | |
e2786ca6 | 360 | { |
b0ac0009 TS |
361 | struct cmp_connection *conn; |
362 | ||
363 | if (stream == &oxfw->tx_stream) | |
364 | conn = &oxfw->out_conn; | |
365 | else | |
366 | conn = &oxfw->in_conn; | |
367 | ||
368 | if (cmp_connection_update(conn) < 0) | |
369 | stop_stream(oxfw, stream); | |
e2786ca6 | 370 | else |
b0ac0009 | 371 | amdtp_stream_update(stream); |
e2786ca6 | 372 | } |
5cd1d3f4 | 373 | |
3c96101f TS |
374 | int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw, |
375 | enum avc_general_plug_dir dir, | |
376 | struct snd_oxfw_stream_formation *formation) | |
377 | { | |
378 | u8 *format; | |
379 | unsigned int len; | |
380 | int err; | |
381 | ||
382 | len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; | |
383 | format = kmalloc(len, GFP_KERNEL); | |
384 | if (format == NULL) | |
385 | return -ENOMEM; | |
386 | ||
387 | err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len); | |
388 | if (err < 0) | |
389 | goto end; | |
390 | if (len < 3) { | |
391 | err = -EIO; | |
392 | goto end; | |
393 | } | |
394 | ||
395 | err = snd_oxfw_stream_parse_format(format, formation); | |
396 | end: | |
397 | kfree(format); | |
398 | return err; | |
399 | } | |
400 | ||
5cd1d3f4 TS |
401 | /* |
402 | * See Table 6.16 - AM824 Stream Format | |
403 | * Figure 6.19 - format_information field for AM824 Compound | |
404 | * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA) | |
405 | * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005 | |
406 | */ | |
407 | int snd_oxfw_stream_parse_format(u8 *format, | |
408 | struct snd_oxfw_stream_formation *formation) | |
409 | { | |
410 | unsigned int i, e, channels, type; | |
411 | ||
412 | memset(formation, 0, sizeof(struct snd_oxfw_stream_formation)); | |
413 | ||
414 | /* | |
415 | * this module can support a hierarchy combination that: | |
416 | * Root: Audio and Music (0x90) | |
417 | * Level 1: AM824 Compound (0x40) | |
418 | */ | |
419 | if ((format[0] != 0x90) || (format[1] != 0x40)) | |
420 | return -ENOSYS; | |
421 | ||
422 | /* check the sampling rate */ | |
423 | for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) { | |
424 | if (format[2] == avc_stream_rate_table[i]) | |
425 | break; | |
426 | } | |
427 | if (i == ARRAY_SIZE(avc_stream_rate_table)) | |
428 | return -ENOSYS; | |
429 | ||
430 | formation->rate = oxfw_rate_table[i]; | |
431 | ||
432 | for (e = 0; e < format[4]; e++) { | |
433 | channels = format[5 + e * 2]; | |
434 | type = format[6 + e * 2]; | |
435 | ||
436 | switch (type) { | |
437 | /* IEC 60958 Conformant, currently handled as MBLA */ | |
438 | case 0x00: | |
439 | /* Multi Bit Linear Audio (Raw) */ | |
440 | case 0x06: | |
441 | formation->pcm += channels; | |
442 | break; | |
443 | /* MIDI Conformant */ | |
444 | case 0x0d: | |
445 | formation->midi = channels; | |
446 | break; | |
447 | /* IEC 61937-3 to 7 */ | |
448 | case 0x01: | |
449 | case 0x02: | |
450 | case 0x03: | |
451 | case 0x04: | |
452 | case 0x05: | |
453 | /* Multi Bit Linear Audio */ | |
454 | case 0x07: /* DVD-Audio */ | |
455 | case 0x0c: /* High Precision */ | |
456 | /* One Bit Audio */ | |
457 | case 0x08: /* (Plain) Raw */ | |
458 | case 0x09: /* (Plain) SACD */ | |
459 | case 0x0a: /* (Encoded) Raw */ | |
460 | case 0x0b: /* (Encoded) SACD */ | |
461 | /* SMPTE Time-Code conformant */ | |
462 | case 0x0e: | |
463 | /* Sample Count */ | |
464 | case 0x0f: | |
465 | /* Anciliary Data */ | |
466 | case 0x10: | |
467 | /* Synchronization Stream (Stereo Raw audio) */ | |
468 | case 0x40: | |
469 | /* Don't care */ | |
470 | case 0xff: | |
471 | default: | |
472 | return -ENOSYS; /* not supported */ | |
473 | } | |
474 | } | |
475 | ||
476 | if (formation->pcm > AMDTP_MAX_CHANNELS_FOR_PCM || | |
477 | formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI) | |
478 | return -ENOSYS; | |
479 | ||
480 | return 0; | |
481 | } | |
482 | ||
483 | static int | |
484 | assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, | |
485 | unsigned int pid, u8 *buf, unsigned int *len, | |
486 | u8 **formats) | |
487 | { | |
488 | struct snd_oxfw_stream_formation formation; | |
489 | unsigned int i, eid; | |
490 | int err; | |
491 | ||
492 | /* get format at current sampling rate */ | |
493 | err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len); | |
494 | if (err < 0) { | |
495 | dev_err(&oxfw->unit->device, | |
496 | "fail to get current stream format for isoc %s plug %d:%d\n", | |
497 | (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out", | |
498 | pid, err); | |
499 | goto end; | |
500 | } | |
501 | ||
502 | /* parse and set stream format */ | |
503 | eid = 0; | |
504 | err = snd_oxfw_stream_parse_format(buf, &formation); | |
505 | if (err < 0) | |
506 | goto end; | |
507 | ||
508 | formats[eid] = kmalloc(*len, GFP_KERNEL); | |
509 | if (formats[eid] == NULL) { | |
510 | err = -ENOMEM; | |
511 | goto end; | |
512 | } | |
513 | memcpy(formats[eid], buf, *len); | |
514 | ||
515 | /* apply the format for each available sampling rate */ | |
516 | for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) { | |
517 | if (formation.rate == oxfw_rate_table[i]) | |
518 | continue; | |
519 | ||
520 | err = avc_general_inquiry_sig_fmt(oxfw->unit, | |
521 | oxfw_rate_table[i], | |
522 | dir, pid); | |
523 | if (err < 0) | |
524 | continue; | |
525 | ||
526 | eid++; | |
527 | formats[eid] = kmalloc(*len, GFP_KERNEL); | |
528 | if (formats[eid] == NULL) { | |
529 | err = -ENOMEM; | |
530 | goto end; | |
531 | } | |
532 | memcpy(formats[eid], buf, *len); | |
533 | formats[eid][2] = avc_stream_rate_table[i]; | |
534 | } | |
535 | ||
536 | err = 0; | |
537 | oxfw->assumed = true; | |
538 | end: | |
539 | return err; | |
540 | } | |
541 | ||
542 | static int fill_stream_formats(struct snd_oxfw *oxfw, | |
543 | enum avc_general_plug_dir dir, | |
544 | unsigned short pid) | |
545 | { | |
546 | u8 *buf, **formats; | |
547 | unsigned int len, eid = 0; | |
548 | struct snd_oxfw_stream_formation dummy; | |
549 | int err; | |
550 | ||
551 | buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL); | |
552 | if (buf == NULL) | |
553 | return -ENOMEM; | |
554 | ||
b0ac0009 TS |
555 | if (dir == AVC_GENERAL_PLUG_DIR_OUT) |
556 | formats = oxfw->tx_stream_formats; | |
557 | else | |
558 | formats = oxfw->rx_stream_formats; | |
5cd1d3f4 TS |
559 | |
560 | /* get first entry */ | |
561 | len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; | |
562 | err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0); | |
563 | if (err == -ENOSYS) { | |
564 | /* LIST subfunction is not implemented */ | |
565 | len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; | |
566 | err = assume_stream_formats(oxfw, dir, pid, buf, &len, | |
567 | formats); | |
568 | goto end; | |
569 | } else if (err < 0) { | |
570 | dev_err(&oxfw->unit->device, | |
571 | "fail to get stream format %d for isoc %s plug %d:%d\n", | |
572 | eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out", | |
573 | pid, err); | |
574 | goto end; | |
575 | } | |
576 | ||
577 | /* LIST subfunction is implemented */ | |
578 | while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) { | |
579 | /* The format is too short. */ | |
580 | if (len < 3) { | |
581 | err = -EIO; | |
582 | break; | |
583 | } | |
584 | ||
585 | /* parse and set stream format */ | |
586 | err = snd_oxfw_stream_parse_format(buf, &dummy); | |
587 | if (err < 0) | |
588 | break; | |
589 | ||
590 | formats[eid] = kmalloc(len, GFP_KERNEL); | |
591 | if (formats[eid] == NULL) { | |
592 | err = -ENOMEM; | |
593 | break; | |
594 | } | |
595 | memcpy(formats[eid], buf, len); | |
596 | ||
597 | /* get next entry */ | |
598 | len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; | |
599 | err = avc_stream_get_format_list(oxfw->unit, dir, 0, | |
600 | buf, &len, ++eid); | |
601 | /* No entries remained. */ | |
602 | if (err == -EINVAL) { | |
603 | err = 0; | |
604 | break; | |
605 | } else if (err < 0) { | |
606 | dev_err(&oxfw->unit->device, | |
607 | "fail to get stream format %d for isoc %s plug %d:%d\n", | |
608 | eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : | |
609 | "out", | |
610 | pid, err); | |
611 | break; | |
612 | } | |
613 | } | |
614 | end: | |
615 | kfree(buf); | |
616 | return err; | |
617 | } | |
618 | ||
619 | int snd_oxfw_stream_discover(struct snd_oxfw *oxfw) | |
620 | { | |
621 | u8 plugs[AVC_PLUG_INFO_BUF_BYTES]; | |
622 | int err; | |
623 | ||
624 | /* the number of plugs for isoc in/out, ext in/out */ | |
625 | err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs); | |
626 | if (err < 0) { | |
627 | dev_err(&oxfw->unit->device, | |
628 | "fail to get info for isoc/external in/out plugs: %d\n", | |
629 | err); | |
630 | goto end; | |
b0ac0009 | 631 | } else if ((plugs[0] == 0) && (plugs[1] == 0)) { |
5cd1d3f4 TS |
632 | err = -ENOSYS; |
633 | goto end; | |
634 | } | |
635 | ||
b0ac0009 TS |
636 | /* use oPCR[0] if exists */ |
637 | if (plugs[1] > 0) { | |
638 | err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0); | |
639 | if (err < 0) | |
640 | goto end; | |
641 | oxfw->has_output = true; | |
642 | } | |
643 | ||
5cd1d3f4 TS |
644 | /* use iPCR[0] if exists */ |
645 | if (plugs[0] > 0) | |
646 | err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0); | |
647 | end: | |
648 | return err; | |
649 | } | |
8985f4ac TS |
650 | |
651 | void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw) | |
652 | { | |
653 | oxfw->dev_lock_changed = true; | |
654 | wake_up(&oxfw->hwdep_wait); | |
655 | } | |
656 | ||
657 | int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw) | |
658 | { | |
659 | int err; | |
660 | ||
661 | spin_lock_irq(&oxfw->lock); | |
662 | ||
663 | /* user land lock this */ | |
664 | if (oxfw->dev_lock_count < 0) { | |
665 | err = -EBUSY; | |
666 | goto end; | |
667 | } | |
668 | ||
669 | /* this is the first time */ | |
670 | if (oxfw->dev_lock_count++ == 0) | |
671 | snd_oxfw_stream_lock_changed(oxfw); | |
672 | err = 0; | |
673 | end: | |
674 | spin_unlock_irq(&oxfw->lock); | |
675 | return err; | |
676 | } | |
677 | ||
678 | void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw) | |
679 | { | |
680 | spin_lock_irq(&oxfw->lock); | |
681 | ||
682 | if (WARN_ON(oxfw->dev_lock_count <= 0)) | |
683 | goto end; | |
684 | if (--oxfw->dev_lock_count == 0) | |
685 | snd_oxfw_stream_lock_changed(oxfw); | |
686 | end: | |
687 | spin_unlock_irq(&oxfw->lock); | |
688 | } |