1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e2786ca6STakashi Sakamoto /*
3e2786ca6STakashi Sakamoto  * oxfw_stream.c - a part of driver for OXFW970/971 based devices
4e2786ca6STakashi Sakamoto  *
5e2786ca6STakashi Sakamoto  * Copyright (c) 2014 Takashi Sakamoto
6e2786ca6STakashi Sakamoto  */
7e2786ca6STakashi Sakamoto 
8e2786ca6STakashi Sakamoto #include "oxfw.h"
9f3699e2cSTakashi Sakamoto #include <linux/delay.h>
10e2786ca6STakashi Sakamoto 
115cd1d3f4STakashi Sakamoto #define AVC_GENERIC_FRAME_MAXIMUM_BYTES	512
12*a4ce4337STakashi Sakamoto #define READY_TIMEOUT_MS	600
135cd1d3f4STakashi Sakamoto 
145cd1d3f4STakashi Sakamoto /*
155cd1d3f4STakashi Sakamoto  * According to datasheet of Oxford Semiconductor:
165cd1d3f4STakashi Sakamoto  *  OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
175cd1d3f4STakashi Sakamoto  *  OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
185cd1d3f4STakashi Sakamoto  */
195cd1d3f4STakashi Sakamoto static const unsigned int oxfw_rate_table[] = {
205cd1d3f4STakashi Sakamoto 	[0] = 32000,
215cd1d3f4STakashi Sakamoto 	[1] = 44100,
225cd1d3f4STakashi Sakamoto 	[2] = 48000,
235cd1d3f4STakashi Sakamoto 	[3] = 88200,
245cd1d3f4STakashi Sakamoto 	[4] = 96000,
255cd1d3f4STakashi Sakamoto 	[5] = 192000,
265cd1d3f4STakashi Sakamoto };
275cd1d3f4STakashi Sakamoto 
285cd1d3f4STakashi Sakamoto /*
295cd1d3f4STakashi Sakamoto  * See Table 5.7 – Sampling frequency for Multi-bit Audio
305cd1d3f4STakashi Sakamoto  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
315cd1d3f4STakashi Sakamoto  */
325cd1d3f4STakashi Sakamoto static const unsigned int avc_stream_rate_table[] = {
335cd1d3f4STakashi Sakamoto 	[0] = 0x02,
345cd1d3f4STakashi Sakamoto 	[1] = 0x03,
355cd1d3f4STakashi Sakamoto 	[2] = 0x04,
365cd1d3f4STakashi Sakamoto 	[3] = 0x0a,
375cd1d3f4STakashi Sakamoto 	[4] = 0x05,
385cd1d3f4STakashi Sakamoto 	[5] = 0x07,
395cd1d3f4STakashi Sakamoto };
405cd1d3f4STakashi Sakamoto 
set_rate(struct snd_oxfw * oxfw,unsigned int rate)41b0ac0009STakashi Sakamoto static int set_rate(struct snd_oxfw *oxfw, unsigned int rate)
42b0ac0009STakashi Sakamoto {
43b0ac0009STakashi Sakamoto 	int err;
44b0ac0009STakashi Sakamoto 
45b0ac0009STakashi Sakamoto 	err = avc_general_set_sig_fmt(oxfw->unit, rate,
46b0ac0009STakashi Sakamoto 				      AVC_GENERAL_PLUG_DIR_IN, 0);
47b0ac0009STakashi Sakamoto 	if (err < 0)
48b0ac0009STakashi Sakamoto 		goto end;
49b0ac0009STakashi Sakamoto 
50b0ac0009STakashi Sakamoto 	if (oxfw->has_output)
51b0ac0009STakashi Sakamoto 		err = avc_general_set_sig_fmt(oxfw->unit, rate,
52b0ac0009STakashi Sakamoto 					      AVC_GENERAL_PLUG_DIR_OUT, 0);
53b0ac0009STakashi Sakamoto end:
54b0ac0009STakashi Sakamoto 	return err;
55b0ac0009STakashi Sakamoto }
56b0ac0009STakashi Sakamoto 
set_stream_format(struct snd_oxfw * oxfw,struct amdtp_stream * s,unsigned int rate,unsigned int pcm_channels)57f3699e2cSTakashi Sakamoto static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
58f3699e2cSTakashi Sakamoto 			     unsigned int rate, unsigned int pcm_channels)
59f3699e2cSTakashi Sakamoto {
60f3699e2cSTakashi Sakamoto 	u8 **formats;
61f3699e2cSTakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
62f3699e2cSTakashi Sakamoto 	enum avc_general_plug_dir dir;
635580ba7bSDan Carpenter 	unsigned int len;
645580ba7bSDan Carpenter 	int i, err;
65f3699e2cSTakashi Sakamoto 
66b0ac0009STakashi Sakamoto 	if (s == &oxfw->tx_stream) {
67b0ac0009STakashi Sakamoto 		formats = oxfw->tx_stream_formats;
68b0ac0009STakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_OUT;
69b0ac0009STakashi Sakamoto 	} else {
70f3699e2cSTakashi Sakamoto 		formats = oxfw->rx_stream_formats;
71f3699e2cSTakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_IN;
72b0ac0009STakashi Sakamoto 	}
73f3699e2cSTakashi Sakamoto 
74f3699e2cSTakashi Sakamoto 	/* Seek stream format for requirements. */
75f3699e2cSTakashi Sakamoto 	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
76f3699e2cSTakashi Sakamoto 		err = snd_oxfw_stream_parse_format(formats[i], &formation);
77f3699e2cSTakashi Sakamoto 		if (err < 0)
78f3699e2cSTakashi Sakamoto 			return err;
79f3699e2cSTakashi Sakamoto 
80f3699e2cSTakashi Sakamoto 		if ((formation.rate == rate) && (formation.pcm == pcm_channels))
81f3699e2cSTakashi Sakamoto 			break;
82f3699e2cSTakashi Sakamoto 	}
83f3699e2cSTakashi Sakamoto 	if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
84f3699e2cSTakashi Sakamoto 		return -EINVAL;
85f3699e2cSTakashi Sakamoto 
86f3699e2cSTakashi Sakamoto 	/* If assumed, just change rate. */
87f3699e2cSTakashi Sakamoto 	if (oxfw->assumed)
88b0ac0009STakashi Sakamoto 		return set_rate(oxfw, rate);
89f3699e2cSTakashi Sakamoto 
90f3699e2cSTakashi Sakamoto 	/* Calculate format length. */
91f3699e2cSTakashi Sakamoto 	len = 5 + formats[i][4] * 2;
92f3699e2cSTakashi Sakamoto 
93f3699e2cSTakashi Sakamoto 	err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
94f3699e2cSTakashi Sakamoto 	if (err < 0)
95f3699e2cSTakashi Sakamoto 		return err;
96f3699e2cSTakashi Sakamoto 
97f3699e2cSTakashi Sakamoto 	/* Some requests just after changing format causes freezing. */
98f3699e2cSTakashi Sakamoto 	msleep(100);
99f3699e2cSTakashi Sakamoto 
100f3699e2cSTakashi Sakamoto 	return 0;
101f3699e2cSTakashi Sakamoto }
102f3699e2cSTakashi Sakamoto 
start_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)103521b2e11STakashi Sakamoto static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
104e2786ca6STakashi Sakamoto {
105f3699e2cSTakashi Sakamoto 	struct cmp_connection *conn;
106f3699e2cSTakashi Sakamoto 	int err;
107f3699e2cSTakashi Sakamoto 
1080356ce3aSTakashi Sakamoto 	if (stream == &oxfw->rx_stream)
109f3699e2cSTakashi Sakamoto 		conn = &oxfw->in_conn;
1100356ce3aSTakashi Sakamoto 	else
111b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
112f3699e2cSTakashi Sakamoto 
1137bc93821STakashi Sakamoto 	err = cmp_connection_establish(conn);
114f3699e2cSTakashi Sakamoto 	if (err < 0)
115e34244ddSTakashi Sakamoto 		return err;
116f3699e2cSTakashi Sakamoto 
117ac5d7786STakashi Sakamoto 	err = amdtp_domain_add_stream(&oxfw->domain, stream,
118ac5d7786STakashi Sakamoto 				      conn->resources.channel, conn->speed);
119f3699e2cSTakashi Sakamoto 	if (err < 0) {
120f3699e2cSTakashi Sakamoto 		cmp_connection_break(conn);
121e34244ddSTakashi Sakamoto 		return err;
122f3699e2cSTakashi Sakamoto 	}
123f3699e2cSTakashi Sakamoto 
124e34244ddSTakashi Sakamoto 	return 0;
125f3699e2cSTakashi Sakamoto }
126f3699e2cSTakashi Sakamoto 
check_connection_used_by_others(struct snd_oxfw * oxfw,struct amdtp_stream * stream)127b0ac0009STakashi Sakamoto static int check_connection_used_by_others(struct snd_oxfw *oxfw,
128b0ac0009STakashi Sakamoto 					   struct amdtp_stream *stream)
129f3699e2cSTakashi Sakamoto {
130b0ac0009STakashi Sakamoto 	struct cmp_connection *conn;
131b0ac0009STakashi Sakamoto 	bool used;
132b0ac0009STakashi Sakamoto 	int err;
133b0ac0009STakashi Sakamoto 
134b0ac0009STakashi Sakamoto 	if (stream == &oxfw->tx_stream)
135b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
136b0ac0009STakashi Sakamoto 	else
137b0ac0009STakashi Sakamoto 		conn = &oxfw->in_conn;
138b0ac0009STakashi Sakamoto 
139b0ac0009STakashi Sakamoto 	err = cmp_connection_check_used(conn, &used);
140b0ac0009STakashi Sakamoto 	if ((err >= 0) && used && !amdtp_stream_running(stream)) {
141b0ac0009STakashi Sakamoto 		dev_err(&oxfw->unit->device,
142b0ac0009STakashi Sakamoto 			"Connection established by others: %cPCR[%d]\n",
143b0ac0009STakashi Sakamoto 			(conn->direction == CMP_OUTPUT) ? 'o' : 'i',
144b0ac0009STakashi Sakamoto 			conn->pcr_index);
145b0ac0009STakashi Sakamoto 		err = -EBUSY;
146b0ac0009STakashi Sakamoto 	}
147b0ac0009STakashi Sakamoto 
148b0ac0009STakashi Sakamoto 	return err;
149b0ac0009STakashi Sakamoto }
150b0ac0009STakashi Sakamoto 
init_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)151779f0dbaSTakashi Sakamoto static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
152b0ac0009STakashi Sakamoto {
153b0ac0009STakashi Sakamoto 	struct cmp_connection *conn;
154b0ac0009STakashi Sakamoto 	enum cmp_direction c_dir;
155b0ac0009STakashi Sakamoto 	enum amdtp_stream_direction s_dir;
15667bb66d3STakashi Sakamoto 	unsigned int flags = 0;
157b0ac0009STakashi Sakamoto 	int err;
158b0ac0009STakashi Sakamoto 
15907a35edcSTakashi Sakamoto 	if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION))
160029ffc42STakashi Sakamoto 		flags |= CIP_NONBLOCKING;
16107a35edcSTakashi Sakamoto 	else
162029ffc42STakashi Sakamoto 		flags |= CIP_BLOCKING;
16307a35edcSTakashi Sakamoto 
16467bb66d3STakashi Sakamoto 	// OXFW 970/971 has no function to generate playback timing according to the sequence
16567bb66d3STakashi Sakamoto 	// of value in syt field, thus the packet should include NO_INFO value in the field.
16667bb66d3STakashi Sakamoto 	// However, some models just ignore data blocks in packet with NO_INFO for audio data
16767bb66d3STakashi Sakamoto 	// processing.
16867bb66d3STakashi Sakamoto 	if (!(oxfw->quirks & SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET))
16967bb66d3STakashi Sakamoto 		flags |= CIP_UNAWARE_SYT;
17067bb66d3STakashi Sakamoto 
171b0ac0009STakashi Sakamoto 	if (stream == &oxfw->tx_stream) {
172b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
173b0ac0009STakashi Sakamoto 		c_dir = CMP_OUTPUT;
174b0ac0009STakashi Sakamoto 		s_dir = AMDTP_IN_STREAM;
175a092f000STakashi Sakamoto 
176a092f000STakashi Sakamoto 		if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD)
177a092f000STakashi Sakamoto 			flags |= CIP_JUMBO_PAYLOAD;
178a6f91693STakashi Sakamoto 		if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS)
179a092f000STakashi Sakamoto 			flags |= CIP_WRONG_DBS;
180b0ac0009STakashi Sakamoto 	} else {
181b0ac0009STakashi Sakamoto 		conn = &oxfw->in_conn;
182b0ac0009STakashi Sakamoto 		c_dir = CMP_INPUT;
183b0ac0009STakashi Sakamoto 		s_dir = AMDTP_OUT_STREAM;
184b0ac0009STakashi Sakamoto 	}
185b0ac0009STakashi Sakamoto 
186b0ac0009STakashi Sakamoto 	err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
187b0ac0009STakashi Sakamoto 	if (err < 0)
188779f0dbaSTakashi Sakamoto 		return err;
189b0ac0009STakashi Sakamoto 
190a092f000STakashi Sakamoto 	err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags);
191b0ac0009STakashi Sakamoto 	if (err < 0) {
192b0ac0009STakashi Sakamoto 		cmp_connection_destroy(conn);
193779f0dbaSTakashi Sakamoto 		return err;
194b0ac0009STakashi Sakamoto 	}
195b0ac0009STakashi Sakamoto 
196779f0dbaSTakashi Sakamoto 	return 0;
197b0ac0009STakashi Sakamoto }
198b0ac0009STakashi Sakamoto 
keep_resources(struct snd_oxfw * oxfw,struct amdtp_stream * stream)1990356ce3aSTakashi Sakamoto static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
2000356ce3aSTakashi Sakamoto {
2010356ce3aSTakashi Sakamoto 	enum avc_general_plug_dir dir;
2020356ce3aSTakashi Sakamoto 	u8 **formats;
2030356ce3aSTakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
2047bc93821STakashi Sakamoto 	struct cmp_connection *conn;
2050356ce3aSTakashi Sakamoto 	int i;
2060356ce3aSTakashi Sakamoto 	int err;
2070356ce3aSTakashi Sakamoto 
2080356ce3aSTakashi Sakamoto 	if (stream == &oxfw->rx_stream) {
2090356ce3aSTakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_IN;
2100356ce3aSTakashi Sakamoto 		formats = oxfw->rx_stream_formats;
2117bc93821STakashi Sakamoto 		conn = &oxfw->in_conn;
2120356ce3aSTakashi Sakamoto 	} else {
2130356ce3aSTakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_OUT;
2140356ce3aSTakashi Sakamoto 		formats = oxfw->tx_stream_formats;
2157bc93821STakashi Sakamoto 		conn = &oxfw->out_conn;
2160356ce3aSTakashi Sakamoto 	}
2170356ce3aSTakashi Sakamoto 
2180356ce3aSTakashi Sakamoto 	err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
2190356ce3aSTakashi Sakamoto 	if (err < 0)
2200356ce3aSTakashi Sakamoto 		return err;
2210356ce3aSTakashi Sakamoto 
2220356ce3aSTakashi Sakamoto 	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
2230356ce3aSTakashi Sakamoto 		struct snd_oxfw_stream_formation fmt;
2240356ce3aSTakashi Sakamoto 
2250356ce3aSTakashi Sakamoto 		if (formats[i] == NULL)
2260356ce3aSTakashi Sakamoto 			break;
2270356ce3aSTakashi Sakamoto 
2280356ce3aSTakashi Sakamoto 		err = snd_oxfw_stream_parse_format(formats[i], &fmt);
2290356ce3aSTakashi Sakamoto 		if (err < 0)
2300356ce3aSTakashi Sakamoto 			return err;
2310356ce3aSTakashi Sakamoto 
2320356ce3aSTakashi Sakamoto 		if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
2330356ce3aSTakashi Sakamoto 		    fmt.midi == formation.midi)
2340356ce3aSTakashi Sakamoto 			break;
2350356ce3aSTakashi Sakamoto 	}
2360356ce3aSTakashi Sakamoto 	if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
2370356ce3aSTakashi Sakamoto 		return -EINVAL;
2380356ce3aSTakashi Sakamoto 
2390356ce3aSTakashi Sakamoto 	// The stream should have one pcm channels at least.
2400356ce3aSTakashi Sakamoto 	if (formation.pcm == 0)
2410356ce3aSTakashi Sakamoto 		return -EINVAL;
2420356ce3aSTakashi Sakamoto 
2437bc93821STakashi Sakamoto 	err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
2440356ce3aSTakashi Sakamoto 					 formation.midi * 8, false);
2457bc93821STakashi Sakamoto 	if (err < 0)
2467bc93821STakashi Sakamoto 		return err;
2477bc93821STakashi Sakamoto 
2487bc93821STakashi Sakamoto 	return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
2490356ce3aSTakashi Sakamoto }
2500356ce3aSTakashi Sakamoto 
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)2514f380d00STakashi Sakamoto int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
252b0ac0009STakashi Sakamoto 				   struct amdtp_stream *stream,
2531d6a722cSTakashi Sakamoto 				   unsigned int rate, unsigned int pcm_channels,
2543299d2a0STakashi Sakamoto 				   unsigned int frames_per_period,
2553299d2a0STakashi Sakamoto 				   unsigned int frames_per_buffer)
256b0ac0009STakashi Sakamoto {
257f3699e2cSTakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
258b0ac0009STakashi Sakamoto 	enum avc_general_plug_dir dir;
2594f380d00STakashi Sakamoto 	int err;
260e2786ca6STakashi Sakamoto 
26120358d44STakashi Sakamoto 	// Considering JACK/FFADO streaming:
26220358d44STakashi Sakamoto 	// TODO: This can be removed hwdep functionality becomes popular.
26320358d44STakashi Sakamoto 	err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
26420358d44STakashi Sakamoto 	if (err < 0)
26520358d44STakashi Sakamoto 		return err;
26620358d44STakashi Sakamoto 	if (oxfw->has_output) {
26720358d44STakashi Sakamoto 		err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
26820358d44STakashi Sakamoto 		if (err < 0)
26920358d44STakashi Sakamoto 			return err;
270b0ac0009STakashi Sakamoto 	}
271b0ac0009STakashi Sakamoto 
27220358d44STakashi Sakamoto 	if (stream == &oxfw->tx_stream)
27320358d44STakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_OUT;
27420358d44STakashi Sakamoto 	else
27520358d44STakashi Sakamoto 		dir = AVC_GENERAL_PLUG_DIR_IN;
276b0ac0009STakashi Sakamoto 
277b0ac0009STakashi Sakamoto 	err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
278e2786ca6STakashi Sakamoto 	if (err < 0)
27920358d44STakashi Sakamoto 		return err;
2804f380d00STakashi Sakamoto 	if (rate == 0) {
28105588d34STakashi Sakamoto 		rate = formation.rate;
28205588d34STakashi Sakamoto 		pcm_channels = formation.pcm;
2834f380d00STakashi Sakamoto 	}
2844f380d00STakashi Sakamoto 	if (formation.rate != rate || formation.pcm != pcm_channels) {
285ac5d7786STakashi Sakamoto 		amdtp_domain_stop(&oxfw->domain);
286ac5d7786STakashi Sakamoto 
287e34244ddSTakashi Sakamoto 		cmp_connection_break(&oxfw->in_conn);
2883f2ce83dSTakashi Sakamoto 		cmp_connection_release(&oxfw->in_conn);
289e34244ddSTakashi Sakamoto 
290e34244ddSTakashi Sakamoto 		if (oxfw->has_output) {
291e34244ddSTakashi Sakamoto 			cmp_connection_break(&oxfw->out_conn);
2923f2ce83dSTakashi Sakamoto 			cmp_connection_release(&oxfw->out_conn);
293e34244ddSTakashi Sakamoto 		}
2944f380d00STakashi Sakamoto 	}
295f3699e2cSTakashi Sakamoto 
2964f380d00STakashi Sakamoto 	if (oxfw->substreams_count == 0 ||
2974f380d00STakashi Sakamoto 	    formation.rate != rate || formation.pcm != pcm_channels) {
298b0ac0009STakashi Sakamoto 		err = set_stream_format(oxfw, stream, rate, pcm_channels);
299f3699e2cSTakashi Sakamoto 		if (err < 0) {
300f3699e2cSTakashi Sakamoto 			dev_err(&oxfw->unit->device,
301f3699e2cSTakashi Sakamoto 				"fail to set stream format: %d\n", err);
30220358d44STakashi Sakamoto 			return err;
30320358d44STakashi Sakamoto 		}
3040356ce3aSTakashi Sakamoto 
3050356ce3aSTakashi Sakamoto 		err = keep_resources(oxfw, &oxfw->rx_stream);
3060356ce3aSTakashi Sakamoto 		if (err < 0)
3070356ce3aSTakashi Sakamoto 			return err;
3080356ce3aSTakashi Sakamoto 
3090356ce3aSTakashi Sakamoto 		if (oxfw->has_output) {
3100356ce3aSTakashi Sakamoto 			err = keep_resources(oxfw, &oxfw->tx_stream);
3117bc93821STakashi Sakamoto 			if (err < 0) {
3127bc93821STakashi Sakamoto 				cmp_connection_release(&oxfw->in_conn);
3130356ce3aSTakashi Sakamoto 				return err;
3140356ce3aSTakashi Sakamoto 			}
315f3699e2cSTakashi Sakamoto 		}
3161d6a722cSTakashi Sakamoto 
3171d6a722cSTakashi Sakamoto 		err = amdtp_domain_set_events_per_period(&oxfw->domain,
3183299d2a0STakashi Sakamoto 					frames_per_period, frames_per_buffer);
3191d6a722cSTakashi Sakamoto 		if (err < 0) {
3201d6a722cSTakashi Sakamoto 			cmp_connection_release(&oxfw->in_conn);
3211d6a722cSTakashi Sakamoto 			if (oxfw->has_output)
3221d6a722cSTakashi Sakamoto 				cmp_connection_release(&oxfw->out_conn);
3231d6a722cSTakashi Sakamoto 			return err;
3241d6a722cSTakashi Sakamoto 		}
3257bc93821STakashi Sakamoto 	}
326b0ac0009STakashi Sakamoto 
3274f380d00STakashi Sakamoto 	return 0;
3284f380d00STakashi Sakamoto }
3294f380d00STakashi Sakamoto 
snd_oxfw_stream_start_duplex(struct snd_oxfw * oxfw)3304f380d00STakashi Sakamoto int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
3314f380d00STakashi Sakamoto {
3324f380d00STakashi Sakamoto 	int err;
3334f380d00STakashi Sakamoto 
3344f380d00STakashi Sakamoto 	if (oxfw->substreams_count == 0)
3354f380d00STakashi Sakamoto 		return -EIO;
3364f380d00STakashi Sakamoto 
3374f380d00STakashi Sakamoto 	if (amdtp_streaming_error(&oxfw->rx_stream) ||
3384f380d00STakashi Sakamoto 	    amdtp_streaming_error(&oxfw->tx_stream)) {
339ac5d7786STakashi Sakamoto 		amdtp_domain_stop(&oxfw->domain);
3404f380d00STakashi Sakamoto 
341ac5d7786STakashi Sakamoto 		cmp_connection_break(&oxfw->in_conn);
342ac5d7786STakashi Sakamoto 		if (oxfw->has_output)
3434f380d00STakashi Sakamoto 			cmp_connection_break(&oxfw->out_conn);
3444f380d00STakashi Sakamoto 	}
3454f380d00STakashi Sakamoto 
34620358d44STakashi Sakamoto 	if (!amdtp_stream_running(&oxfw->rx_stream)) {
347029ffc42STakashi Sakamoto 		unsigned int tx_init_skip_cycles = 0;
348029ffc42STakashi Sakamoto 		bool replay_seq = false;
349029ffc42STakashi Sakamoto 
35020358d44STakashi Sakamoto 		err = start_stream(oxfw, &oxfw->rx_stream);
351b0ac0009STakashi Sakamoto 		if (err < 0) {
352b0ac0009STakashi Sakamoto 			dev_err(&oxfw->unit->device,
353ac5d7786STakashi Sakamoto 				"fail to prepare rx stream: %d\n", err);
354ac5d7786STakashi Sakamoto 			goto error;
355ac5d7786STakashi Sakamoto 		}
356ac5d7786STakashi Sakamoto 
357ac5d7786STakashi Sakamoto 		if (oxfw->has_output &&
358ac5d7786STakashi Sakamoto 		    !amdtp_stream_running(&oxfw->tx_stream)) {
359ac5d7786STakashi Sakamoto 			err = start_stream(oxfw, &oxfw->tx_stream);
360ac5d7786STakashi Sakamoto 			if (err < 0) {
361ac5d7786STakashi Sakamoto 				dev_err(&oxfw->unit->device,
362ac5d7786STakashi Sakamoto 					"fail to prepare tx stream: %d\n", err);
36320358d44STakashi Sakamoto 				goto error;
36420358d44STakashi Sakamoto 			}
365029ffc42STakashi Sakamoto 
366029ffc42STakashi Sakamoto 			if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) {
367029ffc42STakashi Sakamoto 				// Just after changing sampling transfer frequency, many cycles are
368029ffc42STakashi Sakamoto 				// skipped for packet transmission.
369029ffc42STakashi Sakamoto 				tx_init_skip_cycles = 400;
370*a4ce4337STakashi Sakamoto 			} else if (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) {
371*a4ce4337STakashi Sakamoto 				// It takes a bit time for target device to adjust event frequency
372*a4ce4337STakashi Sakamoto 				// according to nominal event frequency in isochronous packets from
373*a4ce4337STakashi Sakamoto 				// ALSA oxfw driver.
374*a4ce4337STakashi Sakamoto 				tx_init_skip_cycles = 4000;
375029ffc42STakashi Sakamoto 			} else {
376029ffc42STakashi Sakamoto 				replay_seq = true;
377029ffc42STakashi Sakamoto 			}
37820358d44STakashi Sakamoto 		}
37920358d44STakashi Sakamoto 
380029ffc42STakashi Sakamoto 		// NOTE: The device ignores presentation time expressed by the value of syt field
381029ffc42STakashi Sakamoto 		// of CIP header in received packets. The sequence of the number of data blocks per
382029ffc42STakashi Sakamoto 		// packet is important for media clock recovery.
383029ffc42STakashi Sakamoto 		err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false);
384ac5d7786STakashi Sakamoto 		if (err < 0)
385ac5d7786STakashi Sakamoto 			goto error;
386ac5d7786STakashi Sakamoto 
387bdaedca7STakashi Sakamoto 		if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
388ac5d7786STakashi Sakamoto 			err = -ETIMEDOUT;
38920358d44STakashi Sakamoto 			goto error;
390b0ac0009STakashi Sakamoto 		}
391f3699e2cSTakashi Sakamoto 	}
392f3699e2cSTakashi Sakamoto 
39320358d44STakashi Sakamoto 	return 0;
39420358d44STakashi Sakamoto error:
395ac5d7786STakashi Sakamoto 	amdtp_domain_stop(&oxfw->domain);
396ac5d7786STakashi Sakamoto 
39720358d44STakashi Sakamoto 	cmp_connection_break(&oxfw->in_conn);
398ac5d7786STakashi Sakamoto 	if (oxfw->has_output)
39920358d44STakashi Sakamoto 		cmp_connection_break(&oxfw->out_conn);
400ac5d7786STakashi Sakamoto 
401e2786ca6STakashi Sakamoto 	return err;
402e2786ca6STakashi Sakamoto }
403e2786ca6STakashi Sakamoto 
snd_oxfw_stream_stop_duplex(struct snd_oxfw * oxfw)404779f0dbaSTakashi Sakamoto void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
405e2786ca6STakashi Sakamoto {
4064a0a0472STakashi Sakamoto 	if (oxfw->substreams_count == 0) {
407ac5d7786STakashi Sakamoto 		amdtp_domain_stop(&oxfw->domain);
408ac5d7786STakashi Sakamoto 
409e34244ddSTakashi Sakamoto 		cmp_connection_break(&oxfw->in_conn);
4107bc93821STakashi Sakamoto 		cmp_connection_release(&oxfw->in_conn);
411b0ac0009STakashi Sakamoto 
412e34244ddSTakashi Sakamoto 		if (oxfw->has_output) {
413e34244ddSTakashi Sakamoto 			cmp_connection_break(&oxfw->out_conn);
4147bc93821STakashi Sakamoto 			cmp_connection_release(&oxfw->out_conn);
415e34244ddSTakashi Sakamoto 		}
41620358d44STakashi Sakamoto 	}
417e2786ca6STakashi Sakamoto }
418e2786ca6STakashi Sakamoto 
destroy_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)419779f0dbaSTakashi Sakamoto static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
420e2786ca6STakashi Sakamoto {
421b0ac0009STakashi Sakamoto 	struct cmp_connection *conn;
422e2786ca6STakashi Sakamoto 
423b0ac0009STakashi Sakamoto 	if (stream == &oxfw->tx_stream)
424b0ac0009STakashi Sakamoto 		conn = &oxfw->out_conn;
425e2786ca6STakashi Sakamoto 	else
426b0ac0009STakashi Sakamoto 		conn = &oxfw->in_conn;
427b0ac0009STakashi Sakamoto 
428b0ac0009STakashi Sakamoto 	amdtp_stream_destroy(stream);
429b0ac0009STakashi Sakamoto 	cmp_connection_destroy(conn);
430b0ac0009STakashi Sakamoto }
431b0ac0009STakashi Sakamoto 
snd_oxfw_stream_init_duplex(struct snd_oxfw * oxfw)432779f0dbaSTakashi Sakamoto int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
433779f0dbaSTakashi Sakamoto {
434779f0dbaSTakashi Sakamoto 	int err;
435779f0dbaSTakashi Sakamoto 
436779f0dbaSTakashi Sakamoto 	err = init_stream(oxfw, &oxfw->rx_stream);
437779f0dbaSTakashi Sakamoto 	if (err < 0)
438779f0dbaSTakashi Sakamoto 		return err;
439779f0dbaSTakashi Sakamoto 
440779f0dbaSTakashi Sakamoto 	if (oxfw->has_output) {
441779f0dbaSTakashi Sakamoto 		err = init_stream(oxfw, &oxfw->tx_stream);
442779f0dbaSTakashi Sakamoto 		if (err < 0) {
443779f0dbaSTakashi Sakamoto 			destroy_stream(oxfw, &oxfw->rx_stream);
444779f0dbaSTakashi Sakamoto 			return err;
445779f0dbaSTakashi Sakamoto 		}
446779f0dbaSTakashi Sakamoto 	}
447779f0dbaSTakashi Sakamoto 
448ac5d7786STakashi Sakamoto 	err = amdtp_domain_init(&oxfw->domain);
449ac5d7786STakashi Sakamoto 	if (err < 0) {
450ac5d7786STakashi Sakamoto 		destroy_stream(oxfw, &oxfw->rx_stream);
451ac5d7786STakashi Sakamoto 		if (oxfw->has_output)
452ac5d7786STakashi Sakamoto 			destroy_stream(oxfw, &oxfw->tx_stream);
453ac5d7786STakashi Sakamoto 	}
454ac5d7786STakashi Sakamoto 
455ac5d7786STakashi Sakamoto 	return err;
456779f0dbaSTakashi Sakamoto }
457779f0dbaSTakashi Sakamoto 
458779f0dbaSTakashi Sakamoto // This function should be called before starting the stream or after stopping
459779f0dbaSTakashi Sakamoto // the streams.
snd_oxfw_stream_destroy_duplex(struct snd_oxfw * oxfw)460779f0dbaSTakashi Sakamoto void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
461779f0dbaSTakashi Sakamoto {
462ac5d7786STakashi Sakamoto 	amdtp_domain_destroy(&oxfw->domain);
463ac5d7786STakashi Sakamoto 
464779f0dbaSTakashi Sakamoto 	destroy_stream(oxfw, &oxfw->rx_stream);
465779f0dbaSTakashi Sakamoto 
466779f0dbaSTakashi Sakamoto 	if (oxfw->has_output)
467779f0dbaSTakashi Sakamoto 		destroy_stream(oxfw, &oxfw->tx_stream);
468779f0dbaSTakashi Sakamoto }
469779f0dbaSTakashi Sakamoto 
snd_oxfw_stream_update_duplex(struct snd_oxfw * oxfw)470779f0dbaSTakashi Sakamoto void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
471b0ac0009STakashi Sakamoto {
472ac5d7786STakashi Sakamoto 	amdtp_domain_stop(&oxfw->domain);
473ac5d7786STakashi Sakamoto 
474e34244ddSTakashi Sakamoto 	cmp_connection_break(&oxfw->in_conn);
475b0ac0009STakashi Sakamoto 
476e34244ddSTakashi Sakamoto 	amdtp_stream_pcm_abort(&oxfw->rx_stream);
477e34244ddSTakashi Sakamoto 
478e34244ddSTakashi Sakamoto 	if (oxfw->has_output) {
479e34244ddSTakashi Sakamoto 		cmp_connection_break(&oxfw->out_conn);
480e34244ddSTakashi Sakamoto 
481e34244ddSTakashi Sakamoto 		amdtp_stream_pcm_abort(&oxfw->tx_stream);
482e34244ddSTakashi Sakamoto 	}
483e2786ca6STakashi Sakamoto }
4845cd1d3f4STakashi Sakamoto 
snd_oxfw_stream_get_current_formation(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,struct snd_oxfw_stream_formation * formation)4853c96101fSTakashi Sakamoto int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
4863c96101fSTakashi Sakamoto 				enum avc_general_plug_dir dir,
4873c96101fSTakashi Sakamoto 				struct snd_oxfw_stream_formation *formation)
4883c96101fSTakashi Sakamoto {
4893c96101fSTakashi Sakamoto 	u8 *format;
4903c96101fSTakashi Sakamoto 	unsigned int len;
4913c96101fSTakashi Sakamoto 	int err;
4923c96101fSTakashi Sakamoto 
4933c96101fSTakashi Sakamoto 	len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
4943c96101fSTakashi Sakamoto 	format = kmalloc(len, GFP_KERNEL);
4953c96101fSTakashi Sakamoto 	if (format == NULL)
4963c96101fSTakashi Sakamoto 		return -ENOMEM;
4973c96101fSTakashi Sakamoto 
4983c96101fSTakashi Sakamoto 	err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
4993c96101fSTakashi Sakamoto 	if (err < 0)
5003c96101fSTakashi Sakamoto 		goto end;
5013c96101fSTakashi Sakamoto 	if (len < 3) {
5023c96101fSTakashi Sakamoto 		err = -EIO;
5033c96101fSTakashi Sakamoto 		goto end;
5043c96101fSTakashi Sakamoto 	}
5053c96101fSTakashi Sakamoto 
5063c96101fSTakashi Sakamoto 	err = snd_oxfw_stream_parse_format(format, formation);
5073c96101fSTakashi Sakamoto end:
5083c96101fSTakashi Sakamoto 	kfree(format);
5093c96101fSTakashi Sakamoto 	return err;
5103c96101fSTakashi Sakamoto }
5113c96101fSTakashi Sakamoto 
5125cd1d3f4STakashi Sakamoto /*
5135cd1d3f4STakashi Sakamoto  * See Table 6.16 - AM824 Stream Format
5145cd1d3f4STakashi Sakamoto  *     Figure 6.19 - format_information field for AM824 Compound
5155cd1d3f4STakashi Sakamoto  * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
5165cd1d3f4STakashi Sakamoto  * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
5175cd1d3f4STakashi Sakamoto  */
snd_oxfw_stream_parse_format(u8 * format,struct snd_oxfw_stream_formation * formation)5185cd1d3f4STakashi Sakamoto int snd_oxfw_stream_parse_format(u8 *format,
5195cd1d3f4STakashi Sakamoto 				 struct snd_oxfw_stream_formation *formation)
5205cd1d3f4STakashi Sakamoto {
5215cd1d3f4STakashi Sakamoto 	unsigned int i, e, channels, type;
5225cd1d3f4STakashi Sakamoto 
5235cd1d3f4STakashi Sakamoto 	memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
5245cd1d3f4STakashi Sakamoto 
5255cd1d3f4STakashi Sakamoto 	/*
5265cd1d3f4STakashi Sakamoto 	 * this module can support a hierarchy combination that:
5275cd1d3f4STakashi Sakamoto 	 *  Root:	Audio and Music (0x90)
5285cd1d3f4STakashi Sakamoto 	 *  Level 1:	AM824 Compound  (0x40)
5295cd1d3f4STakashi Sakamoto 	 */
5305cd1d3f4STakashi Sakamoto 	if ((format[0] != 0x90) || (format[1] != 0x40))
53103be63b2STakashi Sakamoto 		return -ENXIO;
5325cd1d3f4STakashi Sakamoto 
5335cd1d3f4STakashi Sakamoto 	/* check the sampling rate */
5345cd1d3f4STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
5355cd1d3f4STakashi Sakamoto 		if (format[2] == avc_stream_rate_table[i])
5365cd1d3f4STakashi Sakamoto 			break;
5375cd1d3f4STakashi Sakamoto 	}
5385cd1d3f4STakashi Sakamoto 	if (i == ARRAY_SIZE(avc_stream_rate_table))
53903be63b2STakashi Sakamoto 		return -ENXIO;
5405cd1d3f4STakashi Sakamoto 
5415cd1d3f4STakashi Sakamoto 	formation->rate = oxfw_rate_table[i];
5425cd1d3f4STakashi Sakamoto 
5435cd1d3f4STakashi Sakamoto 	for (e = 0; e < format[4]; e++) {
5445cd1d3f4STakashi Sakamoto 		channels = format[5 + e * 2];
5455cd1d3f4STakashi Sakamoto 		type = format[6 + e * 2];
5465cd1d3f4STakashi Sakamoto 
5475cd1d3f4STakashi Sakamoto 		switch (type) {
5485cd1d3f4STakashi Sakamoto 		/* IEC 60958 Conformant, currently handled as MBLA */
5495cd1d3f4STakashi Sakamoto 		case 0x00:
5505cd1d3f4STakashi Sakamoto 		/* Multi Bit Linear Audio (Raw) */
5515cd1d3f4STakashi Sakamoto 		case 0x06:
5525cd1d3f4STakashi Sakamoto 			formation->pcm += channels;
5535cd1d3f4STakashi Sakamoto 			break;
5545cd1d3f4STakashi Sakamoto 		/* MIDI Conformant */
5555cd1d3f4STakashi Sakamoto 		case 0x0d:
5565cd1d3f4STakashi Sakamoto 			formation->midi = channels;
5575cd1d3f4STakashi Sakamoto 			break;
5585cd1d3f4STakashi Sakamoto 		/* IEC 61937-3 to 7 */
5595cd1d3f4STakashi Sakamoto 		case 0x01:
5605cd1d3f4STakashi Sakamoto 		case 0x02:
5615cd1d3f4STakashi Sakamoto 		case 0x03:
5625cd1d3f4STakashi Sakamoto 		case 0x04:
5635cd1d3f4STakashi Sakamoto 		case 0x05:
5645cd1d3f4STakashi Sakamoto 		/* Multi Bit Linear Audio */
5655cd1d3f4STakashi Sakamoto 		case 0x07:	/* DVD-Audio */
5665cd1d3f4STakashi Sakamoto 		case 0x0c:	/* High Precision */
5675cd1d3f4STakashi Sakamoto 		/* One Bit Audio */
5685cd1d3f4STakashi Sakamoto 		case 0x08:	/* (Plain) Raw */
5695cd1d3f4STakashi Sakamoto 		case 0x09:	/* (Plain) SACD */
5705cd1d3f4STakashi Sakamoto 		case 0x0a:	/* (Encoded) Raw */
5715cd1d3f4STakashi Sakamoto 		case 0x0b:	/* (Encoded) SACD */
5725cd1d3f4STakashi Sakamoto 		/* SMPTE Time-Code conformant */
5735cd1d3f4STakashi Sakamoto 		case 0x0e:
5745cd1d3f4STakashi Sakamoto 		/* Sample Count */
5755cd1d3f4STakashi Sakamoto 		case 0x0f:
5765cd1d3f4STakashi Sakamoto 		/* Anciliary Data */
5775cd1d3f4STakashi Sakamoto 		case 0x10:
5785cd1d3f4STakashi Sakamoto 		/* Synchronization Stream (Stereo Raw audio) */
5795cd1d3f4STakashi Sakamoto 		case 0x40:
5805cd1d3f4STakashi Sakamoto 		/* Don't care */
5815cd1d3f4STakashi Sakamoto 		case 0xff:
5825cd1d3f4STakashi Sakamoto 		default:
58303be63b2STakashi Sakamoto 			return -ENXIO;	/* not supported */
5845cd1d3f4STakashi Sakamoto 		}
5855cd1d3f4STakashi Sakamoto 	}
5865cd1d3f4STakashi Sakamoto 
58749c7b3fcSTakashi Sakamoto 	if (formation->pcm  > AM824_MAX_CHANNELS_FOR_PCM ||
58849c7b3fcSTakashi Sakamoto 	    formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
58903be63b2STakashi Sakamoto 		return -ENXIO;
5905cd1d3f4STakashi Sakamoto 
5915cd1d3f4STakashi Sakamoto 	return 0;
5925cd1d3f4STakashi Sakamoto }
5935cd1d3f4STakashi Sakamoto 
5945cd1d3f4STakashi Sakamoto 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)5955cd1d3f4STakashi Sakamoto assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
5965cd1d3f4STakashi Sakamoto 		      unsigned int pid, u8 *buf, unsigned int *len,
5975cd1d3f4STakashi Sakamoto 		      u8 **formats)
5985cd1d3f4STakashi Sakamoto {
5995cd1d3f4STakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
6005cd1d3f4STakashi Sakamoto 	unsigned int i, eid;
6015cd1d3f4STakashi Sakamoto 	int err;
6025cd1d3f4STakashi Sakamoto 
6035cd1d3f4STakashi Sakamoto 	/* get format at current sampling rate */
6045cd1d3f4STakashi Sakamoto 	err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
6055cd1d3f4STakashi Sakamoto 	if (err < 0) {
6065cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
6075cd1d3f4STakashi Sakamoto 		"fail to get current stream format for isoc %s plug %d:%d\n",
6085cd1d3f4STakashi Sakamoto 			(dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
6095cd1d3f4STakashi Sakamoto 			pid, err);
6105cd1d3f4STakashi Sakamoto 		goto end;
6115cd1d3f4STakashi Sakamoto 	}
6125cd1d3f4STakashi Sakamoto 
6135cd1d3f4STakashi Sakamoto 	/* parse and set stream format */
6145cd1d3f4STakashi Sakamoto 	eid = 0;
6155cd1d3f4STakashi Sakamoto 	err = snd_oxfw_stream_parse_format(buf, &formation);
6165cd1d3f4STakashi Sakamoto 	if (err < 0)
6175cd1d3f4STakashi Sakamoto 		goto end;
6185cd1d3f4STakashi Sakamoto 
619cd3b7116STakashi Sakamoto 	formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
620cd3b7116STakashi Sakamoto 				    GFP_KERNEL);
621cd3b7116STakashi Sakamoto 	if (!formats[eid]) {
6225cd1d3f4STakashi Sakamoto 		err = -ENOMEM;
6235cd1d3f4STakashi Sakamoto 		goto end;
6245cd1d3f4STakashi Sakamoto 	}
6255cd1d3f4STakashi Sakamoto 
6265cd1d3f4STakashi Sakamoto 	/* apply the format for each available sampling rate */
6275cd1d3f4STakashi Sakamoto 	for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
6285cd1d3f4STakashi Sakamoto 		if (formation.rate == oxfw_rate_table[i])
6295cd1d3f4STakashi Sakamoto 			continue;
6305cd1d3f4STakashi Sakamoto 
6315cd1d3f4STakashi Sakamoto 		err = avc_general_inquiry_sig_fmt(oxfw->unit,
6325cd1d3f4STakashi Sakamoto 						  oxfw_rate_table[i],
6335cd1d3f4STakashi Sakamoto 						  dir, pid);
6345cd1d3f4STakashi Sakamoto 		if (err < 0)
6355cd1d3f4STakashi Sakamoto 			continue;
6365cd1d3f4STakashi Sakamoto 
6375cd1d3f4STakashi Sakamoto 		eid++;
638cd3b7116STakashi Sakamoto 		formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
639cd3b7116STakashi Sakamoto 					    GFP_KERNEL);
6405cd1d3f4STakashi Sakamoto 		if (formats[eid] == NULL) {
6415cd1d3f4STakashi Sakamoto 			err = -ENOMEM;
6425cd1d3f4STakashi Sakamoto 			goto end;
6435cd1d3f4STakashi Sakamoto 		}
6445cd1d3f4STakashi Sakamoto 		formats[eid][2] = avc_stream_rate_table[i];
6455cd1d3f4STakashi Sakamoto 	}
6465cd1d3f4STakashi Sakamoto 
6475cd1d3f4STakashi Sakamoto 	err = 0;
6485cd1d3f4STakashi Sakamoto 	oxfw->assumed = true;
6495cd1d3f4STakashi Sakamoto end:
6505cd1d3f4STakashi Sakamoto 	return err;
6515cd1d3f4STakashi Sakamoto }
6525cd1d3f4STakashi Sakamoto 
fill_stream_formats(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,unsigned short pid)6535cd1d3f4STakashi Sakamoto static int fill_stream_formats(struct snd_oxfw *oxfw,
6545cd1d3f4STakashi Sakamoto 			       enum avc_general_plug_dir dir,
6555cd1d3f4STakashi Sakamoto 			       unsigned short pid)
6565cd1d3f4STakashi Sakamoto {
6575cd1d3f4STakashi Sakamoto 	u8 *buf, **formats;
6585cd1d3f4STakashi Sakamoto 	unsigned int len, eid = 0;
6595cd1d3f4STakashi Sakamoto 	struct snd_oxfw_stream_formation dummy;
6605cd1d3f4STakashi Sakamoto 	int err;
6615cd1d3f4STakashi Sakamoto 
6625cd1d3f4STakashi Sakamoto 	buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
6635cd1d3f4STakashi Sakamoto 	if (buf == NULL)
6645cd1d3f4STakashi Sakamoto 		return -ENOMEM;
6655cd1d3f4STakashi Sakamoto 
666b0ac0009STakashi Sakamoto 	if (dir == AVC_GENERAL_PLUG_DIR_OUT)
667b0ac0009STakashi Sakamoto 		formats = oxfw->tx_stream_formats;
668b0ac0009STakashi Sakamoto 	else
6695cd1d3f4STakashi Sakamoto 		formats = oxfw->rx_stream_formats;
6705cd1d3f4STakashi Sakamoto 
6715cd1d3f4STakashi Sakamoto 	/* get first entry */
6725cd1d3f4STakashi Sakamoto 	len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
6735cd1d3f4STakashi Sakamoto 	err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
67403be63b2STakashi Sakamoto 	if (err == -ENXIO) {
6755cd1d3f4STakashi Sakamoto 		/* LIST subfunction is not implemented */
6765cd1d3f4STakashi Sakamoto 		len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
6775cd1d3f4STakashi Sakamoto 		err = assume_stream_formats(oxfw, dir, pid, buf, &len,
6785cd1d3f4STakashi Sakamoto 					    formats);
6795cd1d3f4STakashi Sakamoto 		goto end;
6805cd1d3f4STakashi Sakamoto 	} else if (err < 0) {
6815cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
6825cd1d3f4STakashi Sakamoto 			"fail to get stream format %d for isoc %s plug %d:%d\n",
6835cd1d3f4STakashi Sakamoto 			eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
6845cd1d3f4STakashi Sakamoto 			pid, err);
6855cd1d3f4STakashi Sakamoto 		goto end;
6865cd1d3f4STakashi Sakamoto 	}
6875cd1d3f4STakashi Sakamoto 
6885cd1d3f4STakashi Sakamoto 	/* LIST subfunction is implemented */
6895cd1d3f4STakashi Sakamoto 	while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
6905cd1d3f4STakashi Sakamoto 		/* The format is too short. */
6915cd1d3f4STakashi Sakamoto 		if (len < 3) {
6925cd1d3f4STakashi Sakamoto 			err = -EIO;
6935cd1d3f4STakashi Sakamoto 			break;
6945cd1d3f4STakashi Sakamoto 		}
6955cd1d3f4STakashi Sakamoto 
6965cd1d3f4STakashi Sakamoto 		/* parse and set stream format */
6975cd1d3f4STakashi Sakamoto 		err = snd_oxfw_stream_parse_format(buf, &dummy);
6985cd1d3f4STakashi Sakamoto 		if (err < 0)
6995cd1d3f4STakashi Sakamoto 			break;
7005cd1d3f4STakashi Sakamoto 
701cd3b7116STakashi Sakamoto 		formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
702cd3b7116STakashi Sakamoto 					    GFP_KERNEL);
703cd3b7116STakashi Sakamoto 		if (!formats[eid]) {
7045cd1d3f4STakashi Sakamoto 			err = -ENOMEM;
7055cd1d3f4STakashi Sakamoto 			break;
7065cd1d3f4STakashi Sakamoto 		}
7075cd1d3f4STakashi Sakamoto 
7085cd1d3f4STakashi Sakamoto 		/* get next entry */
7095cd1d3f4STakashi Sakamoto 		len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
7105cd1d3f4STakashi Sakamoto 		err = avc_stream_get_format_list(oxfw->unit, dir, 0,
7115cd1d3f4STakashi Sakamoto 						 buf, &len, ++eid);
7125cd1d3f4STakashi Sakamoto 		/* No entries remained. */
7135cd1d3f4STakashi Sakamoto 		if (err == -EINVAL) {
7145cd1d3f4STakashi Sakamoto 			err = 0;
7155cd1d3f4STakashi Sakamoto 			break;
7165cd1d3f4STakashi Sakamoto 		} else if (err < 0) {
7175cd1d3f4STakashi Sakamoto 			dev_err(&oxfw->unit->device,
7185cd1d3f4STakashi Sakamoto 			"fail to get stream format %d for isoc %s plug %d:%d\n",
7195cd1d3f4STakashi Sakamoto 				eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
7205cd1d3f4STakashi Sakamoto 									"out",
7215cd1d3f4STakashi Sakamoto 				pid, err);
7225cd1d3f4STakashi Sakamoto 			break;
7235cd1d3f4STakashi Sakamoto 		}
7245cd1d3f4STakashi Sakamoto 	}
7255cd1d3f4STakashi Sakamoto end:
7265cd1d3f4STakashi Sakamoto 	kfree(buf);
7275cd1d3f4STakashi Sakamoto 	return err;
7285cd1d3f4STakashi Sakamoto }
7295cd1d3f4STakashi Sakamoto 
snd_oxfw_stream_discover(struct snd_oxfw * oxfw)7305cd1d3f4STakashi Sakamoto int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
7315cd1d3f4STakashi Sakamoto {
7325cd1d3f4STakashi Sakamoto 	u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
73332056041STakashi Sakamoto 	struct snd_oxfw_stream_formation formation;
73432056041STakashi Sakamoto 	u8 *format;
73532056041STakashi Sakamoto 	unsigned int i;
7365cd1d3f4STakashi Sakamoto 	int err;
7375cd1d3f4STakashi Sakamoto 
7385cd1d3f4STakashi Sakamoto 	/* the number of plugs for isoc in/out, ext in/out  */
7395cd1d3f4STakashi Sakamoto 	err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
7405cd1d3f4STakashi Sakamoto 	if (err < 0) {
7415cd1d3f4STakashi Sakamoto 		dev_err(&oxfw->unit->device,
7425cd1d3f4STakashi Sakamoto 		"fail to get info for isoc/external in/out plugs: %d\n",
7435cd1d3f4STakashi Sakamoto 			err);
7445cd1d3f4STakashi Sakamoto 		goto end;
745b0ac0009STakashi Sakamoto 	} else if ((plugs[0] == 0) && (plugs[1] == 0)) {
74603be63b2STakashi Sakamoto 		err = -ENXIO;
7475cd1d3f4STakashi Sakamoto 		goto end;
7485cd1d3f4STakashi Sakamoto 	}
7495cd1d3f4STakashi Sakamoto 
750b0ac0009STakashi Sakamoto 	/* use oPCR[0] if exists */
751b0ac0009STakashi Sakamoto 	if (plugs[1] > 0) {
752b0ac0009STakashi Sakamoto 		err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
75341dbc792STakashi Sakamoto 		if (err < 0) {
75441dbc792STakashi Sakamoto 			if (err != -ENXIO)
75541dbc792STakashi Sakamoto 				return err;
75632056041STakashi Sakamoto 
75741dbc792STakashi Sakamoto 			// The oPCR is not available for isoc communication.
75841dbc792STakashi Sakamoto 			err = 0;
75941dbc792STakashi Sakamoto 		} else {
76032056041STakashi Sakamoto 			for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
76132056041STakashi Sakamoto 				format = oxfw->tx_stream_formats[i];
76232056041STakashi Sakamoto 				if (format == NULL)
76332056041STakashi Sakamoto 					continue;
76441dbc792STakashi Sakamoto 				err = snd_oxfw_stream_parse_format(format,
76541dbc792STakashi Sakamoto 								   &formation);
76632056041STakashi Sakamoto 				if (err < 0)
76732056041STakashi Sakamoto 					continue;
76832056041STakashi Sakamoto 
76932056041STakashi Sakamoto 				/* Add one MIDI port. */
77032056041STakashi Sakamoto 				if (formation.midi > 0)
77132056041STakashi Sakamoto 					oxfw->midi_input_ports = 1;
77232056041STakashi Sakamoto 			}
77332056041STakashi Sakamoto 
774b0ac0009STakashi Sakamoto 			oxfw->has_output = true;
775b0ac0009STakashi Sakamoto 		}
77641dbc792STakashi Sakamoto 	}
777b0ac0009STakashi Sakamoto 
7785cd1d3f4STakashi Sakamoto 	/* use iPCR[0] if exists */
77932056041STakashi Sakamoto 	if (plugs[0] > 0) {
7805cd1d3f4STakashi Sakamoto 		err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
78141dbc792STakashi Sakamoto 		if (err < 0) {
78241dbc792STakashi Sakamoto 			if (err != -ENXIO)
78341dbc792STakashi Sakamoto 				return err;
78432056041STakashi Sakamoto 
78541dbc792STakashi Sakamoto 			// The iPCR is not available for isoc communication.
78641dbc792STakashi Sakamoto 			err = 0;
78741dbc792STakashi Sakamoto 		} else {
78832056041STakashi Sakamoto 			for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
78932056041STakashi Sakamoto 				format = oxfw->rx_stream_formats[i];
79032056041STakashi Sakamoto 				if (format == NULL)
79132056041STakashi Sakamoto 					continue;
79241dbc792STakashi Sakamoto 				err = snd_oxfw_stream_parse_format(format,
79341dbc792STakashi Sakamoto 								   &formation);
79432056041STakashi Sakamoto 				if (err < 0)
79532056041STakashi Sakamoto 					continue;
79632056041STakashi Sakamoto 
79732056041STakashi Sakamoto 				/* Add one MIDI port. */
79832056041STakashi Sakamoto 				if (formation.midi > 0)
79932056041STakashi Sakamoto 					oxfw->midi_output_ports = 1;
80032056041STakashi Sakamoto 			}
80106a42a74STakashi Sakamoto 
80206a42a74STakashi Sakamoto 			oxfw->has_input = true;
80332056041STakashi Sakamoto 		}
80441dbc792STakashi Sakamoto 	}
8055cd1d3f4STakashi Sakamoto end:
8065cd1d3f4STakashi Sakamoto 	return err;
8075cd1d3f4STakashi Sakamoto }
8088985f4acSTakashi Sakamoto 
snd_oxfw_stream_lock_changed(struct snd_oxfw * oxfw)8098985f4acSTakashi Sakamoto void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
8108985f4acSTakashi Sakamoto {
8118985f4acSTakashi Sakamoto 	oxfw->dev_lock_changed = true;
8128985f4acSTakashi Sakamoto 	wake_up(&oxfw->hwdep_wait);
8138985f4acSTakashi Sakamoto }
8148985f4acSTakashi Sakamoto 
snd_oxfw_stream_lock_try(struct snd_oxfw * oxfw)8158985f4acSTakashi Sakamoto int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
8168985f4acSTakashi Sakamoto {
8178985f4acSTakashi Sakamoto 	int err;
8188985f4acSTakashi Sakamoto 
8198985f4acSTakashi Sakamoto 	spin_lock_irq(&oxfw->lock);
8208985f4acSTakashi Sakamoto 
8218985f4acSTakashi Sakamoto 	/* user land lock this */
8228985f4acSTakashi Sakamoto 	if (oxfw->dev_lock_count < 0) {
8238985f4acSTakashi Sakamoto 		err = -EBUSY;
8248985f4acSTakashi Sakamoto 		goto end;
8258985f4acSTakashi Sakamoto 	}
8268985f4acSTakashi Sakamoto 
8278985f4acSTakashi Sakamoto 	/* this is the first time */
8288985f4acSTakashi Sakamoto 	if (oxfw->dev_lock_count++ == 0)
8298985f4acSTakashi Sakamoto 		snd_oxfw_stream_lock_changed(oxfw);
8308985f4acSTakashi Sakamoto 	err = 0;
8318985f4acSTakashi Sakamoto end:
8328985f4acSTakashi Sakamoto 	spin_unlock_irq(&oxfw->lock);
8338985f4acSTakashi Sakamoto 	return err;
8348985f4acSTakashi Sakamoto }
8358985f4acSTakashi Sakamoto 
snd_oxfw_stream_lock_release(struct snd_oxfw * oxfw)8368985f4acSTakashi Sakamoto void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
8378985f4acSTakashi Sakamoto {
8388985f4acSTakashi Sakamoto 	spin_lock_irq(&oxfw->lock);
8398985f4acSTakashi Sakamoto 
8408985f4acSTakashi Sakamoto 	if (WARN_ON(oxfw->dev_lock_count <= 0))
8418985f4acSTakashi Sakamoto 		goto end;
8428985f4acSTakashi Sakamoto 	if (--oxfw->dev_lock_count == 0)
8438985f4acSTakashi Sakamoto 		snd_oxfw_stream_lock_changed(oxfw);
8448985f4acSTakashi Sakamoto end:
8458985f4acSTakashi Sakamoto 	spin_unlock_irq(&oxfw->lock);
8468985f4acSTakashi Sakamoto }
847