Skip to content

Commit

Permalink
firewire: Include iso timestamp in headers when header_size > 4
Browse files Browse the repository at this point in the history
Previously, when an iso context had header_size > 4, the iso header
(len/tag/channel/tcode/sy) was passed to userspace followed by quadlets
stripped from the payload.  This patch changes the behavior:
header_size = 8 now passes the header quadlet followed by the timestamp
quadlet.  When header_size > 8, quadlets are stripped from the payload.
The header_size = 4 case remains identical.

Since this alters the semantics of the API, the firewire API version
needs to be bumped concurrently with this change.

This change also refactors the header copying code slightly to be much
easier to read.

Signed-off-by: David Moore <dcm@acm.org>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
  • Loading branch information
David Moore authored and Stefan Richter committed Mar 24, 2009
1 parent 8e0ee43 commit 1aa292b
Showing 1 changed file with 35 additions and 38 deletions.
73 changes: 35 additions & 38 deletions drivers/firewire/fw-ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1765,6 +1765,28 @@ ohci_get_bus_time(struct fw_card *card)
return bus_time;
}

static void copy_iso_headers(struct iso_context *ctx, void *p)
{
int i = ctx->header_length;

if (i + ctx->base.header_size > PAGE_SIZE)
return;

/*
* The iso header is byteswapped to little endian by
* the controller, but the remaining header quadlets
* are big endian. We want to present all the headers
* as big endian, so we have to swap the first quadlet.
*/
if (ctx->base.header_size > 0)
*(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
if (ctx->base.header_size > 4)
*(u32 *) (ctx->header + i + 4) = __swab32(*(u32 *) p);
if (ctx->base.header_size > 8)
memcpy(ctx->header + i + 8, p + 8, ctx->base.header_size - 8);
ctx->header_length += ctx->base.header_size;
}

static int handle_ir_dualbuffer_packet(struct context *context,
struct descriptor *d,
struct descriptor *last)
Expand All @@ -1775,7 +1797,6 @@ static int handle_ir_dualbuffer_packet(struct context *context,
__le32 *ir_header;
size_t header_length;
void *p, *end;
int i;

if (db->first_res_count != 0 && db->second_res_count != 0) {
if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) {
Expand All @@ -1788,25 +1809,14 @@ static int handle_ir_dualbuffer_packet(struct context *context,
header_length = le16_to_cpu(db->first_req_count) -
le16_to_cpu(db->first_res_count);

i = ctx->header_length;
p = db + 1;
end = p + header_length;
while (p < end && i + ctx->base.header_size <= PAGE_SIZE) {
/*
* The iso header is byteswapped to little endian by
* the controller, but the remaining header quadlets
* are big endian. We want to present all the headers
* as big endian, so we have to swap the first
* quadlet.
*/
*(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
i += ctx->base.header_size;
while (p < end) {
copy_iso_headers(ctx, p);
ctx->excess_bytes +=
(le32_to_cpu(*(__le32 *)(p + 4)) >> 16) & 0xffff;
p += ctx->base.header_size + 4;
p += max(ctx->base.header_size, (size_t)8);
}
ctx->header_length = i;

ctx->excess_bytes -= le16_to_cpu(db->second_req_count) -
le16_to_cpu(db->second_res_count);
Expand All @@ -1832,7 +1842,6 @@ static int handle_ir_packet_per_buffer(struct context *context,
struct descriptor *pd;
__le32 *ir_header;
void *p;
int i;

for (pd = d; pd <= last; pd++) {
if (pd->transfer_status)
Expand All @@ -1842,21 +1851,8 @@ static int handle_ir_packet_per_buffer(struct context *context,
/* Descriptor(s) not done yet, stop iteration */
return 0;

i = ctx->header_length;
p = last + 1;

if (ctx->base.header_size > 0 &&
i + ctx->base.header_size <= PAGE_SIZE) {
/*
* The iso header is byteswapped to little endian by
* the controller, but the remaining header quadlets
* are big endian. We want to present all the headers
* as big endian, so we have to swap the first quadlet.
*/
*(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
ctx->header_length += ctx->base.header_size;
}
p = last + 1;
copy_iso_headers(ctx, p);

if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {
ir_header = (__le32 *) p;
Expand Down Expand Up @@ -2151,11 +2147,11 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
z = 2;

/*
* The OHCI controller puts the status word in the header
* buffer too, so we need 4 extra bytes per packet.
* The OHCI controller puts the isochronous header and trailer in the
* buffer, so we need at least 8 bytes.
*/
packet_count = p->header_length / ctx->base.header_size;
header_size = packet_count * (ctx->base.header_size + 4);
header_size = packet_count * max(ctx->base.header_size, (size_t)8);

/* Get header size in number of descriptors. */
header_z = DIV_ROUND_UP(header_size, sizeof(*d));
Expand All @@ -2173,7 +2169,8 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
db = (struct db_descriptor *) d;
db->control = cpu_to_le16(DESCRIPTOR_STATUS |
DESCRIPTOR_BRANCH_ALWAYS);
db->first_size = cpu_to_le16(ctx->base.header_size + 4);
db->first_size =
cpu_to_le16(max(ctx->base.header_size, (size_t)8));
if (p->skip && rest == p->payload_length) {
db->control |= cpu_to_le16(DESCRIPTOR_WAIT);
db->first_req_count = db->first_size;
Expand Down Expand Up @@ -2223,11 +2220,11 @@ ohci_queue_iso_receive_packet_per_buffer(struct fw_iso_context *base,
int page, offset, packet_count, header_size, payload_per_buffer;

/*
* The OHCI controller puts the status word in the
* buffer too, so we need 4 extra bytes per packet.
* The OHCI controller puts the isochronous header and trailer in the
* buffer, so we need at least 8 bytes.
*/
packet_count = p->header_length / ctx->base.header_size;
header_size = ctx->base.header_size + 4;
header_size = max(ctx->base.header_size, (size_t)8);

/* Get header size in number of descriptors. */
header_z = DIV_ROUND_UP(header_size, sizeof(*d));
Expand Down

0 comments on commit 1aa292b

Please sign in to comment.