Autoformatted with astyle

pull/10952/head
George Beckstein 2019-03-14 22:23:19 -04:00 committed by Arto Kinnunen
parent b2ae05f991
commit 974e8899e0
2 changed files with 443 additions and 401 deletions

View File

@ -21,8 +21,8 @@
#include "USBPhy.h" #include "USBPhy.h"
extern "C" { extern "C" {
#include "nrf_drv_usbd.h" #include "nrf_drv_usbd.h"
#include "nrfx_power.h" #include "nrfx_power.h"
} }
class USBPhyHw : public USBPhy { class USBPhyHw : public USBPhy {
@ -41,7 +41,7 @@ public:
virtual void sof_disable(); virtual void sof_disable();
virtual void set_address(uint8_t address); virtual void set_address(uint8_t address);
virtual void remote_wakeup(); virtual void remote_wakeup();
virtual const usb_ep_table_t* endpoint_table(); virtual const usb_ep_table_t *endpoint_table();
virtual uint32_t ep0_set_max_packet(uint32_t max_packet); virtual uint32_t ep0_set_max_packet(uint32_t max_packet);
virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size); virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size);
@ -62,7 +62,7 @@ public:
virtual void process(); virtual void process();
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(nrfx_power_usb_evt_t event); static void _usb_power_event_handler(nrfx_power_usb_evt_t event);
static void _usb_virtual_status_event_handler(void); static void _usb_virtual_status_event_handler(void);
@ -73,10 +73,10 @@ private:
bool connect_enabled; bool connect_enabled;
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_VIRTUAL_STATUS = 3
} usb_hw_event_type_t; } usb_hw_event_type_t;
// Event type to process // Event type to process
@ -95,7 +95,7 @@ private:
nrf_drv_usbd_transfer_t transfer_buf[18]; nrf_drv_usbd_transfer_t transfer_buf[18];
// Returns the appropriate transfer structure buffer for the given endpoint // Returns the appropriate transfer structure buffer for the given endpoint
nrf_drv_usbd_transfer_t* get_transfer_buffer(usb_ep_t endpoint); nrf_drv_usbd_transfer_t *get_transfer_buffer(usb_ep_t endpoint);
// Returns the corresponding enumeration given an mbed endpoint number // Returns the corresponding enumeration given an mbed endpoint number
static nrf_drv_usbd_ep_t get_nordic_endpoint(usb_ep_t endpoint); static nrf_drv_usbd_ep_t get_nordic_endpoint(usb_ep_t endpoint);

View File

