@@ -62,6 +62,7 @@ enum TransferState {
62
62
#[ derive( Copy , Clone ) ]
63
63
struct EP0State {
64
64
direction : UsbDirection ,
65
+ remaining_size : u16 ,
65
66
in_transfer_state : TransferState ,
66
67
is_set_address : bool ,
67
68
}
@@ -109,6 +110,7 @@ impl<'c> Usbd<'c> {
109
110
iso_out_used : false ,
110
111
ep0_state : Mutex :: new ( Cell :: new ( EP0State {
111
112
direction : UsbDirection :: Out ,
113
+ remaining_size : 0 ,
112
114
in_transfer_state : TransferState :: NoTransfer ,
113
115
is_set_address : false ,
114
116
} ) ) ,
@@ -193,7 +195,7 @@ impl<'c> Usbd<'c> {
193
195
false => UsbDirection :: In ,
194
196
true => UsbDirection :: Out ,
195
197
} ;
196
-
198
+ ep0_state . remaining_size = ( buf [ 6 ] as u16 ) | ( ( buf [ 7 ] as u16 ) << 8 ) ;
197
199
ep0_state. is_set_address = ( buf[ 0 ] == 0x00 ) && ( buf[ 1 ] == 0x05 ) ;
198
200
199
201
if ep0_state. direction == UsbDirection :: Out {
@@ -435,6 +437,14 @@ impl UsbBus for Usbd<'_> {
435
437
return true ;
436
438
}
437
439
440
+ if ep0_state. direction == UsbDirection :: In && ep0_state. remaining_size == 0 {
441
+ // Device sent all the requested data, no need to send ZLP.
442
+ // Host will issue an OUT transfer in this case, device should
443
+ // respond with a status stage.
444
+ regs. tasks_ep0status . write ( |w| w. tasks_ep0status ( ) . set_bit ( ) ) ;
445
+ return true ;
446
+ }
447
+
438
448
false
439
449
} ) ;
440
450
@@ -499,6 +509,10 @@ impl UsbBus for Usbd<'_> {
499
509
}
500
510
} ) ;
501
511
512
+ let mut ep0_state = self . ep0_state . borrow ( cs) . get ( ) ;
513
+ ep0_state. remaining_size = ep0_state. remaining_size . saturating_sub ( buf. len ( ) as u16 ) ;
514
+ self . ep0_state . borrow ( cs) . set ( ep0_state) ;
515
+
502
516
// Hack: trigger status stage if the IN transfer is not acknowledged after a few frames,
503
517
// so record the current frame here; the actual test and status stage activation happens
504
518
// in the poll method.
0 commit comments