diff options
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/fw-ohci.c | 44 |
1 files changed, 24 insertions, 20 deletions
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 436a855a4c60..a44d16d0c505 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
@@ -125,6 +125,7 @@ struct context { | |||
125 | struct iso_context { | 125 | struct iso_context { |
126 | struct fw_iso_context base; | 126 | struct fw_iso_context base; |
127 | struct context context; | 127 | struct context context; |
128 | int excess_bytes; | ||
128 | void *header; | 129 | void *header; |
129 | size_t header_length; | 130 | size_t header_length; |
130 | }; | 131 | }; |
@@ -1408,9 +1409,13 @@ static int handle_ir_dualbuffer_packet(struct context *context, | |||
1408 | void *p, *end; | 1409 | void *p, *end; |
1409 | int i; | 1410 | int i; |
1410 | 1411 | ||
1411 | if (db->first_res_count > 0 && db->second_res_count > 0) | 1412 | if (db->first_res_count > 0 && db->second_res_count > 0) { |
1412 | /* This descriptor isn't done yet, stop iteration. */ | 1413 | if (ctx->excess_bytes <= le16_to_cpu(db->second_req_count)) { |
1413 | return 0; | 1414 | /* This descriptor isn't done yet, stop iteration. */ |
1415 | return 0; | ||
1416 | } | ||
1417 | ctx->excess_bytes -= le16_to_cpu(db->second_req_count); | ||
1418 | } | ||
1414 | 1419 | ||
1415 | header_length = le16_to_cpu(db->first_req_count) - | 1420 | header_length = le16_to_cpu(db->first_req_count) - |
1416 | le16_to_cpu(db->first_res_count); | 1421 | le16_to_cpu(db->first_res_count); |
@@ -1429,11 +1434,15 @@ static int handle_ir_dualbuffer_packet(struct context *context, | |||
1429 | *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); | 1434 | *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4)); |
1430 | memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4); | 1435 | memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4); |
1431 | i += ctx->base.header_size; | 1436 | i += ctx->base.header_size; |
1437 | ctx->excess_bytes += | ||
1438 | (le32_to_cpu(*(u32 *)(p + 4)) >> 16) & 0xffff; | ||
1432 | p += ctx->base.header_size + 4; | 1439 | p += ctx->base.header_size + 4; |
1433 | } | 1440 | } |
1434 | |||
1435 | ctx->header_length = i; | 1441 | ctx->header_length = i; |
1436 | 1442 | ||
1443 | ctx->excess_bytes -= le16_to_cpu(db->second_req_count) - | ||
1444 | le16_to_cpu(db->second_res_count); | ||
1445 | |||
1437 | if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) { | 1446 | if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) { |
1438 | ir_header = (__le32 *) (db + 1); | 1447 | ir_header = (__le32 *) (db + 1); |
1439 | ctx->base.callback(&ctx->base, | 1448 | ctx->base.callback(&ctx->base, |
@@ -1775,19 +1784,6 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, | |||
1775 | * packet, retransmit or terminate.. | 1784 | * packet, retransmit or terminate.. |
1776 | */ | 1785 | */ |
1777 | 1786 | ||
1778 | if (packet->skip) { | ||
1779 | d = context_get_descriptors(&ctx->context, 2, &d_bus); | ||
1780 | if (d == NULL) | ||
1781 | return -ENOMEM; | ||
1782 | |||
1783 | db = (struct db_descriptor *) d; | ||
1784 | db->control = cpu_to_le16(DESCRIPTOR_STATUS | | ||
1785 | DESCRIPTOR_BRANCH_ALWAYS | | ||
1786 | DESCRIPTOR_WAIT); | ||
1787 | db->first_size = cpu_to_le16(ctx->base.header_size + 4); | ||
1788 | context_append(&ctx->context, d, 2, 0); | ||
1789 | } | ||
1790 | |||
1791 | p = packet; | 1787 | p = packet; |
1792 | z = 2; | 1788 | z = 2; |
1793 | 1789 | ||
@@ -1815,11 +1811,18 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, | |||
1815 | db->control = cpu_to_le16(DESCRIPTOR_STATUS | | 1811 | db->control = cpu_to_le16(DESCRIPTOR_STATUS | |
1816 | DESCRIPTOR_BRANCH_ALWAYS); | 1812 | DESCRIPTOR_BRANCH_ALWAYS); |
1817 | db->first_size = cpu_to_le16(ctx->base.header_size + 4); | 1813 | db->first_size = cpu_to_le16(ctx->base.header_size + 4); |
1818 | db->first_req_count = cpu_to_le16(header_size); | 1814 | if (p->skip && rest == p->payload_length) { |
1815 | db->control |= cpu_to_le16(DESCRIPTOR_WAIT); | ||
1816 | db->first_req_count = db->first_size; | ||
1817 | } else { | ||
1818 | db->first_req_count = cpu_to_le16(header_size); | ||
1819 | } | ||
1819 | db->first_res_count = db->first_req_count; | 1820 | db->first_res_count = db->first_req_count; |
1820 | db->first_buffer = cpu_to_le32(d_bus + sizeof(*db)); | 1821 | db->first_buffer = cpu_to_le32(d_bus + sizeof(*db)); |
1821 | 1822 | ||
1822 | if (offset + rest < PAGE_SIZE) | 1823 | if (p->skip && rest == p->payload_length) |
1824 | length = 4; | ||
1825 | else if (offset + rest < PAGE_SIZE) | ||
1823 | length = rest; | 1826 | length = rest; |
1824 | else | 1827 | else |
1825 | length = PAGE_SIZE - offset; | 1828 | length = PAGE_SIZE - offset; |
@@ -1835,7 +1838,8 @@ ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base, | |||
1835 | context_append(&ctx->context, d, z, header_z); | 1838 | context_append(&ctx->context, d, z, header_z); |
1836 | offset = (offset + length) & ~PAGE_MASK; | 1839 | offset = (offset + length) & ~PAGE_MASK; |
1837 | rest -= length; | 1840 | rest -= length; |
1838 | page++; | 1841 | if (offset == 0) |
1842 | page++; | ||
1839 | } | 1843 | } |
1840 | 1844 | ||
1841 | return 0; | 1845 | return 0; |