mirror of https://github.com/ARMmbed/mbed-os.git
Fix LPC17XX and LPC40XX USB race condition
If a SETUP packet arrives shortly after an IN then the packets will be processed in the wrong order - SETUP first then IN. This causes the subsequent control transfer to fail. Fix this problem by processing IN packets before processing SETUP packets.pull/5878/head
parent
635a82495c
commit
eda332cbf8
|
@ -590,6 +590,25 @@ void USBHAL::usbisr(void) {
|
|||
if (LPC_USB->USBDevIntSt & EP_SLOW) {
|
||||
// (Slow) Endpoint Interrupt
|
||||
|
||||
// Process IN packets before SETUP packets
|
||||
// Note - order of OUT and SETUP does not matter as OUT packets
|
||||
// are clobbered by SETUP packets and thus ignored.
|
||||
//
|
||||
// A SETUP packet can arrive at any time where as an IN packet is
|
||||
// only sent after calling EP0write and an OUT packet after EP0read.
|
||||
// The functions EP0write and EP0read are called only in response to
|
||||
// a setup packet or IN/OUT packets sent in response to that
|
||||
// setup packet. Therefore, if an IN or OUT packet is pending
|
||||
// at the same time as a SETUP packet, the IN or OUT packet belongs
|
||||
// to the previous control transfer and should either be processed
|
||||
// before the SETUP packet (in the case of IN) or dropped (in the
|
||||
// case of OUT as SETUP clobbers the OUT data).
|
||||
if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
|
||||
selectEndpointClearInterrupt(EP0IN);
|
||||
LPC_USB->USBDevIntClr = EP_SLOW;
|
||||
EP0in();
|
||||
}
|
||||
|
||||
// Process each endpoint interrupt
|
||||
if (LPC_USB->USBEpIntSt & EP(EP0OUT)) {
|
||||
if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) {
|
||||
|
@ -601,12 +620,6 @@ void USBHAL::usbisr(void) {
|
|||
LPC_USB->USBDevIntClr = EP_SLOW;
|
||||
}
|
||||
|
||||
if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
|
||||
selectEndpointClearInterrupt(EP0IN);
|
||||
LPC_USB->USBDevIntClr = EP_SLOW;
|
||||
EP0in();
|
||||
}
|
||||
|
||||
for (uint8_t num = 2; num < 16*2; num++) {
|
||||
if (LPC_USB->USBEpIntSt & EP(num)) {
|
||||
selectEndpointClearInterrupt(num);
|
||||
|
|
|
@ -595,6 +595,25 @@ void USBHAL::usbisr(void) {
|
|||
if (LPC_USB->DevIntSt & EP_SLOW) {
|
||||
// (Slow) Endpoint Interrupt
|
||||
|
||||
// Process IN packets before SETUP packets
|
||||
// Note - order of OUT and SETUP does not matter as OUT packets
|
||||
// are clobbered by SETUP packets and thus ignored.
|
||||
//
|
||||
// A SETUP packet can arrive at any time where as an IN packet is
|
||||
// only sent after calling EP0write and an OUT packet after EP0read.
|
||||
// The functions EP0write and EP0read are called only in response to
|
||||
// a setup packet or IN/OUT packets sent in response to that
|
||||
// setup packet. Therefore, if an IN or OUT packet is pending
|
||||
// at the same time as a SETUP packet, the IN or OUT packet belongs
|
||||
// to the previous control transfer and should either be processed
|
||||
// before the SETUP packet (in the case of IN) or dropped (in the
|
||||
// case of OUT as SETUP clobbers the OUT data).
|
||||
if (LPC_USB->EpIntSt & EP(EP0IN)) {
|
||||
selectEndpointClearInterrupt(EP0IN);
|
||||
LPC_USB->DevIntClr = EP_SLOW;
|
||||
EP0in();
|
||||
}
|
||||
|
||||
// Process each endpoint interrupt
|
||||
if (LPC_USB->EpIntSt & EP(EP0OUT)) {
|
||||
if (selectEndpointClearInterrupt(EP0OUT) & SIE_SE_STP) {
|
||||
|
@ -606,12 +625,6 @@ void USBHAL::usbisr(void) {
|
|||
LPC_USB->DevIntClr = EP_SLOW;
|
||||
}
|
||||
|
||||
if (LPC_USB->EpIntSt & EP(EP0IN)) {
|
||||
selectEndpointClearInterrupt(EP0IN);
|
||||
LPC_USB->DevIntClr = EP_SLOW;
|
||||
EP0in();
|
||||
}
|
||||
|
||||
for (uint8_t num = 2; num < 16*2; num++) {
|
||||
if (LPC_USB->EpIntSt & EP(num)) {
|
||||
selectEndpointClearInterrupt(num);
|
||||
|
|
Loading…
Reference in New Issue