mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Alternate Kinetis USB stuck sending bug fix
If an IN endpoint is stalled during a transfer then the data being sent will repeated and flood the USB bus. This patch prevents endpoints from being stalled in the middle of a transfer by control requests by keeping USB suspended until the setup phase of the control request is done.pull/9768/head
							parent
							
								
									a75b40a778
								
							
						
					
					
						commit
						c76d80e36e
					
				| 
						 | 
				
			
			@ -89,6 +89,7 @@ uint8_t ep1_buffer[2][MAX_PACKET_SIZE_EP1];
 | 
			
		|||
uint8_t ep2_buffer[2][MAX_PACKET_SIZE_EP2];
 | 
			
		||||
uint8_t ep3_buffer[2][MAX_PACKET_SIZE_EP3];
 | 
			
		||||
 | 
			
		||||
static bool setup_suspend = false;
 | 
			
		||||
static uint8_t set_addr = 0;
 | 
			
		||||
static uint8_t addr = 0;
 | 
			
		||||
static ctrl_xfer_t ctrl_xfer = CTRL_XFER_READY;
 | 
			
		||||
| 
						 | 
				
			
			@ -317,6 +318,12 @@ void USBPhyHw::ep0_read(uint8_t *data, uint32_t size)
 | 
			
		|||
    } else {
 | 
			
		||||
        endpoint_read(EP0OUT, data, size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clear suspend after the setup stage
 | 
			
		||||
    if (setup_suspend) {
 | 
			
		||||
        USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
 | 
			
		||||
        setup_suspend = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t USBPhyHw::ep0_read_result()
 | 
			
		||||
| 
						 | 
				
			
			@ -336,6 +343,12 @@ void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size)
 | 
			
		|||
        ctrl_xfer = CTRL_XFER_READY;
 | 
			
		||||
     }
 | 
			
		||||
    endpoint_write(EP0IN, buffer, size);
 | 
			
		||||
 | 
			
		||||
    // Clear suspend after the setup stage
 | 
			
		||||
    if (setup_suspend) {
 | 
			
		||||
        USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
 | 
			
		||||
        setup_suspend = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void USBPhyHw::ep0_stall()
 | 
			
		||||
| 
						 | 
				
			
			@ -345,6 +358,13 @@ void USBPhyHw::ep0_stall()
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ctrl_xfer = CTRL_XFER_READY;
 | 
			
		||||
 | 
			
		||||
    // Clear suspend after the setup stage
 | 
			
		||||
    if (setup_suspend) {
 | 
			
		||||
        USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
 | 
			
		||||
        setup_suspend = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    core_util_critical_section_enter();
 | 
			
		||||
    endpoint_stall(EP0OUT);
 | 
			
		||||
    // Prepare for next setup packet
 | 
			
		||||
| 
						 | 
				
			
			@ -503,7 +523,6 @@ bool USBPhyHw::endpoint_read_result_core(usb_ep_t endpoint, uint8_t *data, uint3
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
 | 
			
		||||
    *bytes_read = sz;
 | 
			
		||||
 | 
			
		||||
    epComplete &= ~EP(DESC_TO_PHY(endpoint));
 | 
			
		||||
| 
						 | 
				
			
			@ -564,6 +583,7 @@ void USBPhyHw::process()
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        // enable control endpoint
 | 
			
		||||
        setup_suspend = false;
 | 
			
		||||
        endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
 | 
			
		||||
        endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +628,7 @@ void USBPhyHw::process()
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // token interrupt
 | 
			
		||||
    if (istat & 1<<3) {
 | 
			
		||||
    if (istat & USB_ISTAT_TOKDNE_MASK) {
 | 
			
		||||
        uint32_t num  = (USB0->STAT >> 4) & 0x0F;
 | 
			
		||||
        uint32_t dir  = (USB0->STAT >> 3) & 0x01;
 | 
			
		||||
        uint32_t ev_odd = (USB0->STAT >> 2) & 0x01;
 | 
			
		||||
| 
						 | 
				
			
			@ -616,6 +636,7 @@ void USBPhyHw::process()
 | 
			
		|||
 | 
			
		||||
        // setup packet
 | 
			
		||||
        if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) {
 | 
			
		||||
            setup_suspend = true;
 | 
			
		||||
            Data1 |= 0x02 | 0x01; // set DATA1 for TX and RX
 | 
			
		||||
            bdt[EP_BDT_IDX(0, TX, EVEN)].info &= ~BD_OWN_MASK;
 | 
			
		||||
            bdt[EP_BDT_IDX(0, TX, ODD)].info  &= ~BD_OWN_MASK;
 | 
			
		||||
| 
						 | 
				
			
			@ -665,6 +686,16 @@ void USBPhyHw::process()
 | 
			
		|||
        USB0->ISTAT = USB_ISTAT_ERROR_MASK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check if the suspend condition should be removed here
 | 
			
		||||
    // 1. Don't attempt to clear USB_CTL_TXSUSPENDTOKENBUSY_MASK if it isn't set. This
 | 
			
		||||
    //      is to avoid potential race conditions.
 | 
			
		||||
    // 2. If a setup packet is being processed then remove suspend on the next control transfer rather than here
 | 
			
		||||
    // 3. Process all pending packets before removing suspend
 | 
			
		||||
    bool suspended = (USB0->CTL & USB_CTL_TXSUSPENDTOKENBUSY_MASK) != 0;
 | 
			
		||||
    if (suspended && !setup_suspend && ((USB0->ISTAT & USB_ISTAT_TOKDNE_MASK) == 0)) {
 | 
			
		||||
        USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    NVIC_ClearPendingIRQ(USB0_IRQn);
 | 
			
		||||
    NVIC_EnableIRQ(USB0_IRQn);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue