summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2019-03-17 20:25:06 +0900
committerTakashi Iwai <tiwai@suse.de>2019-03-18 14:50:35 +0100
commitcc4f8e91c4ed04a9a972c6e10c158d4b71be3f2f (patch)
tree1244d4365cb2827544c0b08a16b002d208810eb0
parent35033d8cb71b4dd4fa8d8d28a534af1ee921b9a0 (diff)
downloadlinux-cc4f8e91c4ed04a9a972c6e10c158d4b71be3f2f.tar.bz2
ALSA: firewire-lib: use 8 byte header for IR context to get isochronous cycle
In kernel API of Linux FireWire subsystem, handlers of isochronous receive (IR) context can get context headers as an argument of callback. When 4 byte header is used, the context header includes isochronous packet header for each packet. When 8 byte header is used, it includes isochronous cycle as well. ALSA IEC 61883-1/6 engine uses 4 byte header, and computes isochronous cycle from the cycle of interrupt. The usage of 8 byte header can obsolete the computation. Furthermore, this change works well for a case that a series of packet in one interrupt includes skipped isochronous cycle, This commit uses 8 byte header to handle isochronous cycle. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/firewire/amdtp-stream.c44
1 files changed, 19 insertions, 25 deletions
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c
index 3ada55ed5381..43f28b813386 100644
--- a/sound/firewire/amdtp-stream.c
+++ b/sound/firewire/amdtp-stream.c
@@ -56,8 +56,9 @@
#define INTERRUPT_INTERVAL 16
#define QUEUE_LENGTH 48
-#define IN_PACKET_HEADER_SIZE 4
+#define IR_HEADER_SIZE 8 // For header and timestamp.
#define OUT_PACKET_HEADER_SIZE 0
+#define HEADER_TSTAMP_MASK 0x0000ffff
static void pcm_period_tasklet(unsigned long data);
@@ -456,7 +457,7 @@ static inline int queue_out_packet(struct amdtp_stream *s,
static inline int queue_in_packet(struct amdtp_stream *s)
{
- return queue_packet(s, IN_PACKET_HEADER_SIZE, s->max_payload_length);
+ return queue_packet(s, IR_HEADER_SIZE, s->max_payload_length);
}
static int handle_out_packet(struct amdtp_stream *s,
@@ -701,13 +702,6 @@ static inline u32 increment_cycle_count(u32 cycle, unsigned int addend)
return cycle;
}
-static inline u32 decrement_cycle_count(u32 cycle, unsigned int subtrahend)
-{
- if (cycle < subtrahend)
- cycle += 8 * CYCLES_PER_SECOND;
- return cycle - subtrahend;
-}
-
static void out_stream_callback(struct fw_iso_context *context, u32 tstamp,
size_t header_length, void *header,
void *private_data)
@@ -745,29 +739,26 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
struct amdtp_stream *s = private_data;
unsigned int i, packets;
unsigned int payload_length, max_payload_length;
- __be32 *headers = header;
- u32 cycle;
+ __be32 *ctx_header = header;
if (s->packet_index < 0)
return;
/* The number of packets in buffer */
- packets = header_length / IN_PACKET_HEADER_SIZE;
-
- cycle = compute_cycle_count(tstamp);
-
- /* Align to actual cycle count for the last packet. */
- cycle = decrement_cycle_count(cycle, packets);
+ packets = header_length / IR_HEADER_SIZE;
/* For buffer-over-run prevention. */
max_payload_length = s->max_payload_length;
for (i = 0; i < packets; i++) {
- cycle = increment_cycle_count(cycle, 1);
+ u32 iso_header = be32_to_cpu(ctx_header[0]);
+ unsigned int cycle;
+
+ tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
+ cycle = compute_cycle_count(tstamp);
/* The number of bytes in this packet */
- payload_length =
- (be32_to_cpu(headers[i]) >> ISO_DATA_LENGTH_SHIFT);
+ payload_length = iso_header >> ISO_DATA_LENGTH_SHIFT;
if (payload_length > max_payload_length) {
dev_err(&s->unit->device,
"Detect jumbo payload: %04x %04x\n",
@@ -777,6 +768,8 @@ static void in_stream_callback(struct fw_iso_context *context, u32 tstamp,
if (s->handle_packet(s, payload_length, cycle, i) < 0)
break;
+
+ ctx_header += IR_HEADER_SIZE / sizeof(__be32);
}
/* Queueing error or detecting invalid payload. */
@@ -797,6 +790,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
void *header, void *private_data)
{
struct amdtp_stream *s = private_data;
+ __be32 *ctx_header = header;
u32 cycle;
unsigned int packets;
@@ -807,11 +801,10 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
s->callbacked = true;
wake_up(&s->callback_wait);
- cycle = compute_cycle_count(tstamp);
-
if (s->direction == AMDTP_IN_STREAM) {
- packets = header_length / IN_PACKET_HEADER_SIZE;
- cycle = decrement_cycle_count(cycle, packets);
+ tstamp = be32_to_cpu(ctx_header[1]) & HEADER_TSTAMP_MASK;
+ cycle = compute_cycle_count(tstamp);
+
context->callback.sc = in_stream_callback;
if (s->flags & CIP_NO_HEADER)
s->handle_packet = handle_in_packet_without_header;
@@ -819,6 +812,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
s->handle_packet = handle_in_packet;
} else {
packets = header_length / 4;
+ cycle = compute_cycle_count(tstamp);
cycle = increment_cycle_count(cycle, QUEUE_LENGTH - packets);
context->callback.sc = out_stream_callback;
if (s->flags & CIP_NO_HEADER)
@@ -880,7 +874,7 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
if (s->direction == AMDTP_IN_STREAM) {
dir = DMA_FROM_DEVICE;
type = FW_ISO_CONTEXT_RECEIVE;
- header_size = IN_PACKET_HEADER_SIZE;
+ header_size = IR_HEADER_SIZE;
} else {
dir = DMA_TO_DEVICE;
type = FW_ISO_CONTEXT_TRANSMIT;