aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-12-08 10:10:46 -0500
committerTakashi Iwai <tiwai@suse.de>2014-12-10 04:48:59 -0500
commitb0ac00095fe1485f60bb8ea7326426d3d02a1aec (patch)
treeffc60793adba922ceb4fa9ca34f63cc552a2c79b /sound/firewire
parentec4dba5053e1109368fb80d1c0b88f2a9c971122 (diff)
ALSA: oxfw: Add support AMDTP in-stream
Previous commit adds support for some devices which can capture PCM samples. These devices transmit AMDTP stream in non-blocking mode. This commit adds functionality to handle AMDTP incoming stream. OXFW seems to have two quirks: - Transmits packets with non-zero dbc in its beginning - Transmits packets with wrong values in syt field For the first quirk, this commit adds CIP_SKIP_INIT_DBC_CHECK flag for incoming stream to skip first check of dbc. For the second quirk, this commit doesn't add duplex stream which Fireworks/BeBoB drivers use. So OXFW driver generates syt value for outgoing stream. Here are examples of a sequence of packets transmitted by Behringer F-Control Audio 202. There are differences between sequences of syt value when OXFW driver transfers outgoing stream or not. When driver gives no outgoing stream: Index Payload CIP_Header_0 CIP_Header_1 38 14 00020092 900103D1 39 12 00020098 900102FF 40 12 0002009D 9001027F 41 14 000200A2 90010396 42 14 000200A8 900102E8 43 12 000200AE 90010219 44 14 000200B3 90010331 45 12 000200B9 9001025F 46 14 000200BE 90010376 47 12 000200C4 900102A1 00 12 000200C9 9001023E 01 14 000200CE 90010358 02 12 000200D4 90010289 03 16 000200D9 900103A3 04 12 000200E0 900102DD 05 14 000200E5 900103F1 06 12 000200EB 90010335 07 12 000200F0 90010263 08 14 000200F5 9001037C 09 12 000200FB 900102AE When driver gives outgoing stream: Index Payload CIP_Header_0 CIP_Header_1 38 12 000200BD 900104A8 39 14 000200C2 900104A8 40 12 000200C8 900104AC 41 14 000200CD 900104A9 42 12 000200D3 900104B1 43 14 000200D8 900104A8 44 12 000200DE 900104AA 45 14 000200E3 900104A9 46 14 000200E9 900104AE 47 12 000200EF 900104A8 00 14 000200F4 900104AD 01 12 000200FA 900104A7 02 14 000200FF 900104A9 03 12 00020005 900104A9 04 14 0002000A 900104B1 05 12 00020010 900104AA 06 14 00020015 900104AD 07 12 0002001B 900104A7 08 14 00020020 900104AC 09 12 00020026 900104A7 Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Acked-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c6
-rw-r--r--sound/firewire/oxfw/oxfw-proc.c29
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c270
-rw-r--r--sound/firewire/oxfw/oxfw.c25
-rw-r--r--sound/firewire/oxfw/oxfw.h24
5 files changed, 279 insertions, 75 deletions
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index ea2b439253cf..a78339c81de8 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -177,7 +177,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
177 struct snd_oxfw *oxfw = substream->private_data; 177 struct snd_oxfw *oxfw = substream->private_data;
178 178
179 mutex_lock(&oxfw->mutex); 179 mutex_lock(&oxfw->mutex);
180 snd_oxfw_stream_stop_simplex(oxfw); 180 snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
181 mutex_unlock(&oxfw->mutex); 181 mutex_unlock(&oxfw->mutex);
182 182
183 return snd_pcm_lib_free_vmalloc_buffer(substream); 183 return snd_pcm_lib_free_vmalloc_buffer(substream);
@@ -190,8 +190,8 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
190 int err; 190 int err;
191 191
192 mutex_lock(&oxfw->mutex); 192 mutex_lock(&oxfw->mutex);
193 err = snd_oxfw_stream_start_simplex(oxfw, runtime->rate, 193 err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream,
194 runtime->channels); 194 runtime->rate, runtime->channels);
195 mutex_unlock(&oxfw->mutex); 195 mutex_unlock(&oxfw->mutex);
196 if (err < 0) 196 if (err < 0)
197 goto end; 197 goto end;
diff --git a/sound/firewire/oxfw/oxfw-proc.c b/sound/firewire/oxfw/oxfw-proc.c
index 18e030572708..604808e5526d 100644
--- a/sound/firewire/oxfw/oxfw-proc.c
+++ b/sound/firewire/oxfw/oxfw-proc.c
@@ -44,6 +44,35 @@ static void proc_read_formation(struct snd_info_entry *entry,
44 formation.rate, formation.pcm, formation.midi); 44 formation.rate, formation.pcm, formation.midi);
45 } 45 }
46 46
47 if (!oxfw->has_output)
48 return;
49
50 /* Show output. */
51 err = snd_oxfw_stream_get_current_formation(oxfw,
52 AVC_GENERAL_PLUG_DIR_OUT,
53 &curr);
54 if (err < 0)
55 return;
56
57 snd_iprintf(buffer, "Output Stream from device:\n");
58 snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
59 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
60 format = oxfw->tx_stream_formats[i];
61 if (format == NULL)
62 continue;
63
64 err = snd_oxfw_stream_parse_format(format, &formation);
65 if (err < 0)
66 continue;
67
68 if (memcmp(&formation, &curr, sizeof(curr)) == 0)
69 flag = '*';
70 else
71 flag = ' ';
72
73 snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
74 formation.rate, formation.pcm, formation.midi);
75 }
47} 76}
48 77
49static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root, 78static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root,
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 1820497f4bbf..1d154284873e 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -39,6 +39,22 @@ static const unsigned int avc_stream_rate_table[] = {
39 [5] = 0x07, 39 [5] = 0x07,
40}; 40};
41 41
42static 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);
54end:
55 return err;
56}
57
42static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s, 58static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
43 unsigned int rate, unsigned int pcm_channels) 59 unsigned int rate, unsigned int pcm_channels)
44{ 60{
@@ -47,8 +63,13 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
47 enum avc_general_plug_dir dir; 63 enum avc_general_plug_dir dir;
48 unsigned int i, err, len; 64 unsigned int i, err, len;
49 65
50 formats = oxfw->rx_stream_formats; 66 if (s == &oxfw->tx_stream) {
51 dir = AVC_GENERAL_PLUG_DIR_IN; 67 formats = oxfw->tx_stream_formats;
68 dir = AVC_GENERAL_PLUG_DIR_OUT;
69 } else {
70 formats = oxfw->rx_stream_formats;
71 dir = AVC_GENERAL_PLUG_DIR_IN;
72 }
52 73
53 /* Seek stream format for requirements. */ 74 /* Seek stream format for requirements. */
54 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 75 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
@@ -64,8 +85,7 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
64 85
65 /* If assumed, just change rate. */ 86 /* If assumed, just change rate. */
66 if (oxfw->assumed) 87 if (oxfw->assumed)
67 return avc_general_set_sig_fmt(oxfw->unit, rate, 88 return set_rate(oxfw, rate);
68 AVC_GENERAL_PLUG_DIR_IN, 0);
69 89
70 /* Calculate format length. */ 90 /* Calculate format length. */
71 len = 5 + formats[i][4] * 2; 91 len = 5 + formats[i][4] * 2;
@@ -80,47 +100,35 @@ static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
80 return 0; 100 return 0;
81} 101}
82 102
83int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw) 103static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
84{ 104{
85 int err; 105 amdtp_stream_pcm_abort(stream);
86 106 amdtp_stream_stop(stream);
87 err = cmp_connection_init(&oxfw->in_conn, oxfw->unit,
88 CMP_INPUT, 0);
89 if (err < 0)
90 goto end;
91 107
92 err = amdtp_stream_init(&oxfw->rx_stream, oxfw->unit, 108 if (stream == &oxfw->tx_stream)
93 AMDTP_OUT_STREAM, CIP_NONBLOCKING); 109 cmp_connection_break(&oxfw->out_conn);
94 if (err < 0) { 110 else
95 amdtp_stream_destroy(&oxfw->rx_stream); 111 cmp_connection_break(&oxfw->in_conn);
96 cmp_connection_destroy(&oxfw->in_conn);
97 }
98end:
99 return err;
100}
101
102static void stop_stream(struct snd_oxfw *oxfw)
103{
104 amdtp_stream_pcm_abort(&oxfw->rx_stream);
105 amdtp_stream_stop(&oxfw->rx_stream);
106 cmp_connection_break(&oxfw->in_conn);
107} 112}
108 113
109static int start_stream(struct snd_oxfw *oxfw, unsigned int rate, 114static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
110 unsigned int pcm_channels) 115 unsigned int rate, unsigned int pcm_channels)
111{ 116{
112 u8 **formats; 117 u8 **formats;
113 struct cmp_connection *conn; 118 struct cmp_connection *conn;
114 struct snd_oxfw_stream_formation formation; 119 struct snd_oxfw_stream_formation formation;
115 unsigned int i, midi_ports; 120 unsigned int i, midi_ports;
116 struct amdtp_stream *stream;
117 int err; 121 int err;
118 122
119 stream = &oxfw->rx_stream; 123 if (stream == &oxfw->rx_stream) {
120 formats = oxfw->rx_stream_formats; 124 formats = oxfw->rx_stream_formats;
121 conn = &oxfw->in_conn; 125 conn = &oxfw->in_conn;
126 } else {
127 formats = oxfw->tx_stream_formats;
128 conn = &oxfw->out_conn;
129 }
122 130
123 /* Get stream formation */ 131 /* Get stream format */
124 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { 132 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
125 if (formats[i] == NULL) 133 if (formats[i] == NULL)
126 break; 134 break;
@@ -164,67 +172,196 @@ static int start_stream(struct snd_oxfw *oxfw, unsigned int rate,
164 /* Wait first packet */ 172 /* Wait first packet */
165 err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT); 173 err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
166 if (err < 0) 174 if (err < 0)
167 stop_stream(oxfw); 175 stop_stream(oxfw, stream);
168end: 176end:
169 return err; 177 return err;
170} 178}
171 179
172int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, unsigned int rate, 180static int check_connection_used_by_others(struct snd_oxfw *oxfw,
173 unsigned int pcm_channels) 181 struct amdtp_stream *stream)
174{ 182{
183 struct cmp_connection *conn;
184 bool used;
185 int err;
186
187 if (stream == &oxfw->tx_stream)
188 conn = &oxfw->out_conn;
189 else
190 conn = &oxfw->in_conn;
191
192 err = cmp_connection_check_used(conn, &used);
193 if ((err >= 0) && used && !amdtp_stream_running(stream)) {
194 dev_err(&oxfw->unit->device,
195 "Connection established by others: %cPCR[%d]\n",
196 (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
197 conn->pcr_index);
198 err = -EBUSY;
199 }
200
201 return err;
202}
203
204int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
205 struct amdtp_stream *stream)
206{
207 struct cmp_connection *conn;
208 enum cmp_direction c_dir;
209 enum amdtp_stream_direction s_dir;
210 int err;
211
212 if (stream == &oxfw->tx_stream) {
213 conn = &oxfw->out_conn;
214 c_dir = CMP_OUTPUT;
215 s_dir = AMDTP_IN_STREAM;
216 } else {
217 conn = &oxfw->in_conn;
218 c_dir = CMP_INPUT;
219 s_dir = AMDTP_OUT_STREAM;
220 }
221
222 err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
223 if (err < 0)
224 goto end;
225
226 err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
227 if (err < 0) {
228 amdtp_stream_destroy(stream);
229 cmp_connection_destroy(conn);
230 goto end;
231 }
232
233 /* OXFW starts to transmit packets with non-zero dbc. */
234 if (stream == &oxfw->tx_stream)
235 oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK;
236end:
237 return err;
238}
239
240int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
241 struct amdtp_stream *stream,
242 unsigned int rate, unsigned int pcm_channels)
243{
244 struct amdtp_stream *opposite;
175 struct snd_oxfw_stream_formation formation; 245 struct snd_oxfw_stream_formation formation;
246 enum avc_general_plug_dir dir;
247 unsigned int substreams, opposite_substreams;
176 int err = 0; 248 int err = 0;
177 249
250 if (stream == &oxfw->tx_stream) {
251 substreams = oxfw->capture_substreams;
252 opposite = &oxfw->rx_stream;
253 opposite_substreams = oxfw->playback_substreams;
254 dir = AVC_GENERAL_PLUG_DIR_OUT;
255 } else {
256 substreams = oxfw->playback_substreams;
257 opposite_substreams = oxfw->capture_substreams;
258
259 if (oxfw->has_output)
260 opposite = &oxfw->rx_stream;
261 else
262 opposite = NULL;
263
264 dir = AVC_GENERAL_PLUG_DIR_IN;
265 }
266
267 if (substreams == 0)
268 goto end;
269
270 /*
271 * Considering JACK/FFADO streaming:
272 * TODO: This can be removed hwdep functionality becomes popular.
273 */
274 err = check_connection_used_by_others(oxfw, stream);
275 if (err < 0)
276 goto end;
277
178 /* packet queueing error */ 278 /* packet queueing error */
179 if (amdtp_streaming_error(&oxfw->rx_stream)) 279 if (amdtp_streaming_error(stream))
180 stop_stream(oxfw); 280 stop_stream(oxfw, stream);
181 281
182 err = snd_oxfw_stream_get_current_formation(oxfw, 282 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
183 AVC_GENERAL_PLUG_DIR_IN,
184 &formation);
185 if (err < 0) 283 if (err < 0)
186 goto end; 284 goto end;
187 285
188 if ((formation.rate != rate) || (formation.pcm != pcm_channels)) { 286 if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
189 stop_stream(oxfw); 287 if (opposite != NULL) {
288 err = check_connection_used_by_others(oxfw, opposite);
289 if (err < 0)
290 goto end;
291 stop_stream(oxfw, opposite);
292 }
293 stop_stream(oxfw, stream);
190 294
191 /* arrange sampling rate */ 295 err = set_stream_format(oxfw, stream, rate, pcm_channels);
192 err = set_stream_format(oxfw, &oxfw->rx_stream, rate,
193 pcm_channels);
194 if (err < 0) { 296 if (err < 0) {
195 dev_err(&oxfw->unit->device, 297 dev_err(&oxfw->unit->device,
196 "fail to set stream format: %d\n", err); 298 "fail to set stream format: %d\n", err);
197 goto end; 299 goto end;
198 } 300 }
301
302 /* Start opposite stream if needed. */
303 if (opposite && !amdtp_stream_running(opposite) &&
304 (opposite_substreams > 0)) {
305 err = start_stream(oxfw, opposite, rate, 0);
306 if (err < 0) {
307 dev_err(&oxfw->unit->device,
308 "fail to restart stream: %d\n", err);
309 goto end;
310 }
311 }
199 } 312 }
200 313
201 err = start_stream(oxfw, rate, pcm_channels); 314 /* Start requested stream. */
202 if (err < 0) 315 if (!amdtp_stream_running(stream)) {
203 dev_err(&oxfw->unit->device, 316 err = start_stream(oxfw, stream, rate, pcm_channels);
204 "fail to start stream: %d\n", err); 317 if (err < 0)
318 dev_err(&oxfw->unit->device,
319 "fail to start stream: %d\n", err);
320 }
205end: 321end:
206 return err; 322 return err;
207} 323}
208 324
209void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw) 325void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
326 struct amdtp_stream *stream)
210{ 327{
211 stop_stream(oxfw); 328 if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
329 ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
330 return;
331
332 stop_stream(oxfw, stream);
212} 333}
213 334
214void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw) 335void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
336 struct amdtp_stream *stream)
215{ 337{
216 stop_stream(oxfw); 338 struct cmp_connection *conn;
339
340 if (stream == &oxfw->tx_stream)
341 conn = &oxfw->out_conn;
342 else
343 conn = &oxfw->in_conn;
217 344
218 amdtp_stream_destroy(&oxfw->rx_stream); 345 stop_stream(oxfw, stream);
219 cmp_connection_destroy(&oxfw->in_conn); 346
347 amdtp_stream_destroy(stream);
348 cmp_connection_destroy(conn);
220} 349}
221 350
222void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw) 351void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
352 struct amdtp_stream *stream)
223{ 353{
224 if (cmp_connection_update(&oxfw->in_conn) < 0) 354 struct cmp_connection *conn;
225 stop_stream(oxfw); 355
356 if (stream == &oxfw->tx_stream)
357 conn = &oxfw->out_conn;
358 else
359 conn = &oxfw->in_conn;
360
361 if (cmp_connection_update(conn) < 0)
362 stop_stream(oxfw, stream);
226 else 363 else
227 amdtp_stream_update(&oxfw->rx_stream); 364 amdtp_stream_update(stream);
228} 365}
229 366
230int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw, 367int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
@@ -408,7 +545,10 @@ static int fill_stream_formats(struct snd_oxfw *oxfw,
408 if (buf == NULL) 545 if (buf == NULL)
409 return -ENOMEM; 546 return -ENOMEM;
410 547
411 formats = oxfw->rx_stream_formats; 548 if (dir == AVC_GENERAL_PLUG_DIR_OUT)
549 formats = oxfw->tx_stream_formats;
550 else
551 formats = oxfw->rx_stream_formats;
412 552
413 /* get first entry */ 553 /* get first entry */
414 len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; 554 len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
@@ -481,11 +621,19 @@ int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
481 "fail to get info for isoc/external in/out plugs: %d\n", 621 "fail to get info for isoc/external in/out plugs: %d\n",
482 err); 622 err);
483 goto end; 623 goto end;
484 } else if (plugs[0] == 0) { 624 } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
485 err = -ENOSYS; 625 err = -ENOSYS;
486 goto end; 626 goto end;
487 } 627 }
488 628
629 /* use oPCR[0] if exists */
630 if (plugs[1] > 0) {
631 err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
632 if (err < 0)
633 goto end;
634 oxfw->has_output = true;
635 }
636
489 /* use iPCR[0] if exists */ 637 /* use iPCR[0] if exists */
490 if (plugs[0] > 0) 638 if (plugs[0] > 0)
491 err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0); 639 err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 797af33c7bcb..23c00a2bb7d3 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -109,8 +109,10 @@ static void oxfw_card_free(struct snd_card *card)
109 struct snd_oxfw *oxfw = card->private_data; 109 struct snd_oxfw *oxfw = card->private_data;
110 unsigned int i; 110 unsigned int i;
111 111
112 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) 112 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
113 kfree(oxfw->tx_stream_formats[i]);
113 kfree(oxfw->rx_stream_formats[i]); 114 kfree(oxfw->rx_stream_formats[i]);
115 }
114 116
115 mutex_destroy(&oxfw->mutex); 117 mutex_destroy(&oxfw->mutex);
116} 118}
@@ -157,13 +159,20 @@ static int oxfw_probe(struct fw_unit *unit,
157 159
158 snd_oxfw_proc_init(oxfw); 160 snd_oxfw_proc_init(oxfw);
159 161
160 err = snd_oxfw_stream_init_simplex(oxfw); 162 err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream);
161 if (err < 0) 163 if (err < 0)
162 goto error; 164 goto error;
165 if (oxfw->has_output) {
166 err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream);
167 if (err < 0)
168 goto error;
169 }
163 170
164 err = snd_card_register(card); 171 err = snd_card_register(card);
165 if (err < 0) { 172 if (err < 0) {
166 snd_oxfw_stream_destroy_simplex(oxfw); 173 snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
174 if (oxfw->has_output)
175 snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
167 goto error; 176 goto error;
168 } 177 }
169 dev_set_drvdata(&unit->device, oxfw); 178 dev_set_drvdata(&unit->device, oxfw);
@@ -181,7 +190,11 @@ static void oxfw_bus_reset(struct fw_unit *unit)
181 fcp_bus_reset(oxfw->unit); 190 fcp_bus_reset(oxfw->unit);
182 191
183 mutex_lock(&oxfw->mutex); 192 mutex_lock(&oxfw->mutex);
184 snd_oxfw_stream_update_simplex(oxfw); 193
194 snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream);
195 if (oxfw->has_output)
196 snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
197
185 mutex_unlock(&oxfw->mutex); 198 mutex_unlock(&oxfw->mutex);
186} 199}
187 200
@@ -191,7 +204,9 @@ static void oxfw_remove(struct fw_unit *unit)
191 204
192 snd_card_disconnect(oxfw->card); 205 snd_card_disconnect(oxfw->card);
193 206
194 snd_oxfw_stream_destroy_simplex(oxfw); 207 snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
208 if (oxfw->has_output)
209 snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
195 210
196 snd_card_free_when_closed(oxfw->card); 211 snd_card_free_when_closed(oxfw->card);
197} 212}
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index c09ef38c22ba..2211d11a79e1 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -44,10 +44,16 @@ struct snd_oxfw {
44 const struct device_info *device_info; 44 const struct device_info *device_info;
45 struct mutex mutex; 45 struct mutex mutex;
46 46
47 bool has_output;
48 u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
47 u8 *rx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES]; 49 u8 *rx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
48 bool assumed; 50 bool assumed;
51 struct cmp_connection out_conn;
49 struct cmp_connection in_conn; 52 struct cmp_connection in_conn;
53 struct amdtp_stream tx_stream;
50 struct amdtp_stream rx_stream; 54 struct amdtp_stream rx_stream;
55 unsigned int capture_substreams;
56 unsigned int playback_substreams;
51 57
52 bool mute; 58 bool mute;
53 s16 volume[6]; 59 s16 volume[6];
@@ -88,12 +94,17 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
88 enum avc_general_plug_dir dir, 94 enum avc_general_plug_dir dir,
89 unsigned short pid); 95 unsigned short pid);
90 96
91int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw); 97int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
92int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, unsigned int rate, 98 struct amdtp_stream *stream);
93 unsigned int pcm_channels); 99int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
94void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); 100 struct amdtp_stream *stream,
95void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw); 101 unsigned int rate, unsigned int pcm_channels);
96void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); 102void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
103 struct amdtp_stream *stream);
104void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
105 struct amdtp_stream *stream);
106void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
107 struct amdtp_stream *stream);
97 108
98struct snd_oxfw_stream_formation { 109struct snd_oxfw_stream_formation {
99 unsigned int rate; 110 unsigned int rate;
@@ -105,6 +116,7 @@ int snd_oxfw_stream_parse_format(u8 *format,
105int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw, 116int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
106 enum avc_general_plug_dir dir, 117 enum avc_general_plug_dir dir,
107 struct snd_oxfw_stream_formation *formation); 118 struct snd_oxfw_stream_formation *formation);
119
108int snd_oxfw_stream_discover(struct snd_oxfw *oxfw); 120int snd_oxfw_stream_discover(struct snd_oxfw *oxfw);
109 121
110int snd_oxfw_create_pcm(struct snd_oxfw *oxfw); 122int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);