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/target | |
parent | a4ff42d146668b38aa76597fd756e5d0b3b10e00 (diff) | |
download | rockbox-1dd216ba066ffcb433e09dfd5c5df3edadb4b578.tar.gz rockbox-1dd216ba066ffcb433e09dfd5c5df3edadb4b578.zip |
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/target')
-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 94dc9b7b5e..3b1146cc5c 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) | |||
917 | int pipe = ep * 2 + dir; | 917 | int pipe = ep * 2 + dir; |
918 | if (mask & pipe2mask[pipe]) { | 918 | if (mask & pipe2mask[pipe]) { |
919 | struct queue_head* qh = &qh_array[pipe]; | 919 | struct queue_head* qh = &qh_array[pipe]; |
920 | if(qh->wait) { | 920 | |
921 | qh->wait=0; | ||
922 | wakeup_signal(&transfer_completion_signal[pipe]); | ||
923 | } | ||
924 | int length=0; | 921 | int length=0; |
925 | struct transfer_descriptor* td=&td_array[pipe*NUM_TDS_PER_EP]; | 922 | struct transfer_descriptor* td=&td_array[pipe*NUM_TDS_PER_EP]; |
926 | while(td!=(struct transfer_descriptor*)DTD_NEXT_TERMINATE && td!=0) | 923 | while(td!=(struct transfer_descriptor*)DTD_NEXT_TERMINATE && td!=0) |
927 | { | 924 | { |
925 | /* It seems that the controller sets the pipe bit to one even if the TD | ||
926 | * dosn't have the IOC bit set. So we have the rely the active status bit | ||
927 | * to check that all the TDs of the transfer are really finished and let | ||
928 | * the transfer continue if it's no the case */ | ||
929 | if(td->size_ioc_sts & DTD_STATUS_ACTIVE) | ||
930 | { | ||
931 | logf("skip half finished transfer"); | ||
932 | goto Lskip; | ||
933 | } | ||
928 | length += ((td->reserved & DTD_RESERVED_LENGTH_MASK) - | 934 | length += ((td->reserved & DTD_RESERVED_LENGTH_MASK) - |
929 | ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS)); | 935 | ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS)); |
930 | td=(struct transfer_descriptor*) td->next_td_ptr; | 936 | td=(struct transfer_descriptor*) td->next_td_ptr; |
931 | } | 937 | } |
938 | if(qh->wait) { | ||
939 | qh->wait=0; | ||
940 | wakeup_signal(&transfer_completion_signal[pipe]); | ||
941 | } | ||
942 | |||
932 | usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT, | 943 | usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT, |
933 | qh->status, length); | 944 | qh->status, length); |
945 | Lskip: | ||
946 | continue; | ||
934 | } | 947 | } |
935 | } | 948 | } |
936 | } | 949 | } |