1e2786ca6STakashi Sakamoto /*
2e2786ca6STakashi Sakamoto  * oxfw_stream.c - a part of driver for OXFW970/971 based devices
3e2786ca6STakashi Sakamoto  *
4e2786ca6STakashi Sakamoto  * Copyright (c) 2014 Takashi Sakamoto
5e2786ca6STakashi Sakamoto  *
6e2786ca6STakashi Sakamoto  * Licensed under the terms of the GNU General Public License, version 2.
7e2786ca6STakashi Sakamoto  */
8e2786ca6STakashi Sakamoto 
9e2786ca6STakashi Sakamoto #include "oxfw.h"
10f3699e2cSTakashi Sakamoto #include <linux/delay.h>
11e2786ca6STakashi Sakamoto 
125cd1d3f4STakashi Sakamoto #define AVC_GENERIC_FRAME_MAXIMUM_BYTES	512
13f3699e2cSTakashi Sakamoto #define CALLBACK_TIMEOUT	200
145cd1d3f4STakashi Sakamoto 
155cd1d3f4STakashi Sakamoto /*
165cd1d3f4STakashi Sakamoto  * According to datasheet of Oxford Semiconductor:
175cd1d3f4STakashi Sakamoto  *  OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
185cd1d3f4STakashi Sakamoto  *  OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
195cd1d3f4STakashi Sakamoto  */
205cd1d3f4STakashi Sakamoto static const unsigned int oxfw_rate_table[] = {
215cd1d3f4STakashi Sakamoto 	[0] = 32000,
225cd1d3f4STakashi Sakamoto 	[1] = 44100,
235cd1d3f4STakashi Sakamoto 	[2] = 48000,
245cd1d3f4STakashi Sakamoto 	[3] = 88200,
255cd1d3f4STakashi Sakamoto 	[4] = 96000,
265cd1d3f4STakashi Sakamoto 	[5] = 192000,
275cd1d3f4STakashi Sakamoto };
285cd1d3f4STakashi Sakamoto 
295cd1d3f4STakashi Sakamoto /*
305cd1d3f4STakashi Sakamoto  * See Table 5.7 – Sampling frequency for Multi-bit Audio
315cd1d3f4STakashi Sakamoto  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
325cd1d3f4STakashi Sakamoto  */
335cd1d3f4STakashi Sakamoto static const unsigned int avc_stream_rate_table[] = {
345cd1d3f4STakashi Sakamoto 	[0] = 0x02,
355cd1d3f4STakashi Sakamoto 	[1] = 0x03,
365cd1d3f4STakashi Sakamoto 	[2] = 0x04,
375cd1d3f4STakashi Sakamoto 	[3] = 0x0a,
385cd1d3f4STakashi Sakamoto 	[4] = 0x05,
395cd1d3f4STakashi Sakamoto 	[5] = 0x07,
405cd1d3f4STakashi Sakamoto };
415cd1d3f4STakashi Sakamoto 
42b0ac0009STakashi Sakamoto static int set_rate(struct snd_oxfw *oxfw, unsigned int rate)
43b0ac0009STakashi Sakamoto {
44b0ac0009STakashi Sakamoto 	int err;
45b0ac0009STakashi Sakamoto 
46b0ac0009STakashi Sakamoto 	err = avc_general_set_sig_fmt(oxfw->unit, rate,
47b0ac0009STakashi Sakamoto 				      AVC_GENERAL_PLUG_DIR_IN, 0);
48b0ac0009STakashi Sakamoto 	if (err < 0)
49b0ac0009STakashi Sakamoto 		goto end;
50b0ac0009STakashi Sakamoto 
51b0ac0009STakashi Sakamoto 	if (oxfw->has_output)
52b0ac0009STakashi Sakamoto 		err = avc_general_set_sig_fmt(oxfw->unit, rate,
53b0ac0009STakashi Sakamoto 					      AVC_GENERAL_PLUG_DIR_OUT, 0);
54b0ac0009STakashi Sakamoto end:
55b0ac0009STakashi Sakamoto 	return err;
56b0ac0009STakashi Sakamoto }
57b0ac0009STakashi Sakamoto 
58f3699e2cSTakashi Sakamoto static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
59f3699e2cSTakashi Sakamoto 			     unsigned int rate, unsigned int pcm_channels)
60f3699e2cSTakashi Sakamoto {
61f3699e2cSTakashi Sakamoto 	u8 **formats;
62f3699e2cSTakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
63f3699e2cSTakashi Sakamoto 	enum avc_general_plug_dir dir;
645580ba7bSDan Carpenter 	unsigned int len;
655580ba7bSDan Carpenter 	int i, err;
66f3699e2cSTakashi Sakamoto 
67b0ac0009STakashi Sakamoto 	if (s == &oxfw->tx_stream) {
68b0ac0009STakashi Sakamoto 		formats = oxfw->tx_stream_formats;
69b0ac0009STakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_OUT;
70b0ac0009STakashi Sakamoto 	} else {
71f3699e2cSTakashi Sakamoto 		formats = oxfw->rx_stream_formats;
72f3699e2cSTakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_IN;
73b0ac0009STakashi Sakamoto 	}
74f3699e2cSTakashi Sakamoto 
75f3699e2cSTakashi Sakamoto 	/* Seek stream format for requirements. */
76f3699e2cSTakashi Sakamoto 	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
77f3699e2cSTakashi Sakamoto 		err = snd_oxfw_stream_parse_format(formats[i], &formation);
78f3699e2cSTakashi Sakamoto 		if (err < 0)
79f3699e2cSTakashi Sakamoto 			return err;
80f3699e2cSTakashi Sakamoto 
81f3699e2cSTakashi Sakamoto 		if ((formation.rate == rate) && (formation.pcm == pcm_channels))
82f3699e2cSTakashi Sakamoto 			break;
83f3699e2cSTakashi Sakamoto 	}
84f3699e2cSTakashi Sakamoto 	if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
85f3699e2cSTakashi Sakamoto 		return -EINVAL;
86f3699e2cSTakashi Sakamoto 
87f3699e2cSTakashi Sakamoto 	/* If assumed, just change rate. */
88f3699e2cSTakashi Sakamoto 	if (oxfw->assumed)
89b0ac0009STakashi Sakamoto 		return set_rate(oxfw, rate);
90f3699e2cSTakashi Sakamoto 
91f3699e2cSTakashi Sakamoto 	/* Calculate format length. */
92f3699e2cSTakashi Sakamoto 	len = 5 + formats[i][4] * 2;
93f3699e2cSTakashi Sakamoto 
94f3699e2cSTakashi Sakamoto 	err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
95f3699e2cSTakashi Sakamoto 	if (err < 0)
96f3699e2cSTakashi Sakamoto 		return err;
97f3699e2cSTakashi Sakamoto 
98f3699e2cSTakashi Sakamoto 	/* Some requests just after changing format causes freezing. */
99f3699e2cSTakashi Sakamoto 	msleep(100);
100f3699e2cSTakashi Sakamoto 
101f3699e2cSTakashi Sakamoto 	return 0;
102f3699e2cSTakashi Sakamoto }
103f3699e2cSTakashi Sakamoto 
104521b2e11STakashi Sakamoto static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
105e2786ca6STakashi Sakamoto {
106f3699e2cSTakashi Sakamoto 	struct cmp_connection *conn;
107f3699e2cSTakashi Sakamoto 	int err;
108f3699e2cSTakashi Sakamoto 
1090356ce3aSTakashi Sakamoto 	if (stream == &oxfw->rx_stream)
110f3699e2cSTakashi Sakamoto 		conn = &oxfw->in_conn;
1110356ce3aSTakashi Sakamoto 	else
112b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
113f3699e2cSTakashi Sakamoto 
114f3699e2cSTakashi Sakamoto 	err = cmp_connection_establish(conn,
115f3699e2cSTakashi Sakamoto 				       amdtp_stream_get_max_payload(stream));
116f3699e2cSTakashi Sakamoto 	if (err < 0)
117e34244ddSTakashi Sakamoto 		return err;
118f3699e2cSTakashi Sakamoto 
119e34244ddSTakashi Sakamoto 	err = amdtp_stream_start(stream, conn->resources.channel, conn->speed);
120f3699e2cSTakashi Sakamoto 	if (err < 0) {
121f3699e2cSTakashi Sakamoto 		cmp_connection_break(conn);
122e34244ddSTakashi Sakamoto 		return err;
123f3699e2cSTakashi Sakamoto 	}
124f3699e2cSTakashi Sakamoto 
125e34244ddSTakashi Sakamoto 	// Wait first packet.
126f2b14c0bSTakashi Sakamoto 	if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
127e34244ddSTakashi Sakamoto 		amdtp_stream_stop(stream);
128e34244ddSTakashi Sakamoto 		cmp_connection_break(conn);
129e34244ddSTakashi Sakamoto 		return -ETIMEDOUT;
130f2b14c0bSTakashi Sakamoto 	}
131e34244ddSTakashi Sakamoto 
132e34244ddSTakashi Sakamoto 	return 0;
133f3699e2cSTakashi Sakamoto }
134f3699e2cSTakashi Sakamoto 
135b0ac0009STakashi Sakamoto static int check_connection_used_by_others(struct snd_oxfw *oxfw,
136b0ac0009STakashi Sakamoto 					   struct amdtp_stream *stream)
137f3699e2cSTakashi Sakamoto {
138b0ac0009STakashi Sakamoto 	struct cmp_connection *conn;
139b0ac0009STakashi Sakamoto 	bool used;
140b0ac0009STakashi Sakamoto 	int err;
141b0ac0009STakashi Sakamoto 
142b0ac0009STakashi Sakamoto 	if (stream == &oxfw->tx_stream)
143b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
144b0ac0009STakashi Sakamoto 	else
145b0ac0009STakashi Sakamoto 		conn = &oxfw->in_conn;
146b0ac0009STakashi Sakamoto 
147b0ac0009STakashi Sakamoto 	err = cmp_connection_check_used(conn, &used);
148b0ac0009STakashi Sakamoto 	if ((err >= 0) && used && !amdtp_stream_running(stream)) {
149b0ac0009STakashi Sakamoto 		dev_err(&oxfw->unit->device,
150b0ac0009STakashi Sakamoto 			"Connection established by others: %cPCR[%d]\n",
151b0ac0009STakashi Sakamoto 			(conn->direction == CMP_OUTPUT) ? 'o' : 'i',
152b0ac0009STakashi Sakamoto 			conn->pcr_index);
153b0ac0009STakashi Sakamoto 		err = -EBUSY;
154b0ac0009STakashi Sakamoto 	}
155b0ac0009STakashi Sakamoto 
156b0ac0009STakashi Sakamoto 	return err;
157b0ac0009STakashi Sakamoto }
158b0ac0009STakashi Sakamoto 
159779f0dbaSTakashi Sakamoto static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
160b0ac0009STakashi Sakamoto {
161b0ac0009STakashi Sakamoto 	struct cmp_connection *conn;
162b0ac0009STakashi Sakamoto 	enum cmp_direction c_dir;
163b0ac0009STakashi Sakamoto 	enum amdtp_stream_direction s_dir;
164b0ac0009STakashi Sakamoto 	int err;
165b0ac0009STakashi Sakamoto 
166b0ac0009STakashi Sakamoto 	if (stream == &oxfw->tx_stream) {
167b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
168b0ac0009STakashi Sakamoto 		c_dir = CMP_OUTPUT;
169b0ac0009STakashi Sakamoto 		s_dir = AMDTP_IN_STREAM;
170b0ac0009STakashi Sakamoto 	} else {
171b0ac0009STakashi Sakamoto 		conn = &oxfw->in_conn;
172b0ac0009STakashi Sakamoto 		c_dir = CMP_INPUT;
173b0ac0009STakashi Sakamoto 		s_dir = AMDTP_OUT_STREAM;
174b0ac0009STakashi Sakamoto 	}
175b0ac0009STakashi Sakamoto 
176b0ac0009STakashi Sakamoto 	err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
177b0ac0009STakashi Sakamoto 	if (err < 0)
178779f0dbaSTakashi Sakamoto 		return err;
179b0ac0009STakashi Sakamoto 
1805955815eSTakashi Sakamoto 	err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
181b0ac0009STakashi Sakamoto 	if (err < 0) {
182b0ac0009STakashi Sakamoto 		cmp_connection_destroy(conn);
183779f0dbaSTakashi Sakamoto 		return err;
184b0ac0009STakashi Sakamoto 	}
185b0ac0009STakashi Sakamoto 
186a2064710STakashi Sakamoto 	/*
187a2064710STakashi Sakamoto 	 * OXFW starts to transmit packets with non-zero dbc.
188a2064710STakashi Sakamoto 	 * OXFW postpone transferring packets till handling any asynchronous
189a2064710STakashi Sakamoto 	 * packets. As a result, next isochronous packet includes more data
190a2064710STakashi Sakamoto 	 * blocks than IEC 61883-6 defines.
191a2064710STakashi Sakamoto 	 */
19213f3a46dSTakashi Sakamoto 	if (stream == &oxfw->tx_stream) {
19362f00e40STakashi Sakamoto 		oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD;
19413f3a46dSTakashi Sakamoto 		if (oxfw->wrong_dbs)
19513f3a46dSTakashi Sakamoto 			oxfw->tx_stream.flags |= CIP_WRONG_DBS;
19613f3a46dSTakashi Sakamoto 	}
197779f0dbaSTakashi Sakamoto 
198779f0dbaSTakashi Sakamoto 	return 0;
199b0ac0009STakashi Sakamoto }
200b0ac0009STakashi Sakamoto 
2010356ce3aSTakashi Sakamoto static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
2020356ce3aSTakashi Sakamoto {
2030356ce3aSTakashi Sakamoto 	enum avc_general_plug_dir dir;
2040356ce3aSTakashi Sakamoto 	u8 **formats;
2050356ce3aSTakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
2060356ce3aSTakashi Sakamoto 	int i;
2070356ce3aSTakashi Sakamoto 	int err;
2080356ce3aSTakashi Sakamoto 
2090356ce3aSTakashi Sakamoto 	if (stream == &oxfw->rx_stream) {
2100356ce3aSTakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_IN;
2110356ce3aSTakashi Sakamoto 		formats = oxfw->rx_stream_formats;
2120356ce3aSTakashi Sakamoto 	} else {
2130356ce3aSTakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_OUT;
2140356ce3aSTakashi Sakamoto 		formats = oxfw->tx_stream_formats;
2150356ce3aSTakashi Sakamoto 	}
2160356ce3aSTakashi Sakamoto 
2170356ce3aSTakashi Sakamoto 	err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
2180356ce3aSTakashi Sakamoto 	if (err < 0)
2190356ce3aSTakashi Sakamoto 		return err;
2200356ce3aSTakashi Sakamoto 
2210356ce3aSTakashi Sakamoto 	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
2220356ce3aSTakashi Sakamoto 		struct snd_oxfw_stream_formation fmt;
2230356ce3aSTakashi Sakamoto 
2240356ce3aSTakashi Sakamoto 		if (formats[i] == NULL)
2250356ce3aSTakashi Sakamoto 			break;
2260356ce3aSTakashi Sakamoto 
2270356ce3aSTakashi Sakamoto 		err = snd_oxfw_stream_parse_format(formats[i], &fmt);
2280356ce3aSTakashi Sakamoto 		if (err < 0)
2290356ce3aSTakashi Sakamoto 			return err;
2300356ce3aSTakashi Sakamoto 
2310356ce3aSTakashi Sakamoto 		if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
2320356ce3aSTakashi Sakamoto 		    fmt.midi == formation.midi)
2330356ce3aSTakashi Sakamoto 			break;
2340356ce3aSTakashi Sakamoto 	}
2350356ce3aSTakashi Sakamoto 	if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
2360356ce3aSTakashi Sakamoto 		return -EINVAL;
2370356ce3aSTakashi Sakamoto 
2380356ce3aSTakashi Sakamoto 	// The stream should have one pcm channels at least.
2390356ce3aSTakashi Sakamoto 	if (formation.pcm == 0)
2400356ce3aSTakashi Sakamoto 		return -EINVAL;
2410356ce3aSTakashi Sakamoto 
2420356ce3aSTakashi Sakamoto 	return amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
2430356ce3aSTakashi Sakamoto 					 formation.midi * 8, false);
2440356ce3aSTakashi Sakamoto }
2450356ce3aSTakashi Sakamoto 
2464f380d00STakashi Sakamoto int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
247b0ac0009STakashi Sakamoto 				   struct amdtp_stream *stream,
248b0ac0009STakashi Sakamoto 				   unsigned int rate, unsigned int pcm_channels)
249b0ac0009STakashi Sakamoto {
250f3699e2cSTakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
251b0ac0009STakashi Sakamoto 	enum avc_general_plug_dir dir;
2524f380d00STakashi Sakamoto 	int err;
253e2786ca6STakashi Sakamoto 
25420358d44STakashi Sakamoto 	// Considering JACK/FFADO streaming:
25520358d44STakashi Sakamoto 	// TODO: This can be removed hwdep functionality becomes popular.
25620358d44STakashi Sakamoto 	err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
25720358d44STakashi Sakamoto 	if (err < 0)
25820358d44STakashi Sakamoto 		return err;
25920358d44STakashi Sakamoto 	if (oxfw->has_output) {
26020358d44STakashi Sakamoto 		err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
26120358d44STakashi Sakamoto 		if (err < 0)
26220358d44STakashi Sakamoto 			return err;
263b0ac0009STakashi Sakamoto 	}
264b0ac0009STakashi Sakamoto 
26520358d44STakashi Sakamoto 	if (stream == &oxfw->tx_stream)
26620358d44STakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_OUT;
26720358d44STakashi Sakamoto 	else
26820358d44STakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_IN;
269b0ac0009STakashi Sakamoto 
270b0ac0009STakashi Sakamoto 	err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
271e2786ca6STakashi Sakamoto 	if (err < 0)
27220358d44STakashi Sakamoto 		return err;
2734f380d00STakashi Sakamoto 	if (rate == 0) {
27405588d34STakashi Sakamoto 		rate = formation.rate;
27505588d34STakashi Sakamoto 		pcm_channels = formation.pcm;
2764f380d00STakashi Sakamoto 	}
2774f380d00STakashi Sakamoto 	if (formation.rate != rate || formation.pcm != pcm_channels) {
278e34244ddSTakashi Sakamoto 		amdtp_stream_stop(&oxfw->rx_stream);
279e34244ddSTakashi Sakamoto 		cmp_connection_break(&oxfw->in_conn);
280e34244ddSTakashi Sakamoto 
281e34244ddSTakashi Sakamoto 		if (oxfw->has_output) {
282e34244ddSTakashi Sakamoto 			amdtp_stream_stop(&oxfw->tx_stream);
283e34244ddSTakashi Sakamoto 			cmp_connection_break(&oxfw->out_conn);
284e34244ddSTakashi Sakamoto 		}
2854f380d00STakashi Sakamoto 	}
286f3699e2cSTakashi Sakamoto 
2874f380d00STakashi Sakamoto 	if (oxfw->substreams_count == 0 ||
2884f380d00STakashi Sakamoto 	    formation.rate != rate || formation.pcm != pcm_channels) {
289b0ac0009STakashi Sakamoto 		err = set_stream_format(oxfw, stream, rate, pcm_channels);
290f3699e2cSTakashi Sakamoto 		if (err < 0) {
291f3699e2cSTakashi Sakamoto 			dev_err(&oxfw->unit->device,
292f3699e2cSTakashi Sakamoto 				"fail to set stream format: %d\n", err);
29320358d44STakashi Sakamoto 			return err;
29420358d44STakashi Sakamoto 		}
2950356ce3aSTakashi Sakamoto 
2960356ce3aSTakashi Sakamoto 		err = keep_resources(oxfw, &oxfw->rx_stream);
2970356ce3aSTakashi Sakamoto 		if (err < 0)
2980356ce3aSTakashi Sakamoto 			return err;
2990356ce3aSTakashi Sakamoto 
3000356ce3aSTakashi Sakamoto 		if (oxfw->has_output) {
3010356ce3aSTakashi Sakamoto 			err = keep_resources(oxfw, &oxfw->tx_stream);
3020356ce3aSTakashi Sakamoto 			if (err < 0)
3030356ce3aSTakashi Sakamoto 				return err;
3040356ce3aSTakashi Sakamoto 		}
305f3699e2cSTakashi Sakamoto 	}
306b0ac0009STakashi Sakamoto 
3074f380d00STakashi Sakamoto 	return 0;
3084f380d00STakashi Sakamoto }
3094f380d00STakashi Sakamoto 
3104f380d00STakashi Sakamoto int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
3114f380d00STakashi Sakamoto {
3124f380d00STakashi Sakamoto 	int err;
3134f380d00STakashi Sakamoto 
3144f380d00STakashi Sakamoto 	if (oxfw->substreams_count == 0)
3154f380d00STakashi Sakamoto 		return -EIO;
3164f380d00STakashi Sakamoto 
3174f380d00STakashi Sakamoto 	if (amdtp_streaming_error(&oxfw->rx_stream) ||
3184f380d00STakashi Sakamoto 	    amdtp_streaming_error(&oxfw->tx_stream)) {
3194f380d00STakashi Sakamoto 		amdtp_stream_stop(&oxfw->rx_stream);
3204f380d00STakashi Sakamoto 		cmp_connection_break(&oxfw->in_conn);
3214f380d00STakashi Sakamoto 
3224f380d00STakashi Sakamoto 		if (oxfw->has_output) {
3234f380d00STakashi Sakamoto 			amdtp_stream_stop(&oxfw->tx_stream);
3244f380d00STakashi Sakamoto 			cmp_connection_break(&oxfw->out_conn);
3254f380d00STakashi Sakamoto 		}
3264f380d00STakashi Sakamoto 	}
3274f380d00STakashi Sakamoto 
32820358d44STakashi Sakamoto 	if (!amdtp_stream_running(&oxfw->rx_stream)) {
32920358d44STakashi Sakamoto 		err = start_stream(oxfw, &oxfw->rx_stream);
330b0ac0009STakashi Sakamoto 		if (err < 0) {
331b0ac0009STakashi Sakamoto 			dev_err(&oxfw->unit->device,
33220358d44STakashi Sakamoto 				"fail to start rx stream: %d\n", err);
33320358d44STakashi Sakamoto 			goto error;
33420358d44STakashi Sakamoto 		}
33520358d44STakashi Sakamoto 	}
33620358d44STakashi Sakamoto 
33720358d44STakashi Sakamoto 	if (oxfw->has_output) {
33820358d44STakashi Sakamoto 		if (!amdtp_stream_running(&oxfw->tx_stream)) {
33920358d44STakashi Sakamoto 			err = start_stream(oxfw, &oxfw->tx_stream);
34020358d44STakashi Sakamoto 			if (err < 0) {
34120358d44STakashi Sakamoto 				dev_err(&oxfw->unit->device,
34220358d44STakashi Sakamoto 					"fail to start tx stream: %d\n", err);
34320358d44STakashi Sakamoto 				goto error;
344b0ac0009STakashi Sakamoto 			}
345b0ac0009STakashi Sakamoto 		}
346f3699e2cSTakashi Sakamoto 	}
347f3699e2cSTakashi Sakamoto 
34820358d44STakashi Sakamoto 	return 0;
34920358d44STakashi Sakamoto error:
350e34244ddSTakashi Sakamoto 	amdtp_stream_stop(&oxfw->rx_stream);
35120358d44STakashi Sakamoto 	cmp_connection_break(&oxfw->in_conn);
35220358d44STakashi Sakamoto 	if (oxfw->has_output) {
353e34244ddSTakashi Sakamoto 		amdtp_stream_stop(&oxfw->tx_stream);
35420358d44STakashi Sakamoto 		cmp_connection_break(&oxfw->out_conn);
355b0ac0009STakashi Sakamoto 	}
356e2786ca6STakashi Sakamoto 	return err;
357e2786ca6STakashi Sakamoto }
358e2786ca6STakashi Sakamoto 
359779f0dbaSTakashi Sakamoto void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
360e2786ca6STakashi Sakamoto {
3614a0a0472STakashi Sakamoto 	if (oxfw->substreams_count == 0) {
362e34244ddSTakashi Sakamoto 		amdtp_stream_stop(&oxfw->rx_stream);
363e34244ddSTakashi Sakamoto 		cmp_connection_break(&oxfw->in_conn);
364b0ac0009STakashi Sakamoto 
365e34244ddSTakashi Sakamoto 		if (oxfw->has_output) {
366e34244ddSTakashi Sakamoto 			amdtp_stream_stop(&oxfw->tx_stream);
367e34244ddSTakashi Sakamoto 			cmp_connection_break(&oxfw->out_conn);
368e34244ddSTakashi Sakamoto 		}
36920358d44STakashi Sakamoto 	}
370e2786ca6STakashi Sakamoto }
371e2786ca6STakashi Sakamoto 
372779f0dbaSTakashi Sakamoto static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
373e2786ca6STakashi Sakamoto {
374b0ac0009STakashi Sakamoto 	struct cmp_connection *conn;
375e2786ca6STakashi Sakamoto 
376b0ac0009STakashi Sakamoto 	if (stream == &oxfw->tx_stream)
377b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
378e2786ca6STakashi Sakamoto 	else
379b0ac0009STakashi Sakamoto 		conn = &oxfw->in_conn;
380b0ac0009STakashi Sakamoto 
381b0ac0009STakashi Sakamoto 	amdtp_stream_destroy(stream);
382b0ac0009STakashi Sakamoto 	cmp_connection_destroy(conn);
383b0ac0009STakashi Sakamoto }
384b0ac0009STakashi Sakamoto 
385779f0dbaSTakashi Sakamoto int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
386779f0dbaSTakashi Sakamoto {
387779f0dbaSTakashi Sakamoto 	int err;
388779f0dbaSTakashi Sakamoto 
389779f0dbaSTakashi Sakamoto 	err = init_stream(oxfw, &oxfw->rx_stream);
390779f0dbaSTakashi Sakamoto 	if (err < 0)
391779f0dbaSTakashi Sakamoto 		return err;
392779f0dbaSTakashi Sakamoto 
393779f0dbaSTakashi Sakamoto 	if (oxfw->has_output) {
394779f0dbaSTakashi Sakamoto 		err = init_stream(oxfw, &oxfw->tx_stream);
395779f0dbaSTakashi Sakamoto 		if (err < 0) {
396779f0dbaSTakashi Sakamoto 			destroy_stream(oxfw, &oxfw->rx_stream);
397779f0dbaSTakashi Sakamoto 			return err;
398779f0dbaSTakashi Sakamoto 		}
399779f0dbaSTakashi Sakamoto 	}
400779f0dbaSTakashi Sakamoto 
401779f0dbaSTakashi Sakamoto 	return 0;
402779f0dbaSTakashi Sakamoto }
403779f0dbaSTakashi Sakamoto 
404779f0dbaSTakashi Sakamoto // This function should be called before starting the stream or after stopping
405779f0dbaSTakashi Sakamoto // the streams.
406779f0dbaSTakashi Sakamoto void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
407779f0dbaSTakashi Sakamoto {
408779f0dbaSTakashi Sakamoto 	destroy_stream(oxfw, &oxfw->rx_stream);
409779f0dbaSTakashi Sakamoto 
410779f0dbaSTakashi Sakamoto 	if (oxfw->has_output)
411779f0dbaSTakashi Sakamoto 		destroy_stream(oxfw, &oxfw->tx_stream);
412779f0dbaSTakashi Sakamoto }
413779f0dbaSTakashi Sakamoto 
414779f0dbaSTakashi Sakamoto void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
415b0ac0009STakashi Sakamoto {
416e34244ddSTakashi Sakamoto 	amdtp_stream_stop(&oxfw->rx_stream);
417e34244ddSTakashi Sakamoto 	cmp_connection_break(&oxfw->in_conn);
418b0ac0009STakashi Sakamoto 
419e34244ddSTakashi Sakamoto 	amdtp_stream_pcm_abort(&oxfw->rx_stream);
420e34244ddSTakashi Sakamoto 
421e34244ddSTakashi Sakamoto 	if (oxfw->has_output) {
422e34244ddSTakashi Sakamoto 		amdtp_stream_stop(&oxfw->tx_stream);
423e34244ddSTakashi Sakamoto 		cmp_connection_break(&oxfw->out_conn);
424e34244ddSTakashi Sakamoto 
425e34244ddSTakashi Sakamoto 		amdtp_stream_pcm_abort(&oxfw->tx_stream);
426e34244ddSTakashi Sakamoto 	}
427e2786ca6STakashi Sakamoto }
4285cd1d3f4STakashi Sakamoto 
4293c96101fSTakashi Sakamoto int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
4303c96101fSTakashi Sakamoto 				enum avc_general_plug_dir dir,
4313c96101fSTakashi Sakamoto 				struct snd_oxfw_stream_formation *formation)
4323c96101fSTakashi Sakamoto {
4333c96101fSTakashi Sakamoto 	u8 *format;
4343c96101fSTakashi Sakamoto 	unsigned int len;
4353c96101fSTakashi Sakamoto 	int err;
4363c96101fSTakashi Sakamoto 
4373c96101fSTakashi Sakamoto 	len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
4383c96101fSTakashi Sakamoto 	format = kmalloc(len, GFP_KERNEL);
4393c96101fSTakashi Sakamoto 	if (format == NULL)
4403c96101fSTakashi Sakamoto 		return -ENOMEM;
4413c96101fSTakashi Sakamoto 
4423c96101fSTakashi Sakamoto 	err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
4433c96101fSTakashi Sakamoto 	if (err < 0)
4443c96101fSTakashi Sakamoto 		goto end;
4453c96101fSTakashi Sakamoto 	if (len < 3) {
4463c96101fSTakashi Sakamoto 		err = -EIO;
4473c96101fSTakashi Sakamoto 		goto end;
4483c96101fSTakashi Sakamoto 	}
4493c96101fSTakashi Sakamoto 
4503c96101fSTakashi Sakamoto 	err = snd_oxfw_stream_parse_format(format, formation);
4513c96101fSTakashi Sakamoto end:
4523c96101fSTakashi Sakamoto 	kfree(format);
4533c96101fSTakashi Sakamoto 	return err;
4543c96101fSTakashi Sakamoto }
4553c96101fSTakashi Sakamoto 
4565cd1d3f4STakashi Sakamoto /*
4575cd1d3f4STakashi Sakamoto  * See Table 6.16 - AM824 Stream Format
4585cd1d3f4STakashi Sakamoto  *     Figure 6.19 - format_information field for AM824 Compound
4595cd1d3f4STakashi Sakamoto  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
4605cd1d3f4STakashi Sakamoto  * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
4615cd1d3f4STakashi Sakamoto  */
4625cd1d3f4STakashi Sakamoto int snd_oxfw_stream_parse_format(u8 *format,
4635cd1d3f4STakashi Sakamoto 				 struct snd_oxfw_stream_formation *formation)
4645cd1d3f4STakashi Sakamoto {
4655cd1d3f4STakashi Sakamoto 	unsigned int i, e, channels, type;
4665cd1d3f4STakashi Sakamoto 
4675cd1d3f4STakashi Sakamoto 	memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
4685cd1d3f4STakashi Sakamoto 
4695cd1d3f4STakashi Sakamoto 	/*
4705cd1d3f4STakashi Sakamoto 	 * this module can support a hierarchy combination that:
4715cd1d3f4STakashi Sakamoto 	 *  Root:	Audio and Music (0x90)
4725cd1d3f4STakashi Sakamoto 	 *  Level 1:	AM824 Compound  (0x40)
4735cd1d3f4STakashi Sakamoto 	 */
4745cd1d3f4STakashi Sakamoto 	if ((format[0] != 0x90) || (format[1] != 0x40))
4755cd1d3f4STakashi Sakamoto 		return -ENOSYS;
4765cd1d3f4STakashi Sakamoto 
4775cd1d3f4STakashi Sakamoto 	/* check the sampling rate */
4785cd1d3f4STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
4795cd1d3f4STakashi Sakamoto 		if (format[2] == avc_stream_rate_table[i])
4805cd1d3f4STakashi Sakamoto 			break;
4815cd1d3f4STakashi Sakamoto 	}
4825cd1d3f4STakashi Sakamoto 	if (i == ARRAY_SIZE(avc_stream_rate_table))
4835cd1d3f4STakashi Sakamoto 		return -ENOSYS;
4845cd1d3f4STakashi Sakamoto 
4855cd1d3f4STakashi Sakamoto 	formation->rate = oxfw_rate_table[i];
4865cd1d3f4STakashi Sakamoto 
4875cd1d3f4STakashi Sakamoto 	for (e = 0; e < format[4]; e++) {
4885cd1d3f4STakashi Sakamoto 		channels = format[5 + e * 2];
4895cd1d3f4STakashi Sakamoto 		type = format[6 + e * 2];
4905cd1d3f4STakashi Sakamoto 
4915cd1d3f4STakashi Sakamoto 		switch (type) {
4925cd1d3f4STakashi Sakamoto 		/* IEC 60958 Conformant, currently handled as MBLA */
4935cd1d3f4STakashi Sakamoto 		case 0x00:
4945cd1d3f4STakashi Sakamoto 		/* Multi Bit Linear Audio (Raw) */
4955cd1d3f4STakashi Sakamoto 		case 0x06:
4965cd1d3f4STakashi Sakamoto 			formation->pcm += channels;
4975cd1d3f4STakashi Sakamoto 			break;
4985cd1d3f4STakashi Sakamoto 		/* MIDI Conformant */
4995cd1d3f4STakashi Sakamoto 		case 0x0d:
5005cd1d3f4STakashi Sakamoto 			formation->midi = channels;
5015cd1d3f4STakashi Sakamoto 			break;
5025cd1d3f4STakashi Sakamoto 		/* IEC 61937-3 to 7 */
5035cd1d3f4STakashi Sakamoto 		case 0x01:
5045cd1d3f4STakashi Sakamoto 		case 0x02:
5055cd1d3f4STakashi Sakamoto 		case 0x03:
5065cd1d3f4STakashi Sakamoto 		case 0x04:
5075cd1d3f4STakashi Sakamoto 		case 0x05:
5085cd1d3f4STakashi Sakamoto 		/* Multi Bit Linear Audio */
5095cd1d3f4STakashi Sakamoto 		case 0x07:	/* DVD-Audio */
5105cd1d3f4STakashi Sakamoto 		case 0x0c:	/* High Precision */
5115cd1d3f4STakashi Sakamoto 		/* One Bit Audio */
5125cd1d3f4STakashi Sakamoto 		case 0x08:	/* (Plain) Raw */
5135cd1d3f4STakashi Sakamoto 		case 0x09:	/* (Plain) SACD */
5145cd1d3f4STakashi Sakamoto 		case 0x0a:	/* (Encoded) Raw */
5155cd1d3f4STakashi Sakamoto 		case 0x0b:	/* (Encoded) SACD */
5165cd1d3f4STakashi Sakamoto 		/* SMPTE Time-Code conformant */
5175cd1d3f4STakashi Sakamoto 		case 0x0e:
5185cd1d3f4STakashi Sakamoto 		/* Sample Count */
5195cd1d3f4STakashi Sakamoto 		case 0x0f:
5205cd1d3f4STakashi Sakamoto 		/* Anciliary Data */
5215cd1d3f4STakashi Sakamoto 		case 0x10:
5225cd1d3f4STakashi Sakamoto 		/* Synchronization Stream (Stereo Raw audio) */
5235cd1d3f4STakashi Sakamoto 		case 0x40:
5245cd1d3f4STakashi Sakamoto 		/* Don't care */
5255cd1d3f4STakashi Sakamoto 		case 0xff:
5265cd1d3f4STakashi Sakamoto 		default:
5275cd1d3f4STakashi Sakamoto 			return -ENOSYS;	/* not supported */
5285cd1d3f4STakashi Sakamoto 		}
5295cd1d3f4STakashi Sakamoto 	}
5305cd1d3f4STakashi Sakamoto 
53149c7b3fcSTakashi Sakamoto 	if (formation->pcm  > AM824_MAX_CHANNELS_FOR_PCM ||
53249c7b3fcSTakashi Sakamoto 	    formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
5335cd1d3f4STakashi Sakamoto 		return -ENOSYS;
5345cd1d3f4STakashi Sakamoto 
5355cd1d3f4STakashi Sakamoto 	return 0;
5365cd1d3f4STakashi Sakamoto }
5375cd1d3f4STakashi Sakamoto 
5385cd1d3f4STakashi Sakamoto static int
5395cd1d3f4STakashi Sakamoto assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
5405cd1d3f4STakashi Sakamoto 		      unsigned int pid, u8 *buf, unsigned int *len,
5415cd1d3f4STakashi Sakamoto 		      u8 **formats)
5425cd1d3f4STakashi Sakamoto {
5435cd1d3f4STakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
5445cd1d3f4STakashi Sakamoto 	unsigned int i, eid;
5455cd1d3f4STakashi Sakamoto 	int err;
5465cd1d3f4STakashi Sakamoto 
5475cd1d3f4STakashi Sakamoto 	/* get format at current sampling rate */
5485cd1d3f4STakashi Sakamoto 	err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
5495cd1d3f4STakashi Sakamoto 	if (err < 0) {
5505cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
5515cd1d3f4STakashi Sakamoto 		"fail to get current stream format for isoc %s plug %d:%d\n",
5525cd1d3f4STakashi Sakamoto 			(dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
5535cd1d3f4STakashi Sakamoto 			pid, err);
5545cd1d3f4STakashi Sakamoto 		goto end;
5555cd1d3f4STakashi Sakamoto 	}
5565cd1d3f4STakashi Sakamoto 
5575cd1d3f4STakashi Sakamoto 	/* parse and set stream format */
5585cd1d3f4STakashi Sakamoto 	eid = 0;
5595cd1d3f4STakashi Sakamoto 	err = snd_oxfw_stream_parse_format(buf, &formation);
5605cd1d3f4STakashi Sakamoto 	if (err < 0)
5615cd1d3f4STakashi Sakamoto 		goto end;
5625cd1d3f4STakashi Sakamoto 
563cd3b7116STakashi Sakamoto 	formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
564cd3b7116STakashi Sakamoto 				    GFP_KERNEL);
565cd3b7116STakashi Sakamoto 	if (!formats[eid]) {
5665cd1d3f4STakashi Sakamoto 		err = -ENOMEM;
5675cd1d3f4STakashi Sakamoto 		goto end;
5685cd1d3f4STakashi Sakamoto 	}
5695cd1d3f4STakashi Sakamoto 
5705cd1d3f4STakashi Sakamoto 	/* apply the format for each available sampling rate */
5715cd1d3f4STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
5725cd1d3f4STakashi Sakamoto 		if (formation.rate == oxfw_rate_table[i])
5735cd1d3f4STakashi Sakamoto 			continue;
5745cd1d3f4STakashi Sakamoto 
5755cd1d3f4STakashi Sakamoto 		err = avc_general_inquiry_sig_fmt(oxfw->unit,
5765cd1d3f4STakashi Sakamoto 						  oxfw_rate_table[i],
5775cd1d3f4STakashi Sakamoto 						  dir, pid);
5785cd1d3f4STakashi Sakamoto 		if (err < 0)
5795cd1d3f4STakashi Sakamoto 			continue;
5805cd1d3f4STakashi Sakamoto 
5815cd1d3f4STakashi Sakamoto 		eid++;
582cd3b7116STakashi Sakamoto 		formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
583cd3b7116STakashi Sakamoto 					    GFP_KERNEL);
5845cd1d3f4STakashi Sakamoto 		if (formats[eid] == NULL) {
5855cd1d3f4STakashi Sakamoto 			err = -ENOMEM;
5865cd1d3f4STakashi Sakamoto 			goto end;
5875cd1d3f4STakashi Sakamoto 		}
5885cd1d3f4STakashi Sakamoto 		formats[eid][2] = avc_stream_rate_table[i];
5895cd1d3f4STakashi Sakamoto 	}
5905cd1d3f4STakashi Sakamoto 
5915cd1d3f4STakashi Sakamoto 	err = 0;
5925cd1d3f4STakashi Sakamoto 	oxfw->assumed = true;
5935cd1d3f4STakashi Sakamoto end:
5945cd1d3f4STakashi Sakamoto 	return err;
5955cd1d3f4STakashi Sakamoto }
5965cd1d3f4STakashi Sakamoto 
5975cd1d3f4STakashi Sakamoto static int fill_stream_formats(struct snd_oxfw *oxfw,
5985cd1d3f4STakashi Sakamoto 			       enum avc_general_plug_dir dir,
5995cd1d3f4STakashi Sakamoto 			       unsigned short pid)
6005cd1d3f4STakashi Sakamoto {
6015cd1d3f4STakashi Sakamoto 	u8 *buf, **formats;
6025cd1d3f4STakashi Sakamoto 	unsigned int len, eid = 0;
6035cd1d3f4STakashi Sakamoto 	struct snd_oxfw_stream_formation dummy;
6045cd1d3f4STakashi Sakamoto 	int err;
6055cd1d3f4STakashi Sakamoto 
6065cd1d3f4STakashi Sakamoto 	buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
6075cd1d3f4STakashi Sakamoto 	if (buf == NULL)
6085cd1d3f4STakashi Sakamoto 		return -ENOMEM;
6095cd1d3f4STakashi Sakamoto 
610b0ac0009STakashi Sakamoto 	if (dir == AVC_GENERAL_PLUG_DIR_OUT)
611b0ac0009STakashi Sakamoto 		formats = oxfw->tx_stream_formats;
612b0ac0009STakashi Sakamoto 	else
6135cd1d3f4STakashi Sakamoto 		formats = oxfw->rx_stream_formats;
6145cd1d3f4STakashi Sakamoto 
6155cd1d3f4STakashi Sakamoto 	/* get first entry */
6165cd1d3f4STakashi Sakamoto 	len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
6175cd1d3f4STakashi Sakamoto 	err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
6185cd1d3f4STakashi Sakamoto 	if (err == -ENOSYS) {
6195cd1d3f4STakashi Sakamoto 		/* LIST subfunction is not implemented */
6205cd1d3f4STakashi Sakamoto 		len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
6215cd1d3f4STakashi Sakamoto 		err = assume_stream_formats(oxfw, dir, pid, buf, &len,
6225cd1d3f4STakashi Sakamoto 					    formats);
6235cd1d3f4STakashi Sakamoto 		goto end;
6245cd1d3f4STakashi Sakamoto 	} else if (err < 0) {
6255cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
6265cd1d3f4STakashi Sakamoto 			"fail to get stream format %d for isoc %s plug %d:%d\n",
6275cd1d3f4STakashi Sakamoto 			eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
6285cd1d3f4STakashi Sakamoto 			pid, err);
6295cd1d3f4STakashi Sakamoto 		goto end;
6305cd1d3f4STakashi Sakamoto 	}
6315cd1d3f4STakashi Sakamoto 
6325cd1d3f4STakashi Sakamoto 	/* LIST subfunction is implemented */
6335cd1d3f4STakashi Sakamoto 	while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
6345cd1d3f4STakashi Sakamoto 		/* The format is too short. */
6355cd1d3f4STakashi Sakamoto 		if (len < 3) {
6365cd1d3f4STakashi Sakamoto 			err = -EIO;
6375cd1d3f4STakashi Sakamoto 			break;
6385cd1d3f4STakashi Sakamoto 		}
6395cd1d3f4STakashi Sakamoto 
6405cd1d3f4STakashi Sakamoto 		/* parse and set stream format */
6415cd1d3f4STakashi Sakamoto 		err = snd_oxfw_stream_parse_format(buf, &dummy);
6425cd1d3f4STakashi Sakamoto 		if (err < 0)
6435cd1d3f4STakashi Sakamoto 			break;
6445cd1d3f4STakashi Sakamoto 
645cd3b7116STakashi Sakamoto 		formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
646cd3b7116STakashi Sakamoto 					    GFP_KERNEL);
647cd3b7116STakashi Sakamoto 		if (!formats[eid]) {
6485cd1d3f4STakashi Sakamoto 			err = -ENOMEM;
6495cd1d3f4STakashi Sakamoto 			break;
6505cd1d3f4STakashi Sakamoto 		}
6515cd1d3f4STakashi Sakamoto 
6525cd1d3f4STakashi Sakamoto 		/* get next entry */
6535cd1d3f4STakashi Sakamoto 		len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
6545cd1d3f4STakashi Sakamoto 		err = avc_stream_get_format_list(oxfw->unit, dir, 0,
6555cd1d3f4STakashi Sakamoto 						 buf, &len, ++eid);
6565cd1d3f4STakashi Sakamoto 		/* No entries remained. */
6575cd1d3f4STakashi Sakamoto 		if (err == -EINVAL) {
6585cd1d3f4STakashi Sakamoto 			err = 0;
6595cd1d3f4STakashi Sakamoto 			break;
6605cd1d3f4STakashi Sakamoto 		} else if (err < 0) {
6615cd1d3f4STakashi Sakamoto 			dev_err(&oxfw->unit->device,
6625cd1d3f4STakashi Sakamoto 			"fail to get stream format %d for isoc %s plug %d:%d\n",
6635cd1d3f4STakashi Sakamoto 				eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
6645cd1d3f4STakashi Sakamoto 									"out",
6655cd1d3f4STakashi Sakamoto 				pid, err);
6665cd1d3f4STakashi Sakamoto 			break;
6675cd1d3f4STakashi Sakamoto 		}
6685cd1d3f4STakashi Sakamoto 	}
6695cd1d3f4STakashi Sakamoto end:
6705cd1d3f4STakashi Sakamoto 	kfree(buf);
6715cd1d3f4STakashi Sakamoto 	return err;
6725cd1d3f4STakashi Sakamoto }
6735cd1d3f4STakashi Sakamoto 
6745cd1d3f4STakashi Sakamoto int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
6755cd1d3f4STakashi Sakamoto {
6765cd1d3f4STakashi Sakamoto 	u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
67732056041STakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
67832056041STakashi Sakamoto 	u8 *format;
67932056041STakashi Sakamoto 	unsigned int i;
6805cd1d3f4STakashi Sakamoto 	int err;
6815cd1d3f4STakashi Sakamoto 
6825cd1d3f4STakashi Sakamoto 	/* the number of plugs for isoc in/out, ext in/out  */
6835cd1d3f4STakashi Sakamoto 	err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
6845cd1d3f4STakashi Sakamoto 	if (err < 0) {
6855cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
6865cd1d3f4STakashi Sakamoto 		"fail to get info for isoc/external in/out plugs: %d\n",
6875cd1d3f4STakashi Sakamoto 			err);
6885cd1d3f4STakashi Sakamoto 		goto end;
689b0ac0009STakashi Sakamoto 	} else if ((plugs[0] == 0) && (plugs[1] == 0)) {
6905cd1d3f4STakashi Sakamoto 		err = -ENOSYS;
6915cd1d3f4STakashi Sakamoto 		goto end;
6925cd1d3f4STakashi Sakamoto 	}
6935cd1d3f4STakashi Sakamoto 
694b0ac0009STakashi Sakamoto 	/* use oPCR[0] if exists */
695b0ac0009STakashi Sakamoto 	if (plugs[1] > 0) {
696b0ac0009STakashi Sakamoto 		err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
697b0ac0009STakashi Sakamoto 		if (err < 0)
698b0ac0009STakashi Sakamoto 			goto end;
69932056041STakashi Sakamoto 
70032056041STakashi Sakamoto 		for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
70132056041STakashi Sakamoto 			format = oxfw->tx_stream_formats[i];
70232056041STakashi Sakamoto 			if (format == NULL)
70332056041STakashi Sakamoto 				continue;
70432056041STakashi Sakamoto 			err = snd_oxfw_stream_parse_format(format, &formation);
70532056041STakashi Sakamoto 			if (err < 0)
70632056041STakashi Sakamoto 				continue;
70732056041STakashi Sakamoto 
70832056041STakashi Sakamoto 			/* Add one MIDI port. */
70932056041STakashi Sakamoto 			if (formation.midi > 0)
71032056041STakashi Sakamoto 				oxfw->midi_input_ports = 1;
71132056041STakashi Sakamoto 		}
71232056041STakashi Sakamoto 
713b0ac0009STakashi Sakamoto 		oxfw->has_output = true;
714b0ac0009STakashi Sakamoto 	}
715b0ac0009STakashi Sakamoto 
7165cd1d3f4STakashi Sakamoto 	/* use iPCR[0] if exists */
71732056041STakashi Sakamoto 	if (plugs[0] > 0) {
7185cd1d3f4STakashi Sakamoto 		err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
71932056041STakashi Sakamoto 		if (err < 0)
72032056041STakashi Sakamoto 			goto end;
72132056041STakashi Sakamoto 
72232056041STakashi Sakamoto 		for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
72332056041STakashi Sakamoto 			format = oxfw->rx_stream_formats[i];
72432056041STakashi Sakamoto 			if (format == NULL)
72532056041STakashi Sakamoto 				continue;
72632056041STakashi Sakamoto 			err = snd_oxfw_stream_parse_format(format, &formation);
72732056041STakashi Sakamoto 			if (err < 0)
72832056041STakashi Sakamoto 				continue;
72932056041STakashi Sakamoto 
73032056041STakashi Sakamoto 			/* Add one MIDI port. */
73132056041STakashi Sakamoto 			if (formation.midi > 0)
73232056041STakashi Sakamoto 				oxfw->midi_output_ports = 1;
73332056041STakashi Sakamoto 		}
73432056041STakashi Sakamoto 	}
7355cd1d3f4STakashi Sakamoto end:
7365cd1d3f4STakashi Sakamoto 	return err;
7375cd1d3f4STakashi Sakamoto }
7388985f4acSTakashi Sakamoto 
7398985f4acSTakashi Sakamoto void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
7408985f4acSTakashi Sakamoto {
7418985f4acSTakashi Sakamoto 	oxfw->dev_lock_changed = true;
7428985f4acSTakashi Sakamoto 	wake_up(&oxfw->hwdep_wait);
7438985f4acSTakashi Sakamoto }
7448985f4acSTakashi Sakamoto 
7458985f4acSTakashi Sakamoto int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
7468985f4acSTakashi Sakamoto {
7478985f4acSTakashi Sakamoto 	int err;
7488985f4acSTakashi Sakamoto 
7498985f4acSTakashi Sakamoto 	spin_lock_irq(&oxfw->lock);
7508985f4acSTakashi Sakamoto 
7518985f4acSTakashi Sakamoto 	/* user land lock this */
7528985f4acSTakashi Sakamoto 	if (oxfw->dev_lock_count < 0) {
7538985f4acSTakashi Sakamoto 		err = -EBUSY;
7548985f4acSTakashi Sakamoto 		goto end;
7558985f4acSTakashi Sakamoto 	}
7568985f4acSTakashi Sakamoto 
7578985f4acSTakashi Sakamoto 	/* this is the first time */
7588985f4acSTakashi Sakamoto 	if (oxfw->dev_lock_count++ == 0)
7598985f4acSTakashi Sakamoto 		snd_oxfw_stream_lock_changed(oxfw);
7608985f4acSTakashi Sakamoto 	err = 0;
7618985f4acSTakashi Sakamoto end:
7628985f4acSTakashi Sakamoto 	spin_unlock_irq(&oxfw->lock);
7638985f4acSTakashi Sakamoto 	return err;
7648985f4acSTakashi Sakamoto }
7658985f4acSTakashi Sakamoto 
7668985f4acSTakashi Sakamoto void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
7678985f4acSTakashi Sakamoto {
7688985f4acSTakashi Sakamoto 	spin_lock_irq(&oxfw->lock);
7698985f4acSTakashi Sakamoto 
7708985f4acSTakashi Sakamoto 	if (WARN_ON(oxfw->dev_lock_count <= 0))
7718985f4acSTakashi Sakamoto 		goto end;
7728985f4acSTakashi Sakamoto 	if (--oxfw->dev_lock_count == 0)
7738985f4acSTakashi Sakamoto 		snd_oxfw_stream_lock_changed(oxfw);
7748985f4acSTakashi Sakamoto end:
7758985f4acSTakashi Sakamoto 	spin_unlock_irq(&oxfw->lock);
7768985f4acSTakashi Sakamoto }
777