1 // SPDX-License-Identifier: GPL-2.0-only
3 * ff-stream.c - a part of driver for RME Fireface series
5 * Copyright (c) 2015-2017 Takashi Sakamoto
10 #define CALLBACK_TIMEOUT_MS 200
12 int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc
,
13 enum snd_ff_stream_mode
*mode
)
15 static const enum snd_ff_stream_mode modes
[] = {
16 [CIP_SFC_32000
] = SND_FF_STREAM_MODE_LOW
,
17 [CIP_SFC_44100
] = SND_FF_STREAM_MODE_LOW
,
18 [CIP_SFC_48000
] = SND_FF_STREAM_MODE_LOW
,
19 [CIP_SFC_88200
] = SND_FF_STREAM_MODE_MID
,
20 [CIP_SFC_96000
] = SND_FF_STREAM_MODE_MID
,
21 [CIP_SFC_176400
] = SND_FF_STREAM_MODE_HIGH
,
22 [CIP_SFC_192000
] = SND_FF_STREAM_MODE_HIGH
,
25 if (sfc
>= CIP_SFC_COUNT
)
33 static inline void finish_session(struct snd_ff
*ff
)
35 ff
->spec
->protocol
->finish_session(ff
);
36 ff
->spec
->protocol
->switch_fetching_mode(ff
, false);
39 static int init_stream(struct snd_ff
*ff
, struct amdtp_stream
*s
)
41 struct fw_iso_resources
*resources
;
42 enum amdtp_stream_direction dir
;
45 if (s
== &ff
->tx_stream
) {
46 resources
= &ff
->tx_resources
;
47 dir
= AMDTP_IN_STREAM
;
49 resources
= &ff
->rx_resources
;
50 dir
= AMDTP_OUT_STREAM
;
53 err
= fw_iso_resources_init(resources
, ff
->unit
);
57 err
= amdtp_ff_init(s
, ff
->unit
, dir
);
59 fw_iso_resources_destroy(resources
);
64 static void destroy_stream(struct snd_ff
*ff
, struct amdtp_stream
*s
)
66 amdtp_stream_destroy(s
);
68 if (s
== &ff
->tx_stream
)
69 fw_iso_resources_destroy(&ff
->tx_resources
);
71 fw_iso_resources_destroy(&ff
->rx_resources
);
74 int snd_ff_stream_init_duplex(struct snd_ff
*ff
)
78 err
= init_stream(ff
, &ff
->rx_stream
);
82 err
= init_stream(ff
, &ff
->tx_stream
);
84 destroy_stream(ff
, &ff
->rx_stream
);
88 err
= amdtp_domain_init(&ff
->domain
);
90 destroy_stream(ff
, &ff
->rx_stream
);
91 destroy_stream(ff
, &ff
->tx_stream
);
98 * This function should be called before starting streams or after stopping
101 void snd_ff_stream_destroy_duplex(struct snd_ff
*ff
)
103 amdtp_domain_destroy(&ff
->domain
);
105 destroy_stream(ff
, &ff
->rx_stream
);
106 destroy_stream(ff
, &ff
->tx_stream
);
109 int snd_ff_stream_reserve_duplex(struct snd_ff
*ff
, unsigned int rate
,
110 unsigned int frames_per_period
,
111 unsigned int frames_per_buffer
)
113 unsigned int curr_rate
;
114 enum snd_ff_clock_src src
;
117 err
= ff
->spec
->protocol
->get_clock(ff
, &curr_rate
, &src
);
121 if (ff
->substreams_counter
== 0 || curr_rate
!= rate
) {
122 enum snd_ff_stream_mode mode
;
125 amdtp_domain_stop(&ff
->domain
);
128 fw_iso_resources_free(&ff
->tx_resources
);
129 fw_iso_resources_free(&ff
->rx_resources
);
131 for (i
= 0; i
< CIP_SFC_COUNT
; ++i
) {
132 if (amdtp_rate_table
[i
] == rate
)
135 if (i
>= CIP_SFC_COUNT
)
138 err
= snd_ff_stream_get_multiplier_mode(i
, &mode
);
142 err
= amdtp_ff_set_parameters(&ff
->tx_stream
, rate
,
143 ff
->spec
->pcm_capture_channels
[mode
]);
147 err
= amdtp_ff_set_parameters(&ff
->rx_stream
, rate
,
148 ff
->spec
->pcm_playback_channels
[mode
]);
152 err
= ff
->spec
->protocol
->allocate_resources(ff
, rate
);
156 err
= amdtp_domain_set_events_per_period(&ff
->domain
,
157 frames_per_period
, frames_per_buffer
);
159 fw_iso_resources_free(&ff
->tx_resources
);
160 fw_iso_resources_free(&ff
->rx_resources
);
168 int snd_ff_stream_start_duplex(struct snd_ff
*ff
, unsigned int rate
)
172 if (ff
->substreams_counter
== 0)
175 if (amdtp_streaming_error(&ff
->tx_stream
) ||
176 amdtp_streaming_error(&ff
->rx_stream
)) {
177 amdtp_domain_stop(&ff
->domain
);
182 * Regardless of current source of clock signal, drivers transfer some
183 * packets. Then, the device transfers packets.
185 if (!amdtp_stream_running(&ff
->rx_stream
)) {
186 int spd
= fw_parent_device(ff
->unit
)->max_speed
;
188 err
= ff
->spec
->protocol
->begin_session(ff
, rate
);
192 err
= amdtp_domain_add_stream(&ff
->domain
, &ff
->rx_stream
,
193 ff
->rx_resources
.channel
, spd
);
197 err
= amdtp_domain_add_stream(&ff
->domain
, &ff
->tx_stream
,
198 ff
->tx_resources
.channel
, spd
);
202 err
= amdtp_domain_start(&ff
->domain
, 0);
206 if (!amdtp_stream_wait_callback(&ff
->rx_stream
,
207 CALLBACK_TIMEOUT_MS
) ||
208 !amdtp_stream_wait_callback(&ff
->tx_stream
,
209 CALLBACK_TIMEOUT_MS
)) {
214 err
= ff
->spec
->protocol
->switch_fetching_mode(ff
, true);
221 amdtp_domain_stop(&ff
->domain
);
227 void snd_ff_stream_stop_duplex(struct snd_ff
*ff
)
229 if (ff
->substreams_counter
== 0) {
230 amdtp_domain_stop(&ff
->domain
);
233 fw_iso_resources_free(&ff
->tx_resources
);
234 fw_iso_resources_free(&ff
->rx_resources
);
238 void snd_ff_stream_update_duplex(struct snd_ff
*ff
)
240 amdtp_domain_stop(&ff
->domain
);
242 // The device discontinue to transfer packets.
243 amdtp_stream_pcm_abort(&ff
->tx_stream
);
244 amdtp_stream_pcm_abort(&ff
->rx_stream
);
247 void snd_ff_stream_lock_changed(struct snd_ff
*ff
)
249 ff
->dev_lock_changed
= true;
250 wake_up(&ff
->hwdep_wait
);
253 int snd_ff_stream_lock_try(struct snd_ff
*ff
)
257 spin_lock_irq(&ff
->lock
);
259 /* user land lock this */
260 if (ff
->dev_lock_count
< 0) {
265 /* this is the first time */
266 if (ff
->dev_lock_count
++ == 0)
267 snd_ff_stream_lock_changed(ff
);
270 spin_unlock_irq(&ff
->lock
);
274 void snd_ff_stream_lock_release(struct snd_ff
*ff
)
276 spin_lock_irq(&ff
->lock
);
278 if (WARN_ON(ff
->dev_lock_count
<= 0))
280 if (--ff
->dev_lock_count
== 0)
281 snd_ff_stream_lock_changed(ff
);
283 spin_unlock_irq(&ff
->lock
);