summaryrefslogtreecommitdiff
path: root/sound/firewire/amdtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r--sound/firewire/amdtp.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 0bb5e14..5a3a452 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 @@ end:
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;