@ -24,8 +24,8 @@
#define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE #define MAX_PACKET_ISO NRF_DRV_USBD_ISOSIZE
#define ENDPOINT_NON_ISO (USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_ALLOW_INT) #define ENDPOINT_NON_ISO (USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_ALLOW_INT)
#define IS_IN_EP(ep) (ep & 0x80) // Checks if the given endpoint is an IN endpoint (MSB set) #define IS_IN_EP(ep) (ep & 0x80) // Checks if the given endpoint is an IN endpoint (MSB set)
#define IS_OUT_EP(ep) (ep & ~0x80) // Checks if the given endpoint is an OUT endpoint (MSB clear) #define IS_OUT_EP(ep) (ep & ~0x80) // Checks if the given endpoint is an OUT endpoint (MSB clear)
// If this bit is set in setup.bmRequestType, the setup transfer // If this bit is set in setup.bmRequestType, the setup transfer
// is DEVICE->HOST (IN transfer) // is DEVICE->HOST (IN transfer)
@ -45,549 +45,591 @@ static USBPhyHw *instance = 0;
static volatile 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(nrfx_power_usb_evt_t event); static void power_usb_event_handler(nrfx_power_usb_evt_t event);
USBPhy *get_usb_phy() { USBPhy *get_usb_phy()
static USBPhyHw usbphy; {
return &usbphy; static USBPhyHw usbphy;
return &usbphy;
} }
USBPhyHw::USBPhyHw() : USBPhyHw::USBPhyHw() :
events(NULL), sof_enabled(false), connect_enabled(false), events(NULL), sof_enabled(false), connect_enabled(false),
usb_event_type(USB_HW_EVENT_NONE), usb_event_type(USB_HW_EVENT_NONE),
usb_power_event(NRFX_POWER_USB_EVT_REMOVED) { usb_power_event(NRFX_POWER_USB_EVT_REMOVED)
{
} }
USBPhyHw::~USBPhyHw() { USBPhyHw::~USBPhyHw()
{
} }
void USBPhyHw::init(USBPhyEvents *events) { void USBPhyHw::init(USBPhyEvents *events)
{
this->events = events; this->events = events;
ret_code_t ret; ret_code_t ret;
// Initialize power module to track USB Power events // Initialize power module to track USB Power events
ret = nrfx_power_init(NULL); ret = nrfx_power_init(NULL);
MBED_ASSERT(ret == NRF_SUCCESS); MBED_ASSERT(ret == NRF_SUCCESS);
// Register callback for USB Power events // Register callback for USB Power events
static const nrfx_power_usbevt_config_t config = { .handler = static const nrfx_power_usbevt_config_t config = {
power_usb_event_handler }; .handler = power_usb_event_handler
nrfx_power_usbevt_init(&config); };
// Initialize USB Device driver nrfx_power_usbevt_init(&config);
ret = nrf_drv_usbd_init(usbd_event_handler);
MBED_ASSERT(ret == NRF_SUCCESS);
/* Configure selected size of the packed on EP0 */ // Initialize USB Device driver
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, MAX_PACKET_SIZE_SETUP); ret = nrf_drv_usbd_init(usbd_event_handler);
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, MAX_PACKET_SIZE_SETUP); MBED_ASSERT(ret == NRF_SUCCESS);
// Store a reference to this instance /* Configure selected size of the packed on EP0 */
instance = this; nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, MAX_PACKET_SIZE_SETUP);
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, MAX_PACKET_SIZE_SETUP);
virtual_status_xfer_event = false; // Store a reference to this instance
instance = this;
/* virtual_status_xfer_event = false;
* Configure ISOIN endpoint to respond with ZLP when
* no data is ready to be sent
*/
NRF_USBD->ISOINCONFIG |= 0x01; // set RESPONSE to 1 (respond with ZLP)
// Set up the IRQ handler /*
NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_HAL_IRQHandler); * Configure ISOIN endpoint to respond with ZLP when
* no data is ready to be sent
*/
NRF_USBD->ISOINCONFIG |= 0x01; // set RESPONSE to 1 (respond with ZLP)
// Enable the power events // Set up the IRQ handler
nrfx_power_usbevt_enable(); NVIC_SetVector(USBD_IRQn, (uint32_t)USBD_HAL_IRQHandler);
// Enable the power events
nrfx_power_usbevt_enable();
} }
void USBPhyHw::deinit() { void USBPhyHw::deinit()
// Disconnect and disable interrupt {
disconnect(); // Disconnect and disable interrupt
// Disable the USB Device driver disconnect();
ret_code_t ret = nrf_drv_usbd_uninit();
MBED_ASSERT(ret == NRF_SUCCESS);
//NVIC_DisableIRQ(USBD_IRQn); // This is handled by the Nordic driver
// Disable the power peripheral driver // Disable the USB Device driver
nrfx_power_uninit(); ret_code_t ret = nrf_drv_usbd_uninit();
MBED_ASSERT(ret == NRF_SUCCESS);
// Clear the instance pointer // Disable the power peripheral driver
instance = 0; nrfx_power_uninit();
// Clear the instance pointer
instance = 0;
} }
bool USBPhyHw::powered() { bool USBPhyHw::powered()
if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_CONNECTED {
|| nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_READY) if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_CONNECTED
return true; || nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_READY) {
else return true;
return false; } else {
return false;
}
} }
void USBPhyHw::connect() { void USBPhyHw::connect()
{
// To save power, we only enable the USBD peripheral // To save power, we only enable the USBD peripheral
// when there's actually VBUS detected // when there's actually VBUS detected
// So flag that the USB stack is ready to connect // So flag that the USB stack is ready to connect
this->connect_enabled = true; this->connect_enabled = true;
// If VBUS is already available, enable immediately // If VBUS is already available, enable immediately
if(nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_CONNECTED) if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_CONNECTED) {
{ // Enabling USB will cause NRF_DRV_POWER_USB_EVT_READY
// Enabling USB will cause NRF_DRV_POWER_USB_EVT_READY // to occur, which will start the USBD peripheral
// to occur, which will start the USBD peripheral // when the internal regulator has settled
// when the internal regulator has settled if (!nrf_drv_usbd_is_enabled()) {
if(!nrf_drv_usbd_is_enabled()) nrf_drv_usbd_enable();
nrf_drv_usbd_enable(); }
if(nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_READY if (nrfx_power_usbstatus_get() == NRFX_POWER_USB_STATE_READY
&& !nrf_drv_usbd_is_started()) && !nrf_drv_usbd_is_started()) {
nrf_drv_usbd_start(true); nrf_drv_usbd_start(true);
} }
}
} }
void USBPhyHw::disconnect() { void USBPhyHw::disconnect()
{
this->connect_enabled = false; this->connect_enabled = false;
if(nrf_drv_usbd_is_started()) if (nrf_drv_usbd_is_started()) {
nrf_drv_usbd_stop(); nrf_drv_usbd_stop();
if(nrf_drv_usbd_is_enabled()) }
nrf_drv_usbd_disable(); if (nrf_drv_usbd_is_enabled()) {
nrf_drv_usbd_disable();
}
} }
void USBPhyHw::configure() { void USBPhyHw::configure()
// Not needed {
// Not needed
} }
void USBPhyHw::unconfigure() { void USBPhyHw::unconfigure()
// Remove all endpoints (except control, obviously) {
nrf_drv_usbd_ep_default_config(); // Remove all endpoints (except control, obviously)
nrf_drv_usbd_ep_default_config();
} }
void USBPhyHw::sof_enable() { void USBPhyHw::sof_enable()
// TODO - Enable SOF interrupt {
// Can this safely be done if // TODO - Enable SOF interrupt
// nrf_drv_usbd_start is called with SoF enabled? // Can this safely be done if
// For now just mask the interrupt with a boolean flag // nrf_drv_usbd_start is called with SoF enabled?
sof_enabled = true; // For now just mask the interrupt with a boolean flag
sof_enabled = true;
} }
void USBPhyHw::sof_disable() { void USBPhyHw::sof_disable()
// TODO - Disable SOF interrupt {
// Can this safely be done if // TODO - Disable SOF interrupt
// nrf_drv_usbd_start is called with SoF enabled? // Can this safely be done if
sof_enabled = false; // nrf_drv_usbd_start is called with SoF enabled?
sof_enabled = false;
} }
void USBPhyHw::set_address(uint8_t address) { void USBPhyHw::set_address(uint8_t address)
// nothing to do, handled by hardware; but don't STALL {
// nothing to do, handled by hardware; but don't STALL
} }
void USBPhyHw::remote_wakeup() { void USBPhyHw::remote_wakeup()
// Not supported(?) {
// Not supported(?)
} }
const usb_ep_table_t *USBPhyHw::endpoint_table() { const usb_ep_table_t *USBPhyHw::endpoint_table()
{
static const usb_ep_table_t template_table = static const usb_ep_table_t template_table = {
{ 1536, // 64 bytes per bulk/int endpoint pair (8), 1023 bytes for iso endpoint pair (1)
1536, // 64 bytes per bulk/int endpoint pair (8), 1023 bytes for iso endpoint pair (1) {
{ { USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ ENDPOINT_NON_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, { 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 },
{ 0 | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0 }, }
} };
}; return &template_table;
return &template_table;
} }
uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet) { uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet)
disable_usb_interrupts(); {
disable_usb_interrupts();
if (max_packet > MAX_PACKET_SIZE_SETUP) if (max_packet > MAX_PACKET_SIZE_SETUP) {
max_packet = MAX_PACKET_SIZE_SETUP; max_packet = MAX_PACKET_SIZE_SETUP;
}
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, max_packet); nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPOUT0, max_packet);
nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, max_packet); nrf_drv_usbd_ep_max_packet_size_set(NRF_DRV_USBD_EPIN0, max_packet);
enable_usb_interrupts(); enable_usb_interrupts();
return max_packet; return max_packet;
} }
// read setup packet // read setup packet
void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size) { void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size)
{
disable_usb_interrupts(); disable_usb_interrupts();
if (size > sizeof(this->setup_buf)) { if (size > sizeof(this->setup_buf)) {
size = sizeof(this->setup_buf); size = sizeof(this->setup_buf);
} }
memcpy(buffer, &this->setup_buf, size); memcpy(buffer, &this->setup_buf, size);
enable_usb_interrupts(); enable_usb_interrupts();
} }
void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) { void USBPhyHw::ep0_read(uint8_t *data, uint32_t size)
{
// Check for status stage // Check for status stage
if(data == NULL && size == 0) if (data == NULL && size == 0) {
{ // If the data stage transfer direction was OUT
// If the data stage transfer direction was OUT 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
{ // Don't trigger status stage unless endpoint is not busy!
// This is the status stage -- trigger the status task and notify the Mbed stack // (Causes an undocumented hardware-initiated stall on the control endpoint)
// Don't trigger status stage unless endpoint is not busy! if (nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPIN0)) {
// (Causes an undocumented hardware-initiated stall on the control endpoint) nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK);
if(nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPIN0)) } else {
nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK); nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
else }
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
virtual_status_xfer_event = true; virtual_status_xfer_event = true;
// Trigger an interrupt to process the virtual status event // Trigger an interrupt to process the virtual status event
NRFX_IRQ_PENDING_SET(USBD_IRQn); NRFX_IRQ_PENDING_SET(USBD_IRQn);
return; return;
} }
} }
nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer((usb_ep_t)(NRF_DRV_USBD_EPOUT0)); nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer((usb_ep_t)(NRF_DRV_USBD_EPOUT0));
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
transfer->p_data.rx = data; transfer->p_data.rx = data;
transfer->size = size; transfer->size = size;
nrf_drv_usbd_setup_data_clear(); // tell the hardware to receive another OUT packet nrf_drv_usbd_setup_data_clear(); // tell the hardware to receive another OUT packet
ret_code_t ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, transfer); ret_code_t ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, transfer);
MBED_ASSERT(ret == NRF_SUCCESS); MBED_ASSERT(ret == NRF_SUCCESS);
} }
uint32_t USBPhyHw::ep0_read_result() { uint32_t USBPhyHw::ep0_read_result()
return nrf_drv_usbd_epout_size_get(NRF_DRV_USBD_EPOUT0); {
return nrf_drv_usbd_epout_size_get(NRF_DRV_USBD_EPOUT0);
} }
void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) { void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size)
{
// Check for status stage // Check for status stage
if(buffer == NULL && size == 0) if (buffer == NULL && size == 0) {
{ // If the requested size was 0 OR the data stage transfer direction was OUT
// If the requested size was 0 OR the data stage transfer direction was OUT 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
// Don't trigger status stage unless endpoint is not busy! // Don't trigger status stage unless endpoint is not busy!
// (Causes an undocumented hardware-initiated stall on the control endpoint) // (Causes an undocumented hardware-initiated stall on the control endpoint)
if(nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPOUT0)) if (nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPOUT0)) {
nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK); nrf_usbd_shorts_enable(NRF_USBD_SHORT_EP0DATADONE_EP0STATUS_MASK);
else } else {
nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS); nrf_usbd_task_trigger(NRF_USBD_TASK_EP0STATUS);
}
virtual_status_xfer_event = true; virtual_status_xfer_event = true;
// Trigger an interrupt to process the virtual status event // Trigger an interrupt to process the virtual status event
NRFX_IRQ_PENDING_SET(USBD_IRQn); NRFX_IRQ_PENDING_SET(USBD_IRQn);
return; return;
} }
} }
nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer(NRF_DRV_USBD_EPIN0); nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer(NRF_DRV_USBD_EPIN0);
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
transfer->p_data.tx = buffer; transfer->p_data.tx = buffer;
transfer->size = size; transfer->size = size;
if(size == 0) if (size == 0) {
transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG; transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG;
}
ret_code_t ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, transfer); ret_code_t ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, transfer);
MBED_ASSERT(ret == NRF_SUCCESS); MBED_ASSERT(ret == NRF_SUCCESS);
} }
void USBPhyHw::ep0_stall() { void USBPhyHw::ep0_stall()
// Note: This stall must be automatically cleared by the next setup packet {
nrf_drv_usbd_setup_stall(); // Note: This stall must be automatically cleared by the next setup packet
nrf_drv_usbd_setup_stall();
} }
bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) { bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type)
nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint); {
nrf_drv_usbd_ep_enable(nrf_ep); nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint);
nrf_drv_usbd_ep_max_packet_size_set(nrf_ep, max_packet); nrf_drv_usbd_ep_enable(nrf_ep);
return nrf_drv_usbd_ep_enable_check(nrf_ep); nrf_drv_usbd_ep_max_packet_size_set(nrf_ep, max_packet);
return nrf_drv_usbd_ep_enable_check(nrf_ep);
} }
void USBPhyHw::endpoint_remove(usb_ep_t endpoint) { void USBPhyHw::endpoint_remove(usb_ep_t endpoint)
nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint); {
// Reset data toggle for bulk/interrupt endpoints nrf_drv_usbd_ep_t nrf_ep = get_nordic_endpoint(endpoint);
if(nrf_ep != NRF_DRV_USBD_EPOUT8 && nrf_ep != NRF_DRV_USBD_EPIN8) // Reset data toggle for bulk/interrupt endpoints
nrf_drv_usbd_ep_dtoggle_clear(nrf_ep); if (nrf_ep != NRF_DRV_USBD_EPOUT8 && nrf_ep != NRF_DRV_USBD_EPIN8) {
nrf_drv_usbd_ep_dtoggle_clear(nrf_ep);
}
nrf_drv_usbd_ep_disable(nrf_ep); nrf_drv_usbd_ep_disable(nrf_ep);
} }
void USBPhyHw::endpoint_stall(usb_ep_t endpoint) { void USBPhyHw::endpoint_stall(usb_ep_t endpoint)
nrf_drv_usbd_ep_stall(get_nordic_endpoint(endpoint)); {
nrf_drv_usbd_ep_stall(get_nordic_endpoint(endpoint));
} }
void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) { void USBPhyHw::endpoint_unstall(usb_ep_t endpoint)
nrf_drv_usbd_ep_t ep = get_nordic_endpoint(endpoint); {
nrf_drv_usbd_ep_stall_clear(ep); nrf_drv_usbd_ep_t ep = get_nordic_endpoint(endpoint);
nrf_drv_usbd_ep_stall_clear(ep);
/* /*
* This is a somewhat hacky fix to fully "unload" * This is a somewhat hacky fix to fully "unload"
* an IN endpoint after a buffer has been * an IN endpoint after a buffer has been
* transferred via EasyDMA... * transferred via EasyDMA...
*/ */
nrf_drv_usbd_ep_disable(ep); nrf_drv_usbd_ep_disable(ep);
nrf_drv_usbd_ep_enable(ep); nrf_drv_usbd_ep_enable(ep);
} }
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)
nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer(endpoint); {
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer(endpoint);
transfer->p_data.rx = data; memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
transfer->size = size; transfer->p_data.rx = data;
transfer->size = size;
ret_code_t ret = nrf_drv_usbd_ep_transfer(get_nordic_endpoint(endpoint), transfer); ret_code_t ret = nrf_drv_usbd_ep_transfer(get_nordic_endpoint(endpoint), transfer);
return (ret == NRF_SUCCESS); return (ret == NRF_SUCCESS);
} }
uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) { uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint)
return nrf_drv_usbd_epout_size_get(get_nordic_endpoint(endpoint)); {
return nrf_drv_usbd_epout_size_get(get_nordic_endpoint(endpoint));
} }
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)
nrf_drv_usbd_transfer_t* transfer = get_transfer_buffer(endpoint); {
memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t)); nrf_drv_usbd_transfer_t *transfer = get_transfer_buffer(endpoint);
transfer->p_data.tx = data; memset(transfer, 0, sizeof(nrf_drv_usbd_transfer_t));
transfer->size = size; transfer->p_data.tx = data;
transfer->size = size;
// If this is a zero-length-packet (ZLP) // If this is a zero-length-packet (ZLP)
// Set the ZLP flag // Set the ZLP flag
if(size == 0) if (size == 0) {
transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG; transfer->flags |= NRF_DRV_USBD_TRANSFER_ZLP_FLAG;
}
ret_code_t ret = nrf_drv_usbd_ep_transfer(get_nordic_endpoint(endpoint), transfer); ret_code_t ret = nrf_drv_usbd_ep_transfer(get_nordic_endpoint(endpoint), transfer);
return (ret == NRF_SUCCESS); return (ret == NRF_SUCCESS);
} }
void USBPhyHw::endpoint_abort(usb_ep_t endpoint) { void USBPhyHw::endpoint_abort(usb_ep_t endpoint)
nrf_drv_usbd_ep_abort(get_nordic_endpoint(endpoint)); {
nrf_drv_usbd_ep_abort(get_nordic_endpoint(endpoint));
} }
void USBPhyHw::process() { void USBPhyHw::process()
{
if (usb_event_type == USB_HW_EVENT_USBD) { if (usb_event_type == USB_HW_EVENT_USBD) {
// Process regular USBD events // Process regular USBD events
switch (usb_event.type) { switch (usb_event.type) {
case NRF_DRV_USBD_EVT_SUSPEND: case NRF_DRV_USBD_EVT_SUSPEND:
events->suspend(true); events->suspend(true);
break; break;
case NRF_DRV_USBD_EVT_RESUME: case NRF_DRV_USBD_EVT_RESUME:
events->suspend(false); events->suspend(false);
break; break;
case NRF_DRV_USBD_EVT_WUREQ: case NRF_DRV_USBD_EVT_WUREQ:
break; break;
case NRF_DRV_USBD_EVT_RESET: case NRF_DRV_USBD_EVT_RESET:
this->_reset(); this->_reset();
events->reset(); events->reset();
break; break;
case NRF_DRV_USBD_EVT_SOF: case NRF_DRV_USBD_EVT_SOF:
if(sof_enabled) if (sof_enabled) {
events->sof(usb_event.data.sof.framecnt); events->sof(usb_event.data.sof.framecnt);
break; }
case NRF_DRV_USBD_EVT_EPTRANSFER: break;
if(usb_event.data.eptransfer.status == NRF_USBD_EP_OK) case NRF_DRV_USBD_EVT_EPTRANSFER:
{ if (usb_event.data.eptransfer.status == NRF_USBD_EP_OK) {
if(!nrf_drv_usbd_ep_stall_check(usb_event.data.eptransfer.ep)) if (!nrf_drv_usbd_ep_stall_check(usb_event.data.eptransfer.ep)) {
{ 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) {
{ events->ep0_in();
if((usb_event.data.eptransfer.ep & 0x7F) == 0) } else {
events->ep0_in(); events->in((usb_ep_t) usb_event.data.eptransfer.ep);
else }
events->in((usb_ep_t) usb_event.data.eptransfer.ep); } else {
} if ((usb_event.data.eptransfer.ep & 0x7F) == 0) {
else events->ep0_out();
{ } else {
if((usb_event.data.eptransfer.ep & 0x7F) == 0) events->out((usb_ep_t) usb_event.data.eptransfer.ep);
events->ep0_out(); }
else }
events->out((usb_ep_t) usb_event.data.eptransfer.ep); }
} }
} break;
} case NRF_DRV_USBD_EVT_SETUP: {
break; nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN0);
case NRF_DRV_USBD_EVT_SETUP: { nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT0);
nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN0);
nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT0);
// Copy the setup packet into the internal buffer // Copy the setup packet into the internal buffer
nrf_drv_usbd_setup_get(&setup_buf); nrf_drv_usbd_setup_get(&setup_buf);
// Notify the Mbed stack // Notify the Mbed stack
events->ep0_setup(); events->ep0_setup();
} }
break; break;
default: default:
break; break;
} }
} } else if (usb_event_type == USB_HW_EVENT_POWER) {
else if (usb_event_type == USB_HW_EVENT_POWER) // Process USB power-related events
{ switch (usb_power_event) {
// Process USB power-related events case NRFX_POWER_USB_EVT_DETECTED:
switch (usb_power_event) { if (this->connect_enabled) {
case NRFX_POWER_USB_EVT_DETECTED: if (!nrf_drv_usbd_is_enabled()) {
if(this->connect_enabled) { nrf_drv_usbd_enable();
if(!nrf_drv_usbd_is_enabled()) }
nrf_drv_usbd_enable(); events->power(true);
events->power(true); }
} break;
break; case NRFX_POWER_USB_EVT_REMOVED:
case NRFX_POWER_USB_EVT_REMOVED: events->power(false);
events->power(false); break;
break; case NRFX_POWER_USB_EVT_READY:
case NRFX_POWER_USB_EVT_READY: if (!nrf_drv_usbd_is_started()) {
if(!nrf_drv_usbd_is_started()) nrf_drv_usbd_start(true);
nrf_drv_usbd_start(true); }
break; break;
default: default:
ASSERT(false); ASSERT(false);
} }
} } else if (usb_event_type == USB_HW_EVENT_VIRTUAL_STATUS) {
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
// Notify Mbed stack of status stage transfer completion events->ep0_out();
if(setup_buf.bmRequestType & SETUP_TRANSFER_DIR_MASK) // DATA IN transfer, Status OUT transfer } else { // DATA OUT transfer, Status IN transfer
events->ep0_out(); events->ep0_in();
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;
// Re-enable interrupt // Re-enable interrupt
enable_usb_interrupts(); enable_usb_interrupts();
} }
void USBPhyHw::_usb_event_handler( void USBPhyHw::_usb_event_handler(
nrf_drv_usbd_evt_t const * const p_event) { nrf_drv_usbd_evt_t const *const p_event)
disable_usb_interrupts(); {
// Copy the event data into internal memory disable_usb_interrupts();
memcpy(&instance->usb_event, p_event, sizeof(instance->usb_event)); // Copy the event data into internal memory
// Tell the upper layers of the stack to process the event memcpy(&instance->usb_event, p_event, sizeof(instance->usb_event));
instance->usb_event_type = USB_HW_EVENT_USBD; // Tell the upper layers of the stack to process the event
instance->events->start_process(); instance->usb_event_type = USB_HW_EVENT_USBD;
instance->events->start_process();
} }
void USBPhyHw::_usb_power_event_handler(nrfx_power_usb_evt_t event) { void USBPhyHw::_usb_power_event_handler(nrfx_power_usb_evt_t event)
disable_usb_interrupts(); {
// Copy the event data into internal memory disable_usb_interrupts();
instance->usb_power_event = event; // Copy the event data into internal memory
// Tell the upper layers of the stack to process the event instance->usb_power_event = event;
instance->usb_event_type = USB_HW_EVENT_POWER; // Tell the upper layers of the stack to process the event
instance->events->start_process(); instance->usb_event_type = USB_HW_EVENT_POWER;
instance->events->start_process();
} }
void USBPhyHw::_usb_virtual_status_event_handler(void) { void USBPhyHw::_usb_virtual_status_event_handler(void)
disable_usb_interrupts(); {
disable_usb_interrupts();
// Tell the upper layers of the stack to process the event // Tell the upper layers of the stack to process the event
instance->usb_event_type = USB_HW_EVENT_VIRTUAL_STATUS; instance->usb_event_type = USB_HW_EVENT_VIRTUAL_STATUS;
instance->events->start_process(); 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 {
return &transfer_buf[(((endpoint & 0x7F) << 1) + ((endpoint & 0x80) >> 7))]; // Index is base endpoint number * 2 (output), add 1 for input endpoints
return &transfer_buf[(((endpoint & 0x7F) << 1) + ((endpoint & 0x80) >> 7))];
} }
nrf_drv_usbd_ep_t USBPhyHw::get_nordic_endpoint(usb_ep_t endpoint) { nrf_drv_usbd_ep_t USBPhyHw::get_nordic_endpoint(usb_ep_t endpoint)
// Clear the most-significant-bit (input endpoint flag) {
return (nrf_drv_usbd_ep_t) endpoint; // Clear the most-significant-bit (input endpoint flag)
return (nrf_drv_usbd_ep_t) endpoint;
} }
void USBPhyHw::_reset(void) void USBPhyHw::_reset(void)
{ {
// Disable all endpoints except for control endpoints // Disable all endpoints except for control endpoints
nrf_drv_usbd_ep_default_config(); nrf_drv_usbd_ep_default_config();
nrf_drv_usbd_setup_clear(); nrf_drv_usbd_setup_clear();
usb_event_type = USB_HW_EVENT_NONE; usb_event_type = USB_HW_EVENT_NONE;
// Clear all endpoint interrupts // Clear all endpoint interrupts
NRFX_IRQ_PENDING_CLEAR(USBD_IRQn); NRFX_IRQ_PENDING_CLEAR(USBD_IRQn);
nrf_usbd_event_clear((nrf_usbd_event_t)0x01FFFFFF); nrf_usbd_event_clear((nrf_usbd_event_t)0x01FFFFFF);
} }
void USBPhyHw::enable_usb_interrupts(void) { void USBPhyHw::enable_usb_interrupts(void)
// Enable USB and USB-related power interrupts {
NRFX_IRQ_ENABLE(USBD_IRQn); // Enable USB and USB-related power interrupts
nrfx_power_usbevt_enable(); NRFX_IRQ_ENABLE(USBD_IRQn);
nrfx_power_usbevt_enable();
} }
void USBPhyHw::disable_usb_interrupts(void) { void USBPhyHw::disable_usb_interrupts(void)
// Disable USB and USB-related power interrupts {
NRFX_IRQ_DISABLE(USBD_IRQn); // Disable USB and USB-related power interrupts
nrfx_power_usbevt_disable(); NRFX_IRQ_DISABLE(USBD_IRQn);
nrfx_power_usbevt_disable();
} }
static void power_usb_event_handler(nrfx_power_usb_evt_t event) { static void power_usb_event_handler(nrfx_power_usb_evt_t event)
if(instance) { {
// Pass the event on to the USBPhyHW instance if (instance) {
instance->_usb_power_event_handler(event); // Pass the event on to the USBPhyHW instance
} instance->_usb_power_event_handler(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)
if(instance) { {
// Pass the event on to the USBPhyHW instance if (instance) {
instance->_usb_event_handler(p_event); // Pass the event on to the USBPhyHW instance
} instance->_usb_event_handler(p_event);
}
} }
void USBD_HAL_IRQHandler(void) 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) {
{ if (instance) {
if(instance) { instance->_usb_virtual_status_event_handler();
instance->_usb_virtual_status_event_handler(); }
}
virtual_status_xfer_event = false; virtual_status_xfer_event = false;
} }
// Call Nordic driver IRQ handler // Call Nordic driver IRQ handler
USBD_IRQHandler(); USBD_IRQHandler();
} }