@@ -24,7 +24,7 @@ typedef struct
2424{
2525 URB * urb ;
2626 int address ;
27- int sequence ;
27+ LONG sequence ;
2828 int transferFlags ;
2929 int isoLatency ;
3030 int totalLength ;
@@ -60,19 +60,6 @@ void set_urb_transfer_flags(libusb_device_t* dev,
6060 PURB subUrb ,
6161 int transfer_flags ,
6262 int isoLatency );
63-
64- static KIRQL pending_lock_acquire (libusb_device_t * dev )
65- {
66- KIRQL old ;
67- KeAcquireSpinLock (& dev -> pending_lock , & old );
68- return old ;
69- }
70-
71- static void pending_lock_release (libusb_device_t * dev , KIRQL old )
72- {
73- KeReleaseSpinLock (& dev -> pending_lock , old );
74- }
75-
7663static NTSTATUS transfer_next (libusb_device_t * dev ,
7764 IN PIRP irp ,
7865 context_t * context )
@@ -113,11 +100,12 @@ NTSTATUS transfer(libusb_device_t* dev,
113100 IN int totalLength ,
114101 IN int maxTransferSize )
115102{
116- context_t * context ;
103+ context_t * context = NULL ;
117104 NTSTATUS status = STATUS_SUCCESS ;
118105 int sequenceID = InterlockedIncrement (& sequence );
119106 const char * dispTransfer = GetPipeDisplayName (endpoint );
120107 int first_size ;
108+ LONG pending_busy_taken = FALSE, pending_busy = FALSE;
121109
122110 // TODO: reset pipe flag
123111 // status = reset_endpoint(dev,endpoint->address, LIBUSB_DEFAULT_TIMEOUT);
@@ -135,12 +123,25 @@ NTSTATUS transfer(libusb_device_t* dev,
135123 USBMSG ("[%s #%d] EP%02Xh length=%d, packetSize=%d, maxTransferSize=%d\n" ,
136124 dispTransfer , sequenceID , endpoint -> address , totalLength , packetSize , maxTransferSize );
137125 }
138- context = allocate_pool (sizeof (context_t ));
139126
127+ /* Check if another transfer is on-going on same endpoint */
128+ pending_busy = InterlockedCompareExchange (& dev -> pending_busy [endpoint -> address ], 1 , 0 );
129+ if (pending_busy )
130+ {
131+ USBMSG ("sequence %d send aborted due to pending conflict\n" , sequenceID );
132+ goto transfer_free ;
133+ }
134+ pending_busy_taken = TRUE;
135+
136+ /* Save the pending sequence, so that transfer_complete() for older requests do not
137+ order new transfers after this one */
138+ InterlockedExchange (& dev -> pending_sequence [endpoint -> address ], sequenceID );
139+
140+ context = allocate_pool (sizeof (context_t ));
140141 if (!context )
141142 {
142- remove_lock_release ( dev ) ;
143- return complete_irp ( irp , STATUS_NO_MEMORY , 0 ) ;
143+ status = STATUS_NO_MEMORY ;
144+ goto transfer_free ;
144145 }
145146
146147 context -> isoLatency = isoLatency ;
@@ -160,37 +161,43 @@ NTSTATUS transfer(libusb_device_t* dev,
160161 endpoint , packetSize , mdlAddress , first_size );
161162 if (!NT_SUCCESS (status ))
162163 {
163- ExFreePool (context );
164- remove_lock_release (dev );
165- return complete_irp (irp , status , 0 );
164+ goto transfer_free ;
166165 }
167166
168- /* Grab the pending lock. This makes sure a DPC does not arrive
169- while we are sending the next sequence */
170- KIRQL old = pending_lock_acquire (dev );
171- dev -> pending_sequence [context -> address ] = sequenceID ;
172-
173- status = transfer_next (dev , irp , context );
167+ status = transfer_next (dev , irp , context );
174168 if (!NT_SUCCESS (status ))
175169 {
176- pending_lock_release (dev , old );
177-
178- ExFreePool (context -> urb );
179- ExFreePool (context );
180- remove_lock_release (dev );
181- return complete_irp (irp , status , 0 );
170+ goto transfer_free ;
182171 }
183172
184- pending_lock_release ( dev , old );
173+ InterlockedExchange ( & dev -> pending_busy [ endpoint -> address ], 0 );
185174 return status ;
175+
176+ transfer_free :
177+ if (pending_busy_taken )
178+ {
179+ InterlockedExchange (& dev -> pending_busy [endpoint -> address ], 0 );
180+ }
181+ if (context )
182+ {
183+ if (context -> urb )
184+ {
185+ ExFreePool (context -> urb );
186+ }
187+ ExFreePool (context );
188+ }
189+ remove_lock_release (dev );
190+ return complete_irp (irp , status , 0 );
186191}
192+
187193NTSTATUS DDKAPI transfer_complete (DEVICE_OBJECT * device_object , IRP * irp ,
188194 void * context )
189195{
190196 NTSTATUS status = STATUS_SUCCESS ;
191197 context_t * c = (context_t * )context ;
192198 int transmitted = 0 ;
193199 libusb_device_t * dev = device_object -> DeviceExtension ;
200+ LONG pending_busy_taken = FALSE, pending_busy = FALSE;
194201
195202 if (irp -> PendingReturned )
196203 {
@@ -234,22 +241,37 @@ NTSTATUS DDKAPI transfer_complete(DEVICE_OBJECT *device_object, IRP *irp,
234241 /* Update transferred size */
235242 c -> information += transmitted ;
236243
237- USBERR ("sequence %d: pending seq %i\n" , c -> sequence , dev -> pending_sequence [c -> address ]);
238-
239244 /* If this is a success, and there is more data to be transferred, then lets go again
240245 *
241- * Note 1: We do not do this if other requests are already pending on the endpoint,
246+ * Note 1: We do not do this if a newer request is already pending on the endpoint,
242247 * as this could change the order of the arrival of data
243248 */
244249 if (NT_SUCCESS (irp -> IoStatus .Status )
245- && (dev -> pending_sequence [c -> address ] == c -> sequence )
246250 && USBD_SUCCESS (c -> urb -> UrbHeader .Status )
247251 && (c -> urb -> UrbHeader .Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER )
248252 && !(transmitted % c -> maximum_packet_size )
249253 && c -> totalLength )
250254 {
255+ PUCHAR virtualAddress ;
251256 int next_size = (c -> totalLength > c -> maxTransferSize ) ? c -> maxTransferSize : c -> totalLength ;
252- PUCHAR virtualAddress = (PUCHAR )MmGetMdlVirtualAddress (c -> mdlAddress );
257+
258+ /* Check if another transfer is on-going on same endpoint */
259+ pending_busy = InterlockedCompareExchange (& dev -> pending_busy [c -> address ], 1 , 0 );
260+ if (pending_busy )
261+ {
262+ USBMSG ("sequence %d resend aborted due to pending conflict\n" , c -> sequence );
263+ goto transfer_free ;
264+ }
265+ pending_busy_taken = TRUE;
266+
267+ /* Check if a newer sequence is pending */
268+ if (InterlockedAdd (& dev -> pending_sequence [c -> address ], 0 ) != c -> sequence )
269+ {
270+ USBMSG ("sequence %d resend aborted due to newer pending\n" , c -> sequence );
271+ goto transfer_free ;
272+ }
273+
274+ virtualAddress = (PUCHAR )MmGetMdlVirtualAddress (c -> mdlAddress );
253275 if (!virtualAddress )
254276 {
255277 USBERR ("[#%d] MmGetMdlVirtualAddress failed\n" , c -> sequence );
@@ -281,11 +303,16 @@ NTSTATUS DDKAPI transfer_complete(DEVICE_OBJECT *device_object, IRP *irp,
281303 goto transfer_free ;
282304 }
283305
306+ InterlockedExchange (& dev -> pending_busy [c -> address ], 0 );
284307 return STATUS_MORE_PROCESSING_REQUIRED ;
285308 }
286309
287310transfer_free :
288311
312+ if (pending_busy_taken )
313+ {
314+ InterlockedExchange (& dev -> pending_busy [c -> address ], 0 );
315+ }
289316 irp -> IoStatus .Information = c -> information ;
290317 if (c -> subMdl )
291318 {
0 commit comments