diff options
Diffstat (limited to 'sound/firewire/fireworks')
-rw-r--r-- | sound/firewire/fireworks/fireworks.h | 6 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_midi.c | 56 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_pcm.c | 66 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_stream.c | 178 |
4 files changed, 145 insertions, 161 deletions
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 28df49c3542a..31efd4b53b4f 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -88,8 +88,7 @@ struct snd_efw { struct amdtp_stream rx_stream; struct cmp_connection out_conn; struct cmp_connection in_conn; - unsigned int capture_substreams; - unsigned int playback_substreams; + unsigned int substreams_counter; /* hardware metering parameters */ unsigned int phys_out; @@ -206,7 +205,8 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate); int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate); int snd_efw_stream_init_duplex(struct snd_efw *efw); -int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate); +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate); +int snd_efw_stream_start_duplex(struct snd_efw *efw); void snd_efw_stream_stop_duplex(struct snd_efw *efw); void snd_efw_stream_update_duplex(struct snd_efw *efw); void snd_efw_stream_destroy_duplex(struct snd_efw *efw); diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index 14b985c4f304..a9f4a9630d15 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -7,7 +7,7 @@ */ #include "fireworks.h" -static int midi_capture_open(struct snd_rawmidi_substream *substream) +static int midi_open(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; int err; @@ -17,28 +17,13 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) goto end; mutex_lock(&efw->mutex); - efw->capture_substreams++; - err = snd_efw_stream_start_duplex(efw, 0); - mutex_unlock(&efw->mutex); - if (err < 0) - snd_efw_stream_lock_release(efw); - -end: - return err; -} - -static int midi_playback_open(struct snd_rawmidi_substream *substream) -{ - struct snd_efw *efw = substream->rmidi->private_data; - int err; - - err = snd_efw_stream_lock_try(efw); - if (err < 0) - goto end; - - mutex_lock(&efw->mutex); - efw->playback_substreams++; - err = snd_efw_stream_start_duplex(efw, 0); + err = snd_efw_stream_reserve_duplex(efw, 0); + if (err >= 0) { + ++efw->substreams_counter; + err = snd_efw_stream_start_duplex(efw); + if (err < 0) + --efw->substreams_counter; + } mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); @@ -46,25 +31,12 @@ end: return err; } -static int midi_capture_close(struct snd_rawmidi_substream *substream) -{ - struct snd_efw *efw = substream->rmidi->private_data; - - mutex_lock(&efw->mutex); - efw->capture_substreams--; - snd_efw_stream_stop_duplex(efw); - mutex_unlock(&efw->mutex); - - snd_efw_stream_lock_release(efw); - return 0; -} - -static int midi_playback_close(struct snd_rawmidi_substream *substream) +static int midi_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; mutex_lock(&efw->mutex); - efw->playback_substreams--; + --efw->substreams_counter; snd_efw_stream_stop_duplex(efw); mutex_unlock(&efw->mutex); @@ -120,13 +92,13 @@ static void set_midi_substream_names(struct snd_efw *efw, int snd_efw_create_midi_devices(struct snd_efw *efw) { static const struct snd_rawmidi_ops capture_ops = { - .open = midi_capture_open, - .close = midi_capture_close, + .open = midi_open, + .close = midi_close, .trigger = midi_capture_trigger, }; static const struct snd_rawmidi_ops playback_ops = { - .open = midi_playback_open, - .close = midi_playback_close, + .open = midi_open, + .close = midi_close, .trigger = midi_playback_trigger, }; struct snd_rawmidi *rmidi; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index affc50fe2e8e..a7025dccc754 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -218,7 +218,7 @@ static int pcm_close(struct snd_pcm_substream *substream) return 0; } -static int pcm_capture_hw_params(struct snd_pcm_substream *substream, +static int pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_efw *efw = substream->private_data; @@ -230,69 +230,40 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { - mutex_lock(&efw->mutex); - efw->capture_substreams++; - mutex_unlock(&efw->mutex); - } - - return 0; -} -static int pcm_playback_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_efw *efw = substream->private_data; - int err; + unsigned int rate = params_rate(hw_params); - err = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - if (err < 0) - return err; - - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&efw->mutex); - efw->playback_substreams++; + err = snd_efw_stream_reserve_duplex(efw, rate); + if (err >= 0) + ++efw->substreams_counter; mutex_unlock(&efw->mutex); } - return 0; + return err; } -static int pcm_capture_hw_free(struct snd_pcm_substream *substream) +static int pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { - mutex_lock(&efw->mutex); - efw->capture_substreams--; - mutex_unlock(&efw->mutex); - } - - snd_efw_stream_stop_duplex(efw); - - return snd_pcm_lib_free_vmalloc_buffer(substream); -} -static int pcm_playback_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_efw *efw = substream->private_data; + mutex_lock(&efw->mutex); - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { - mutex_lock(&efw->mutex); - efw->playback_substreams--; - mutex_unlock(&efw->mutex); - } + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) + --efw->substreams_counter; snd_efw_stream_stop_duplex(efw); + mutex_unlock(&efw->mutex); + return snd_pcm_lib_free_vmalloc_buffer(substream); } static int pcm_capture_prepare(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err; - err = snd_efw_stream_start_duplex(efw, runtime->rate); + err = snd_efw_stream_start_duplex(efw); if (err >= 0) amdtp_stream_pcm_prepare(&efw->tx_stream); @@ -301,10 +272,9 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream) static int pcm_playback_prepare(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; int err; - err = snd_efw_stream_start_duplex(efw, runtime->rate); + err = snd_efw_stream_start_duplex(efw); if (err >= 0) amdtp_stream_pcm_prepare(&efw->rx_stream); @@ -377,8 +347,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .open = pcm_open, .close = pcm_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_capture_hw_params, - .hw_free = pcm_capture_hw_free, + .hw_params = pcm_hw_params, + .hw_free = pcm_hw_free, .prepare = pcm_capture_prepare, .trigger = pcm_capture_trigger, .pointer = pcm_capture_pointer, @@ -389,8 +359,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw) .open = pcm_open, .close = pcm_close, .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_playback_hw_params, - .hw_free = pcm_playback_hw_free, + .hw_params = pcm_hw_params, + .hw_free = pcm_hw_free, .prepare = pcm_playback_prepare, .trigger = pcm_playback_trigger, .pointer = pcm_playback_pointer, diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 2d3095412427..e659a0b89ba5 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -42,7 +42,6 @@ end: static void stop_stream(struct snd_efw *efw, struct amdtp_stream *stream) { - amdtp_stream_pcm_abort(stream); amdtp_stream_stop(stream); if (stream == &efw->tx_stream) @@ -51,54 +50,37 @@ stop_stream(struct snd_efw *efw, struct amdtp_stream *stream) cmp_connection_break(&efw->in_conn); } -static int -start_stream(struct snd_efw *efw, struct amdtp_stream *stream, - unsigned int sampling_rate) +static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, + unsigned int rate) { struct cmp_connection *conn; - unsigned int mode, pcm_channels, midi_ports; int err; - err = snd_efw_get_multiplier_mode(sampling_rate, &mode); - if (err < 0) - goto end; - if (stream == &efw->tx_stream) { + if (stream == &efw->tx_stream) conn = &efw->out_conn; - pcm_channels = efw->pcm_capture_channels[mode]; - midi_ports = efw->midi_out_ports; - } else { + else conn = &efw->in_conn; - pcm_channels = efw->pcm_playback_channels[mode]; - midi_ports = efw->midi_in_ports; - } - - err = amdtp_am824_set_parameters(stream, sampling_rate, - pcm_channels, midi_ports, false); - if (err < 0) - goto end; - /* establish connection via CMP */ - err = cmp_connection_establish(conn, - amdtp_stream_get_max_payload(stream)); + // Establish connection via CMP. + err = cmp_connection_establish(conn); if (err < 0) - goto end; + return err; - /* start amdtp stream */ - err = amdtp_stream_start(stream, - conn->resources.channel, - conn->speed); + // Start amdtp stream. + err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); if (err < 0) { - stop_stream(efw, stream); - goto end; + cmp_connection_break(conn); + return err; } - /* wait first callback */ + // Wait first callback. if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { - stop_stream(efw, stream); - err = -ETIMEDOUT; + amdtp_stream_stop(stream); + cmp_connection_break(conn); + return -ETIMEDOUT; } -end: - return err; + + return 0; } /* @@ -164,13 +146,13 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) (efw->firmware_version == 0x5070000 || efw->firmware_version == 0x5070300 || efw->firmware_version == 0x5080000)) - efw->tx_stream.tx_first_dbc = 0x02; + efw->tx_stream.ctx_data.tx.first_dbc = 0x02; /* AudioFire9 always reports wrong dbs. */ if (efw->is_af9) efw->tx_stream.flags |= CIP_WRONG_DBS; /* Firmware version 5.5 reports fixed interval for dbc. */ if (efw->firmware_version == 0x5050000) - efw->tx_stream.tx_dbc_interval = 8; + efw->tx_stream.ctx_data.tx.dbc_interval = 8; err = init_stream(efw, &efw->rx_stream); if (err < 0) { @@ -188,75 +170,135 @@ end: return err; } -int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) +static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream, + unsigned int rate, unsigned int mode) { - unsigned int curr_rate; - int err = 0; + unsigned int pcm_channels; + unsigned int midi_ports; + struct cmp_connection *conn; + int err; - /* Need no substreams */ - if (efw->playback_substreams == 0 && efw->capture_substreams == 0) - goto end; + if (stream == &efw->tx_stream) { + pcm_channels = efw->pcm_capture_channels[mode]; + midi_ports = efw->midi_out_ports; + conn = &efw->out_conn; + } else { + pcm_channels = efw->pcm_playback_channels[mode]; + midi_ports = efw->midi_in_ports; + conn = &efw->in_conn; + } - /* - * Considering JACK/FFADO streaming: - * TODO: This can be removed hwdep functionality becomes popular. - */ - err = check_connection_used_by_others(efw, &efw->rx_stream); + err = amdtp_am824_set_parameters(stream, rate, pcm_channels, + midi_ports, false); if (err < 0) - goto end; + return err; - /* packet queueing error */ - if (amdtp_streaming_error(&efw->tx_stream)) - stop_stream(efw, &efw->tx_stream); - if (amdtp_streaming_error(&efw->rx_stream)) - stop_stream(efw, &efw->rx_stream); + return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream)); +} + +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) +{ + unsigned int curr_rate; + int err; - /* stop streams if rate is different */ + // Considering JACK/FFADO streaming: + // TODO: This can be removed hwdep functionality becomes popular. + err = check_connection_used_by_others(efw, &efw->rx_stream); + if (err < 0) + return err; + + // stop streams if rate is different. err = snd_efw_command_get_sampling_rate(efw, &curr_rate); if (err < 0) - goto end; + return err; if (rate == 0) rate = curr_rate; if (rate != curr_rate) { stop_stream(efw, &efw->tx_stream); stop_stream(efw, &efw->rx_stream); + + cmp_connection_release(&efw->out_conn); + cmp_connection_release(&efw->in_conn); } - /* master should be always running */ - if (!amdtp_stream_running(&efw->rx_stream)) { + if (efw->substreams_counter == 0 || rate != curr_rate) { + unsigned int mode; + err = snd_efw_command_set_sampling_rate(efw, rate); if (err < 0) - goto end; + return err; + + err = snd_efw_get_multiplier_mode(rate, &mode); + if (err < 0) + return err; + + err = keep_resources(efw, &efw->tx_stream, rate, mode); + if (err < 0) + return err; + err = keep_resources(efw, &efw->rx_stream, rate, mode); + if (err < 0) { + cmp_connection_release(&efw->in_conn); + return err; + } + } + + return 0; +} + +int snd_efw_stream_start_duplex(struct snd_efw *efw) +{ + unsigned int rate; + int err = 0; + + // Need no substreams. + if (efw->substreams_counter == 0) + return -EIO; + + err = snd_efw_command_get_sampling_rate(efw, &rate); + if (err < 0) + return err; + + if (amdtp_streaming_error(&efw->rx_stream) || + amdtp_streaming_error(&efw->tx_stream)) { + stop_stream(efw, &efw->rx_stream); + stop_stream(efw, &efw->tx_stream); + } + + /* master should be always running */ + if (!amdtp_stream_running(&efw->rx_stream)) { err = start_stream(efw, &efw->rx_stream, rate); if (err < 0) { dev_err(&efw->unit->device, "fail to start AMDTP master stream:%d\n", err); - goto end; + goto error; } } - /* start slave if needed */ - if (efw->capture_substreams > 0 && - !amdtp_stream_running(&efw->tx_stream)) { + if (!amdtp_stream_running(&efw->tx_stream)) { err = start_stream(efw, &efw->tx_stream, rate); if (err < 0) { dev_err(&efw->unit->device, "fail to start AMDTP slave stream:%d\n", err); - stop_stream(efw, &efw->rx_stream); + goto error; } } -end: + + return 0; +error: + stop_stream(efw, &efw->rx_stream); + stop_stream(efw, &efw->tx_stream); return err; } void snd_efw_stream_stop_duplex(struct snd_efw *efw) { - if (efw->capture_substreams == 0) { + if (efw->substreams_counter == 0) { stop_stream(efw, &efw->tx_stream); + stop_stream(efw, &efw->rx_stream); - if (efw->playback_substreams == 0) - stop_stream(efw, &efw->rx_stream); + cmp_connection_release(&efw->out_conn); + cmp_connection_release(&efw->in_conn); } } |