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