|
@@ -580,10 +580,13 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
|
|
|
int ret;
|
|
|
u32 trb_fields[4];
|
|
|
u64 val_64 = virt_to_phys(buffer);
|
|
|
+ void *last_transfer_trb_addr;
|
|
|
+ int available_length;
|
|
|
|
|
|
debug("dev=%p, pipe=%lx, buffer=%p, length=%d\n",
|
|
|
udev, pipe, buffer, length);
|
|
|
|
|
|
+ available_length = length;
|
|
|
ep_index = usb_pipe_ep_index(pipe);
|
|
|
virt_dev = ctrl->devs[slot_id];
|
|
|
|
|
@@ -697,7 +700,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
|
|
|
trb_fields[2] = length_field;
|
|
|
trb_fields[3] = field | TRB_TYPE(TRB_NORMAL);
|
|
|
|
|
|
- queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
|
|
|
+ last_transfer_trb_addr = queue_trb(ctrl, ring, (num_trbs > 1), trb_fields);
|
|
|
|
|
|
--num_trbs;
|
|
|
|
|
@@ -710,6 +713,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
|
|
|
|
|
|
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
|
|
|
|
|
|
+again:
|
|
|
event = xhci_wait_for_event(ctrl, TRB_TRANSFER);
|
|
|
if (!event) {
|
|
|
debug("XHCI bulk transfer timed out, aborting...\n");
|
|
@@ -718,12 +722,20 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
|
|
|
udev->act_len = 0;
|
|
|
return -ETIMEDOUT;
|
|
|
}
|
|
|
- field = le32_to_cpu(event->trans_event.flags);
|
|
|
|
|
|
+ if ((uintptr_t)(le64_to_cpu(event->trans_event.buffer))
|
|
|
+ != (uintptr_t)last_transfer_trb_addr) {
|
|
|
+ available_length -=
|
|
|
+ (int)EVENT_TRB_LEN(le32_to_cpu(event->trans_event.transfer_len));
|
|
|
+ xhci_acknowledge_event(ctrl);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+
|
|
|
+ field = le32_to_cpu(event->trans_event.flags);
|
|
|
BUG_ON(TRB_TO_SLOT_ID(field) != slot_id);
|
|
|
BUG_ON(TRB_TO_EP_INDEX(field) != ep_index);
|
|
|
|
|
|
- record_transfer_result(udev, event, length);
|
|
|
+ record_transfer_result(udev, event, available_length);
|
|
|
xhci_acknowledge_event(ctrl);
|
|
|
xhci_inval_cache((uintptr_t)buffer, length);
|
|
|
|