1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ff-stream.c - a part of driver for RME Fireface series 4 * 5 * Copyright (c) 2015-2017 Takashi Sakamoto 6 */ 7 8 #include "ff.h" 9 10 #define CALLBACK_TIMEOUT_MS 200 11 12 int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc, 13 enum snd_ff_stream_mode *mode) 14 { 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, 23 }; 24 25 if (sfc >= CIP_SFC_COUNT) 26 return -EINVAL; 27 28 *mode = modes[sfc]; 29 30 return 0; 31 } 32 33 static inline void finish_session(struct snd_ff *ff) 34 { 35 amdtp_stream_stop(&ff->tx_stream); 36 amdtp_stream_stop(&ff->rx_stream); 37 38 ff->spec->protocol->finish_session(ff); 39 ff->spec->protocol->switch_fetching_mode(ff, false); 40 } 41 42 static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) 43 { 44 int err; 45 struct fw_iso_resources *resources; 46 struct amdtp_stream *stream; 47 48 if (dir == AMDTP_IN_STREAM) { 49 resources = &ff->tx_resources; 50 stream = &ff->tx_stream; 51 } else { 52 resources = &ff->rx_resources; 53 stream = &ff->rx_stream; 54 } 55 56 err = fw_iso_resources_init(resources, ff->unit); 57 if (err < 0) 58 return err; 59 60 err = amdtp_ff_init(stream, ff->unit, dir); 61 if (err < 0) 62 fw_iso_resources_destroy(resources); 63 64 return err; 65 } 66 67 static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) 68 { 69 if (dir == AMDTP_IN_STREAM) { 70 amdtp_stream_destroy(&ff->tx_stream); 71 fw_iso_resources_destroy(&ff->tx_resources); 72 } else { 73 amdtp_stream_destroy(&ff->rx_stream); 74 fw_iso_resources_destroy(&ff->rx_resources); 75 } 76 } 77 78 int snd_ff_stream_init_duplex(struct snd_ff *ff) 79 { 80 int err; 81 82 err = init_stream(ff, AMDTP_OUT_STREAM); 83 if (err < 0) 84 goto end; 85 86 err = init_stream(ff, AMDTP_IN_STREAM); 87 if (err < 0) 88 destroy_stream(ff, AMDTP_OUT_STREAM); 89 end: 90 return err; 91 } 92 93 /* 94 * This function should be called before starting streams or after stopping 95 * streams. 96 */ 97 void snd_ff_stream_destroy_duplex(struct snd_ff *ff) 98 { 99 destroy_stream(ff, AMDTP_IN_STREAM); 100 destroy_stream(ff, AMDTP_OUT_STREAM); 101 } 102 103 int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) 104 { 105 unsigned int curr_rate; 106 enum snd_ff_clock_src src; 107 int err; 108 109 err = ff->spec->protocol->get_clock(ff, &curr_rate, &src); 110 if (err < 0) 111 return err; 112 113 if (ff->substreams_counter == 0 || curr_rate != rate) { 114 enum snd_ff_stream_mode mode; 115 int i; 116 117 finish_session(ff); 118 119 fw_iso_resources_free(&ff->tx_resources); 120 fw_iso_resources_free(&ff->rx_resources); 121 122 for (i = 0; i < CIP_SFC_COUNT; ++i) { 123 if (amdtp_rate_table[i] == rate) 124 break; 125 } 126 if (i >= CIP_SFC_COUNT) 127 return -EINVAL; 128 129 err = snd_ff_stream_get_multiplier_mode(i, &mode); 130 if (err < 0) 131 return err; 132 133 err = amdtp_ff_set_parameters(&ff->tx_stream, rate, 134 ff->spec->pcm_capture_channels[mode]); 135 if (err < 0) 136 return err; 137 138 err = amdtp_ff_set_parameters(&ff->rx_stream, rate, 139 ff->spec->pcm_playback_channels[mode]); 140 if (err < 0) 141 return err; 142 143 err = ff->spec->protocol->allocate_resources(ff, rate); 144 if (err < 0) 145 return err; 146 } 147 148 return 0; 149 } 150 151 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) 152 { 153 int err; 154 155 if (ff->substreams_counter == 0) 156 return 0; 157 158 if (amdtp_streaming_error(&ff->tx_stream) || 159 amdtp_streaming_error(&ff->rx_stream)) 160 finish_session(ff); 161 162 /* 163 * Regardless of current source of clock signal, drivers transfer some 164 * packets. Then, the device transfers packets. 165 */ 166 if (!amdtp_stream_running(&ff->rx_stream)) { 167 err = ff->spec->protocol->begin_session(ff, rate); 168 if (err < 0) 169 goto error; 170 171 err = amdtp_stream_start(&ff->rx_stream, 172 ff->rx_resources.channel, 173 fw_parent_device(ff->unit)->max_speed); 174 if (err < 0) 175 goto error; 176 177 if (!amdtp_stream_wait_callback(&ff->rx_stream, 178 CALLBACK_TIMEOUT_MS)) { 179 err = -ETIMEDOUT; 180 goto error; 181 } 182 183 err = ff->spec->protocol->switch_fetching_mode(ff, true); 184 if (err < 0) 185 goto error; 186 } 187 188 if (!amdtp_stream_running(&ff->tx_stream)) { 189 err = amdtp_stream_start(&ff->tx_stream, 190 ff->tx_resources.channel, 191 fw_parent_device(ff->unit)->max_speed); 192 if (err < 0) 193 goto error; 194 195 if (!amdtp_stream_wait_callback(&ff->tx_stream, 196 CALLBACK_TIMEOUT_MS)) { 197 err = -ETIMEDOUT; 198 goto error; 199 } 200 } 201 202 return 0; 203 error: 204 finish_session(ff); 205 206 return err; 207 } 208 209 void snd_ff_stream_stop_duplex(struct snd_ff *ff) 210 { 211 if (ff->substreams_counter == 0) { 212 finish_session(ff); 213 214 fw_iso_resources_free(&ff->tx_resources); 215 fw_iso_resources_free(&ff->rx_resources); 216 } 217 } 218 219 void snd_ff_stream_update_duplex(struct snd_ff *ff) 220 { 221 // The device discontinue to transfer packets. 222 amdtp_stream_pcm_abort(&ff->tx_stream); 223 amdtp_stream_stop(&ff->tx_stream); 224 225 amdtp_stream_pcm_abort(&ff->rx_stream); 226 amdtp_stream_stop(&ff->rx_stream); 227 } 228 229 void snd_ff_stream_lock_changed(struct snd_ff *ff) 230 { 231 ff->dev_lock_changed = true; 232 wake_up(&ff->hwdep_wait); 233 } 234 235 int snd_ff_stream_lock_try(struct snd_ff *ff) 236 { 237 int err; 238 239 spin_lock_irq(&ff->lock); 240 241 /* user land lock this */ 242 if (ff->dev_lock_count < 0) { 243 err = -EBUSY; 244 goto end; 245 } 246 247 /* this is the first time */ 248 if (ff->dev_lock_count++ == 0) 249 snd_ff_stream_lock_changed(ff); 250 err = 0; 251 end: 252 spin_unlock_irq(&ff->lock); 253 return err; 254 } 255 256 void snd_ff_stream_lock_release(struct snd_ff *ff) 257 { 258 spin_lock_irq(&ff->lock); 259 260 if (WARN_ON(ff->dev_lock_count <= 0)) 261 goto end; 262 if (--ff->dev_lock_count == 0) 263 snd_ff_stream_lock_changed(ff); 264 end: 265 spin_unlock_irq(&ff->lock); 266 } 267