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
12cddcd547STakashi 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;
180*52592932STakashi Sakamoto if (oxfw->quirks & SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS)
181*52592932STakashi Sakamoto flags |= CIP_DBC_IS_END_EVENT | CIP_DBC_IS_PAYLOAD_QUADLETS;
182b0ac0009STakashi Sakamoto } else {
183b0ac0009STakashi Sakamoto conn = &oxfw->in_conn;
184b0ac0009STakashi Sakamoto c_dir = CMP_INPUT;
185b0ac0009STakashi Sakamoto s_dir = AMDTP_OUT_STREAM;
186b0ac0009STakashi Sakamoto }
187b0ac0009STakashi Sakamoto
188b0ac0009STakashi Sakamoto err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
189b0ac0009STakashi Sakamoto if (err < 0)
190779f0dbaSTakashi Sakamoto return err;
191b0ac0009STakashi Sakamoto
192a092f000STakashi Sakamoto err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags);
193b0ac0009STakashi Sakamoto if (err < 0) {
194b0ac0009STakashi Sakamoto cmp_connection_destroy(conn);
195779f0dbaSTakashi Sakamoto return err;
196b0ac0009STakashi Sakamoto }
197b0ac0009STakashi Sakamoto
198779f0dbaSTakashi Sakamoto return 0;
199b0ac0009STakashi Sakamoto }
200b0ac0009STakashi Sakamoto
keep_resources(struct snd_oxfw * oxfw,struct amdtp_stream * stream)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;
2067bc93821STakashi Sakamoto struct cmp_connection *conn;
2070356ce3aSTakashi Sakamoto int i;
2080356ce3aSTakashi Sakamoto int err;
2090356ce3aSTakashi Sakamoto
2100356ce3aSTakashi Sakamoto if (stream == &oxfw->rx_stream) {
2110356ce3aSTakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_IN;
2120356ce3aSTakashi Sakamoto formats = oxfw->rx_stream_formats;
2137bc93821STakashi Sakamoto conn = &oxfw->in_conn;
2140356ce3aSTakashi Sakamoto } else {
2150356ce3aSTakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_OUT;
2160356ce3aSTakashi Sakamoto formats = oxfw->tx_stream_formats;
2177bc93821STakashi Sakamoto conn = &oxfw->out_conn;
2180356ce3aSTakashi Sakamoto }
2190356ce3aSTakashi Sakamoto
2200356ce3aSTakashi Sakamoto err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
2210356ce3aSTakashi Sakamoto if (err < 0)
2220356ce3aSTakashi Sakamoto return err;
2230356ce3aSTakashi Sakamoto
2240356ce3aSTakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
2250356ce3aSTakashi Sakamoto struct snd_oxfw_stream_formation fmt;
2260356ce3aSTakashi Sakamoto
2270356ce3aSTakashi Sakamoto if (formats[i] == NULL)
2280356ce3aSTakashi Sakamoto break;
2290356ce3aSTakashi Sakamoto
2300356ce3aSTakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], &fmt);
2310356ce3aSTakashi Sakamoto if (err < 0)
2320356ce3aSTakashi Sakamoto return err;
2330356ce3aSTakashi Sakamoto
2340356ce3aSTakashi Sakamoto if (fmt.rate == formation.rate && fmt.pcm == formation.pcm &&
2350356ce3aSTakashi Sakamoto fmt.midi == formation.midi)
2360356ce3aSTakashi Sakamoto break;
2370356ce3aSTakashi Sakamoto }
2380356ce3aSTakashi Sakamoto if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
2390356ce3aSTakashi Sakamoto return -EINVAL;
2400356ce3aSTakashi Sakamoto
2410356ce3aSTakashi Sakamoto // The stream should have one pcm channels at least.
2420356ce3aSTakashi Sakamoto if (formation.pcm == 0)
2430356ce3aSTakashi Sakamoto return -EINVAL;
2440356ce3aSTakashi Sakamoto
2457bc93821STakashi Sakamoto err = amdtp_am824_set_parameters(stream, formation.rate, formation.pcm,
2460356ce3aSTakashi Sakamoto formation.midi * 8, false);
2477bc93821STakashi Sakamoto if (err < 0)
2487bc93821STakashi Sakamoto return err;
2497bc93821STakashi Sakamoto
2507bc93821STakashi Sakamoto return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
2510356ce3aSTakashi Sakamoto }
2520356ce3aSTakashi 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)2534f380d00STakashi Sakamoto int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw,
254b0ac0009STakashi Sakamoto struct amdtp_stream *stream,
2551d6a722cSTakashi Sakamoto unsigned int rate, unsigned int pcm_channels,
2563299d2a0STakashi Sakamoto unsigned int frames_per_period,
2573299d2a0STakashi Sakamoto unsigned int frames_per_buffer)
258b0ac0009STakashi Sakamoto {
259f3699e2cSTakashi Sakamoto struct snd_oxfw_stream_formation formation;
260b0ac0009STakashi Sakamoto enum avc_general_plug_dir dir;
2614f380d00STakashi Sakamoto int err;
262e2786ca6STakashi Sakamoto
26320358d44STakashi Sakamoto // Considering JACK/FFADO streaming:
26420358d44STakashi Sakamoto // TODO: This can be removed hwdep functionality becomes popular.
26520358d44STakashi Sakamoto err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
26620358d44STakashi Sakamoto if (err < 0)
26720358d44STakashi Sakamoto return err;
26820358d44STakashi Sakamoto if (oxfw->has_output) {
26920358d44STakashi Sakamoto err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
27020358d44STakashi Sakamoto if (err < 0)
27120358d44STakashi Sakamoto return err;
272b0ac0009STakashi Sakamoto }
273b0ac0009STakashi Sakamoto
27420358d44STakashi Sakamoto if (stream == &oxfw->tx_stream)
27520358d44STakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_OUT;
27620358d44STakashi Sakamoto else
27720358d44STakashi Sakamoto dir = AVC_GENERAL_PLUG_DIR_IN;
278b0ac0009STakashi Sakamoto
279b0ac0009STakashi Sakamoto err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
280e2786ca6STakashi Sakamoto if (err < 0)
28120358d44STakashi Sakamoto return err;
2824f380d00STakashi Sakamoto if (rate == 0) {
28305588d34STakashi Sakamoto rate = formation.rate;
28405588d34STakashi Sakamoto pcm_channels = formation.pcm;
2854f380d00STakashi Sakamoto }
2864f380d00STakashi Sakamoto if (formation.rate != rate || formation.pcm != pcm_channels) {
287ac5d7786STakashi Sakamoto amdtp_domain_stop(&oxfw->domain);
288ac5d7786STakashi Sakamoto
289e34244ddSTakashi Sakamoto cmp_connection_break(&oxfw->in_conn);
2903f2ce83dSTakashi Sakamoto cmp_connection_release(&oxfw->in_conn);
291e34244ddSTakashi Sakamoto
292e34244ddSTakashi Sakamoto if (oxfw->has_output) {
293e34244ddSTakashi Sakamoto cmp_connection_break(&oxfw->out_conn);
2943f2ce83dSTakashi Sakamoto cmp_connection_release(&oxfw->out_conn);
295e34244ddSTakashi Sakamoto }
2964f380d00STakashi Sakamoto }
297f3699e2cSTakashi Sakamoto
2984f380d00STakashi Sakamoto if (oxfw->substreams_count == 0 ||
2994f380d00STakashi Sakamoto formation.rate != rate || formation.pcm != pcm_channels) {
300b0ac0009STakashi Sakamoto err = set_stream_format(oxfw, stream, rate, pcm_channels);
301f3699e2cSTakashi Sakamoto if (err < 0) {
302f3699e2cSTakashi Sakamoto dev_err(&oxfw->unit->device,
303f3699e2cSTakashi Sakamoto "fail to set stream format: %d\n", err);
30420358d44STakashi Sakamoto return err;
30520358d44STakashi Sakamoto }
3060356ce3aSTakashi Sakamoto
3070356ce3aSTakashi Sakamoto err = keep_resources(oxfw, &oxfw->rx_stream);
3080356ce3aSTakashi Sakamoto if (err < 0)
3090356ce3aSTakashi Sakamoto return err;
3100356ce3aSTakashi Sakamoto
3110356ce3aSTakashi Sakamoto if (oxfw->has_output) {
3120356ce3aSTakashi Sakamoto err = keep_resources(oxfw, &oxfw->tx_stream);
3137bc93821STakashi Sakamoto if (err < 0) {
3147bc93821STakashi Sakamoto cmp_connection_release(&oxfw->in_conn);
3150356ce3aSTakashi Sakamoto return err;
3160356ce3aSTakashi Sakamoto }
317f3699e2cSTakashi Sakamoto }
3181d6a722cSTakashi Sakamoto
3191d6a722cSTakashi Sakamoto err = amdtp_domain_set_events_per_period(&oxfw->domain,
3203299d2a0STakashi Sakamoto frames_per_period, frames_per_buffer);
3211d6a722cSTakashi Sakamoto if (err < 0) {
3221d6a722cSTakashi Sakamoto cmp_connection_release(&oxfw->in_conn);
3231d6a722cSTakashi Sakamoto if (oxfw->has_output)
3241d6a722cSTakashi Sakamoto cmp_connection_release(&oxfw->out_conn);
3251d6a722cSTakashi Sakamoto return err;
3261d6a722cSTakashi Sakamoto }
3277bc93821STakashi Sakamoto }
328b0ac0009STakashi Sakamoto
3294f380d00STakashi Sakamoto return 0;
3304f380d00STakashi Sakamoto }
3314f380d00STakashi Sakamoto
snd_oxfw_stream_start_duplex(struct snd_oxfw * oxfw)3324f380d00STakashi Sakamoto int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
3334f380d00STakashi Sakamoto {
3344f380d00STakashi Sakamoto int err;
3354f380d00STakashi Sakamoto
3364f380d00STakashi Sakamoto if (oxfw->substreams_count == 0)
3374f380d00STakashi Sakamoto return -EIO;
3384f380d00STakashi Sakamoto
3394f380d00STakashi Sakamoto if (amdtp_streaming_error(&oxfw->rx_stream) ||
3404f380d00STakashi Sakamoto amdtp_streaming_error(&oxfw->tx_stream)) {
341ac5d7786STakashi Sakamoto amdtp_domain_stop(&oxfw->domain);
3424f380d00STakashi Sakamoto
343ac5d7786STakashi Sakamoto cmp_connection_break(&oxfw->in_conn);
344ac5d7786STakashi Sakamoto if (oxfw->has_output)
3454f380d00STakashi Sakamoto cmp_connection_break(&oxfw->out_conn);
3464f380d00STakashi Sakamoto }
3474f380d00STakashi Sakamoto
34820358d44STakashi Sakamoto if (!amdtp_stream_running(&oxfw->rx_stream)) {
349029ffc42STakashi Sakamoto unsigned int tx_init_skip_cycles = 0;
350029ffc42STakashi Sakamoto bool replay_seq = false;
351029ffc42STakashi Sakamoto
35220358d44STakashi Sakamoto err = start_stream(oxfw, &oxfw->rx_stream);
353b0ac0009STakashi Sakamoto if (err < 0) {
354b0ac0009STakashi Sakamoto dev_err(&oxfw->unit->device,
355ac5d7786STakashi Sakamoto "fail to prepare rx stream: %d\n", err);
356ac5d7786STakashi Sakamoto goto error;
357ac5d7786STakashi Sakamoto }
358ac5d7786STakashi Sakamoto
359ac5d7786STakashi Sakamoto if (oxfw->has_output &&
360ac5d7786STakashi Sakamoto !amdtp_stream_running(&oxfw->tx_stream)) {
361ac5d7786STakashi Sakamoto err = start_stream(oxfw, &oxfw->tx_stream);
362ac5d7786STakashi Sakamoto if (err < 0) {
363ac5d7786STakashi Sakamoto dev_err(&oxfw->unit->device,
364ac5d7786STakashi Sakamoto "fail to prepare tx stream: %d\n", err);
36520358d44STakashi Sakamoto goto error;
36620358d44STakashi Sakamoto }
367029ffc42STakashi Sakamoto
368029ffc42STakashi Sakamoto if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) {
369029ffc42STakashi Sakamoto // Just after changing sampling transfer frequency, many cycles are
370029ffc42STakashi Sakamoto // skipped for packet transmission.
371029ffc42STakashi Sakamoto tx_init_skip_cycles = 400;
372cddcd547STakashi Sakamoto } else if (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) {
373cddcd547STakashi Sakamoto // It takes a bit time for target device to adjust event frequency
374cddcd547STakashi Sakamoto // according to nominal event frequency in isochronous packets from
375cddcd547STakashi Sakamoto // ALSA oxfw driver.
376cddcd547STakashi Sakamoto tx_init_skip_cycles = 4000;
377029ffc42STakashi Sakamoto } else {
378029ffc42STakashi Sakamoto replay_seq = true;
379029ffc42STakashi Sakamoto }
38020358d44STakashi Sakamoto }
38120358d44STakashi Sakamoto
382029ffc42STakashi Sakamoto // NOTE: The device ignores presentation time expressed by the value of syt field
383029ffc42STakashi Sakamoto // of CIP header in received packets. The sequence of the number of data blocks per
384029ffc42STakashi Sakamoto // packet is important for media clock recovery.
385029ffc42STakashi Sakamoto err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false);
386ac5d7786STakashi Sakamoto if (err < 0)
387ac5d7786STakashi Sakamoto goto error;
388ac5d7786STakashi Sakamoto
389bdaedca7STakashi Sakamoto if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
390ac5d7786STakashi Sakamoto err = -ETIMEDOUT;
39120358d44STakashi Sakamoto goto error;
392b0ac0009STakashi Sakamoto }
393f3699e2cSTakashi Sakamoto }
394f3699e2cSTakashi Sakamoto
39520358d44STakashi Sakamoto return 0;
39620358d44STakashi Sakamoto error:
397ac5d7786STakashi Sakamoto amdtp_domain_stop(&oxfw->domain);
398ac5d7786STakashi Sakamoto
39920358d44STakashi Sakamoto cmp_connection_break(&oxfw->in_conn);
400ac5d7786STakashi Sakamoto if (oxfw->has_output)
40120358d44STakashi Sakamoto cmp_connection_break(&oxfw->out_conn);
402ac5d7786STakashi Sakamoto
403e2786ca6STakashi Sakamoto return err;
404e2786ca6STakashi Sakamoto }
405e2786ca6STakashi Sakamoto
snd_oxfw_stream_stop_duplex(struct snd_oxfw * oxfw)406779f0dbaSTakashi Sakamoto void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw)
407e2786ca6STakashi Sakamoto {
4084a0a0472STakashi Sakamoto if (oxfw->substreams_count == 0) {
409ac5d7786STakashi Sakamoto amdtp_domain_stop(&oxfw->domain);
410ac5d7786STakashi Sakamoto
411e34244ddSTakashi Sakamoto cmp_connection_break(&oxfw->in_conn);
4127bc93821STakashi Sakamoto cmp_connection_release(&oxfw->in_conn);
413b0ac0009STakashi Sakamoto
414e34244ddSTakashi Sakamoto if (oxfw->has_output) {
415e34244ddSTakashi Sakamoto cmp_connection_break(&oxfw->out_conn);
4167bc93821STakashi Sakamoto cmp_connection_release(&oxfw->out_conn);
417e34244ddSTakashi Sakamoto }
41820358d44STakashi Sakamoto }
419e2786ca6STakashi Sakamoto }
420e2786ca6STakashi Sakamoto
destroy_stream(struct snd_oxfw * oxfw,struct amdtp_stream * stream)421779f0dbaSTakashi Sakamoto static void destroy_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
422e2786ca6STakashi Sakamoto {
423b0ac0009STakashi Sakamoto struct cmp_connection *conn;
424e2786ca6STakashi Sakamoto
425b0ac0009STakashi Sakamoto if (stream == &oxfw->tx_stream)
426b0ac0009STakashi Sakamoto conn = &oxfw->out_conn;
427e2786ca6STakashi Sakamoto else
428b0ac0009STakashi Sakamoto conn = &oxfw->in_conn;
429b0ac0009STakashi Sakamoto
430b0ac0009STakashi Sakamoto amdtp_stream_destroy(stream);
431b0ac0009STakashi Sakamoto cmp_connection_destroy(conn);
432b0ac0009STakashi Sakamoto }
433b0ac0009STakashi Sakamoto
snd_oxfw_stream_init_duplex(struct snd_oxfw * oxfw)434779f0dbaSTakashi Sakamoto int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw)
435779f0dbaSTakashi Sakamoto {
436779f0dbaSTakashi Sakamoto int err;
437779f0dbaSTakashi Sakamoto
438779f0dbaSTakashi Sakamoto err = init_stream(oxfw, &oxfw->rx_stream);
439779f0dbaSTakashi Sakamoto if (err < 0)
440779f0dbaSTakashi Sakamoto return err;
441779f0dbaSTakashi Sakamoto
442779f0dbaSTakashi Sakamoto if (oxfw->has_output) {
443779f0dbaSTakashi Sakamoto err = init_stream(oxfw, &oxfw->tx_stream);
444779f0dbaSTakashi Sakamoto if (err < 0) {
445779f0dbaSTakashi Sakamoto destroy_stream(oxfw, &oxfw->rx_stream);
446779f0dbaSTakashi Sakamoto return err;
447779f0dbaSTakashi Sakamoto }
448779f0dbaSTakashi Sakamoto }
449779f0dbaSTakashi Sakamoto
450ac5d7786STakashi Sakamoto err = amdtp_domain_init(&oxfw->domain);
451ac5d7786STakashi Sakamoto if (err < 0) {
452ac5d7786STakashi Sakamoto destroy_stream(oxfw, &oxfw->rx_stream);
453ac5d7786STakashi Sakamoto if (oxfw->has_output)
454ac5d7786STakashi Sakamoto destroy_stream(oxfw, &oxfw->tx_stream);
455ac5d7786STakashi Sakamoto }
456ac5d7786STakashi Sakamoto
457ac5d7786STakashi Sakamoto return err;
458779f0dbaSTakashi Sakamoto }
459779f0dbaSTakashi Sakamoto
460779f0dbaSTakashi Sakamoto // This function should be called before starting the stream or after stopping
461779f0dbaSTakashi Sakamoto // the streams.
snd_oxfw_stream_destroy_duplex(struct snd_oxfw * oxfw)462779f0dbaSTakashi Sakamoto void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
463779f0dbaSTakashi Sakamoto {
464ac5d7786STakashi Sakamoto amdtp_domain_destroy(&oxfw->domain);
465ac5d7786STakashi Sakamoto
466779f0dbaSTakashi Sakamoto destroy_stream(oxfw, &oxfw->rx_stream);
467779f0dbaSTakashi Sakamoto
468779f0dbaSTakashi Sakamoto if (oxfw->has_output)
469779f0dbaSTakashi Sakamoto destroy_stream(oxfw, &oxfw->tx_stream);
470779f0dbaSTakashi Sakamoto }
471779f0dbaSTakashi Sakamoto
snd_oxfw_stream_update_duplex(struct snd_oxfw * oxfw)472779f0dbaSTakashi Sakamoto void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw)
473b0ac0009STakashi Sakamoto {
474ac5d7786STakashi Sakamoto amdtp_domain_stop(&oxfw->domain);
475ac5d7786STakashi Sakamoto
476e34244ddSTakashi Sakamoto cmp_connection_break(&oxfw->in_conn);
477b0ac0009STakashi Sakamoto
478e34244ddSTakashi Sakamoto amdtp_stream_pcm_abort(&oxfw->rx_stream);
479e34244ddSTakashi Sakamoto
480e34244ddSTakashi Sakamoto if (oxfw->has_output) {
481e34244ddSTakashi Sakamoto cmp_connection_break(&oxfw->out_conn);
482e34244ddSTakashi Sakamoto
483e34244ddSTakashi Sakamoto amdtp_stream_pcm_abort(&oxfw->tx_stream);
484e34244ddSTakashi Sakamoto }
485e2786ca6STakashi Sakamoto }
4865cd1d3f4STakashi Sakamoto
snd_oxfw_stream_get_current_formation(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,struct snd_oxfw_stream_formation * formation)4873c96101fSTakashi Sakamoto int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
4883c96101fSTakashi Sakamoto enum avc_general_plug_dir dir,
4893c96101fSTakashi Sakamoto struct snd_oxfw_stream_formation *formation)
4903c96101fSTakashi Sakamoto {
49125ab2b2fSTakashi Sakamoto int err;
49225ab2b2fSTakashi Sakamoto
49325ab2b2fSTakashi Sakamoto if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
4943c96101fSTakashi Sakamoto u8 *format;
4953c96101fSTakashi Sakamoto unsigned int len;
4963c96101fSTakashi Sakamoto
4973c96101fSTakashi Sakamoto len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
4983c96101fSTakashi Sakamoto format = kmalloc(len, GFP_KERNEL);
4993c96101fSTakashi Sakamoto if (format == NULL)
5003c96101fSTakashi Sakamoto return -ENOMEM;
5013c96101fSTakashi Sakamoto
5023c96101fSTakashi Sakamoto err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
50325ab2b2fSTakashi Sakamoto if (err >= 0) {
50425ab2b2fSTakashi Sakamoto if (len < 3)
5053c96101fSTakashi Sakamoto err = -EIO;
50625ab2b2fSTakashi Sakamoto else
50725ab2b2fSTakashi Sakamoto err = snd_oxfw_stream_parse_format(format, formation);
5083c96101fSTakashi Sakamoto }
5093c96101fSTakashi Sakamoto
5103c96101fSTakashi Sakamoto kfree(format);
51125ab2b2fSTakashi Sakamoto } else {
51225ab2b2fSTakashi Sakamoto // Miglia Harmony Audio does not support Extended Stream Format Information
51325ab2b2fSTakashi Sakamoto // command. Use the duplicated hard-coded format, instead.
51425ab2b2fSTakashi Sakamoto unsigned int rate;
51525ab2b2fSTakashi Sakamoto u8 *const *formats;
51625ab2b2fSTakashi Sakamoto int i;
51725ab2b2fSTakashi Sakamoto
51825ab2b2fSTakashi Sakamoto err = avc_general_get_sig_fmt(oxfw->unit, &rate, dir, 0);
51925ab2b2fSTakashi Sakamoto if (err < 0)
52025ab2b2fSTakashi Sakamoto return err;
52125ab2b2fSTakashi Sakamoto
52225ab2b2fSTakashi Sakamoto if (dir == AVC_GENERAL_PLUG_DIR_IN)
52325ab2b2fSTakashi Sakamoto formats = oxfw->rx_stream_formats;
52425ab2b2fSTakashi Sakamoto else
52525ab2b2fSTakashi Sakamoto formats = oxfw->tx_stream_formats;
52625ab2b2fSTakashi Sakamoto
52725ab2b2fSTakashi Sakamoto for (i = 0; (i < SND_OXFW_STREAM_FORMAT_ENTRIES); ++i) {
52825ab2b2fSTakashi Sakamoto if (!formats[i])
52925ab2b2fSTakashi Sakamoto continue;
53025ab2b2fSTakashi Sakamoto
53125ab2b2fSTakashi Sakamoto err = snd_oxfw_stream_parse_format(formats[i], formation);
53225ab2b2fSTakashi Sakamoto if (err < 0)
53325ab2b2fSTakashi Sakamoto continue;
53425ab2b2fSTakashi Sakamoto
53525ab2b2fSTakashi Sakamoto if (formation->rate == rate)
53625ab2b2fSTakashi Sakamoto break;
53725ab2b2fSTakashi Sakamoto }
53825ab2b2fSTakashi Sakamoto if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
53925ab2b2fSTakashi Sakamoto return -EIO;
54025ab2b2fSTakashi Sakamoto }
54125ab2b2fSTakashi Sakamoto
5423c96101fSTakashi Sakamoto return err;
5433c96101fSTakashi Sakamoto }
5443c96101fSTakashi Sakamoto
5455cd1d3f4STakashi Sakamoto /*
5465cd1d3f4STakashi Sakamoto * See Table 6.16 - AM824 Stream Format
5475cd1d3f4STakashi Sakamoto * Figure 6.19 - format_information field for AM824 Compound
5485cd1d3f4STakashi Sakamoto * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
5495cd1d3f4STakashi Sakamoto * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
5505cd1d3f4STakashi Sakamoto */
snd_oxfw_stream_parse_format(const u8 * format,struct snd_oxfw_stream_formation * formation)5515c0a35b2STakashi Sakamoto int snd_oxfw_stream_parse_format(const u8 *format,
5525cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation *formation)
5535cd1d3f4STakashi Sakamoto {
5545cd1d3f4STakashi Sakamoto unsigned int i, e, channels, type;
5555cd1d3f4STakashi Sakamoto
5565cd1d3f4STakashi Sakamoto memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
5575cd1d3f4STakashi Sakamoto
5585cd1d3f4STakashi Sakamoto /*
5595cd1d3f4STakashi Sakamoto * this module can support a hierarchy combination that:
5605cd1d3f4STakashi Sakamoto * Root: Audio and Music (0x90)
5615cd1d3f4STakashi Sakamoto * Level 1: AM824 Compound (0x40)
5625cd1d3f4STakashi Sakamoto */
5635cd1d3f4STakashi Sakamoto if ((format[0] != 0x90) || (format[1] != 0x40))
56403be63b2STakashi Sakamoto return -ENXIO;
5655cd1d3f4STakashi Sakamoto
5665cd1d3f4STakashi Sakamoto /* check the sampling rate */
5675cd1d3f4STakashi Sakamoto for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
5685cd1d3f4STakashi Sakamoto if (format[2] == avc_stream_rate_table[i])
5695cd1d3f4STakashi Sakamoto break;
5705cd1d3f4STakashi Sakamoto }
5715cd1d3f4STakashi Sakamoto if (i == ARRAY_SIZE(avc_stream_rate_table))
57203be63b2STakashi Sakamoto return -ENXIO;
5735cd1d3f4STakashi Sakamoto
5745cd1d3f4STakashi Sakamoto formation->rate = oxfw_rate_table[i];
5755cd1d3f4STakashi Sakamoto
5765cd1d3f4STakashi Sakamoto for (e = 0; e < format[4]; e++) {
5775cd1d3f4STakashi Sakamoto channels = format[5 + e * 2];
5785cd1d3f4STakashi Sakamoto type = format[6 + e * 2];
5795cd1d3f4STakashi Sakamoto
5805cd1d3f4STakashi Sakamoto switch (type) {
5815cd1d3f4STakashi Sakamoto /* IEC 60958 Conformant, currently handled as MBLA */
5825cd1d3f4STakashi Sakamoto case 0x00:
5835cd1d3f4STakashi Sakamoto /* Multi Bit Linear Audio (Raw) */
5845cd1d3f4STakashi Sakamoto case 0x06:
5855cd1d3f4STakashi Sakamoto formation->pcm += channels;
5865cd1d3f4STakashi Sakamoto break;
5875cd1d3f4STakashi Sakamoto /* MIDI Conformant */
5885cd1d3f4STakashi Sakamoto case 0x0d:
5895cd1d3f4STakashi Sakamoto formation->midi = channels;
5905cd1d3f4STakashi Sakamoto break;
5915cd1d3f4STakashi Sakamoto /* IEC 61937-3 to 7 */
5925cd1d3f4STakashi Sakamoto case 0x01:
5935cd1d3f4STakashi Sakamoto case 0x02:
5945cd1d3f4STakashi Sakamoto case 0x03:
5955cd1d3f4STakashi Sakamoto case 0x04:
5965cd1d3f4STakashi Sakamoto case 0x05:
5975cd1d3f4STakashi Sakamoto /* Multi Bit Linear Audio */
5985cd1d3f4STakashi Sakamoto case 0x07: /* DVD-Audio */
5995cd1d3f4STakashi Sakamoto case 0x0c: /* High Precision */
6005cd1d3f4STakashi Sakamoto /* One Bit Audio */
6015cd1d3f4STakashi Sakamoto case 0x08: /* (Plain) Raw */
6025cd1d3f4STakashi Sakamoto case 0x09: /* (Plain) SACD */
6035cd1d3f4STakashi Sakamoto case 0x0a: /* (Encoded) Raw */
6045cd1d3f4STakashi Sakamoto case 0x0b: /* (Encoded) SACD */
6055cd1d3f4STakashi Sakamoto /* SMPTE Time-Code conformant */
6065cd1d3f4STakashi Sakamoto case 0x0e:
6075cd1d3f4STakashi Sakamoto /* Sample Count */
6085cd1d3f4STakashi Sakamoto case 0x0f:
6095cd1d3f4STakashi Sakamoto /* Anciliary Data */
6105cd1d3f4STakashi Sakamoto case 0x10:
6115cd1d3f4STakashi Sakamoto /* Synchronization Stream (Stereo Raw audio) */
6125cd1d3f4STakashi Sakamoto case 0x40:
6135cd1d3f4STakashi Sakamoto /* Don't care */
6145cd1d3f4STakashi Sakamoto case 0xff:
6155cd1d3f4STakashi Sakamoto default:
61603be63b2STakashi Sakamoto return -ENXIO; /* not supported */
6175cd1d3f4STakashi Sakamoto }
6185cd1d3f4STakashi Sakamoto }
6195cd1d3f4STakashi Sakamoto
62049c7b3fcSTakashi Sakamoto if (formation->pcm > AM824_MAX_CHANNELS_FOR_PCM ||
62149c7b3fcSTakashi Sakamoto formation->midi > AM824_MAX_CHANNELS_FOR_MIDI)
62203be63b2STakashi Sakamoto return -ENXIO;
6235cd1d3f4STakashi Sakamoto
6245cd1d3f4STakashi Sakamoto return 0;
6255cd1d3f4STakashi Sakamoto }
6265cd1d3f4STakashi Sakamoto
6275cd1d3f4STakashi 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)6285cd1d3f4STakashi Sakamoto assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
6295cd1d3f4STakashi Sakamoto unsigned int pid, u8 *buf, unsigned int *len,
6305cd1d3f4STakashi Sakamoto u8 **formats)
6315cd1d3f4STakashi Sakamoto {
6325cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation formation;
6335cd1d3f4STakashi Sakamoto unsigned int i, eid;
6345cd1d3f4STakashi Sakamoto int err;
6355cd1d3f4STakashi Sakamoto
63625ab2b2fSTakashi Sakamoto // get format at current sampling rate.
63725ab2b2fSTakashi Sakamoto if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) {
6385cd1d3f4STakashi Sakamoto err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
6395cd1d3f4STakashi Sakamoto if (err < 0) {
6405cd1d3f4STakashi Sakamoto dev_err(&oxfw->unit->device,
6415cd1d3f4STakashi Sakamoto "fail to get current stream format for isoc %s plug %d:%d\n",
6425cd1d3f4STakashi Sakamoto (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
6435cd1d3f4STakashi Sakamoto pid, err);
6445cd1d3f4STakashi Sakamoto goto end;
6455cd1d3f4STakashi Sakamoto }
64625ab2b2fSTakashi Sakamoto } else {
64725ab2b2fSTakashi Sakamoto // Miglia Harmony Audio does not support Extended Stream Format Information
64825ab2b2fSTakashi Sakamoto // command. Use the hard-coded format, instead.
64925ab2b2fSTakashi Sakamoto buf[0] = 0x90;
65025ab2b2fSTakashi Sakamoto buf[1] = 0x40;
65125ab2b2fSTakashi Sakamoto buf[2] = avc_stream_rate_table[0];
65225ab2b2fSTakashi Sakamoto buf[3] = 0x00;
65325ab2b2fSTakashi Sakamoto buf[4] = 0x01;
65425ab2b2fSTakashi Sakamoto
65525ab2b2fSTakashi Sakamoto if (dir == AVC_GENERAL_PLUG_DIR_IN)
65625ab2b2fSTakashi Sakamoto buf[5] = 0x08;
65725ab2b2fSTakashi Sakamoto else
65825ab2b2fSTakashi Sakamoto buf[5] = 0x02;
65925ab2b2fSTakashi Sakamoto
66025ab2b2fSTakashi Sakamoto buf[6] = 0x06;
66125ab2b2fSTakashi Sakamoto
66225ab2b2fSTakashi Sakamoto *len = 7;
66325ab2b2fSTakashi Sakamoto }
6645cd1d3f4STakashi Sakamoto
6655cd1d3f4STakashi Sakamoto /* parse and set stream format */
6665cd1d3f4STakashi Sakamoto eid = 0;
6675cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(buf, &formation);
6685cd1d3f4STakashi Sakamoto if (err < 0)
6695cd1d3f4STakashi Sakamoto goto end;
6705cd1d3f4STakashi Sakamoto
671cd3b7116STakashi Sakamoto formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
672cd3b7116STakashi Sakamoto GFP_KERNEL);
673cd3b7116STakashi Sakamoto if (!formats[eid]) {
6745cd1d3f4STakashi Sakamoto err = -ENOMEM;
6755cd1d3f4STakashi Sakamoto goto end;
6765cd1d3f4STakashi Sakamoto }
6775cd1d3f4STakashi Sakamoto
6785cd1d3f4STakashi Sakamoto /* apply the format for each available sampling rate */
6795cd1d3f4STakashi Sakamoto for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
6805cd1d3f4STakashi Sakamoto if (formation.rate == oxfw_rate_table[i])
6815cd1d3f4STakashi Sakamoto continue;
6825cd1d3f4STakashi Sakamoto
6835cd1d3f4STakashi Sakamoto err = avc_general_inquiry_sig_fmt(oxfw->unit,
6845cd1d3f4STakashi Sakamoto oxfw_rate_table[i],
6855cd1d3f4STakashi Sakamoto dir, pid);
6865cd1d3f4STakashi Sakamoto if (err < 0)
6875cd1d3f4STakashi Sakamoto continue;
6885cd1d3f4STakashi Sakamoto
6895cd1d3f4STakashi Sakamoto eid++;
690cd3b7116STakashi Sakamoto formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
691cd3b7116STakashi Sakamoto GFP_KERNEL);
6925cd1d3f4STakashi Sakamoto if (formats[eid] == NULL) {
6935cd1d3f4STakashi Sakamoto err = -ENOMEM;
6945cd1d3f4STakashi Sakamoto goto end;
6955cd1d3f4STakashi Sakamoto }
6965cd1d3f4STakashi Sakamoto formats[eid][2] = avc_stream_rate_table[i];
6975cd1d3f4STakashi Sakamoto }
6985cd1d3f4STakashi Sakamoto
6995cd1d3f4STakashi Sakamoto err = 0;
7005cd1d3f4STakashi Sakamoto oxfw->assumed = true;
7015cd1d3f4STakashi Sakamoto end:
7025cd1d3f4STakashi Sakamoto return err;
7035cd1d3f4STakashi Sakamoto }
7045cd1d3f4STakashi Sakamoto
fill_stream_formats(struct snd_oxfw * oxfw,enum avc_general_plug_dir dir,unsigned short pid)7055cd1d3f4STakashi Sakamoto static int fill_stream_formats(struct snd_oxfw *oxfw,
7065cd1d3f4STakashi Sakamoto enum avc_general_plug_dir dir,
7075cd1d3f4STakashi Sakamoto unsigned short pid)
7085cd1d3f4STakashi Sakamoto {
7095cd1d3f4STakashi Sakamoto u8 *buf, **formats;
7105cd1d3f4STakashi Sakamoto unsigned int len, eid = 0;
7115cd1d3f4STakashi Sakamoto struct snd_oxfw_stream_formation dummy;
7125cd1d3f4STakashi Sakamoto int err;
7135cd1d3f4STakashi Sakamoto
7145cd1d3f4STakashi Sakamoto buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
7155cd1d3f4STakashi Sakamoto if (buf == NULL)
7165cd1d3f4STakashi Sakamoto return -ENOMEM;
7175cd1d3f4STakashi Sakamoto
718b0ac0009STakashi Sakamoto if (dir == AVC_GENERAL_PLUG_DIR_OUT)
719b0ac0009STakashi Sakamoto formats = oxfw->tx_stream_formats;
720b0ac0009STakashi Sakamoto else
7215cd1d3f4STakashi Sakamoto formats = oxfw->rx_stream_formats;
7225cd1d3f4STakashi Sakamoto
7235cd1d3f4STakashi Sakamoto /* get first entry */
7245cd1d3f4STakashi Sakamoto len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
7255cd1d3f4STakashi Sakamoto err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
72603be63b2STakashi Sakamoto if (err == -ENXIO) {
7275cd1d3f4STakashi Sakamoto /* LIST subfunction is not implemented */
7285cd1d3f4STakashi Sakamoto len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
7295cd1d3f4STakashi Sakamoto err = assume_stream_formats(oxfw, dir, pid, buf, &len,
7305cd1d3f4STakashi Sakamoto formats);
7315cd1d3f4STakashi Sakamoto goto end;
7325cd1d3f4STakashi Sakamoto } else if (err < 0) {
7335cd1d3f4STakashi Sakamoto dev_err(&oxfw->unit->device,
7345cd1d3f4STakashi Sakamoto "fail to get stream format %d for isoc %s plug %d:%d\n",
7355cd1d3f4STakashi Sakamoto eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
7365cd1d3f4STakashi Sakamoto pid, err);
7375cd1d3f4STakashi Sakamoto goto end;
7385cd1d3f4STakashi Sakamoto }
7395cd1d3f4STakashi Sakamoto
7405cd1d3f4STakashi Sakamoto /* LIST subfunction is implemented */
7415cd1d3f4STakashi Sakamoto while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
7425cd1d3f4STakashi Sakamoto /* The format is too short. */
7435cd1d3f4STakashi Sakamoto if (len < 3) {
7445cd1d3f4STakashi Sakamoto err = -EIO;
7455cd1d3f4STakashi Sakamoto break;
7465cd1d3f4STakashi Sakamoto }
7475cd1d3f4STakashi Sakamoto
7485cd1d3f4STakashi Sakamoto /* parse and set stream format */
7495cd1d3f4STakashi Sakamoto err = snd_oxfw_stream_parse_format(buf, &dummy);
7505cd1d3f4STakashi Sakamoto if (err < 0)
7515cd1d3f4STakashi Sakamoto break;
7525cd1d3f4STakashi Sakamoto
753cd3b7116STakashi Sakamoto formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
754cd3b7116STakashi Sakamoto GFP_KERNEL);
755cd3b7116STakashi Sakamoto if (!formats[eid]) {
7565cd1d3f4STakashi Sakamoto err = -ENOMEM;
7575cd1d3f4STakashi Sakamoto break;
7585cd1d3f4STakashi Sakamoto }
7595cd1d3f4STakashi Sakamoto
7605cd1d3f4STakashi Sakamoto /* get next entry */
7615cd1d3f4STakashi Sakamoto len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
7625cd1d3f4STakashi Sakamoto err = avc_stream_get_format_list(oxfw->unit, dir, 0,
7635cd1d3f4STakashi Sakamoto buf, &len, ++eid);
7645cd1d3f4STakashi Sakamoto /* No entries remained. */
7655cd1d3f4STakashi Sakamoto if (err == -EINVAL) {
7665cd1d3f4STakashi Sakamoto err = 0;
7675cd1d3f4STakashi Sakamoto break;
7685cd1d3f4STakashi Sakamoto } else if (err < 0) {
7695cd1d3f4STakashi Sakamoto dev_err(&oxfw->unit->device,
7705cd1d3f4STakashi Sakamoto "fail to get stream format %d for isoc %s plug %d:%d\n",
7715cd1d3f4STakashi Sakamoto eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
7725cd1d3f4STakashi Sakamoto "out",
7735cd1d3f4STakashi Sakamoto pid, err);
7745cd1d3f4STakashi Sakamoto break;
7755cd1d3f4STakashi Sakamoto }
7765cd1d3f4STakashi Sakamoto }
7775cd1d3f4STakashi Sakamoto end:
7785cd1d3f4STakashi Sakamoto kfree(buf);
7795cd1d3f4STakashi Sakamoto return err;
7805cd1d3f4STakashi Sakamoto }
7815cd1d3f4STakashi Sakamoto
snd_oxfw_stream_discover(struct snd_oxfw * oxfw)7825cd1d3f4STakashi Sakamoto int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
7835cd1d3f4STakashi Sakamoto {
7845cd1d3f4STakashi Sakamoto u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
78532056041STakashi Sakamoto struct snd_oxfw_stream_formation formation;
78632056041STakashi Sakamoto u8 *format;
78732056041STakashi Sakamoto unsigned int i;
7885cd1d3f4STakashi Sakamoto int err;
7895cd1d3f4STakashi Sakamoto
7905cd1d3f4STakashi Sakamoto /* the number of plugs for isoc in/out, ext in/out */
7915cd1d3f4STakashi Sakamoto err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
7925cd1d3f4STakashi Sakamoto if (err < 0) {
7935cd1d3f4STakashi Sakamoto dev_err(&oxfw->unit->device,
7945cd1d3f4STakashi Sakamoto "fail to get info for isoc/external in/out plugs: %d\n",
7955cd1d3f4STakashi Sakamoto err);
7965cd1d3f4STakashi Sakamoto goto end;
797b0ac0009STakashi Sakamoto } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
79803be63b2STakashi Sakamoto err = -ENXIO;
7995cd1d3f4STakashi Sakamoto goto end;
8005cd1d3f4STakashi Sakamoto }
8015cd1d3f4STakashi Sakamoto
802b0ac0009STakashi Sakamoto /* use oPCR[0] if exists */
803b0ac0009STakashi Sakamoto if (plugs[1] > 0) {
804b0ac0009STakashi Sakamoto err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
80541dbc792STakashi Sakamoto if (err < 0) {
80641dbc792STakashi Sakamoto if (err != -ENXIO)
80741dbc792STakashi Sakamoto return err;
80832056041STakashi Sakamoto
80941dbc792STakashi Sakamoto // The oPCR is not available for isoc communication.
81041dbc792STakashi Sakamoto err = 0;
81141dbc792STakashi Sakamoto } else {
81232056041STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
81332056041STakashi Sakamoto format = oxfw->tx_stream_formats[i];
81432056041STakashi Sakamoto if (format == NULL)
81532056041STakashi Sakamoto continue;
81641dbc792STakashi Sakamoto err = snd_oxfw_stream_parse_format(format,
81741dbc792STakashi Sakamoto &formation);
81832056041STakashi Sakamoto if (err < 0)
81932056041STakashi Sakamoto continue;
82032056041STakashi Sakamoto
82132056041STakashi Sakamoto /* Add one MIDI port. */
82232056041STakashi Sakamoto if (formation.midi > 0)
82332056041STakashi Sakamoto oxfw->midi_input_ports = 1;
82432056041STakashi Sakamoto }
82532056041STakashi Sakamoto
826b0ac0009STakashi Sakamoto oxfw->has_output = true;
827b0ac0009STakashi Sakamoto }
82841dbc792STakashi Sakamoto }
829b0ac0009STakashi Sakamoto
8305cd1d3f4STakashi Sakamoto /* use iPCR[0] if exists */
83132056041STakashi Sakamoto if (plugs[0] > 0) {
8325cd1d3f4STakashi Sakamoto err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
83341dbc792STakashi Sakamoto if (err < 0) {
83441dbc792STakashi Sakamoto if (err != -ENXIO)
83541dbc792STakashi Sakamoto return err;
83632056041STakashi Sakamoto
83741dbc792STakashi Sakamoto // The iPCR is not available for isoc communication.
83841dbc792STakashi Sakamoto err = 0;
83941dbc792STakashi Sakamoto } else {
84032056041STakashi Sakamoto for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
84132056041STakashi Sakamoto format = oxfw->rx_stream_formats[i];
84232056041STakashi Sakamoto if (format == NULL)
84332056041STakashi Sakamoto continue;
84441dbc792STakashi Sakamoto err = snd_oxfw_stream_parse_format(format,
84541dbc792STakashi Sakamoto &formation);
84632056041STakashi Sakamoto if (err < 0)
84732056041STakashi Sakamoto continue;
84832056041STakashi Sakamoto
84932056041STakashi Sakamoto /* Add one MIDI port. */
85032056041STakashi Sakamoto if (formation.midi > 0)
85132056041STakashi Sakamoto oxfw->midi_output_ports = 1;
85232056041STakashi Sakamoto }
85306a42a74STakashi Sakamoto
85406a42a74STakashi Sakamoto oxfw->has_input = true;
85532056041STakashi Sakamoto }
85641dbc792STakashi Sakamoto }
8575cd1d3f4STakashi Sakamoto end:
8585cd1d3f4STakashi Sakamoto return err;
8595cd1d3f4STakashi Sakamoto }
8608985f4acSTakashi Sakamoto
snd_oxfw_stream_lock_changed(struct snd_oxfw * oxfw)8618985f4acSTakashi Sakamoto void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
8628985f4acSTakashi Sakamoto {
8638985f4acSTakashi Sakamoto oxfw->dev_lock_changed = true;
8648985f4acSTakashi Sakamoto wake_up(&oxfw->hwdep_wait);
8658985f4acSTakashi Sakamoto }
8668985f4acSTakashi Sakamoto
snd_oxfw_stream_lock_try(struct snd_oxfw * oxfw)8678985f4acSTakashi Sakamoto int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
8688985f4acSTakashi Sakamoto {
8698985f4acSTakashi Sakamoto int err;
8708985f4acSTakashi Sakamoto
8718985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
8728985f4acSTakashi Sakamoto
8738985f4acSTakashi Sakamoto /* user land lock this */
8748985f4acSTakashi Sakamoto if (oxfw->dev_lock_count < 0) {
8758985f4acSTakashi Sakamoto err = -EBUSY;
8768985f4acSTakashi Sakamoto goto end;
8778985f4acSTakashi Sakamoto }
8788985f4acSTakashi Sakamoto
8798985f4acSTakashi Sakamoto /* this is the first time */
8808985f4acSTakashi Sakamoto if (oxfw->dev_lock_count++ == 0)
8818985f4acSTakashi Sakamoto snd_oxfw_stream_lock_changed(oxfw);
8828985f4acSTakashi Sakamoto err = 0;
8838985f4acSTakashi Sakamoto end:
8848985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
8858985f4acSTakashi Sakamoto return err;
8868985f4acSTakashi Sakamoto }
8878985f4acSTakashi Sakamoto
snd_oxfw_stream_lock_release(struct snd_oxfw * oxfw)8888985f4acSTakashi Sakamoto void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
8898985f4acSTakashi Sakamoto {
8908985f4acSTakashi Sakamoto spin_lock_irq(&oxfw->lock);
8918985f4acSTakashi Sakamoto
8928985f4acSTakashi Sakamoto if (WARN_ON(oxfw->dev_lock_count <= 0))
8938985f4acSTakashi Sakamoto goto end;
8948985f4acSTakashi Sakamoto if (--oxfw->dev_lock_count == 0)
8958985f4acSTakashi Sakamoto snd_oxfw_stream_lock_changed(oxfw);
8968985f4acSTakashi Sakamoto end:
8978985f4acSTakashi Sakamoto spin_unlock_irq(&oxfw->lock);
8988985f4acSTakashi Sakamoto }
899