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_pcm_abort(stream); 46 amdtp_stream_stop(stream); 47 48 if (stream == &efw->tx_stream) 49 cmp_connection_break(&efw->out_conn); 50 else 51 cmp_connection_break(&efw->in_conn); 52 } 53 54 static int 55 start_stream(struct snd_efw *efw, struct amdtp_stream *stream, 56 unsigned int sampling_rate) 57 { 58 struct cmp_connection *conn; 59 unsigned int mode, pcm_channels, midi_ports; 60 int err; 61 62 err = snd_efw_get_multiplier_mode(sampling_rate, &mode); 63 if (err < 0) 64 goto end; 65 if (stream == &efw->tx_stream) { 66 conn = &efw->out_conn; 67 pcm_channels = efw->pcm_capture_channels[mode]; 68 midi_ports = efw->midi_out_ports; 69 } else { 70 conn = &efw->in_conn; 71 pcm_channels = efw->pcm_playback_channels[mode]; 72 midi_ports = efw->midi_in_ports; 73 } 74 75 err = amdtp_am824_set_parameters(stream, sampling_rate, 76 pcm_channels, midi_ports, false); 77 if (err < 0) 78 goto end; 79 80 /* establish connection via CMP */ 81 err = cmp_connection_establish(conn, 82 amdtp_stream_get_max_payload(stream)); 83 if (err < 0) 84 goto end; 85 86 /* start amdtp stream */ 87 err = amdtp_stream_start(stream, 88 conn->resources.channel, 89 conn->speed); 90 if (err < 0) { 91 stop_stream(efw, stream); 92 goto end; 93 } 94 95 /* wait first callback */ 96 if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { 97 stop_stream(efw, stream); 98 err = -ETIMEDOUT; 99 } 100 end: 101 return err; 102 } 103 104 /* 105 * This function should be called before starting the stream or after stopping 106 * the streams. 107 */ 108 static void 109 destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) 110 { 111 struct cmp_connection *conn; 112 113 if (stream == &efw->tx_stream) 114 conn = &efw->out_conn; 115 else 116 conn = &efw->in_conn; 117 118 amdtp_stream_destroy(stream); 119 cmp_connection_destroy(conn); 120 } 121 122 static int 123 check_connection_used_by_others(struct snd_efw *efw, struct amdtp_stream *s) 124 { 125 struct cmp_connection *conn; 126 bool used; 127 int err; 128 129 if (s == &efw->tx_stream) 130 conn = &efw->out_conn; 131 else 132 conn = &efw->in_conn; 133 134 err = cmp_connection_check_used(conn, &used); 135 if ((err >= 0) && used && !amdtp_stream_running(s)) { 136 dev_err(&efw->unit->device, 137 "Connection established by others: %cPCR[%d]\n", 138 (conn->direction == CMP_OUTPUT) ? 'o' : 'i', 139 conn->pcr_index); 140 err = -EBUSY; 141 } 142 143 return err; 144 } 145 146 int snd_efw_stream_init_duplex(struct snd_efw *efw) 147 { 148 int err; 149 150 err = init_stream(efw, &efw->tx_stream); 151 if (err < 0) 152 goto end; 153 /* Fireworks transmits NODATA packets with TAG0. */ 154 efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; 155 /* Fireworks has its own meaning for dbc. */ 156 efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; 157 /* Fireworks reset dbc at bus reset. */ 158 efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; 159 /* 160 * But Recent firmwares starts packets with non-zero dbc. 161 * Driver version 5.7.6 installs firmware version 5.7.3. 162 */ 163 if (efw->is_fireworks3 && 164 (efw->firmware_version == 0x5070000 || 165 efw->firmware_version == 0x5070300 || 166 efw->firmware_version == 0x5080000)) 167 efw->tx_stream.tx_first_dbc = 0x02; 168 /* AudioFire9 always reports wrong dbs. */ 169 if (efw->is_af9) 170 efw->tx_stream.flags |= CIP_WRONG_DBS; 171 /* Firmware version 5.5 reports fixed interval for dbc. */ 172 if (efw->firmware_version == 0x5050000) 173 efw->tx_stream.tx_dbc_interval = 8; 174 175 err = init_stream(efw, &efw->rx_stream); 176 if (err < 0) { 177 destroy_stream(efw, &efw->tx_stream); 178 goto end; 179 } 180 181 /* set IEC61883 compliant mode (actually not fully compliant...) */ 182 err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); 183 if (err < 0) { 184 destroy_stream(efw, &efw->tx_stream); 185 destroy_stream(efw, &efw->rx_stream); 186 } 187 end: 188 return err; 189 } 190 191 int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) 192 { 193 unsigned int curr_rate; 194 int err = 0; 195 196 /* Need no substreams */ 197 if (efw->playback_substreams == 0 && efw->capture_substreams == 0) 198 goto end; 199 200 /* 201 * Considering JACK/FFADO streaming: 202 * TODO: This can be removed hwdep functionality becomes popular. 203 */ 204 err = check_connection_used_by_others(efw, &efw->rx_stream); 205 if (err < 0) 206 goto end; 207 208 /* packet queueing error */ 209 if (amdtp_streaming_error(&efw->tx_stream)) 210 stop_stream(efw, &efw->tx_stream); 211 if (amdtp_streaming_error(&efw->rx_stream)) 212 stop_stream(efw, &efw->rx_stream); 213 214 /* stop streams if rate is different */ 215 err = snd_efw_command_get_sampling_rate(efw, &curr_rate); 216 if (err < 0) 217 goto end; 218 if (rate == 0) 219 rate = curr_rate; 220 if (rate != curr_rate) { 221 stop_stream(efw, &efw->tx_stream); 222 stop_stream(efw, &efw->rx_stream); 223 } 224 225 /* master should be always running */ 226 if (!amdtp_stream_running(&efw->rx_stream)) { 227 err = snd_efw_command_set_sampling_rate(efw, rate); 228 if (err < 0) 229 goto end; 230 231 err = start_stream(efw, &efw->rx_stream, rate); 232 if (err < 0) { 233 dev_err(&efw->unit->device, 234 "fail to start AMDTP master stream:%d\n", err); 235 goto end; 236 } 237 } 238 239 /* start slave if needed */ 240 if (efw->capture_substreams > 0 && 241 !amdtp_stream_running(&efw->tx_stream)) { 242 err = start_stream(efw, &efw->tx_stream, rate); 243 if (err < 0) { 244 dev_err(&efw->unit->device, 245 "fail to start AMDTP slave stream:%d\n", err); 246 stop_stream(efw, &efw->rx_stream); 247 } 248 } 249 end: 250 return err; 251 } 252 253 void snd_efw_stream_stop_duplex(struct snd_efw *efw) 254 { 255 if (efw->capture_substreams == 0) { 256 stop_stream(efw, &efw->tx_stream); 257 258 if (efw->playback_substreams == 0) 259 stop_stream(efw, &efw->rx_stream); 260 } 261 } 262 263 void snd_efw_stream_update_duplex(struct snd_efw *efw) 264 { 265 if (cmp_connection_update(&efw->out_conn) < 0 || 266 cmp_connection_update(&efw->in_conn) < 0) { 267 stop_stream(efw, &efw->rx_stream); 268 stop_stream(efw, &efw->tx_stream); 269 } else { 270 amdtp_stream_update(&efw->rx_stream); 271 amdtp_stream_update(&efw->tx_stream); 272 } 273 } 274 275 void snd_efw_stream_destroy_duplex(struct snd_efw *efw) 276 { 277 destroy_stream(efw, &efw->rx_stream); 278 destroy_stream(efw, &efw->tx_stream); 279 } 280 281 void snd_efw_stream_lock_changed(struct snd_efw *efw) 282 { 283 efw->dev_lock_changed = true; 284 wake_up(&efw->hwdep_wait); 285 } 286 287 int snd_efw_stream_lock_try(struct snd_efw *efw) 288 { 289 int err; 290 291 spin_lock_irq(&efw->lock); 292 293 /* user land lock this */ 294 if (efw->dev_lock_count < 0) { 295 err = -EBUSY; 296 goto end; 297 } 298 299 /* this is the first time */ 300 if (efw->dev_lock_count++ == 0) 301 snd_efw_stream_lock_changed(efw); 302 err = 0; 303 end: 304 spin_unlock_irq(&efw->lock); 305 return err; 306 } 307 308 void snd_efw_stream_lock_release(struct snd_efw *efw) 309 { 310 spin_lock_irq(&efw->lock); 311 312 if (WARN_ON(efw->dev_lock_count <= 0)) 313 goto end; 314 if (--efw->dev_lock_count == 0) 315 snd_efw_stream_lock_changed(efw); 316 end: 317 spin_unlock_irq(&efw->lock); 318 } 319