mirror of
https://github.com/jam422470459/EPD-nRF52-hema213.git
synced 2025-12-19 14:53:19 +08:00
move components to SDK dir
This commit is contained in:
898
SDK/12.3.0_d7731ad/components/libraries/usbd/app_usbd.c
Normal file
898
SDK/12.3.0_d7731ad/components/libraries/usbd/app_usbd.c
Normal file
@@ -0,0 +1,898 @@
|
||||
/**
|
||||
* Copyright (c) 2016 - 2017, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include "sdk_config.h"
|
||||
#if APP_USBD_ENABLED
|
||||
#include "sdk_common.h"
|
||||
#include "app_usbd.h"
|
||||
#include "app_usbd_core.h"
|
||||
|
||||
/* Base variables tests */
|
||||
|
||||
/* Check event of app_usbd_event_type_t enumerator */
|
||||
STATIC_ASSERT((int32_t)APP_USBD_EVT_FIRST_APP == (int32_t)NRF_DRV_USBD_EVT_CNT);
|
||||
STATIC_ASSERT(sizeof(app_usbd_event_type_t) == sizeof(nrf_drv_usbd_event_type_t));
|
||||
|
||||
STATIC_ASSERT(sizeof(app_usbd_descriptor_header_t) == 2);
|
||||
STATIC_ASSERT(sizeof(app_usbd_descriptor_device_t) == 18);
|
||||
STATIC_ASSERT(sizeof(app_usbd_descriptor_configuration_t) == 9);
|
||||
STATIC_ASSERT(sizeof(app_usbd_descriptor_iface_t) == 9);
|
||||
STATIC_ASSERT(sizeof(app_usbd_descriptor_ep_t) == 7);
|
||||
STATIC_ASSERT(sizeof(app_usbd_descriptor_iad_t) == 8);
|
||||
|
||||
STATIC_ASSERT(sizeof(app_usbd_setup_t) == sizeof(nrf_drv_usbd_setup_t));
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @defgroup app_usbd_internals USBD library internals
|
||||
* @ingroup app_usbd
|
||||
*
|
||||
* Internal variables, auxiliary macros and functions of USBD library.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Variable type for endpoint configuration
|
||||
*
|
||||
* Each endpoint would have assigned this type of configuration structure.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* @brief The class instance
|
||||
*
|
||||
* The pointer to the class instance that is connected to the endpoint.
|
||||
*/
|
||||
app_usbd_class_inst_t const * p_cinst;
|
||||
|
||||
/**
|
||||
* @brief Endpoint event handler.
|
||||
*
|
||||
* Event handler for the endpoint.
|
||||
* It is set to event handler for the class instance during connection by default,
|
||||
* but it can be then updated for as a reaction for @ref APP_USBD_EVT_ATTACHED event.
|
||||
* This way we can speed up the interpretation of endpoint related events.
|
||||
*/
|
||||
app_usbd_ep_event_handler_t event_handler;
|
||||
}app_usbd_ep_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Instances connected with IN endpoints
|
||||
*
|
||||
* Array of instance pointers connected with every IN endpoint.
|
||||
* @sa m_epout_instances
|
||||
*/
|
||||
static app_usbd_ep_conf_t m_epin_conf[NRF_USBD_EPIN_CNT];
|
||||
|
||||
/**
|
||||
* @brief Instances connected with OUT endpoints
|
||||
*
|
||||
* Array of instance pointers connected with every OUT endpoint.
|
||||
* @sa m_epin_instances
|
||||
*/
|
||||
static app_usbd_ep_conf_t m_epout_conf[NRF_USBD_EPIN_CNT];
|
||||
|
||||
/**
|
||||
* @brief Beginning of classes list
|
||||
*
|
||||
* All enabled in current configuration instances are connected into
|
||||
* a single linked list chain.
|
||||
* This variable points to first element.
|
||||
* Core class instance (connected to endpoint 0) is not listed here.
|
||||
*/
|
||||
static app_usbd_class_inst_t const * m_p_first_cinst;
|
||||
|
||||
/**
|
||||
* @brief Classes list that requires SOF events
|
||||
*
|
||||
* @todo RK Implement and documentation
|
||||
*/
|
||||
static app_usbd_class_inst_t const * m_p_first_sof_cinst;
|
||||
|
||||
/**
|
||||
* @brief Class interface call: event handler
|
||||
*
|
||||
* @ref app_usbd_class_interface_t::event_handler
|
||||
*
|
||||
* @param[in] p_cinst Class instance
|
||||
* @param[in] p_event Event passed to class instance
|
||||
*
|
||||
* @return Standard error code @ref ret_code_t
|
||||
* @retval NRF_SUCCESS event handled successfully
|
||||
* @retval NRF_ERROR_NOT_SUPPORTED unsupported event
|
||||
* */
|
||||
static inline ret_code_t class_event_handler(app_usbd_class_inst_t const * const p_cinst,
|
||||
app_usbd_complex_evt_t const * const p_event)
|
||||
{
|
||||
ASSERT(p_cinst != NULL);
|
||||
ASSERT(p_cinst->p_class_methods != NULL);
|
||||
ASSERT(p_cinst->p_class_methods->event_handler != NULL);
|
||||
return p_cinst->p_class_methods->event_handler(p_cinst, p_event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Class interface call: get descriptors
|
||||
*
|
||||
* @ref app_usbd_class_interface_t::get_descriptors
|
||||
*
|
||||
* @param[in] p_inst Class instance
|
||||
* @param[out] p_size Descriptors size
|
||||
*
|
||||
* @return Class descriptors start address
|
||||
* */
|
||||
static inline const void * class_get_descriptors(app_usbd_class_inst_t const * const p_cinst,
|
||||
size_t * p_size)
|
||||
{
|
||||
ASSERT(p_cinst != NULL);
|
||||
ASSERT(p_cinst->p_class_methods != NULL);
|
||||
ASSERT(p_cinst->p_class_methods->get_descriptors != NULL);
|
||||
return p_cinst->p_class_methods->get_descriptors(p_cinst, p_size);
|
||||
}
|
||||
|
||||
const void * app_usbd_class_descriptor_find(app_usbd_class_inst_t const * const p_cinst,
|
||||
uint8_t desc_type,
|
||||
uint8_t desc_index,
|
||||
size_t * p_desc_len)
|
||||
{
|
||||
app_usbd_descriptor_header_t const * p_header;
|
||||
uint8_t const * p_raw = class_get_descriptors(p_cinst, p_desc_len);
|
||||
if (p_raw == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
uint8_t index = 0;
|
||||
while (pos < *p_desc_len)
|
||||
{
|
||||
p_header = (app_usbd_descriptor_header_t const *)(p_raw + pos);
|
||||
if (p_header->bDescriptorType == desc_type)
|
||||
{
|
||||
if (desc_index == index)
|
||||
{
|
||||
*p_desc_len = p_header->bLength;
|
||||
return p_header;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
pos += p_header->bLength;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access into selected endpoint configuration structure
|
||||
*
|
||||
* @param ep Endpoint address
|
||||
* @return A pointer to the endpoint configuration structure
|
||||
*
|
||||
* @note This function would assert when endpoint number is not correct and debugging is enabled.
|
||||
*/
|
||||
static app_usbd_ep_conf_t * app_usbd_ep_conf_access(nrf_drv_usbd_ep_t ep)
|
||||
{
|
||||
if (NRF_USBD_EPIN_CHECK(ep))
|
||||
{
|
||||
uint8_t nr = NRF_USBD_EP_NR_GET(ep);
|
||||
ASSERT(nr < NRF_USBD_EPIN_CNT);
|
||||
return &m_epin_conf[nr];
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t nr = NRF_USBD_EP_NR_GET(ep);
|
||||
ASSERT(nr < NRF_USBD_EPOUT_CNT);
|
||||
return &m_epout_conf[nr];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessing instance connected with selected endpoint
|
||||
*
|
||||
* @param ep Endpoint number
|
||||
*
|
||||
* @return The pointer to the instance connected with endpoint
|
||||
*/
|
||||
static inline app_usbd_class_inst_t const * app_usbd_ep_instance_get(nrf_drv_usbd_ep_t ep)
|
||||
{
|
||||
return app_usbd_ep_conf_access(ep)->p_cinst;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connect instance with selected endpoint
|
||||
*
|
||||
* This function configures instance connected to endpoint but also sets
|
||||
* default event handler function pointer.
|
||||
*
|
||||
* @param ep Endpoint number
|
||||
* @param p_cinst The instance to connect into the selected endpoint.
|
||||
* NULL if endpoint is going to be disconnected.
|
||||
*
|
||||
* @note Disconnecting EP0 is not allowed and protected by assertion.
|
||||
*/
|
||||
static void app_usbd_ep_instance_set(nrf_drv_usbd_ep_t ep, app_usbd_class_inst_t const * p_cinst)
|
||||
{
|
||||
app_usbd_ep_conf_t * p_ep_conf = app_usbd_ep_conf_access(ep);
|
||||
/* Set instance and default event handler */
|
||||
p_ep_conf->p_cinst = p_cinst;
|
||||
if (p_cinst == NULL)
|
||||
{
|
||||
ASSERT((ep != NRF_DRV_USBD_EPOUT0) && (ep != NRF_DRV_USBD_EPIN0)); /* EP0 should never be disconnected */
|
||||
p_ep_conf->event_handler = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ep_conf->event_handler = p_cinst->p_class_methods->event_handler;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the core handler
|
||||
*
|
||||
* Core instance is special kind of instance that is connected only to endpoint 0.
|
||||
* It is not present in instance list.
|
||||
* This auxiliary function makes future changes easier.
|
||||
* Just call the event instance for core module here.
|
||||
*/
|
||||
static inline ret_code_t app_usbd_core_handler_call(nrf_drv_usbd_evt_t const * const p_event)
|
||||
{
|
||||
return m_epout_conf[0].event_handler(m_epout_conf[0].p_cinst,
|
||||
(app_usbd_complex_evt_t const *)p_event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USBD event handler
|
||||
*
|
||||
*
|
||||
*/
|
||||
static void app_usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event)
|
||||
{
|
||||
ASSERT(NULL != m_p_first_cinst);
|
||||
|
||||
/* Note - there should never be situation that event is generated on disconnected endpoint */
|
||||
switch(p_event->type)
|
||||
{
|
||||
case NRF_DRV_USBD_EVT_SOF:
|
||||
{
|
||||
app_usbd_class_inst_t const * p_inst = app_usbd_class_sof_first_get();
|
||||
ASSERT(NULL != p_inst); /* This should not happen - when no SOF instances are in the list, SOF event is disabled */
|
||||
|
||||
while (NULL != p_inst)
|
||||
{
|
||||
ret_code_t r = class_event_handler(p_inst, (app_usbd_complex_evt_t const *)p_event);
|
||||
UNUSED_VARIABLE(r);
|
||||
p_inst = app_usbd_class_sof_next_get(p_inst);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reset and */
|
||||
case NRF_DRV_USBD_EVT_RESET:
|
||||
case NRF_DRV_USBD_EVT_RESUME:
|
||||
{
|
||||
/* Processing core interface (connected only to EP0) and then all instances from the list */
|
||||
UNUSED_RETURN_VALUE(app_usbd_core_handler_call(p_event));
|
||||
app_usbd_all_call((app_usbd_complex_evt_t const *)p_event);
|
||||
break;
|
||||
}
|
||||
case NRF_DRV_USBD_EVT_SUSPEND:
|
||||
{
|
||||
/* Processing all instances from the list and then core interface (connected only to EP0) */
|
||||
app_usbd_all_call((app_usbd_complex_evt_t const *)p_event);
|
||||
UNUSED_RETURN_VALUE(app_usbd_core_handler_call(p_event));
|
||||
break;
|
||||
}
|
||||
|
||||
case NRF_DRV_USBD_EVT_SETUP:
|
||||
{
|
||||
UNUSED_RETURN_VALUE(app_usbd_core_handler_call(p_event));
|
||||
break;
|
||||
}
|
||||
|
||||
case NRF_DRV_USBD_EVT_EPTRANSFER:
|
||||
{
|
||||
app_usbd_ep_conf_t const * p_ep_conf =
|
||||
app_usbd_ep_conf_access(p_event->data.eptransfer.ep);
|
||||
ASSERT(NULL != p_ep_conf->p_cinst);
|
||||
ASSERT(NULL != p_ep_conf->event_handler);
|
||||
|
||||
if (NRF_SUCCESS != p_ep_conf->event_handler(p_ep_conf->p_cinst,
|
||||
(app_usbd_complex_evt_t const *)p_event))
|
||||
{
|
||||
/* If error returned, every bulk/interrupt endpoint would be stalled */
|
||||
if (!(0 == NRF_USBD_EP_NR_GET(p_event->data.eptransfer.ep) ||
|
||||
NRF_USBD_EPISO_CHECK(p_event->data.eptransfer.ep)))
|
||||
{
|
||||
nrf_drv_usbd_ep_stall(p_event->data.eptransfer.ep);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
ret_code_t app_usbd_init(void)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
ret = nrf_drv_usbd_init(app_usbd_event_handler);
|
||||
if (NRF_SUCCESS != ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Clear variables */
|
||||
m_p_first_cinst = NULL;
|
||||
m_p_first_sof_cinst = NULL;
|
||||
memset(m_epin_conf , 0, sizeof(m_epin_conf ));
|
||||
memset(m_epout_conf, 0, sizeof(m_epout_conf));
|
||||
|
||||
/*Pin core class to required endpoints*/
|
||||
uint8_t iface_idx;
|
||||
app_usbd_class_iface_conf_t const * p_iface;
|
||||
app_usbd_class_inst_t const * const p_inst = app_usbd_core_instance_access();
|
||||
iface_idx = 0;
|
||||
while ((p_iface = app_usbd_class_iface_get(p_inst, iface_idx++)) != NULL)
|
||||
{
|
||||
uint8_t ep_idx = 0;
|
||||
app_usbd_class_ep_conf_t const * p_ep;
|
||||
while ((p_ep = app_usbd_class_iface_ep_get(p_iface, ep_idx++)) != NULL)
|
||||
{
|
||||
app_usbd_ep_instance_set(app_usbd_class_ep_address_get(p_ep), p_inst);
|
||||
}
|
||||
}
|
||||
|
||||
/* Successfully attached */
|
||||
const app_usbd_evt_t evt_data = {
|
||||
.type = APP_USBD_EVT_INST_APPEND
|
||||
};
|
||||
|
||||
return class_event_handler(p_inst, (app_usbd_complex_evt_t const *)(&evt_data));
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_uninit(void)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
ret = nrf_drv_usbd_uninit();
|
||||
if(NRF_SUCCESS != ret)
|
||||
return ret;
|
||||
|
||||
/* Unchain instance list */
|
||||
app_usbd_class_inst_t const * * pp_inst;
|
||||
pp_inst = &m_p_first_cinst;
|
||||
while (NULL != (*pp_inst))
|
||||
{
|
||||
app_usbd_class_inst_t const * * pp_next = &app_usbd_class_data_access(*pp_inst)->p_next;
|
||||
(*pp_inst) = NULL;
|
||||
pp_inst = pp_next;
|
||||
}
|
||||
|
||||
/* Unchain SOF list */
|
||||
pp_inst = &m_p_first_sof_cinst;
|
||||
while (NULL != (*pp_inst))
|
||||
{
|
||||
app_usbd_class_inst_t const * * pp_next = &app_usbd_class_data_access(*pp_inst)->p_sof_next;
|
||||
(*pp_inst) = NULL;
|
||||
pp_inst = pp_next;
|
||||
}
|
||||
|
||||
/* Clear all endpoints configurations */
|
||||
memset(m_epin_conf , 0, sizeof(m_epin_conf ));
|
||||
memset(m_epout_conf, 0, sizeof(m_epout_conf));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void app_usbd_enable(void)
|
||||
{
|
||||
nrf_drv_usbd_enable();
|
||||
while (!app_usbd_core_power_regulator_is_ready())
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void app_usbd_disable(void)
|
||||
{
|
||||
if (nrf_drv_usbd_is_started())
|
||||
{
|
||||
app_usbd_stop();
|
||||
}
|
||||
nrf_drv_usbd_disable();
|
||||
}
|
||||
|
||||
|
||||
void app_usbd_start(void)
|
||||
{
|
||||
const app_usbd_evt_t evt_data = {
|
||||
.type = APP_USBD_EVT_START
|
||||
};
|
||||
|
||||
/* Enable all connected endpoints */
|
||||
uint8_t n;
|
||||
for (n = 1; n < ARRAY_SIZE(m_epin_conf); ++n)
|
||||
{
|
||||
if (NULL != m_epin_conf[n].p_cinst)
|
||||
{
|
||||
nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPIN(n));
|
||||
}
|
||||
}
|
||||
for (n = 1; n < ARRAY_SIZE(m_epout_conf); ++n)
|
||||
{
|
||||
if (NULL != m_epout_conf[n].p_cinst)
|
||||
{
|
||||
nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPOUT(n));
|
||||
}
|
||||
}
|
||||
|
||||
/* Send event to all classes */
|
||||
UNUSED_RETURN_VALUE(app_usbd_core_handler_call((nrf_drv_usbd_evt_t const * )&evt_data));
|
||||
app_usbd_all_call((app_usbd_complex_evt_t const *)&evt_data);
|
||||
|
||||
nrf_drv_usbd_start(NULL != m_p_first_sof_cinst);
|
||||
}
|
||||
|
||||
|
||||
void app_usbd_stop(void)
|
||||
{
|
||||
const app_usbd_evt_t evt_data = {
|
||||
.type = APP_USBD_EVT_STOP
|
||||
};
|
||||
|
||||
nrf_drv_usbd_stop();
|
||||
|
||||
/* Send event to all classes */
|
||||
app_usbd_all_call((app_usbd_complex_evt_t const * )&evt_data);
|
||||
UNUSED_RETURN_VALUE(app_usbd_core_handler_call((nrf_drv_usbd_evt_t const *)&evt_data));
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_class_append(app_usbd_class_inst_t const * p_cinst)
|
||||
{
|
||||
ASSERT(NULL != p_cinst);
|
||||
ASSERT(NULL != p_cinst->p_class_methods);
|
||||
ASSERT(NULL != p_cinst->p_class_methods->event_handler);
|
||||
ASSERT(NULL == app_usbd_class_data_access(p_cinst)->p_next);
|
||||
|
||||
/* This should be only called if USBD is disabled
|
||||
* We simply assume that USBD is enabled if its interrupts are */
|
||||
ASSERT(!nrf_drv_usbd_is_enabled() && nrf_drv_usbd_is_initialized());
|
||||
|
||||
/* Check if all required endpoints are available
|
||||
* Checking is splitted from setting to avoid situation that anything
|
||||
* is modified and then operation finishes with error */
|
||||
uint8_t iface_idx;
|
||||
app_usbd_class_iface_conf_t const * p_iface;
|
||||
|
||||
iface_idx = 0;
|
||||
while (NULL != (p_iface = app_usbd_class_iface_get(p_cinst, iface_idx++)))
|
||||
{
|
||||
uint8_t ep_idx = 0;
|
||||
app_usbd_class_ep_conf_t const * p_ep;
|
||||
while (NULL != (p_ep = app_usbd_class_iface_ep_get(p_iface, ep_idx++)))
|
||||
{
|
||||
if (NULL != app_usbd_ep_instance_get(app_usbd_class_ep_address_get(p_ep)))
|
||||
{
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Connecting all required endpoints */
|
||||
iface_idx = 0;
|
||||
while (NULL != (p_iface = app_usbd_class_iface_get(p_cinst, iface_idx++)))
|
||||
{
|
||||
uint8_t ep_idx = 0;
|
||||
app_usbd_class_ep_conf_t const * p_ep;
|
||||
while (NULL != (p_ep = app_usbd_class_iface_ep_get(p_iface, ep_idx++)))
|
||||
{
|
||||
app_usbd_ep_instance_set(app_usbd_class_ep_address_get(p_ep), p_cinst);
|
||||
}
|
||||
}
|
||||
|
||||
/* Adding pointer to this instance to the end of the chain */
|
||||
app_usbd_class_inst_t const * * pp_last = &m_p_first_cinst;
|
||||
while (NULL != (*pp_last))
|
||||
{
|
||||
ASSERT((*pp_last) != p_cinst);
|
||||
pp_last = &(app_usbd_class_data_access(*pp_last)->p_next);
|
||||
}
|
||||
(*pp_last) = p_cinst;
|
||||
|
||||
/* Successfully attached */
|
||||
const app_usbd_evt_t evt_data = {.type = APP_USBD_EVT_INST_APPEND };
|
||||
return class_event_handler(p_cinst, (app_usbd_complex_evt_t const *)(&evt_data));
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_class_remove(app_usbd_class_inst_t const * p_cinst)
|
||||
{
|
||||
ASSERT(NULL != p_cinst);
|
||||
ASSERT(NULL != p_cinst->p_class_methods);
|
||||
ASSERT(NULL != p_cinst->p_class_methods->event_handler);
|
||||
/** This function should be only called if USBD is disabled */
|
||||
ASSERT(!nrf_drv_usbd_is_enabled() && nrf_drv_usbd_is_initialized());
|
||||
ret_code_t ret;
|
||||
/* Remove this class from the chain */
|
||||
app_usbd_class_inst_t const * * pp_last = &m_p_first_cinst;
|
||||
while (NULL != (*pp_last))
|
||||
{
|
||||
if ((*pp_last) == p_cinst)
|
||||
{
|
||||
/* Inform class instance that removing process is going to be started */
|
||||
const app_usbd_evt_t evt_data = {
|
||||
.type = APP_USBD_EVT_INST_REMOVE
|
||||
};
|
||||
ret = class_event_handler(p_cinst, (app_usbd_complex_evt_t const *)(&evt_data));
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Breaking chain */
|
||||
(*pp_last) = (app_usbd_class_data_access(p_cinst)->p_next);
|
||||
app_usbd_class_data_access(p_cinst)->p_next = NULL;
|
||||
|
||||
/* Disconnecting endpoints */
|
||||
uint8_t ep_idx;
|
||||
for (ep_idx = 0; ep_idx < NRF_USBD_EPIN_CNT; ++ep_idx)
|
||||
{
|
||||
nrf_drv_usbd_ep_t ep = NRF_DRV_USBD_EPIN(ep_idx);
|
||||
if (app_usbd_ep_instance_get(ep) == p_cinst)
|
||||
{
|
||||
app_usbd_ep_instance_set(ep, NULL);
|
||||
}
|
||||
}
|
||||
for (ep_idx = 0; ep_idx < NRF_USBD_EPOUT_CNT; ++ep_idx)
|
||||
{
|
||||
nrf_drv_usbd_ep_t ep = NRF_DRV_USBD_EPOUT(ep_idx);
|
||||
if (app_usbd_ep_instance_get(ep) == p_cinst)
|
||||
{
|
||||
app_usbd_ep_instance_set(ep, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
pp_last = &(app_usbd_class_data_access(*pp_last)->p_next);
|
||||
}
|
||||
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_class_remove_all(void)
|
||||
{
|
||||
ret_code_t ret = NRF_SUCCESS;
|
||||
while (NULL != m_p_first_cinst)
|
||||
{
|
||||
ret = app_usbd_class_remove(m_p_first_cinst);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_ep_handler_set(app_usbd_class_inst_t const * const p_cinst,
|
||||
nrf_drv_usbd_ep_t ep,
|
||||
app_usbd_ep_event_handler_t handler)
|
||||
{
|
||||
ASSERT(NULL != p_cinst);
|
||||
ASSERT(NULL != handler);
|
||||
/** This function should be only called if USBD is disabled */
|
||||
ASSERT(!nrf_drv_usbd_is_enabled() && nrf_drv_usbd_is_initialized());
|
||||
|
||||
if (p_cinst != app_usbd_ep_instance_get(ep))
|
||||
{
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
(app_usbd_ep_conf_access(ep))->event_handler = handler;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_class_sof_register(app_usbd_class_inst_t const * p_cinst)
|
||||
{
|
||||
ASSERT(NULL != p_cinst);
|
||||
ASSERT(NULL != p_cinst->p_class_methods);
|
||||
ASSERT(NULL != p_cinst->p_class_methods->event_handler);
|
||||
/** This function should be only called if USBD is disabled */
|
||||
ASSERT(!nrf_drv_usbd_is_enabled() && nrf_drv_usbd_is_initialized());
|
||||
|
||||
/* Next SOF event requiring instance have to be null now */
|
||||
ASSERT(NULL == (app_usbd_class_data_access(p_cinst)->p_sof_next));
|
||||
|
||||
/* Adding pointer to this instance to the end of the chain */
|
||||
app_usbd_class_inst_t const * * pp_last = &m_p_first_sof_cinst;
|
||||
while (NULL != (*pp_last))
|
||||
{
|
||||
|
||||
ASSERT((*pp_last) != p_cinst);
|
||||
pp_last = &(app_usbd_class_data_access(*pp_last)->p_sof_next);
|
||||
}
|
||||
(*pp_last) = p_cinst;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
ret_code_t app_usbd_class_sof_unregister(app_usbd_class_inst_t const * p_cinst)
|
||||
{
|
||||
ASSERT(NULL != p_cinst);
|
||||
/** This function should be only called if USBD is disabled */
|
||||
ASSERT(!nrf_drv_usbd_is_enabled() && nrf_drv_usbd_is_initialized());
|
||||
|
||||
app_usbd_class_inst_t const * * pp_last = &m_p_first_sof_cinst;
|
||||
while (NULL != (*pp_last))
|
||||
{
|
||||
if ((*pp_last) == p_cinst)
|
||||
{
|
||||
/* Breaking chain */
|
||||
(*pp_last) = (app_usbd_class_data_access(p_cinst)->p_sof_next);
|
||||
app_usbd_class_data_access(p_cinst)->p_sof_next = NULL;
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
pp_last = &(app_usbd_class_data_access(*pp_last)->p_sof_next);
|
||||
}
|
||||
return NRF_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
ret_code_t app_usbd_interface_std_req_handle(app_usbd_class_inst_t const * p_cinst,
|
||||
app_usbd_setup_evt_t const * p_setup_ev)
|
||||
{
|
||||
switch (p_setup_ev->setup.bmRequest)
|
||||
{
|
||||
case APP_USBD_SETUP_STDREQ_GET_STATUS:
|
||||
{
|
||||
size_t tx_size;
|
||||
uint16_t * p_tx_buff = app_usbd_core_setup_transfer_buff_get(&tx_size);
|
||||
|
||||
p_tx_buff[0] = 0;
|
||||
return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_tx_buff, sizeof(uint16_t));
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
ret_code_t app_usbd_endpoint_std_req_handle(app_usbd_class_inst_t const * p_cinst,
|
||||
app_usbd_setup_evt_t const * p_setup_ev)
|
||||
{
|
||||
size_t i;
|
||||
nrf_drv_usbd_ep_t ep_addr = NRF_DRV_USBD_EPIN0;
|
||||
for (i = 0; i < app_usbd_class_iface_count_get(p_cinst); ++i)
|
||||
{
|
||||
app_usbd_class_iface_conf_t const * p_iface_conf = app_usbd_class_iface_get(p_cinst, i);
|
||||
const uint8_t ep_count = app_usbd_class_iface_ep_count_get(p_iface_conf);
|
||||
|
||||
ep_addr = (nrf_drv_usbd_ep_t)(p_setup_ev->setup.wIndex.lb);
|
||||
uint8_t ep_idx = app_usbd_class_iface_ep_idx_get(p_iface_conf, ep_addr);
|
||||
if (ep_idx == ep_count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == app_usbd_class_iface_count_get(p_cinst))
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
switch (p_setup_ev->setup.bmRequest)
|
||||
{
|
||||
case APP_USBD_SETUP_STDREQ_GET_STATUS:
|
||||
{
|
||||
size_t tx_size;
|
||||
uint16_t * p_tx_buff = app_usbd_core_setup_transfer_buff_get(&tx_size);
|
||||
|
||||
p_tx_buff[0] = nrf_drv_usbd_ep_stall_check(ep_addr) ? 1 : 0;
|
||||
return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_tx_buff, sizeof(uint16_t));
|
||||
}
|
||||
case APP_USBD_SETUP_STDREQ_SET_FEATURE:
|
||||
{
|
||||
if (p_setup_ev->setup.wValue.w != APP_USBD_SETUP_STDFEATURE_ENDPOINT_HALT)
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
nrf_drv_usbd_ep_stall(ep_addr);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
case APP_USBD_SETUP_STDREQ_CLEAR_FEATURE:
|
||||
{
|
||||
if (p_setup_ev->setup.wValue.w != APP_USBD_SETUP_STDFEATURE_ENDPOINT_HALT)
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (nrf_usbd_dtoggle_get(ep_addr) != NRF_USBD_DTOGGLE_DATA0)
|
||||
{
|
||||
nrf_usbd_dtoggle_set(ep_addr, NRF_USBD_DTOGGLE_DATA0);
|
||||
}
|
||||
|
||||
if (NRF_USBD_EPISO_CHECK(ep_addr) == 0)
|
||||
{
|
||||
nrf_drv_usbd_ep_stall_clear(ep_addr);
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
default:
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t app_usbd_req_std_set_interface(app_usbd_class_inst_t const * const p_cinst,
|
||||
app_usbd_setup_evt_t const * const p_setup_ev)
|
||||
{
|
||||
uint8_t iface_count = app_usbd_class_iface_count_get(p_cinst);
|
||||
|
||||
app_usbd_class_iface_conf_t const * p_iface = NULL;
|
||||
for (uint8_t j = 0; j < iface_count; ++j)
|
||||
{
|
||||
p_iface = app_usbd_class_iface_get(p_cinst, j);
|
||||
if (p_iface->number == p_setup_ev->setup.wIndex.w)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_iface == NULL)
|
||||
{
|
||||
return NRF_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
uint8_t ep_count = app_usbd_class_iface_ep_count_get(p_iface);
|
||||
|
||||
for (uint8_t j = 0; j < ep_count; ++j)
|
||||
{
|
||||
/*Clear stall for every endpoint*/
|
||||
app_usbd_class_ep_conf_t const * p_ep = app_usbd_class_iface_ep_get(p_iface, j);
|
||||
|
||||
if (nrf_usbd_dtoggle_get(p_ep->address) != NRF_USBD_DTOGGLE_DATA0)
|
||||
{
|
||||
nrf_usbd_dtoggle_set(p_ep->address, NRF_USBD_DTOGGLE_DATA0);
|
||||
}
|
||||
|
||||
if (NRF_USBD_EPISO_CHECK(p_ep->address) == 0)
|
||||
{
|
||||
nrf_drv_usbd_ep_stall_clear(p_ep->address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
app_usbd_class_inst_t const * app_usbd_class_first_get(void)
|
||||
{
|
||||
return m_p_first_cinst;
|
||||
}
|
||||
|
||||
app_usbd_class_inst_t const * app_usbd_class_sof_first_get(void)
|
||||
{
|
||||
return m_p_first_sof_cinst;
|
||||
}
|
||||
|
||||
ret_code_t app_usbd_iface_call(uint8_t iface, app_usbd_complex_evt_t const * const p_event)
|
||||
{
|
||||
ASSERT(NULL != m_p_first_cinst);
|
||||
/*Iterate over classes*/
|
||||
app_usbd_class_inst_t const * p_inst = app_usbd_class_first_get();
|
||||
while (p_inst != NULL)
|
||||
{
|
||||
uint8_t iface_count = app_usbd_class_iface_count_get(p_inst);
|
||||
/*Iterate over interfaces*/
|
||||
for (uint8_t i = 0; i < iface_count; ++i)
|
||||
{
|
||||
app_usbd_class_iface_conf_t const * p_iface;
|
||||
p_iface = app_usbd_class_iface_get(p_inst, i);
|
||||
if (app_usbd_class_iface_number_get(p_iface) == iface)
|
||||
{
|
||||
return class_event_handler(p_inst, p_event);
|
||||
}
|
||||
}
|
||||
p_inst = app_usbd_class_next_get(p_inst);
|
||||
}
|
||||
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
}
|
||||
|
||||
ret_code_t app_usbd_ep_call(nrf_drv_usbd_ep_t ep, app_usbd_complex_evt_t const * const p_event)
|
||||
{
|
||||
app_usbd_class_inst_t const * p_inst = app_usbd_ep_conf_access(ep)->p_cinst;
|
||||
if (p_inst != NULL)
|
||||
{
|
||||
return class_event_handler(p_inst, p_event);
|
||||
}
|
||||
|
||||
return NRF_ERROR_INVALID_ADDR;
|
||||
}
|
||||
|
||||
void app_usbd_all_call(app_usbd_complex_evt_t const * const p_event)
|
||||
{
|
||||
app_usbd_class_inst_t const * p_inst;
|
||||
for (p_inst = app_usbd_class_first_get(); NULL != p_inst;
|
||||
p_inst = app_usbd_class_next_get(p_inst))
|
||||
{
|
||||
UNUSED_RETURN_VALUE(class_event_handler(p_inst, p_event));
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t app_usbd_all_until_served_call(app_usbd_complex_evt_t const * const p_event)
|
||||
{
|
||||
app_usbd_class_inst_t const * p_inst;
|
||||
ret_code_t ret = NRF_ERROR_NOT_SUPPORTED;
|
||||
/* Try to process via every instance */
|
||||
for (p_inst = app_usbd_class_first_get(); NULL != p_inst;
|
||||
p_inst = app_usbd_class_next_get(p_inst))
|
||||
{
|
||||
|
||||
ret = class_event_handler(p_inst, p_event);
|
||||
if (NRF_ERROR_NOT_SUPPORTED != ret)
|
||||
{
|
||||
/* Processing finished */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // APP_USBD_ENABLED
|
||||
Reference in New Issue
Block a user