Added simulated status stage interrupt

pull/10689/head
George Beckstein 2019-02-21 21:02:10 -05:00 committed by aglass0fmilk
parent 171c8fa8e5
commit cfea14ce6d
2 changed files with 67 additions and 23 deletions

View File

@ -64,6 +64,7 @@ public:
static void _usb_event_handler(nrf_drv_usbd_evt_t const * const p_event); static void _usb_event_handler(nrf_drv_usbd_evt_t const * const p_event);
static void _usb_power_event_handler(nrf_drv_power_usb_evt_t event); static void _usb_power_event_handler(nrf_drv_power_usb_evt_t event);
static void _usb_virtual_status_event_handler(void);
private: private:
USBPhyEvents *events; USBPhyEvents *events;
@ -74,7 +75,8 @@ private:
typedef enum usb_hw_event_type_t { typedef enum usb_hw_event_type_t {
USB_HW_EVENT_NONE = 0, USB_HW_EVENT_NONE = 0,
USB_HW_EVENT_USBD = 1, USB_HW_EVENT_USBD = 1,
USB_HW_EVENT_POWER = 2 USB_HW_EVENT_POWER = 2,
USB_HW_EVENT_VIRTUAL_STATUS = 3
} usb_hw_event_type_t; } usb_hw_event_type_t;
// Event type to process // Event type to process

View File

@ -65,7 +65,7 @@ void USBD_HAL_IRQHandler(void);
static USBPhyHw *instance = 0; static USBPhyHw *instance = 0;
static bool virtual_status_xfer_event; static volatile bool virtual_status_xfer_event;
static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event); static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event);
static void power_usb_event_handler(nrf_drv_power_usb_evt_t event); static void power_usb_event_handler(nrf_drv_power_usb_evt_t event);
@ -291,13 +291,18 @@ void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) {
if(setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) if(setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK)
{ {
// This is the status stage -- trigger the status task and notify the Mbed stack // This is the status stage -- trigger the status task and notify the Mbed stack
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS); // Don't trigger status stage unless endpoint is not busy!
// (Causes an undocumented hardware-initiated stall on the control endpoint)
if(nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPIN0))
nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK);
else
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
virtual_status_xfer_event = true; virtual_status_xfer_event = true;
// The status stage flag will be handled during the next interrupt // Trigger an interrupt to process the virtual status event
NVIC_SetPendingIRQ(USBD_IRQn); NVIC_SetPendingIRQ(USBD_IRQn);
//events->ep0_out();
return; return;
} }
} }
@ -325,14 +330,21 @@ void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) {
if(setup_buf.wLength == 0 if(setup_buf.wLength == 0
|| ((setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) == 0)) || ((setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) == 0))
{ {
// This is the status stage -- trigger the status task and notify the Mbed stack // This is the status stage -- trigger the status task and notify the Mbed stack
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
// Don't trigger status stage unless endpoint is not busy!
// (Causes an undocumented hardware-initiated stall on the control endpoint)
if(nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPOUT0))
nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK);
else
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
virtual_status_xfer_event = true; virtual_status_xfer_event = true;
// The status stage flag will be handled during the next interrupt // Trigger an interrupt to process the virtual status event
//NVIC_SetPendingIRQ(USBD_IRQn); NVIC_SetPendingIRQ(USBD_IRQn);
//events->ep0_in();
return; return;
} }
} }
@ -415,17 +427,7 @@ void USBPhyHw::endpoint_abort(usb_ep_t endpoint) {
void USBPhyHw::process() { void USBPhyHw::process() {
// Process virtual status transfers if (usb_event_type == USB_HW_EVENT_USBD) {
if(virtual_status_xfer_event)
{
virtual_status_xfer_event = false;
// Notify Mbed stack of status stage transfer completion
if(setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) // DATA IN transfer, Status OUT transfer
events->ep0_out();
else // DATA OUT transfer, Status IN transfer
events->ep0_in();
}
else if (usb_event_type == USB_HW_EVENT_USBD) {
// Process regular USBD events // Process regular USBD events
switch (usb_event.type) { switch (usb_event.type) {
@ -451,14 +453,36 @@ void USBPhyHw::process() {
if(IS_IN_EP(usb_event.data.eptransfer.ep)) if(IS_IN_EP(usb_event.data.eptransfer.ep))
{ {
if((usb_event.data.eptransfer.ep & 0x7F) == 0) if((usb_event.data.eptransfer.ep & 0x7F) == 0)
{
events->ep0_in(); events->ep0_in();
// Check for pending virtual status transfer
if(virtual_status_xfer_event)
{
// Notify the upper stack that the status transfer is done
// as well at this point
virtual_status_xfer_event = false;
events->ep0_out();
}
}
else else
events->in((usb_ep_t) usb_event.data.eptransfer.ep); events->in((usb_ep_t) usb_event.data.eptransfer.ep);
} }
else else
{ {
if((usb_event.data.eptransfer.ep & 0x7F) == 0) if((usb_event.data.eptransfer.ep & 0x7F) == 0)
{
events->ep0_out(); events->ep0_out();
// Check for pending virtual status transfer
if(virtual_status_xfer_event)
{
// Notify the upper stack that the status transfer is done
// as well at this point
virtual_status_xfer_event = false;
events->ep0_in();
}
}
else else
events->out((usb_ep_t) usb_event.data.eptransfer.ep); events->out((usb_ep_t) usb_event.data.eptransfer.ep);
} }
@ -502,6 +526,14 @@ void USBPhyHw::process() {
ASSERT(false); ASSERT(false);
} }
} }
else if (usb_event_type == USB_HW_EVENT_VIRTUAL_STATUS)
{
// Notify Mbed stack of status stage transfer completion
if(setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) // DATA IN transfer, Status OUT transfer
events->ep0_out();
else // DATA OUT transfer, Status IN transfer
events->ep0_in();
}
// Unflag the event type // Unflag the event type
usb_event_type = USB_HW_EVENT_NONE; usb_event_type = USB_HW_EVENT_NONE;
@ -529,6 +561,14 @@ void USBPhyHw::_usb_power_event_handler(nrf_drv_power_usb_evt_t event) {
instance->events->start_process(); instance->events->start_process();
} }
void USBPhyHw::_usb_virtual_status_event_handler(void) {
disable_usb_interrupts();
// Tell the upper layers of the stack to process the event
instance->usb_event_type = USB_HW_EVENT_VIRTUAL_STATUS;
instance->events->start_process();
}
nrf_drv_usbd_transfer_t* USBPhyHw::get_transfer_buffer(usb_ep_t endpoint) { nrf_drv_usbd_transfer_t* USBPhyHw::get_transfer_buffer(usb_ep_t endpoint) {
// Index is base endpoint number * 2 (output), add 1 for input endpoints // Index is base endpoint number * 2 (output), add 1 for input endpoints
return &transfer_buf[(((endpoint & 0x7F) << 1) + ((endpoint & 0x80) >> 7))]; return &transfer_buf[(((endpoint & 0x7F) << 1) + ((endpoint & 0x80) >> 7))];
@ -589,9 +629,11 @@ void USBD_HAL_IRQHandler(void)
// Process the virtual status stage transfer event // Process the virtual status stage transfer event
if(virtual_status_xfer_event) if(virtual_status_xfer_event)
{ {
// Trigger a dummy event handler if(instance) {
nrf_drv_usbd_evt_t dummy; instance->_usb_virtual_status_event_handler();
usbd_event_handler(&dummy); }
virtual_status_xfer_event = false;
} }
// Call Nordic driver IRQ handler // Call Nordic driver IRQ handler
USBD_IRQHandler(); USBD_IRQHandler();