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