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