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