int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) { struct amdtp_stream *master, *slave; atomic_t *slave_substreams; enum cip_flags sync_mode; unsigned int curr_rate; int err = 0; mutex_lock(&efw->mutex); /* Need no substreams */ if ((atomic_read(&efw->playback_substreams) == 0) && (atomic_read(&efw->capture_substreams) == 0)) goto end; err = get_sync_mode(efw, &sync_mode); if (err < 0) goto end; if (sync_mode == CIP_SYNC_TO_DEVICE) { master = &efw->tx_stream; slave = &efw->rx_stream; slave_substreams = &efw->playback_substreams; } else { master = &efw->rx_stream; slave = &efw->tx_stream; slave_substreams = &efw->capture_substreams; } /* * Considering JACK/FFADO streaming: * TODO: This can be removed hwdep functionality becomes popular. */ err = check_connection_used_by_others(efw, master); if (err < 0) goto end; /* packet queueing error */ if (amdtp_streaming_error(slave)) stop_stream(efw, slave); if (amdtp_streaming_error(master)) stop_stream(efw, master); /* stop streams if rate is different */ err = snd_efw_command_get_sampling_rate(efw, &curr_rate); if (err < 0) goto end; if (rate == 0) rate = curr_rate; if (rate != curr_rate) { stop_stream(efw, slave); stop_stream(efw, master); } /* master should be always running */ if (!amdtp_stream_running(master)) { amdtp_stream_set_sync(sync_mode, master, slave); efw->master = master; err = snd_efw_command_set_sampling_rate(efw, rate); if (err < 0) goto end; err = start_stream(efw, master, rate); if (err < 0) { dev_err(&efw->unit->device, "fail to start AMDTP master stream:%d\n", err); goto end; } } /* start slave if needed */ if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { err = start_stream(efw, slave, rate); if (err < 0) { dev_err(&efw->unit->device, "fail to start AMDTP slave stream:%d\n", err); stop_stream(efw, master); } } end: mutex_unlock(&efw->mutex); return err; }
int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, unsigned int rate, unsigned int pcm_channels) { struct amdtp_stream *opposite; struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; unsigned int substreams, opposite_substreams; int err = 0; if (stream == &oxfw->tx_stream) { substreams = oxfw->capture_substreams; opposite = &oxfw->rx_stream; opposite_substreams = oxfw->playback_substreams; dir = AVC_GENERAL_PLUG_DIR_OUT; } else { substreams = oxfw->playback_substreams; opposite_substreams = oxfw->capture_substreams; if (oxfw->has_output) opposite = &oxfw->rx_stream; else opposite = NULL; dir = AVC_GENERAL_PLUG_DIR_IN; } if (substreams == 0) goto end; /* * Considering JACK/FFADO streaming: * TODO: This can be removed hwdep functionality becomes popular. */ err = check_connection_used_by_others(oxfw, stream); if (err < 0) goto end; /* packet queueing error */ if (amdtp_streaming_error(stream)) stop_stream(oxfw, stream); err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation); if (err < 0) goto end; if (rate == 0) rate = formation.rate; if (pcm_channels == 0) pcm_channels = formation.pcm; if ((formation.rate != rate) || (formation.pcm != pcm_channels)) { if (opposite != NULL) { err = check_connection_used_by_others(oxfw, opposite); if (err < 0) goto end; stop_stream(oxfw, opposite); } stop_stream(oxfw, stream); err = set_stream_format(oxfw, stream, rate, pcm_channels); if (err < 0) { dev_err(&oxfw->unit->device, "fail to set stream format: %d\n", err); goto end; } /* Start opposite stream if needed. */ if (opposite && !amdtp_stream_running(opposite) && (opposite_substreams > 0)) { err = start_stream(oxfw, opposite, rate, 0); if (err < 0) { dev_err(&oxfw->unit->device, "fail to restart stream: %d\n", err); goto end; } } } /* Start requested stream. */ if (!amdtp_stream_running(stream)) { err = start_stream(oxfw, stream, rate, pcm_channels); if (err < 0) dev_err(&oxfw->unit->device, "fail to start stream: %d\n", err); } end: return err; }
int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate) { const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate; unsigned int curr_rate; int err = 0; /* Need no substreams */ if (bebob->substreams_counter == 0) goto end; /* * Considering JACK/FFADO streaming: * TODO: This can be removed hwdep functionality becomes popular. */ err = check_connection_used_by_others(bebob, &bebob->rx_stream); if (err < 0) goto end; /* * packet queueing error or detecting discontinuity * * At bus reset, connections should not be broken here. So streams need * to be re-started. This is a reason to use SKIP_INIT_DBC_CHECK flag. */ if (amdtp_streaming_error(&bebob->rx_stream)) amdtp_stream_stop(&bebob->rx_stream); if (amdtp_streaming_error(&bebob->tx_stream)) amdtp_stream_stop(&bebob->tx_stream); if (!amdtp_stream_running(&bebob->rx_stream) && !amdtp_stream_running(&bebob->tx_stream)) break_both_connections(bebob); /* stop streams if rate is different */ err = rate_spec->get(bebob, &curr_rate); if (err < 0) { dev_err(&bebob->unit->device, "fail to get sampling rate: %d\n", err); goto end; } if (rate == 0) rate = curr_rate; if (rate != curr_rate) { amdtp_stream_stop(&bebob->rx_stream); amdtp_stream_stop(&bebob->tx_stream); break_both_connections(bebob); } /* master should be always running */ if (!amdtp_stream_running(&bebob->rx_stream)) { /* * NOTE: * If establishing connections at first, Yamaha GO46 * (and maybe Terratec X24) don't generate sound. * * For firmware customized by M-Audio, refer to next NOTE. */ if (bebob->maudio_special_quirk == NULL) { err = rate_spec->set(bebob, rate); if (err < 0) { dev_err(&bebob->unit->device, "fail to set sampling rate: %d\n", err); goto end; } } err = make_both_connections(bebob, rate); if (err < 0) goto end; err = start_stream(bebob, &bebob->rx_stream, rate); if (err < 0) { dev_err(&bebob->unit->device, "fail to run AMDTP master stream:%d\n", err); break_both_connections(bebob); goto end; } /* * NOTE: * The firmware customized by M-Audio uses these commands to * start transmitting stream. This is not usual way. */ if (bebob->maudio_special_quirk != NULL) { err = rate_spec->set(bebob, rate); if (err < 0) { dev_err(&bebob->unit->device, "fail to ensure sampling rate: %d\n", err); amdtp_stream_stop(&bebob->rx_stream); break_both_connections(bebob); goto end; } } /* wait first callback */ if (!amdtp_stream_wait_callback(&bebob->rx_stream, CALLBACK_TIMEOUT)) { amdtp_stream_stop(&bebob->rx_stream); break_both_connections(bebob); err = -ETIMEDOUT; goto end; } } /* start slave if needed */ if (!amdtp_stream_running(&bebob->tx_stream)) { err = start_stream(bebob, &bebob->tx_stream, rate); if (err < 0) { dev_err(&bebob->unit->device, "fail to run AMDTP slave stream:%d\n", err); amdtp_stream_stop(&bebob->rx_stream); break_both_connections(bebob); goto end; } /* wait first callback */ if (!amdtp_stream_wait_callback(&bebob->tx_stream, CALLBACK_TIMEOUT)) { amdtp_stream_stop(&bebob->tx_stream); amdtp_stream_stop(&bebob->rx_stream); break_both_connections(bebob); err = -ETIMEDOUT; } } end: return err; }