Implement LPC1768 USB abort function

Implement the USB abort function so interrupts wont fire for a
transfer that has been aborted. The transfer may still take place
but the buffer passed into endpoint_write or endpoint_read will not
be used.
pull/9768/head
Russ Butler 2018-05-15 19:32:48 -05:00
parent 044804200b
commit 67498e384a
1 changed files with 56 additions and 30 deletions

View File

@ -120,7 +120,7 @@
static USBPhyHw *instance; static USBPhyHw *instance;
static volatile int epComplete; static uint32_t opStarted;
static void SIECommand(uint32_t command) static void SIECommand(uint32_t command)
{ {
@ -250,16 +250,24 @@ static uint8_t selectEndpointClearInterrupt(uint8_t endpoint)
static void enableEndpointEvent(uint8_t endpoint) static void enableEndpointEvent(uint8_t endpoint)
{ {
// Enable an endpoint interrupt // Route endpoint events to USBEpIntSt so they trigger an interrupt
LPC_USB->USBEpIntEn |= EP(endpoint); LPC_USB->USBEpIntEn |= EP(endpoint);
} }
// Do not use disableEndpointEvent. If an endpoint's event is disabled
// and a transfer occurs on that endpoint then that endpoint will enter
// a bad state. Future transfers on that endpoint will not trigger an
// interrupt even if the endpoint event is enabled again or the
// endpoint is reinitialized
/*
static void disableEndpointEvent(uint8_t endpoint) __attribute__((unused)); static void disableEndpointEvent(uint8_t endpoint) __attribute__((unused));
static void disableEndpointEvent(uint8_t endpoint) static void disableEndpointEvent(uint8_t endpoint)
{ {
// Disable an endpoint interrupt // Don't set endpoint interrupt to pending in USBEpIntSt when an event occurs.
// Instead route them to USBDMARSt so they can be ignored.
LPC_USB->USBEpIntEn &= ~EP(endpoint); LPC_USB->USBEpIntEn &= ~EP(endpoint);
} }
*/
static uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer, uint32_t size) static uint32_t endpointReadcore(uint8_t endpoint, uint8_t *buffer, uint32_t size)
@ -392,10 +400,18 @@ void USBPhyHw::init(USBPhyEvents *events)
// Connect must be low for at least 2.5uS // Connect must be low for at least 2.5uS
wait(0.3); wait(0.3);
// Disable control endpoints
SIEsetEndpointStatus(EP0IN, SIE_SES_DA);
SIEsetEndpointStatus(EP0OUT, SIE_SES_DA);
// Set the maximum packet size for the control endpoints // Set the maximum packet size for the control endpoints
endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL); endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL); endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL);
// Map interrupts to USBEpIntSt
enableEndpointEvent(EP0IN);
enableEndpointEvent(EP0OUT);
// Attach IRQ // Attach IRQ
instance = this; instance = this;
NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr); NVIC_SetVector(USB_IRQn, (uint32_t)&_usbisr);
@ -413,6 +429,7 @@ void USBPhyHw::deinit()
// Disable USB interrupts // Disable USB interrupts
NVIC_DisableIRQ(USB_IRQn); NVIC_DisableIRQ(USB_IRQn);
events = NULL; events = NULL;
opStarted = 0;
} }
bool USBPhyHw::powered() bool USBPhyHw::powered()
@ -422,8 +439,9 @@ bool USBPhyHw::powered()
void USBPhyHw::connect(void) void USBPhyHw::connect(void)
{ {
enableEndpointEvent(EP0IN); // Enable control endpoints
enableEndpointEvent(EP0OUT); SIEsetEndpointStatus(EP0IN, 0);
SIEsetEndpointStatus(EP0OUT, 0);
// Connect USB device // Connect USB device
SIEconnect(); SIEconnect();
@ -431,8 +449,9 @@ void USBPhyHw::connect(void)
void USBPhyHw::disconnect(void) void USBPhyHw::disconnect(void)
{ {
disableEndpointEvent(EP0IN); // Disable control endpoints
disableEndpointEvent(EP0OUT); SIEsetEndpointStatus(EP0IN, SIE_SES_DA);
SIEsetEndpointStatus(EP0OUT, SIE_SES_DA);
if (LPC_USB->USBEpIntSt & EP(EP0IN)) { if (LPC_USB->USBEpIntSt & EP(EP0IN)) {
selectEndpointClearInterrupt(EP0IN); selectEndpointClearInterrupt(EP0IN);
@ -512,9 +531,9 @@ void USBPhyHw::ep0_stall(void)
bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size)
{ {
opStarted |= EP(endpoint);
read_buffers[endpoint] = data; read_buffers[endpoint] = data;
read_sizes[endpoint] = size; read_sizes[endpoint] = size;
enableEndpointEvent(endpoint);
uint8_t status = SIEselectEndpoint(endpoint); uint8_t status = SIEselectEndpoint(endpoint);
if (status & ((1 << 5) | (1 << 6))) { if (status & ((1 << 5) | (1 << 6))) {
// If any buffer has data then set the interrupt flag // If any buffer has data then set the interrupt flag
@ -525,13 +544,7 @@ bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size)
uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint)
{ {
opStarted &= ~EP(endpoint);
//for isochronous endpoint, we don't wait an interrupt
if ((DESC_TO_PHY(endpoint) >> 1) % 3 || (DESC_TO_PHY(endpoint) >> 1) == 0) {
if (!(epComplete & EP(endpoint))) {
return 0;
}
}
uint32_t bytesRead = endpointReadcore(endpoint, read_buffers[endpoint], read_sizes[endpoint]); uint32_t bytesRead = endpointReadcore(endpoint, read_buffers[endpoint], read_sizes[endpoint]);
read_buffers[endpoint] = NULL; read_buffers[endpoint] = NULL;
@ -543,13 +556,12 @@ uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint)
SIEclearBuffer(); SIEclearBuffer();
} }
epComplete &= ~EP(endpoint);
return bytesRead; return bytesRead;
} }
bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size)
{ {
epComplete &= ~EP(endpoint); opStarted |= EP(endpoint);
endpointWritecore(endpoint, data, size); endpointWritecore(endpoint, data, size);
return true; return true;
@ -557,7 +569,13 @@ bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size)
void USBPhyHw::endpoint_abort(usb_ep_t endpoint) void USBPhyHw::endpoint_abort(usb_ep_t endpoint)
{ {
//TODO - needs to be implemented opStarted &= ~EP(endpoint);
// Clear out transfer buffers since the transfer has been aborted
if (OUT_EP(endpoint)) {
read_buffers[endpoint] = NULL;
read_sizes[endpoint] = 0;
}
} }
bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t maxPacket, usb_ep_type_t type) bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t maxPacket, usb_ep_type_t type)
@ -571,9 +589,12 @@ bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t maxPacket, usb_ep_type_t
while (!(LPC_USB->USBDevIntSt & EP_RLZED)); while (!(LPC_USB->USBDevIntSt & EP_RLZED));
LPC_USB->USBDevIntClr = EP_RLZED; LPC_USB->USBDevIntClr = EP_RLZED;
if (IN_EP(endpoint)) { // Map interrupts to USBEpIntSt
enableEndpointEvent(endpoint); enableEndpointEvent(endpoint);
}
// Enable this endpoint
SIEsetEndpointStatus(endpoint, 0);
return true; return true;
} }
@ -581,10 +602,15 @@ void USBPhyHw::endpoint_remove(usb_ep_t endpoint)
{ {
// Unrealise an endpoint // Unrealise an endpoint
disableEndpointEvent(endpoint); opStarted &= ~EP(endpoint);
// reset this endpoint, including data toggle // Disable this endpoint
SIEsetEndpointStatus(endpoint, 0); SIEsetEndpointStatus(endpoint, SIE_SES_DA);
// Clear the given interrupt bit in USBEpIntSt if it is set
if (LPC_USB->USBEpIntSt & EP(endpoint)) {
selectEndpointClearInterrupt(endpoint);
}
LPC_USB->USBDevIntClr = EP_RLZED; LPC_USB->USBDevIntClr = EP_RLZED;
LPC_USB->USBReEp &= ~EP(endpoint); LPC_USB->USBReEp &= ~EP(endpoint);
@ -731,15 +757,15 @@ void USBPhyHw::process(void)
uint8_t endpoint = PHY_TO_DESC(num); uint8_t endpoint = PHY_TO_DESC(num);
if (LPC_USB->USBEpIntSt & EP(endpoint)) { if (LPC_USB->USBEpIntSt & EP(endpoint)) {
selectEndpointClearInterrupt(endpoint); selectEndpointClearInterrupt(endpoint);
epComplete |= EP(endpoint); if (opStarted & EP(endpoint)) {
if (IN_EP(endpoint)) { if (IN_EP(endpoint)) {
events->in(endpoint); events->in(endpoint);
} else { } else {
disableEndpointEvent(endpoint);
events->out(endpoint); events->out(endpoint);
} }
} }
} }
}
LPC_USB->USBDevIntClr = EP_SLOW; LPC_USB->USBDevIntClr = EP_SLOW;
} }