Skip to content

Kinetis USB improvements and fixes #5877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions features/unsupported/USBDevice/USBDevice/USBDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,27 +187,8 @@ bool USBDevice::controlOut(void)
/* Check we should be transferring data OUT */
if (transfer.direction != HOST_TO_DEVICE)
{
#if defined(TARGET_KL25Z) | defined(TARGET_KL43Z) | defined(TARGET_KL46Z) | defined(TARGET_K20D5M) | defined(TARGET_K64F) | defined(TARGET_K22F) | defined(TARGET_TEENSY3_1)
/*
* We seem to have a pending device-to-host transfer. The host must have
* sent a new control request without waiting for us to finish processing
* the previous one. This appears to happen when we're connected to certain
* USB 3.0 host chip set. Do a zeor-length send to tell the host we're not
* ready for the new request - that'll make it resend - and then just
* pretend we were successful here so that the pending transfer can finish.
*/
uint8_t buf[1] = { 0 };
EP0write(buf, 0);

/* execute our pending ttransfer */
controlIn();

/* indicate success */
return true;
#else
/* for other platforms, count on the HAL to handle this case */
return false;
#endif
}

/* Read from endpoint */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "fsl_common.h"
#endif
#include "USBHAL.h"
#include "mbed_critical.h"

USBHAL * USBHAL::instance;

Expand Down Expand Up @@ -64,6 +65,13 @@ typedef struct BDT {
uint32_t address; // Addr
} BDT;

typedef enum {
CTRL_XFER_READY,
CTRL_XFER_IN,
CTRL_XFER_NONE,
CTRL_XFER_OUT
} ctrl_xfer_t;

// there are:
// * 4 bidirectionnal endpt -> 8 physical endpt
// * as there are ODD and EVEN buffer -> 8*2 bdt
Expand All @@ -73,6 +81,7 @@ uint8_t * endpoint_buffer[NUMBER_OF_PHYSICAL_ENDPOINTS * 2];

static uint8_t set_addr = 0;
static uint8_t addr = 0;
static ctrl_xfer_t ctrl_xfer = CTRL_XFER_READY;

static uint32_t Data1 = 0x55555555;

Expand Down Expand Up @@ -223,11 +232,16 @@ bool USBHAL::realiseEndpoint(uint8_t endpoint, uint32_t maxPacket, uint32_t flag
USB_ENDPT_EPRXEN_MASK; // en RX (OUT) tran.
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].byte_count = maxPacket;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].address = (uint32_t) buf;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_OWN_MASK | BD_DTS_MASK;
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info = BD_DTS_MASK;
bdt[EP_BDT_IDX(log_endpoint, RX, EVEN)].info = 0;
if (log_endpoint == 0) {
// Prepare for setup packet
bdt[EP_BDT_IDX(log_endpoint, RX, ODD )].info |= BD_OWN_MASK;
}
}

Data1 |= (1 << endpoint);
// First transfer will be a DATA0 packet
Data1 &= ~(1 << endpoint);

return true;
}
Expand All @@ -239,13 +253,35 @@ void USBHAL::EP0setup(uint8_t *buffer) {
}

void USBHAL::EP0readStage(void) {
Data1 &= ~1UL; // set DATA0
bdt[0].info = (BD_DTS_MASK | BD_OWN_MASK);
// Not needed
}

void USBHAL::EP0read(void) {
uint32_t idx = EP_BDT_IDX(PHY_TO_LOG(EP0OUT), RX, 0);
bdt[idx].byte_count = MAX_PACKET_SIZE_EP0;
if (ctrl_xfer == CTRL_XFER_READY) {
// Transfer is done so ignore call
return;
}
if (ctrl_xfer == CTRL_XFER_IN) {
ctrl_xfer = CTRL_XFER_READY;
// Control transfer with a data IN stage.
// The next packet received will be the status packet - an OUT packet using DATA1
//
// PROBLEM:
// If a Setup packet is received after status packet of
// a Control In transfer has been received in the RX buffer
// but before the processor has had a chance the prepare
// this buffer for the Setup packet, the Setup packet
// will be dropped.
//
// WORKAROUND:
// Set data toggle to DATA0 so if the status stage of a
// Control In transfer arrives it will be ACKed by hardware
// but will be discarded without filling the RX buffer.
// This allows a subsequent SETUP packet to be stored
// without any processor intervention.
Data1 &= ~1UL; // set DATA0
}
endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
}

uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
Expand All @@ -255,20 +291,50 @@ uint32_t USBHAL::EP0getReadResult(uint8_t *buffer) {
}

void USBHAL::EP0write(uint8_t *buffer, uint32_t size) {
if (ctrl_xfer == CTRL_XFER_READY) {
// Transfer is done so ignore call
return;
}
if ((ctrl_xfer == CTRL_XFER_NONE) || (ctrl_xfer == CTRL_XFER_OUT)) {
// Prepare for next setup packet
endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
ctrl_xfer = CTRL_XFER_READY;
}
endpointWrite(EP0IN, buffer, size);
}

void USBHAL::EP0getWriteResult(void) {
}

void USBHAL::EP0stall(void) {
if (ctrl_xfer == CTRL_XFER_READY) {
// Transfer is done so ignore call
return;
}
ctrl_xfer = CTRL_XFER_READY;
core_util_critical_section_enter();
stallEndpoint(EP0OUT);
// Prepare for next setup packet
// Note - time between stalling and setting up the endpoint
// must be kept to a minimum to prevent a dropped SETUP
// packet.
endpointRead(EP0OUT, MAX_PACKET_SIZE_EP0);
core_util_critical_section_exit();
}

EP_STATUS USBHAL::endpointRead(uint8_t endpoint, uint32_t maximumSize) {
endpoint = PHY_TO_LOG(endpoint);
uint32_t idx = EP_BDT_IDX(endpoint, RX, 0);
uint8_t log_endpoint = PHY_TO_LOG(endpoint);

uint32_t idx = EP_BDT_IDX(log_endpoint, RX, 0);
bdt[idx].byte_count = maximumSize;
if ((Data1 >> endpoint) & 1) {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
}
else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
}

Data1 ^= (1 << endpoint);
return EP_PENDING;
}

Expand Down Expand Up @@ -307,18 +373,14 @@ EP_STATUS USBHAL::endpointReadResult(uint8_t endpoint, uint8_t * buffer, uint32_
buffer[n] = ep_buf[n];
}

if (((Data1 >> endpoint) & 1) == ((bdt[idx].info >> 6) & 1)) {
if (setup && (buffer[6] == 0)) // if no setup data stage,
Data1 &= ~1UL; // set DATA0
else
Data1 ^= (1 << endpoint);
}

if (((Data1 >> endpoint) & 1)) {
bdt[idx].info = BD_DTS_MASK | BD_DATA01_MASK | BD_OWN_MASK;
}
else {
bdt[idx].info = BD_DTS_MASK | BD_OWN_MASK;
if (setup) {
// Record the setup type
if (buffer[6] == 0) {
ctrl_xfer = CTRL_XFER_NONE;
} else {
uint8_t in_xfer = (buffer[0] >> 7) & 1;
ctrl_xfer = in_xfer ? CTRL_XFER_IN : CTRL_XFER_OUT;
}
}

USB0->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
Expand Down Expand Up @@ -351,9 +413,9 @@ EP_STATUS USBHAL::endpointWrite(uint8_t endpoint, uint8_t *data, uint32_t size)
}

if ((Data1 >> endpoint) & 1) {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
} else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK | BD_DATA01_MASK;
} else {
bdt[idx].info = BD_OWN_MASK | BD_DTS_MASK;
}

Data1 ^= (1 << endpoint);
Expand Down Expand Up @@ -450,7 +512,7 @@ void USBHAL::usbisr(void) {

// setup packet
if ((num == 0) && (TOK_PID((EP_BDT_IDX(num, dir, ev_odd))) == SETUP_TOKEN)) {
Data1 &= ~0x02;
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;

Expand Down