diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 0bb5e14b66278ec6fdba3e761731cde83a745fa0..5a3a4529194ac53f6b3dde16e8153f0c9f03a92d 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -657,28 +657,42 @@ static inline int queue_in_packet(struct amdtp_stream *s) amdtp_stream_get_max_payload(s), false); } +unsigned int process_rx_data_blocks(struct amdtp_stream *s, __be32 *buffer, + unsigned int data_blocks, unsigned int *syt) +{ + struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + unsigned int pcm_frames; + + if (pcm) { + s->transfer_samples(s, pcm, buffer, data_blocks); + pcm_frames = data_blocks * s->frame_multiplier; + } else { + write_pcm_silence(s, buffer, data_blocks); + pcm_frames = 0; + } + + if (s->midi_ports) + write_midi_messages(s, buffer, data_blocks); + + return pcm_frames; +} + static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, unsigned int syt) { __be32 *buffer; unsigned int payload_length; + unsigned int pcm_frames; struct snd_pcm_substream *pcm; buffer = s->buffer.packets[s->packet_index].buffer; + pcm_frames = process_rx_data_blocks(s, buffer + 2, data_blocks, &syt); + buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) | (s->data_block_quadlets << CIP_DBS_SHIFT) | s->data_block_counter); buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 | (s->sfc << CIP_FDF_SHIFT) | syt); - buffer += 2; - - pcm = ACCESS_ONCE(s->pcm); - if (pcm) - s->transfer_samples(s, pcm, buffer, data_blocks); - else - write_pcm_silence(s, buffer, data_blocks); - if (s->midi_ports) - write_midi_messages(s, buffer, data_blocks); s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff; @@ -686,20 +700,41 @@ static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks, if (queue_out_packet(s, payload_length, false) < 0) return -EIO; - if (pcm) - update_pcm_pointers(s, pcm, data_blocks * s->frame_multiplier); + pcm = ACCESS_ONCE(s->pcm); + if (pcm && pcm_frames > 0) + update_pcm_pointers(s, pcm, pcm_frames); /* No need to return the number of handled data blocks. */ return 0; } +unsigned int process_tx_data_blocks(struct amdtp_stream *s, __be32 *buffer, + unsigned int data_blocks, unsigned int *syt) +{ + struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); + unsigned int pcm_frames; + + if (pcm) { + s->transfer_samples(s, pcm, buffer, data_blocks); + pcm_frames = data_blocks * s->frame_multiplier; + } else { + pcm_frames = 0; + } + + if (s->midi_ports) + read_midi_messages(s, buffer, data_blocks); + + return pcm_frames; +} + static int handle_in_packet(struct amdtp_stream *s, unsigned int payload_quadlets, __be32 *buffer, - unsigned int *data_blocks) + unsigned int *data_blocks, unsigned int syt) { u32 cip_header[2]; unsigned int data_block_quadlets, data_block_counter, dbc_interval; - struct snd_pcm_substream *pcm = NULL; + struct snd_pcm_substream *pcm; + unsigned int pcm_frames; bool lost; cip_header[0] = be32_to_cpu(buffer[0]); @@ -716,6 +751,7 @@ static int handle_in_packet(struct amdtp_stream *s, "Invalid CIP header for AMDTP: %08X:%08X\n", cip_header[0], cip_header[1]); *data_blocks = 0; + pcm_frames = 0; goto end; } @@ -769,16 +805,7 @@ static int handle_in_packet(struct amdtp_stream *s, return -EIO; } - if (*data_blocks > 0) { - buffer += 2; - - pcm = ACCESS_ONCE(s->pcm); - if (pcm) - s->transfer_samples(s, pcm, buffer, *data_blocks); - - if (s->midi_ports) - read_midi_messages(s, buffer, *data_blocks); - } + pcm_frames = process_tx_data_blocks(s, buffer + 2, *data_blocks, &syt); if (s->flags & CIP_DBC_IS_END_EVENT) s->data_block_counter = data_block_counter; @@ -789,8 +816,9 @@ static int handle_in_packet(struct amdtp_stream *s, if (queue_in_packet(s) < 0) return -EIO; - if (pcm) - update_pcm_pointers(s, pcm, *data_blocks * s->frame_multiplier); + pcm = ACCESS_ONCE(s->pcm); + if (pcm && pcm_frames > 0) + update_pcm_pointers(s, pcm, pcm_frames); return 0; } @@ -860,15 +888,15 @@ static void in_stream_callback(struct fw_iso_context *context, u32 cycle, break; } + syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK; if (handle_in_packet(s, payload_quadlets, buffer, - &data_blocks) < 0) { + &data_blocks, syt) < 0) { s->packet_index = -1; break; } /* Process sync slave stream */ if (s->sync_slave && s->sync_slave->callbacked) { - syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK; if (handle_out_packet(s->sync_slave, data_blocks, syt) < 0) { s->packet_index = -1;