diff options
-rw-r--r-- | drivers/firewire/ohci.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 9dcb17d51aee..5826ae333b19 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -739,7 +739,7 @@ static void ar_context_tasklet(unsigned long data) | |||
739 | d = &ab->descriptor; | 739 | d = &ab->descriptor; |
740 | 740 | ||
741 | if (d->res_count == 0) { | 741 | if (d->res_count == 0) { |
742 | size_t size, rest, offset; | 742 | size_t size, size2, rest, pktsize, size3, offset; |
743 | dma_addr_t start_bus; | 743 | dma_addr_t start_bus; |
744 | void *start; | 744 | void *start; |
745 | 745 | ||
@@ -756,12 +756,41 @@ static void ar_context_tasklet(unsigned long data) | |||
756 | ab = ab->next; | 756 | ab = ab->next; |
757 | d = &ab->descriptor; | 757 | d = &ab->descriptor; |
758 | size = buffer + PAGE_SIZE - ctx->pointer; | 758 | size = buffer + PAGE_SIZE - ctx->pointer; |
759 | /* valid buffer data in the next page */ | ||
759 | rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); | 760 | rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count); |
761 | /* what actually fits in this page */ | ||
762 | size2 = min(rest, (size_t)PAGE_SIZE - size); | ||
760 | memmove(buffer, ctx->pointer, size); | 763 | memmove(buffer, ctx->pointer, size); |
761 | memcpy(buffer + size, ab->data, rest); | 764 | memcpy(buffer + size, ab->data, size2); |
762 | ctx->current_buffer = ab; | 765 | ctx->current_buffer = ab; |
763 | ctx->pointer = (void *) ab->data + rest; | 766 | ctx->pointer = (void *) ab->data + rest; |
764 | end = buffer + size + rest; | 767 | |
768 | while (size > 0) { | ||
769 | void *next = handle_ar_packet(ctx, buffer); | ||
770 | pktsize = next - buffer; | ||
771 | if (pktsize >= size) { | ||
772 | /* | ||
773 | * We have handled all the data that was | ||
774 | * originally in this page, so we can now | ||
775 | * continue in the next page. | ||
776 | */ | ||
777 | buffer = next; | ||
778 | break; | ||
779 | } | ||
780 | /* move the next packet to the start of the buffer */ | ||
781 | memmove(buffer, next, size + size2 - pktsize); | ||
782 | size -= pktsize; | ||
783 | /* fill up this page again */ | ||
784 | size3 = min(rest - size2, | ||
785 | (size_t)PAGE_SIZE - size - size2); | ||
786 | memcpy(buffer + size + size2, | ||
787 | (void *) ab->data + size2, size3); | ||
788 | size2 += size3; | ||
789 | } | ||
790 | |||
791 | /* handle the packets that are fully in the next page */ | ||
792 | buffer = (void *) ab->data + (buffer - (start + size)); | ||
793 | end = (void *) ab->data + rest; | ||
765 | 794 | ||
766 | while (buffer < end) | 795 | while (buffer < end) |
767 | buffer = handle_ar_packet(ctx, buffer); | 796 | buffer = handle_ar_packet(ctx, buffer); |