1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * fireworks_stream.c - a part of driver for Fireworks based devices 4 * 5 * Copyright (c) 2013-2014 Takashi Sakamoto 6 */ 7 #include "./fireworks.h" 8 9 #define CALLBACK_TIMEOUT 100 10 11 static int 12 init_stream(struct snd_efw *efw, struct amdtp_stream *stream) 13 { 14 struct cmp_connection *conn; 15 enum cmp_direction c_dir; 16 enum amdtp_stream_direction s_dir; 17 int err; 18 19 if (stream == &efw->tx_stream) { 20 conn = &efw->out_conn; 21 c_dir = CMP_OUTPUT; 22 s_dir = AMDTP_IN_STREAM; 23 } else { 24 conn = &efw->in_conn; 25 c_dir = CMP_INPUT; 26 s_dir = AMDTP_OUT_STREAM; 27 } 28 29 err = cmp_connection_init(conn, efw->unit, c_dir, 0); 30 if (err < 0) 31 goto end; 32 33 err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING); 34 if (err < 0) { 35 amdtp_stream_destroy(stream); 36 cmp_connection_destroy(conn); 37 } 38 end: 39 return err; 40 } 41 42 static void 43 stop_stream(struct snd_efw *efw, struct amdtp_stream *stream) 44 { 45 amdtp_stream_stop(stream); 46 47 if (stream == &efw->tx_stream) 48 cmp_connection_break(&efw->out_conn); 49 else 50 cmp_connection_break(&efw->in_conn); 51 } 52 53 static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, 54 unsigned int rate) 55 { 56 struct cmp_connection *conn; 57 int err; 58 59 if (stream == &efw->tx_stream) 60 conn = &efw->out_conn; 61 else 62 conn = &efw->in_conn; 63 64 // Establish connection via CMP. 65 err = cmp_connection_establish(conn); 66 if (err < 0) 67 return err; 68 69 // Start amdtp stream. 70 err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); 71 if (err < 0) { 72 cmp_connection_break(conn); 73 return err; 74 } 75 76 // Wait first callback. 77 if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { 78 amdtp_stream_stop(stream); 79 cmp_connection_break(conn); 80 return -ETIMEDOUT; 81 } 82 83 return 0; 84 } 85 86 /* 87 * This function should be called before starting the stream or after stopping 88 * the streams. 89 */ 90 static void 91 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) 92 { 93 struct cmp_connection *conn; 94 95 if (stream == &efw->tx_stream) 96 conn = &efw->out_conn; 97 else 98 conn = &efw->in_conn; 99 100 amdtp_stream_destroy(stream); 101 cmp_connection_destroy(conn); 102 } 103 104 static int 105 check_connection_used_by_others(struct snd_efw *efw, struct amdtp_stream *s) 106 { 107 struct cmp_connection *conn; 108 bool used; 109 int err; 110 111 if (s == &efw->tx_stream) 112 conn = &efw->out_conn; 113 else 114 conn = &efw->in_conn; 115 116 err = cmp_connection_check_used(conn, &used); 117 if ((err >= 0) && used && !amdtp_stream_running(s)) { 118 dev_err(&efw->unit->device, 119 "Connection established by others: %cPCR[%d]\n", 120 (conn->direction == CMP_OUTPUT) ? 'o' : 'i', 121 conn->pcr_index); 122 err = -EBUSY; 123 } 124 125 return err; 126 } 127 128 int snd_efw_stream_init_duplex(struct snd_efw *efw) 129 { 130 int err; 131 132 err = init_stream(efw, &efw->tx_stream); 133 if (err < 0) 134 goto end; 135 /* Fireworks transmits NODATA packets with TAG0. */ 136 efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; 137 /* Fireworks has its own meaning for dbc. */ 138 efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; 139 /* Fireworks reset dbc at bus reset. */ 140 efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; 141 /* 142 * But Recent firmwares starts packets with non-zero dbc. 143 * Driver version 5.7.6 installs firmware version 5.7.3. 144 */ 145 if (efw->is_fireworks3 && 146 (efw->firmware_version == 0x5070000 || 147 efw->firmware_version == 0x5070300 || 148 efw->firmware_version == 0x5080000)) 149 efw->tx_stream.ctx_data.tx.first_dbc = 0x02; 150 /* AudioFire9 always reports wrong dbs. */ 151 if (efw->is_af9) 152 efw->tx_stream.flags |= CIP_WRONG_DBS; 153 /* Firmware version 5.5 reports fixed interval for dbc. */ 154 if (efw->firmware_version == 0x5050000) 155 efw->tx_stream.ctx_data.tx.dbc_interval = 8; 156 157 err = init_stream(efw, &efw->rx_stream); 158 if (err < 0) { 159 destroy_stream(efw, &efw->tx_stream); 160 goto end; 161 } 162 163 /* set IEC61883 compliant mode (actually not fully compliant...) */ 164 err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); 165 if (err < 0) { 166 destroy_stream(efw, &efw->tx_stream); 167 destroy_stream(efw, &efw->rx_stream); 168 } 169 end: 170 return err; 171 } 172 173 static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream, 174 unsigned int rate, unsigned int mode) 175 { 176 unsigned int pcm_channels; 177 unsigned int midi_ports; 178 struct cmp_connection *conn; 179 int err; 180 181 if (stream == &efw->tx_stream) { 182 pcm_channels = efw->pcm_capture_channels[mode]; 183 midi_ports = efw->midi_out_ports; 184 conn = &efw->out_conn; 185 } else { 186 pcm_channels = efw->pcm_playback_channels[mode]; 187 midi_ports = efw->midi_in_ports; 188 conn = &efw->in_conn; 189 } 190 191 err = amdtp_am824_set_parameters(stream, rate, pcm_channels, 192 midi_ports, false); 193 if (err < 0) 194 return err; 195 196 return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream)); 197 } 198 199 int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) 200 { 201 unsigned int curr_rate; 202 int err; 203 204 // Considering JACK/FFADO streaming: 205 // TODO: This can be removed hwdep functionality becomes popular. 206 err = check_connection_used_by_others(efw, &efw->rx_stream); 207 if (err < 0) 208 return err; 209 210 // stop streams if rate is different. 211 err = snd_efw_command_get_sampling_rate(efw, &curr_rate); 212 if (err < 0) 213 return err; 214 if (rate == 0) 215 rate = curr_rate; 216 if (rate != curr_rate) { 217 stop_stream(efw, &efw->tx_stream); 218 stop_stream(efw, &efw->rx_stream); 219 220 cmp_connection_release(&efw->out_conn); 221 cmp_connection_release(&efw->in_conn); 222 } 223 224 if (efw->substreams_counter == 0 || rate != curr_rate) { 225 unsigned int mode; 226 227 err = snd_efw_command_set_sampling_rate(efw, rate); 228 if (err < 0) 229 return err; 230 231 err = snd_efw_get_multiplier_mode(rate, &mode); 232 if (err < 0) 233 return err; 234 235 err = keep_resources(efw, &efw->tx_stream, rate, mode); 236 if (err < 0) 237 return err; 238 239 err = keep_resources(efw, &efw->rx_stream, rate, mode); 240 if (err < 0) { 241 cmp_connection_release(&efw->in_conn); 242 return err; 243 } 244 } 245 246 return 0; 247 } 248 249 int snd_efw_stream_start_duplex(struct snd_efw *efw) 250 { 251 unsigned int rate; 252 int err = 0; 253 254 // Need no substreams. 255 if (efw->substreams_counter == 0) 256 return -EIO; 257 258 err = snd_efw_command_get_sampling_rate(efw, &rate); 259 if (err < 0) 260 return err; 261 262 if (amdtp_streaming_error(&efw->rx_stream) || 263 amdtp_streaming_error(&efw->tx_stream)) { 264 stop_stream(efw, &efw->rx_stream); 265 stop_stream(efw, &efw->tx_stream); 266 } 267 268 /* master should be always running */ 269 if (!amdtp_stream_running(&efw->rx_stream)) { 270 err = start_stream(efw, &efw->rx_stream, rate); 271 if (err < 0) { 272 dev_err(&efw->unit->device, 273 "fail to start AMDTP master stream:%d\n", err); 274 goto error; 275 } 276 } 277 278 if (!amdtp_stream_running(&efw->tx_stream)) { 279 err = start_stream(efw, &efw->tx_stream, rate); 280 if (err < 0) { 281 dev_err(&efw->unit->device, 282 "fail to start AMDTP slave stream:%d\n", err); 283 goto error; 284 } 285 } 286 287 return 0; 288 error: 289 stop_stream(efw, &efw->rx_stream); 290 stop_stream(efw, &efw->tx_stream); 291 return err; 292 } 293 294 void snd_efw_stream_stop_duplex(struct snd_efw *efw) 295 { 296 if (efw->substreams_counter == 0) { 297 stop_stream(efw, &efw->tx_stream); 298 stop_stream(efw, &efw->rx_stream); 299 300 cmp_connection_release(&efw->out_conn); 301 cmp_connection_release(&efw->in_conn); 302 } 303 } 304 305 void snd_efw_stream_update_duplex(struct snd_efw *efw) 306 { 307 if (cmp_connection_update(&efw->out_conn) < 0 || 308 cmp_connection_update(&efw->in_conn) < 0) { 309 stop_stream(efw, &efw->rx_stream); 310 stop_stream(efw, &efw->tx_stream); 311 } else { 312 amdtp_stream_update(&efw->rx_stream); 313 amdtp_stream_update(&efw->tx_stream); 314 } 315 } 316 317 void snd_efw_stream_destroy_duplex(struct snd_efw *efw) 318 { 319 destroy_stream(efw, &efw->rx_stream); 320 destroy_stream(efw, &efw->tx_stream); 321 } 322 323 void snd_efw_stream_lock_changed(struct snd_efw *efw) 324 { 325 efw->dev_lock_changed = true; 326 wake_up(&efw->hwdep_wait); 327 } 328 329 int snd_efw_stream_lock_try(struct snd_efw *efw) 330 { 331 int err; 332 333 spin_lock_irq(&efw->lock); 334 335 /* user land lock this */ 336 if (efw->dev_lock_count < 0) { 337 err = -EBUSY; 338 goto end; 339 } 340 341 /* this is the first time */ 342 if (efw->dev_lock_count++ == 0) 343 snd_efw_stream_lock_changed(efw); 344 err = 0; 345 end: 346 spin_unlock_irq(&efw->lock); 347 return err; 348 } 349 350 void snd_efw_stream_lock_release(struct snd_efw *efw) 351 { 352 spin_lock_irq(&efw->lock); 353 354 if (WARN_ON(efw->dev_lock_count <= 0)) 355 goto end; 356 if (--efw->dev_lock_count == 0) 357 snd_efw_stream_lock_changed(efw); 358 end: 359 spin_unlock_irq(&efw->lock); 360 } 361