diff options
| author | Amaury Pouly <pamaury@rockbox.org> | 2010-03-25 13:45:19 +0000 |
|---|---|---|
| committer | Amaury Pouly <pamaury@rockbox.org> | 2010-03-25 13:45:19 +0000 |
| commit | 1dd216ba066ffcb433e09dfd5c5df3edadb4b578 (patch) | |
| tree | 769923b21a8bad7748d0c4742fed00024c88eb5b /firmware | |
| parent | a4ff42d146668b38aa76597fd756e5d0b3b10e00 (diff) | |
| download | rockbox-1dd216ba066ffcb433e09dfd5c5df3edadb4b578.zip rockbox-1dd216ba066ffcb433e09dfd5c5df3edadb4b578.tar.gz rockbox-1dd216ba066ffcb433e09dfd5c5df3edadb4b578.tar.bz2 rockbox-1dd216ba066ffcb433e09dfd5c5df3edadb4b578.tar.xz | |
Fix usb-arc driver: the driver would prematurely mark a transfer as complete whereas only a part of it actually is, check the active of the TDs to avoid that. This should fix some HID+UMS bugs.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25328 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
| -rw-r--r-- | firmware/target/arm/usb-drv-arc.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c index 94dc9b7..3b1146c 100644 --- a/firmware/target/arm/usb-drv-arc.c +++ b/firmware/target/arm/usb-drv-arc.c @@ -917,20 +917,33 @@ static void transfer_completed(void) int pipe = ep * 2 + dir; if (mask & pipe2mask[pipe]) { struct queue_head* qh = &qh_array[pipe]; - if(qh->wait) { - qh->wait=0; - wakeup_signal(&transfer_completion_signal[pipe]); - } + int length=0; struct transfer_descriptor* td=&td_array[pipe*NUM_TDS_PER_EP]; while(td!=(struct transfer_descriptor*)DTD_NEXT_TERMINATE && td!=0) { + /* It seems that the controller sets the pipe bit to one even if the TD + * dosn't have the IOC bit set. So we have the rely the active status bit + * to check that all the TDs of the transfer are really finished and let + * the transfer continue if it's no the case */ + if(td->size_ioc_sts & DTD_STATUS_ACTIVE) + { + logf("skip half finished transfer"); + goto Lskip; + } length += ((td->reserved & DTD_RESERVED_LENGTH_MASK) - ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS)); td=(struct transfer_descriptor*) td->next_td_ptr; } + if(qh->wait) { + qh->wait=0; + wakeup_signal(&transfer_completion_signal[pipe]); + } + usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT, qh->status, length); + Lskip: + continue; } } } |