summaryrefslogtreecommitdiff
path: root/sound/firewire/amdtp-stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire/amdtp-stream.c')
-rw-r--r--sound/firewire/amdtp-stream.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 4484242da0e6..46f1167bf69f 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -548,26 +548,44 @@ end:
return 0;
}
-static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
+/*
+ * In CYCLE_TIMER register of IEEE 1394, 7 bits are used to represent second. On
+ * the other hand, in DMA descriptors of 1394 OHCI, 3 bits are used to represent
+ * it. Thus, via Linux firewire subsystem, we can get the 3 bits for second.
+ */
+static inline u32 compute_cycle_count(u32 tstamp)
+{
+ return (((tstamp >> 13) & 0x07) * 8000) + (tstamp & 0x1fff);
+}
+
+static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
+{
+ cycle += addend;
+ if (cycle >= 8 * CYCLES_PER_SECOND)
+ cycle -= 8 * CYCLES_PER_SECOND;
+ return cycle;
+}
+
+static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
size_t header_length, void *header,
void *private_data)
{
struct amdtp_stream *s = private_data;
unsigned int i, syt, packets = header_length / 4;
unsigned int data_blocks;
+ u32 cycle;
if (s->packet_index < 0)
return;
- /*
- * Compute the cycle of the last queued packet.
- * (We need only the four lowest bits for the SYT, so we can ignore
- * that bits 0-11 must wrap around at 3072.)
- */
- cycle += QUEUE_LENGTH - packets;
+ cycle = compute_cycle_count(tstamp);
+
+ /* Align to actual cycle count for the last packet. */
+ cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
for (i = 0; i < packets; ++i) {
- syt = calculate_syt(s, ++cycle);
+ cycle = increment_cycle_count(cycle, 1);
+ syt = calculate_syt(s, cycle);
data_blocks = calculate_data_blocks(s, syt);
if (handle_out_packet(s, data_blocks, syt) < 0) {
@@ -580,7 +598,7 @@ static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
fw_iso_context_queue_flush(s->context);
}
-static void in_stream_callback(struct fw_iso_context *context, u32 cycle,
+static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
size_t header_length, void *header,
void *private_data)
{
@@ -650,7 +668,7 @@ static void in_stream_callback(struct fw_iso_context *context, u32 cycle,
}
/* processing is done by master callback */
-static void slave_stream_callback(struct fw_iso_context *context, u32 cycle,
+static void slave_stream_callback(struct fw_iso_context *context, u32 tstamp,
size_t header_length, void *header,
void *private_data)
{
@@ -659,7 +677,7 @@ static void slave_stream_callback(struct fw_iso_context *context, u32 cycle,
/* this is executed one time */
static void amdtp_stream_first_callback(struct fw_iso_context *context,
- u32 cycle, size_t header_length,
+ u32 tstamp, size_t header_length,
void *header, void *private_data)
{
struct amdtp_stream *s = private_data;
@@ -678,7 +696,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
else
context->callback.sc = out_stream_callback;
- context->callback.sc(context, cycle, header_length, header, s);
+ context->callback.sc(context, tstamp, header_length, header, s);
}
/**