forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/sound/firewire/fireworks/fireworks_stream.c
....@@ -1,16 +1,14 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * fireworks_stream.c - a part of driver for Fireworks based devices
34 *
45 * Copyright (c) 2013-2014 Takashi Sakamoto
5
- *
6
- * Licensed under the terms of the GNU General Public License, version 2.
76 */
87 #include "./fireworks.h"
98
109 #define CALLBACK_TIMEOUT 100
1110
12
-static int
13
-init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
11
+static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
1412 {
1513 struct cmp_connection *conn;
1614 enum cmp_direction c_dir;
....@@ -29,95 +27,77 @@
2927
3028 err = cmp_connection_init(conn, efw->unit, c_dir, 0);
3129 if (err < 0)
32
- goto end;
30
+ return err;
3331
3432 err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING);
3533 if (err < 0) {
3634 amdtp_stream_destroy(stream);
3735 cmp_connection_destroy(conn);
36
+ return err;
3837 }
39
-end:
38
+
39
+ if (stream == &efw->tx_stream) {
40
+ // Fireworks transmits NODATA packets with TAG0.
41
+ efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0;
42
+ // Fireworks has its own meaning for dbc.
43
+ efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT;
44
+ // Fireworks reset dbc at bus reset.
45
+ efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK;
46
+ // But Recent firmwares starts packets with non-zero dbc.
47
+ // Driver version 5.7.6 installs firmware version 5.7.3.
48
+ if (efw->is_fireworks3 &&
49
+ (efw->firmware_version == 0x5070000 ||
50
+ efw->firmware_version == 0x5070300 ||
51
+ efw->firmware_version == 0x5080000))
52
+ efw->tx_stream.flags |= CIP_UNALIGHED_DBC;
53
+ // AudioFire9 always reports wrong dbs.
54
+ if (efw->is_af9)
55
+ efw->tx_stream.flags |= CIP_WRONG_DBS;
56
+ // Firmware version 5.5 reports fixed interval for dbc.
57
+ if (efw->firmware_version == 0x5050000)
58
+ efw->tx_stream.ctx_data.tx.dbc_interval = 8;
59
+ }
60
+
4061 return err;
4162 }
4263
43
-static void
44
-stop_stream(struct snd_efw *efw, struct amdtp_stream *stream)
45
-{
46
- amdtp_stream_pcm_abort(stream);
47
- amdtp_stream_stop(stream);
48
-
49
- if (stream == &efw->tx_stream)
50
- cmp_connection_break(&efw->out_conn);
51
- else
52
- cmp_connection_break(&efw->in_conn);
53
-}
54
-
55
-static int
56
-start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
57
- unsigned int sampling_rate)
64
+static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream,
65
+ unsigned int rate)
5866 {
5967 struct cmp_connection *conn;
60
- unsigned int mode, pcm_channels, midi_ports;
6168 int err;
6269
63
- err = snd_efw_get_multiplier_mode(sampling_rate, &mode);
64
- if (err < 0)
65
- goto end;
66
- if (stream == &efw->tx_stream) {
67
- conn = &efw->out_conn;
68
- pcm_channels = efw->pcm_capture_channels[mode];
69
- midi_ports = efw->midi_out_ports;
70
- } else {
71
- conn = &efw->in_conn;
72
- pcm_channels = efw->pcm_playback_channels[mode];
73
- midi_ports = efw->midi_in_ports;
74
- }
75
-
76
- err = amdtp_am824_set_parameters(stream, sampling_rate,
77
- pcm_channels, midi_ports, false);
78
- if (err < 0)
79
- goto end;
80
-
81
- /* establish connection via CMP */
82
- err = cmp_connection_establish(conn,
83
- amdtp_stream_get_max_payload(stream));
84
- if (err < 0)
85
- goto end;
86
-
87
- /* start amdtp stream */
88
- err = amdtp_stream_start(stream,
89
- conn->resources.channel,
90
- conn->speed);
91
- if (err < 0) {
92
- stop_stream(efw, stream);
93
- goto end;
94
- }
95
-
96
- /* wait first callback */
97
- if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) {
98
- stop_stream(efw, stream);
99
- err = -ETIMEDOUT;
100
- }
101
-end:
102
- return err;
103
-}
104
-
105
-/*
106
- * This function should be called before starting the stream or after stopping
107
- * the streams.
108
- */
109
-static void
110
-destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
111
-{
112
- struct cmp_connection *conn;
113
-
11470 if (stream == &efw->tx_stream)
11571 conn = &efw->out_conn;
11672 else
11773 conn = &efw->in_conn;
11874
75
+ // Establish connection via CMP.
76
+ err = cmp_connection_establish(conn);
77
+ if (err < 0)
78
+ return err;
79
+
80
+ // Start amdtp stream.
81
+ err = amdtp_domain_add_stream(&efw->domain, stream,
82
+ conn->resources.channel, conn->speed);
83
+ if (err < 0) {
84
+ cmp_connection_break(conn);
85
+ return err;
86
+ }
87
+
88
+ return 0;
89
+}
90
+
91
+// This function should be called before starting the stream or after stopping
92
+// the streams.
93
+static void destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
94
+{
11995 amdtp_stream_destroy(stream);
120
- cmp_connection_destroy(conn);
96
+
97
+ if (stream == &efw->tx_stream)
98
+ cmp_connection_destroy(&efw->out_conn);
99
+ else
100
+ cmp_connection_destroy(&efw->in_conn);
121101 }
122102
123103 static int
....@@ -150,131 +130,200 @@
150130
151131 err = init_stream(efw, &efw->tx_stream);
152132 if (err < 0)
153
- goto end;
154
- /* Fireworks transmits NODATA packets with TAG0. */
155
- efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0;
156
- /* Fireworks has its own meaning for dbc. */
157
- efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT;
158
- /* Fireworks reset dbc at bus reset. */
159
- efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK;
160
- /*
161
- * But Recent firmwares starts packets with non-zero dbc.
162
- * Driver version 5.7.6 installs firmware version 5.7.3.
163
- */
164
- if (efw->is_fireworks3 &&
165
- (efw->firmware_version == 0x5070000 ||
166
- efw->firmware_version == 0x5070300 ||
167
- efw->firmware_version == 0x5080000))
168
- efw->tx_stream.tx_first_dbc = 0x02;
169
- /* AudioFire9 always reports wrong dbs. */
170
- if (efw->is_af9)
171
- efw->tx_stream.flags |= CIP_WRONG_DBS;
172
- /* Firmware version 5.5 reports fixed interval for dbc. */
173
- if (efw->firmware_version == 0x5050000)
174
- efw->tx_stream.tx_dbc_interval = 8;
133
+ return err;
175134
176135 err = init_stream(efw, &efw->rx_stream);
177136 if (err < 0) {
178137 destroy_stream(efw, &efw->tx_stream);
179
- goto end;
138
+ return err;
180139 }
181140
182
- /* set IEC61883 compliant mode (actually not fully compliant...) */
141
+ err = amdtp_domain_init(&efw->domain);
142
+ if (err < 0) {
143
+ destroy_stream(efw, &efw->tx_stream);
144
+ destroy_stream(efw, &efw->rx_stream);
145
+ return err;
146
+ }
147
+
148
+ // set IEC61883 compliant mode (actually not fully compliant...).
183149 err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883);
184150 if (err < 0) {
185151 destroy_stream(efw, &efw->tx_stream);
186152 destroy_stream(efw, &efw->rx_stream);
187153 }
188
-end:
154
+
189155 return err;
190156 }
191157
192
-int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate)
158
+static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream,
159
+ unsigned int rate, unsigned int mode)
160
+{
161
+ unsigned int pcm_channels;
162
+ unsigned int midi_ports;
163
+ struct cmp_connection *conn;
164
+ int err;
165
+
166
+ if (stream == &efw->tx_stream) {
167
+ pcm_channels = efw->pcm_capture_channels[mode];
168
+ midi_ports = efw->midi_out_ports;
169
+ conn = &efw->out_conn;
170
+ } else {
171
+ pcm_channels = efw->pcm_playback_channels[mode];
172
+ midi_ports = efw->midi_in_ports;
173
+ conn = &efw->in_conn;
174
+ }
175
+
176
+ err = amdtp_am824_set_parameters(stream, rate, pcm_channels,
177
+ midi_ports, false);
178
+ if (err < 0)
179
+ return err;
180
+
181
+ return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream));
182
+}
183
+
184
+int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate,
185
+ unsigned int frames_per_period,
186
+ unsigned int frames_per_buffer)
193187 {
194188 unsigned int curr_rate;
195
- int err = 0;
189
+ int err;
196190
197
- /* Need no substreams */
198
- if (efw->playback_substreams == 0 && efw->capture_substreams == 0)
199
- goto end;
200
-
201
- /*
202
- * Considering JACK/FFADO streaming:
203
- * TODO: This can be removed hwdep functionality becomes popular.
204
- */
191
+ // Considering JACK/FFADO streaming:
192
+ // TODO: This can be removed hwdep functionality becomes popular.
205193 err = check_connection_used_by_others(efw, &efw->rx_stream);
206194 if (err < 0)
207
- goto end;
195
+ return err;
208196
209
- /* packet queueing error */
210
- if (amdtp_streaming_error(&efw->tx_stream))
211
- stop_stream(efw, &efw->tx_stream);
212
- if (amdtp_streaming_error(&efw->rx_stream))
213
- stop_stream(efw, &efw->rx_stream);
214
-
215
- /* stop streams if rate is different */
197
+ // stop streams if rate is different.
216198 err = snd_efw_command_get_sampling_rate(efw, &curr_rate);
217199 if (err < 0)
218
- goto end;
200
+ return err;
219201 if (rate == 0)
220202 rate = curr_rate;
221203 if (rate != curr_rate) {
222
- stop_stream(efw, &efw->tx_stream);
223
- stop_stream(efw, &efw->rx_stream);
204
+ amdtp_domain_stop(&efw->domain);
205
+
206
+ cmp_connection_break(&efw->out_conn);
207
+ cmp_connection_break(&efw->in_conn);
208
+
209
+ cmp_connection_release(&efw->out_conn);
210
+ cmp_connection_release(&efw->in_conn);
224211 }
225212
226
- /* master should be always running */
227
- if (!amdtp_stream_running(&efw->rx_stream)) {
213
+ if (efw->substreams_counter == 0 || rate != curr_rate) {
214
+ unsigned int mode;
215
+
228216 err = snd_efw_command_set_sampling_rate(efw, rate);
229217 if (err < 0)
230
- goto end;
218
+ return err;
231219
220
+ err = snd_efw_get_multiplier_mode(rate, &mode);
221
+ if (err < 0)
222
+ return err;
223
+
224
+ err = keep_resources(efw, &efw->tx_stream, rate, mode);
225
+ if (err < 0)
226
+ return err;
227
+
228
+ err = keep_resources(efw, &efw->rx_stream, rate, mode);
229
+ if (err < 0) {
230
+ cmp_connection_release(&efw->in_conn);
231
+ return err;
232
+ }
233
+
234
+ err = amdtp_domain_set_events_per_period(&efw->domain,
235
+ frames_per_period, frames_per_buffer);
236
+ if (err < 0) {
237
+ cmp_connection_release(&efw->in_conn);
238
+ cmp_connection_release(&efw->out_conn);
239
+ return err;
240
+ }
241
+ }
242
+
243
+ return 0;
244
+}
245
+
246
+int snd_efw_stream_start_duplex(struct snd_efw *efw)
247
+{
248
+ unsigned int rate;
249
+ int err = 0;
250
+
251
+ // Need no substreams.
252
+ if (efw->substreams_counter == 0)
253
+ return -EIO;
254
+
255
+ if (amdtp_streaming_error(&efw->rx_stream) ||
256
+ amdtp_streaming_error(&efw->tx_stream)) {
257
+ amdtp_domain_stop(&efw->domain);
258
+ cmp_connection_break(&efw->out_conn);
259
+ cmp_connection_break(&efw->in_conn);
260
+ }
261
+
262
+ err = snd_efw_command_get_sampling_rate(efw, &rate);
263
+ if (err < 0)
264
+ return err;
265
+
266
+ if (!amdtp_stream_running(&efw->rx_stream)) {
232267 err = start_stream(efw, &efw->rx_stream, rate);
233
- if (err < 0) {
234
- dev_err(&efw->unit->device,
235
- "fail to start AMDTP master stream:%d\n", err);
236
- goto end;
268
+ if (err < 0)
269
+ goto error;
270
+
271
+ err = start_stream(efw, &efw->tx_stream, rate);
272
+ if (err < 0)
273
+ goto error;
274
+
275
+ err = amdtp_domain_start(&efw->domain, 0);
276
+ if (err < 0)
277
+ goto error;
278
+
279
+ // Wait first callback.
280
+ if (!amdtp_stream_wait_callback(&efw->rx_stream,
281
+ CALLBACK_TIMEOUT) ||
282
+ !amdtp_stream_wait_callback(&efw->tx_stream,
283
+ CALLBACK_TIMEOUT)) {
284
+ err = -ETIMEDOUT;
285
+ goto error;
237286 }
238287 }
239288
240
- /* start slave if needed */
241
- if (efw->capture_substreams > 0 &&
242
- !amdtp_stream_running(&efw->tx_stream)) {
243
- err = start_stream(efw, &efw->tx_stream, rate);
244
- if (err < 0) {
245
- dev_err(&efw->unit->device,
246
- "fail to start AMDTP slave stream:%d\n", err);
247
- stop_stream(efw, &efw->rx_stream);
248
- }
249
- }
250
-end:
289
+ return 0;
290
+error:
291
+ amdtp_domain_stop(&efw->domain);
292
+
293
+ cmp_connection_break(&efw->out_conn);
294
+ cmp_connection_break(&efw->in_conn);
295
+
251296 return err;
252297 }
253298
254299 void snd_efw_stream_stop_duplex(struct snd_efw *efw)
255300 {
256
- if (efw->capture_substreams == 0) {
257
- stop_stream(efw, &efw->tx_stream);
301
+ if (efw->substreams_counter == 0) {
302
+ amdtp_domain_stop(&efw->domain);
258303
259
- if (efw->playback_substreams == 0)
260
- stop_stream(efw, &efw->rx_stream);
304
+ cmp_connection_break(&efw->out_conn);
305
+ cmp_connection_break(&efw->in_conn);
306
+
307
+ cmp_connection_release(&efw->out_conn);
308
+ cmp_connection_release(&efw->in_conn);
261309 }
262310 }
263311
264312 void snd_efw_stream_update_duplex(struct snd_efw *efw)
265313 {
266
- if (cmp_connection_update(&efw->out_conn) < 0 ||
267
- cmp_connection_update(&efw->in_conn) < 0) {
268
- stop_stream(efw, &efw->rx_stream);
269
- stop_stream(efw, &efw->tx_stream);
270
- } else {
271
- amdtp_stream_update(&efw->rx_stream);
272
- amdtp_stream_update(&efw->tx_stream);
273
- }
314
+ amdtp_domain_stop(&efw->domain);
315
+
316
+ cmp_connection_break(&efw->out_conn);
317
+ cmp_connection_break(&efw->in_conn);
318
+
319
+ amdtp_stream_pcm_abort(&efw->rx_stream);
320
+ amdtp_stream_pcm_abort(&efw->tx_stream);
274321 }
275322
276323 void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
277324 {
325
+ amdtp_domain_destroy(&efw->domain);
326
+
278327 destroy_stream(efw, &efw->rx_stream);
279328 destroy_stream(efw, &efw->tx_stream);
280329 }