xref: /openbmc/linux/sound/firewire/motu/motu-stream.c (revision 9b2bb4f2f4a213a768a84fa25c14be54844f5bb6)
1*9b2bb4f2STakashi Sakamoto /*
2*9b2bb4f2STakashi Sakamoto  * motu-stream.c - a part of driver for MOTU FireWire series
3*9b2bb4f2STakashi Sakamoto  *
4*9b2bb4f2STakashi Sakamoto  * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp>
5*9b2bb4f2STakashi Sakamoto  *
6*9b2bb4f2STakashi Sakamoto  * Licensed under the terms of the GNU General Public License, version 2.
7*9b2bb4f2STakashi Sakamoto  */
8*9b2bb4f2STakashi Sakamoto 
9*9b2bb4f2STakashi Sakamoto #include "motu.h"
10*9b2bb4f2STakashi Sakamoto 
11*9b2bb4f2STakashi Sakamoto #define	CALLBACK_TIMEOUT	200
12*9b2bb4f2STakashi Sakamoto 
13*9b2bb4f2STakashi Sakamoto #define ISOC_COMM_CONTROL_OFFSET		0x0b00
14*9b2bb4f2STakashi Sakamoto #define  ISOC_COMM_CONTROL_MASK			0xffff0000
15*9b2bb4f2STakashi Sakamoto #define  CHANGE_RX_ISOC_COMM_STATE		0x80000000
16*9b2bb4f2STakashi Sakamoto #define  RX_ISOC_COMM_IS_ACTIVATED		0x40000000
17*9b2bb4f2STakashi Sakamoto #define  RX_ISOC_COMM_CHANNEL_MASK		0x3f000000
18*9b2bb4f2STakashi Sakamoto #define  RX_ISOC_COMM_CHANNEL_SHIFT		24
19*9b2bb4f2STakashi Sakamoto #define  CHANGE_TX_ISOC_COMM_STATE		0x00800000
20*9b2bb4f2STakashi Sakamoto #define  TX_ISOC_COMM_IS_ACTIVATED		0x00400000
21*9b2bb4f2STakashi Sakamoto #define  TX_ISOC_COMM_CHANNEL_MASK		0x003f0000
22*9b2bb4f2STakashi Sakamoto #define  TX_ISOC_COMM_CHANNEL_SHIFT		16
23*9b2bb4f2STakashi Sakamoto 
24*9b2bb4f2STakashi Sakamoto #define PACKET_FORMAT_OFFSET			0x0b10
25*9b2bb4f2STakashi Sakamoto #define  TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS	0x00000080
26*9b2bb4f2STakashi Sakamoto #define  RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS	0x00000040
27*9b2bb4f2STakashi Sakamoto #define  TX_PACKET_TRANSMISSION_SPEED_MASK	0x0000000f
28*9b2bb4f2STakashi Sakamoto 
29*9b2bb4f2STakashi Sakamoto static int start_both_streams(struct snd_motu *motu, unsigned int rate)
30*9b2bb4f2STakashi Sakamoto {
31*9b2bb4f2STakashi Sakamoto 	__be32 reg;
32*9b2bb4f2STakashi Sakamoto 	u32 data;
33*9b2bb4f2STakashi Sakamoto 	int err;
34*9b2bb4f2STakashi Sakamoto 
35*9b2bb4f2STakashi Sakamoto 	/* Set packet formation to our packet streaming engine. */
36*9b2bb4f2STakashi Sakamoto 	err = amdtp_motu_set_parameters(&motu->rx_stream, rate,
37*9b2bb4f2STakashi Sakamoto 					&motu->rx_packet_formats);
38*9b2bb4f2STakashi Sakamoto 	if (err < 0)
39*9b2bb4f2STakashi Sakamoto 		return err;
40*9b2bb4f2STakashi Sakamoto 
41*9b2bb4f2STakashi Sakamoto 	err = amdtp_motu_set_parameters(&motu->tx_stream, rate,
42*9b2bb4f2STakashi Sakamoto 					&motu->tx_packet_formats);
43*9b2bb4f2STakashi Sakamoto 	if (err < 0)
44*9b2bb4f2STakashi Sakamoto 		return err;
45*9b2bb4f2STakashi Sakamoto 
46*9b2bb4f2STakashi Sakamoto 
47*9b2bb4f2STakashi Sakamoto 	/* Get isochronous resources on the bus. */
48*9b2bb4f2STakashi Sakamoto 	err = fw_iso_resources_allocate(&motu->rx_resources,
49*9b2bb4f2STakashi Sakamoto 				amdtp_stream_get_max_payload(&motu->rx_stream),
50*9b2bb4f2STakashi Sakamoto 				fw_parent_device(motu->unit)->max_speed);
51*9b2bb4f2STakashi Sakamoto 	if (err < 0)
52*9b2bb4f2STakashi Sakamoto 		return err;
53*9b2bb4f2STakashi Sakamoto 
54*9b2bb4f2STakashi Sakamoto 	err = fw_iso_resources_allocate(&motu->tx_resources,
55*9b2bb4f2STakashi Sakamoto 				amdtp_stream_get_max_payload(&motu->tx_stream),
56*9b2bb4f2STakashi Sakamoto 				fw_parent_device(motu->unit)->max_speed);
57*9b2bb4f2STakashi Sakamoto 	if (err < 0)
58*9b2bb4f2STakashi Sakamoto 		return err;
59*9b2bb4f2STakashi Sakamoto 
60*9b2bb4f2STakashi Sakamoto 	/* Configure the unit to start isochronous communication. */
61*9b2bb4f2STakashi Sakamoto 	err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
62*9b2bb4f2STakashi Sakamoto 					sizeof(reg));
63*9b2bb4f2STakashi Sakamoto 	if (err < 0)
64*9b2bb4f2STakashi Sakamoto 		return err;
65*9b2bb4f2STakashi Sakamoto 	data = be32_to_cpu(reg) & ~ISOC_COMM_CONTROL_MASK;
66*9b2bb4f2STakashi Sakamoto 
67*9b2bb4f2STakashi Sakamoto 	data |= CHANGE_RX_ISOC_COMM_STATE | RX_ISOC_COMM_IS_ACTIVATED |
68*9b2bb4f2STakashi Sakamoto 		(motu->rx_resources.channel << RX_ISOC_COMM_CHANNEL_SHIFT) |
69*9b2bb4f2STakashi Sakamoto 		CHANGE_TX_ISOC_COMM_STATE | TX_ISOC_COMM_IS_ACTIVATED |
70*9b2bb4f2STakashi Sakamoto 		(motu->tx_resources.channel << TX_ISOC_COMM_CHANNEL_SHIFT);
71*9b2bb4f2STakashi Sakamoto 
72*9b2bb4f2STakashi Sakamoto 	reg = cpu_to_be32(data);
73*9b2bb4f2STakashi Sakamoto 	return snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
74*9b2bb4f2STakashi Sakamoto 					  sizeof(reg));
75*9b2bb4f2STakashi Sakamoto }
76*9b2bb4f2STakashi Sakamoto 
77*9b2bb4f2STakashi Sakamoto static void stop_both_streams(struct snd_motu *motu)
78*9b2bb4f2STakashi Sakamoto {
79*9b2bb4f2STakashi Sakamoto 	__be32 reg;
80*9b2bb4f2STakashi Sakamoto 	u32 data;
81*9b2bb4f2STakashi Sakamoto 	int err;
82*9b2bb4f2STakashi Sakamoto 
83*9b2bb4f2STakashi Sakamoto 	err = motu->spec->protocol->switch_fetching_mode(motu, false);
84*9b2bb4f2STakashi Sakamoto 	if (err < 0)
85*9b2bb4f2STakashi Sakamoto 		return;
86*9b2bb4f2STakashi Sakamoto 
87*9b2bb4f2STakashi Sakamoto 	err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
88*9b2bb4f2STakashi Sakamoto 					sizeof(reg));
89*9b2bb4f2STakashi Sakamoto 	if (err < 0)
90*9b2bb4f2STakashi Sakamoto 		return;
91*9b2bb4f2STakashi Sakamoto 	data = be32_to_cpu(reg);
92*9b2bb4f2STakashi Sakamoto 
93*9b2bb4f2STakashi Sakamoto 	data &= ~(RX_ISOC_COMM_IS_ACTIVATED | TX_ISOC_COMM_IS_ACTIVATED);
94*9b2bb4f2STakashi Sakamoto 	data |= CHANGE_RX_ISOC_COMM_STATE | CHANGE_TX_ISOC_COMM_STATE;
95*9b2bb4f2STakashi Sakamoto 
96*9b2bb4f2STakashi Sakamoto 	reg = cpu_to_be32(data);
97*9b2bb4f2STakashi Sakamoto 	snd_motu_transaction_write(motu, ISOC_COMM_CONTROL_OFFSET, &reg,
98*9b2bb4f2STakashi Sakamoto 				   sizeof(reg));
99*9b2bb4f2STakashi Sakamoto 
100*9b2bb4f2STakashi Sakamoto 	fw_iso_resources_free(&motu->tx_resources);
101*9b2bb4f2STakashi Sakamoto 	fw_iso_resources_free(&motu->rx_resources);
102*9b2bb4f2STakashi Sakamoto }
103*9b2bb4f2STakashi Sakamoto 
104*9b2bb4f2STakashi Sakamoto static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
105*9b2bb4f2STakashi Sakamoto {
106*9b2bb4f2STakashi Sakamoto 	struct fw_iso_resources *resources;
107*9b2bb4f2STakashi Sakamoto 	int err;
108*9b2bb4f2STakashi Sakamoto 
109*9b2bb4f2STakashi Sakamoto 	if (stream == &motu->rx_stream)
110*9b2bb4f2STakashi Sakamoto 		resources = &motu->rx_resources;
111*9b2bb4f2STakashi Sakamoto 	else
112*9b2bb4f2STakashi Sakamoto 		resources = &motu->tx_resources;
113*9b2bb4f2STakashi Sakamoto 
114*9b2bb4f2STakashi Sakamoto 	err = amdtp_stream_start(stream, resources->channel,
115*9b2bb4f2STakashi Sakamoto 				 fw_parent_device(motu->unit)->max_speed);
116*9b2bb4f2STakashi Sakamoto 	if (err < 0)
117*9b2bb4f2STakashi Sakamoto 		return err;
118*9b2bb4f2STakashi Sakamoto 
119*9b2bb4f2STakashi Sakamoto 	if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
120*9b2bb4f2STakashi Sakamoto 		amdtp_stream_stop(stream);
121*9b2bb4f2STakashi Sakamoto 		fw_iso_resources_free(resources);
122*9b2bb4f2STakashi Sakamoto 		return -ETIMEDOUT;
123*9b2bb4f2STakashi Sakamoto 	}
124*9b2bb4f2STakashi Sakamoto 
125*9b2bb4f2STakashi Sakamoto 	return 0;
126*9b2bb4f2STakashi Sakamoto }
127*9b2bb4f2STakashi Sakamoto 
128*9b2bb4f2STakashi Sakamoto static void stop_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream)
129*9b2bb4f2STakashi Sakamoto {
130*9b2bb4f2STakashi Sakamoto 	struct fw_iso_resources *resources;
131*9b2bb4f2STakashi Sakamoto 
132*9b2bb4f2STakashi Sakamoto 	if (stream == &motu->rx_stream)
133*9b2bb4f2STakashi Sakamoto 		resources = &motu->rx_resources;
134*9b2bb4f2STakashi Sakamoto 	else
135*9b2bb4f2STakashi Sakamoto 		resources = &motu->tx_resources;
136*9b2bb4f2STakashi Sakamoto 
137*9b2bb4f2STakashi Sakamoto 	amdtp_stream_stop(stream);
138*9b2bb4f2STakashi Sakamoto 	fw_iso_resources_free(resources);
139*9b2bb4f2STakashi Sakamoto }
140*9b2bb4f2STakashi Sakamoto 
141*9b2bb4f2STakashi Sakamoto static int ensure_packet_formats(struct snd_motu *motu)
142*9b2bb4f2STakashi Sakamoto {
143*9b2bb4f2STakashi Sakamoto 	__be32 reg;
144*9b2bb4f2STakashi Sakamoto 	u32 data;
145*9b2bb4f2STakashi Sakamoto 	int err;
146*9b2bb4f2STakashi Sakamoto 
147*9b2bb4f2STakashi Sakamoto 	err = snd_motu_transaction_read(motu, PACKET_FORMAT_OFFSET, &reg,
148*9b2bb4f2STakashi Sakamoto 					sizeof(reg));
149*9b2bb4f2STakashi Sakamoto 	if (err < 0)
150*9b2bb4f2STakashi Sakamoto 		return err;
151*9b2bb4f2STakashi Sakamoto 	data = be32_to_cpu(reg);
152*9b2bb4f2STakashi Sakamoto 
153*9b2bb4f2STakashi Sakamoto 	data &= ~(TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS |
154*9b2bb4f2STakashi Sakamoto 		  RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS|
155*9b2bb4f2STakashi Sakamoto 		  TX_PACKET_TRANSMISSION_SPEED_MASK);
156*9b2bb4f2STakashi Sakamoto 	if (motu->tx_packet_formats.differed_part_pcm_chunks[0] == 0)
157*9b2bb4f2STakashi Sakamoto 		data |= TX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
158*9b2bb4f2STakashi Sakamoto 	if (motu->rx_packet_formats.differed_part_pcm_chunks[0] == 0)
159*9b2bb4f2STakashi Sakamoto 		data |= RX_PACKET_EXCLUDE_DIFFERED_DATA_CHUNKS;
160*9b2bb4f2STakashi Sakamoto 	data |= fw_parent_device(motu->unit)->max_speed;
161*9b2bb4f2STakashi Sakamoto 
162*9b2bb4f2STakashi Sakamoto 	reg = cpu_to_be32(data);
163*9b2bb4f2STakashi Sakamoto 	return snd_motu_transaction_write(motu, PACKET_FORMAT_OFFSET, &reg,
164*9b2bb4f2STakashi Sakamoto 					  sizeof(reg));
165*9b2bb4f2STakashi Sakamoto }
166*9b2bb4f2STakashi Sakamoto 
167*9b2bb4f2STakashi Sakamoto int snd_motu_stream_start_duplex(struct snd_motu *motu, unsigned int rate)
168*9b2bb4f2STakashi Sakamoto {
169*9b2bb4f2STakashi Sakamoto 	const struct snd_motu_protocol *protocol = motu->spec->protocol;
170*9b2bb4f2STakashi Sakamoto 	unsigned int curr_rate;
171*9b2bb4f2STakashi Sakamoto 	int err = 0;
172*9b2bb4f2STakashi Sakamoto 
173*9b2bb4f2STakashi Sakamoto 	if (motu->capture_substreams == 0 && motu->playback_substreams == 0)
174*9b2bb4f2STakashi Sakamoto 		return 0;
175*9b2bb4f2STakashi Sakamoto 
176*9b2bb4f2STakashi Sakamoto 	/* Some packet queueing errors. */
177*9b2bb4f2STakashi Sakamoto 	if (amdtp_streaming_error(&motu->rx_stream) ||
178*9b2bb4f2STakashi Sakamoto 	    amdtp_streaming_error(&motu->tx_stream)) {
179*9b2bb4f2STakashi Sakamoto 		amdtp_stream_stop(&motu->rx_stream);
180*9b2bb4f2STakashi Sakamoto 		amdtp_stream_stop(&motu->tx_stream);
181*9b2bb4f2STakashi Sakamoto 		stop_both_streams(motu);
182*9b2bb4f2STakashi Sakamoto 	}
183*9b2bb4f2STakashi Sakamoto 
184*9b2bb4f2STakashi Sakamoto 	err = protocol->cache_packet_formats(motu);
185*9b2bb4f2STakashi Sakamoto 	if (err < 0)
186*9b2bb4f2STakashi Sakamoto 		return err;
187*9b2bb4f2STakashi Sakamoto 
188*9b2bb4f2STakashi Sakamoto 	/* Stop stream if rate is different. */
189*9b2bb4f2STakashi Sakamoto 	err = protocol->get_clock_rate(motu, &curr_rate);
190*9b2bb4f2STakashi Sakamoto 	if (err < 0) {
191*9b2bb4f2STakashi Sakamoto 		dev_err(&motu->unit->device,
192*9b2bb4f2STakashi Sakamoto 			"fail to get sampling rate: %d\n", err);
193*9b2bb4f2STakashi Sakamoto 		return err;
194*9b2bb4f2STakashi Sakamoto 	}
195*9b2bb4f2STakashi Sakamoto 	if (rate == 0)
196*9b2bb4f2STakashi Sakamoto 		rate = curr_rate;
197*9b2bb4f2STakashi Sakamoto 	if (rate != curr_rate) {
198*9b2bb4f2STakashi Sakamoto 		amdtp_stream_stop(&motu->rx_stream);
199*9b2bb4f2STakashi Sakamoto 		amdtp_stream_stop(&motu->tx_stream);
200*9b2bb4f2STakashi Sakamoto 		stop_both_streams(motu);
201*9b2bb4f2STakashi Sakamoto 	}
202*9b2bb4f2STakashi Sakamoto 
203*9b2bb4f2STakashi Sakamoto 	if (!amdtp_stream_running(&motu->rx_stream)) {
204*9b2bb4f2STakashi Sakamoto 		err = protocol->set_clock_rate(motu, rate);
205*9b2bb4f2STakashi Sakamoto 		if (err < 0) {
206*9b2bb4f2STakashi Sakamoto 			dev_err(&motu->unit->device,
207*9b2bb4f2STakashi Sakamoto 				"fail to set sampling rate: %d\n", err);
208*9b2bb4f2STakashi Sakamoto 			return err;
209*9b2bb4f2STakashi Sakamoto 		}
210*9b2bb4f2STakashi Sakamoto 
211*9b2bb4f2STakashi Sakamoto 		err = ensure_packet_formats(motu);
212*9b2bb4f2STakashi Sakamoto 		if (err < 0)
213*9b2bb4f2STakashi Sakamoto 			return err;
214*9b2bb4f2STakashi Sakamoto 
215*9b2bb4f2STakashi Sakamoto 		err = start_both_streams(motu, rate);
216*9b2bb4f2STakashi Sakamoto 		if (err < 0) {
217*9b2bb4f2STakashi Sakamoto 			dev_err(&motu->unit->device,
218*9b2bb4f2STakashi Sakamoto 				"fail to start isochronous comm: %d\n", err);
219*9b2bb4f2STakashi Sakamoto 			stop_both_streams(motu);
220*9b2bb4f2STakashi Sakamoto 			return err;
221*9b2bb4f2STakashi Sakamoto 		}
222*9b2bb4f2STakashi Sakamoto 
223*9b2bb4f2STakashi Sakamoto 		err = start_isoc_ctx(motu, &motu->rx_stream);
224*9b2bb4f2STakashi Sakamoto 		if (err < 0) {
225*9b2bb4f2STakashi Sakamoto 			dev_err(&motu->unit->device,
226*9b2bb4f2STakashi Sakamoto 				"fail to start IT context: %d\n", err);
227*9b2bb4f2STakashi Sakamoto 			stop_both_streams(motu);
228*9b2bb4f2STakashi Sakamoto 			return err;
229*9b2bb4f2STakashi Sakamoto 		}
230*9b2bb4f2STakashi Sakamoto 
231*9b2bb4f2STakashi Sakamoto 		err = protocol->switch_fetching_mode(motu, true);
232*9b2bb4f2STakashi Sakamoto 		if (err < 0) {
233*9b2bb4f2STakashi Sakamoto 			dev_err(&motu->unit->device,
234*9b2bb4f2STakashi Sakamoto 				"fail to enable frame fetching: %d\n", err);
235*9b2bb4f2STakashi Sakamoto 			stop_both_streams(motu);
236*9b2bb4f2STakashi Sakamoto 			return err;
237*9b2bb4f2STakashi Sakamoto 		}
238*9b2bb4f2STakashi Sakamoto 	}
239*9b2bb4f2STakashi Sakamoto 
240*9b2bb4f2STakashi Sakamoto 	if (!amdtp_stream_running(&motu->tx_stream) &&
241*9b2bb4f2STakashi Sakamoto 	    motu->capture_substreams > 0) {
242*9b2bb4f2STakashi Sakamoto 		err = start_isoc_ctx(motu, &motu->tx_stream);
243*9b2bb4f2STakashi Sakamoto 		if (err < 0) {
244*9b2bb4f2STakashi Sakamoto 			dev_err(&motu->unit->device,
245*9b2bb4f2STakashi Sakamoto 				"fail to start IR context: %d", err);
246*9b2bb4f2STakashi Sakamoto 			amdtp_stream_stop(&motu->rx_stream);
247*9b2bb4f2STakashi Sakamoto 			stop_both_streams(motu);
248*9b2bb4f2STakashi Sakamoto 			return err;
249*9b2bb4f2STakashi Sakamoto 		}
250*9b2bb4f2STakashi Sakamoto 	}
251*9b2bb4f2STakashi Sakamoto 
252*9b2bb4f2STakashi Sakamoto 	return 0;
253*9b2bb4f2STakashi Sakamoto }
254*9b2bb4f2STakashi Sakamoto 
255*9b2bb4f2STakashi Sakamoto void snd_motu_stream_stop_duplex(struct snd_motu *motu)
256*9b2bb4f2STakashi Sakamoto {
257*9b2bb4f2STakashi Sakamoto 	if (motu->capture_substreams == 0) {
258*9b2bb4f2STakashi Sakamoto 		if (amdtp_stream_running(&motu->tx_stream))
259*9b2bb4f2STakashi Sakamoto 			stop_isoc_ctx(motu, &motu->tx_stream);
260*9b2bb4f2STakashi Sakamoto 
261*9b2bb4f2STakashi Sakamoto 		if (motu->playback_substreams == 0) {
262*9b2bb4f2STakashi Sakamoto 			if (amdtp_stream_running(&motu->rx_stream))
263*9b2bb4f2STakashi Sakamoto 				stop_isoc_ctx(motu, &motu->rx_stream);
264*9b2bb4f2STakashi Sakamoto 			stop_both_streams(motu);
265*9b2bb4f2STakashi Sakamoto 		}
266*9b2bb4f2STakashi Sakamoto 	}
267*9b2bb4f2STakashi Sakamoto }
268*9b2bb4f2STakashi Sakamoto 
269*9b2bb4f2STakashi Sakamoto static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir)
270*9b2bb4f2STakashi Sakamoto {
271*9b2bb4f2STakashi Sakamoto 	int err;
272*9b2bb4f2STakashi Sakamoto 	struct amdtp_stream *stream;
273*9b2bb4f2STakashi Sakamoto 	struct fw_iso_resources *resources;
274*9b2bb4f2STakashi Sakamoto 
275*9b2bb4f2STakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
276*9b2bb4f2STakashi Sakamoto 		stream = &motu->tx_stream;
277*9b2bb4f2STakashi Sakamoto 		resources = &motu->tx_resources;
278*9b2bb4f2STakashi Sakamoto 	} else {
279*9b2bb4f2STakashi Sakamoto 		stream = &motu->rx_stream;
280*9b2bb4f2STakashi Sakamoto 		resources = &motu->rx_resources;
281*9b2bb4f2STakashi Sakamoto 	}
282*9b2bb4f2STakashi Sakamoto 
283*9b2bb4f2STakashi Sakamoto 	err = fw_iso_resources_init(resources, motu->unit);
284*9b2bb4f2STakashi Sakamoto 	if (err < 0)
285*9b2bb4f2STakashi Sakamoto 		return err;
286*9b2bb4f2STakashi Sakamoto 
287*9b2bb4f2STakashi Sakamoto 	err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol);
288*9b2bb4f2STakashi Sakamoto 	if (err < 0) {
289*9b2bb4f2STakashi Sakamoto 		amdtp_stream_destroy(stream);
290*9b2bb4f2STakashi Sakamoto 		fw_iso_resources_destroy(resources);
291*9b2bb4f2STakashi Sakamoto 	}
292*9b2bb4f2STakashi Sakamoto 
293*9b2bb4f2STakashi Sakamoto 	return err;
294*9b2bb4f2STakashi Sakamoto }
295*9b2bb4f2STakashi Sakamoto 
296*9b2bb4f2STakashi Sakamoto static void destroy_stream(struct snd_motu *motu,
297*9b2bb4f2STakashi Sakamoto 			   enum amdtp_stream_direction dir)
298*9b2bb4f2STakashi Sakamoto {
299*9b2bb4f2STakashi Sakamoto 	struct amdtp_stream *stream;
300*9b2bb4f2STakashi Sakamoto 	struct fw_iso_resources *resources;
301*9b2bb4f2STakashi Sakamoto 
302*9b2bb4f2STakashi Sakamoto 	if (dir == AMDTP_IN_STREAM) {
303*9b2bb4f2STakashi Sakamoto 		stream = &motu->tx_stream;
304*9b2bb4f2STakashi Sakamoto 		resources = &motu->tx_resources;
305*9b2bb4f2STakashi Sakamoto 	} else {
306*9b2bb4f2STakashi Sakamoto 		stream = &motu->rx_stream;
307*9b2bb4f2STakashi Sakamoto 		resources = &motu->rx_resources;
308*9b2bb4f2STakashi Sakamoto 	}
309*9b2bb4f2STakashi Sakamoto 
310*9b2bb4f2STakashi Sakamoto 	amdtp_stream_destroy(stream);
311*9b2bb4f2STakashi Sakamoto 	fw_iso_resources_free(resources);
312*9b2bb4f2STakashi Sakamoto }
313*9b2bb4f2STakashi Sakamoto 
314*9b2bb4f2STakashi Sakamoto int snd_motu_stream_init_duplex(struct snd_motu *motu)
315*9b2bb4f2STakashi Sakamoto {
316*9b2bb4f2STakashi Sakamoto 	int err;
317*9b2bb4f2STakashi Sakamoto 
318*9b2bb4f2STakashi Sakamoto 	err = init_stream(motu, AMDTP_IN_STREAM);
319*9b2bb4f2STakashi Sakamoto 	if (err < 0)
320*9b2bb4f2STakashi Sakamoto 		return err;
321*9b2bb4f2STakashi Sakamoto 
322*9b2bb4f2STakashi Sakamoto 	err = init_stream(motu, AMDTP_OUT_STREAM);
323*9b2bb4f2STakashi Sakamoto 	if (err < 0)
324*9b2bb4f2STakashi Sakamoto 		destroy_stream(motu, AMDTP_IN_STREAM);
325*9b2bb4f2STakashi Sakamoto 
326*9b2bb4f2STakashi Sakamoto 	return err;
327*9b2bb4f2STakashi Sakamoto }
328*9b2bb4f2STakashi Sakamoto 
329*9b2bb4f2STakashi Sakamoto /*
330*9b2bb4f2STakashi Sakamoto  * This function should be called before starting streams or after stopping
331*9b2bb4f2STakashi Sakamoto  * streams.
332*9b2bb4f2STakashi Sakamoto  */
333*9b2bb4f2STakashi Sakamoto void snd_motu_stream_destroy_duplex(struct snd_motu *motu)
334*9b2bb4f2STakashi Sakamoto {
335*9b2bb4f2STakashi Sakamoto 	destroy_stream(motu, AMDTP_IN_STREAM);
336*9b2bb4f2STakashi Sakamoto 	destroy_stream(motu, AMDTP_OUT_STREAM);
337*9b2bb4f2STakashi Sakamoto 
338*9b2bb4f2STakashi Sakamoto 	motu->playback_substreams = 0;
339*9b2bb4f2STakashi Sakamoto 	motu->capture_substreams = 0;
340*9b2bb4f2STakashi Sakamoto }
341