123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248 |
- /**
- * Copyright (c) 2016 - 2020, 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_common.h"
- #if NRF_MODULE_ENABLED(APP_USBD)
- #include "app_usbd_core.h"
- #include "app_usbd.h"
- #include "app_usbd_request.h"
- #include "app_usbd_string_desc.h"
- #include "nrf.h"
- #include "nrf_atomic.h"
- #include "app_util_platform.h"
- #include "app_usbd.h"
- #include "app_usbd_class_base.h"
- #define NRF_LOG_MODULE_NAME app_usbd_core
- #if APP_USBD_CONFIG_LOG_ENABLED
- #define NRF_LOG_LEVEL APP_USBD_CONFIG_LOG_LEVEL
- #define NRF_LOG_INFO_COLOR APP_USBD_CONFIG_INFO_COLOR
- #define NRF_LOG_DEBUG_COLOR APP_USBD_CONFIG_DEBUG_COLOR
- #else //APP_USBD_CONFIG_LOG_ENABLED
- #define NRF_LOG_LEVEL 0
- #endif //APP_USBD_CONFIG_LOG_ENABLED
- #include "nrf_log.h"
- NRF_LOG_MODULE_REGISTER();
- /* Test if VID was configured */
- #ifndef APP_USBD_VID
- #error APP_USBD_VID not properly defined.
- #endif
- /* Device version checking */
- #if defined(APP_USBD_DEVICE_VER_MAJOR) && defined(APP_USBD_DEVICE_VER_MINOR)
- #if ((APP_USBD_DEVICE_VER_MAJOR)) > 99 || ((APP_USBD_DEVICE_VER_MINOR) > 99)
- #error Major and minor device version value have to be limited to 99.
- #endif
- #else
- #error The definition of a pair APP_USBD_DEVICE_VER_MAJOR and APP_USBD_DEVICE_VER_MINOR required.
- #endif
- /**
- * @internal
- * @defgroup app_usbd_core_internals USB Device high level library core module internals
- * @ingroup app_usbd_core
- *
- * Internal variables, auxiliary macros and functions of USBD high level core module.
- * @{
- */
- /** @brief Make USB power value */
- #define APP_USBD_POWER_MAKE(ma) (((ma) + 1) / 2)
- /**
- @brief Default device descriptor initializer @ref app_usbd_descriptor_device_t
- * */
- #define APP_USBD_CORE_DEVICE_DESCRIPTOR { \
- .bLength = sizeof(app_usbd_descriptor_device_t), /* descriptor size */ \
- .bDescriptorType = APP_USBD_DESCRIPTOR_DEVICE, /* descriptor type */ \
- .bcdUSB = APP_USBD_BCD_VER_MAKE(2,0,0), /* USB BCD version: 2.0 */ \
- .bDeviceClass = 0, /* device class: 0 - specified by interface */ \
- .bDeviceSubClass = 0, /* device subclass: 0 - specified by interface */ \
- .bDeviceProtocol = 0, /* device protocol: 0 - specified by interface */ \
- .bMaxPacketSize0 = NRF_DRV_USBD_EPSIZE, /* endpoint size: fixed to: NRF_DRV_USBD_EPSIZE*/ \
- .idVendor = APP_USBD_VID, /* Vendor ID*/ \
- .idProduct = APP_USBD_PID, /* Product ID*/ \
- .bcdDevice = APP_USBD_BCD_VER_MAKE( /* Device version BCD */ \
- APP_USBD_DEVICE_VER_MAJOR, \
- APP_USBD_DEVICE_VER_MINOR, \
- APP_USBD_DEVICE_VER_SUB), \
- .iManufacturer = APP_USBD_STRING_ID_MANUFACTURER, /* String ID: manufacturer */ \
- .iProduct = APP_USBD_STRING_ID_PRODUCT, /* String ID: product */ \
- .iSerialNumber = APP_USBD_STRING_ID_SERIAL, /* String ID: serial */ \
- .bNumConfigurations = 1 /* Fixed value: only one configuration supported*/\
- }
- #define APP_USBD_CORE_CONFIGURATION_DESCRIPTOR { \
- .bLength = sizeof(app_usbd_descriptor_configuration_t), \
- .bDescriptorType = APP_USBD_DESCRIPTOR_CONFIGURATION, \
- .wTotalLength = 0, /*Calculated dynamically*/ \
- .bNumInterfaces = 0, /*Calculated dynamically*/ \
- .bConfigurationValue = 1, /*Value passed to set configuration*/ \
- .iConfiguration = APP_USBD_STRING_ID_CONFIGURATION, /*Configuration ID*/ \
- .bmAttributes = APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_ALWAYS_SET_MASK | \
- ((APP_USBD_CONFIG_SELF_POWERED) ? \
- APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_SELF_POWERED_MASK \
- : \
- 0), \
- .bMaxPower = APP_USBD_POWER_MAKE(APP_USBD_CONFIG_MAX_POWER), \
- }
- /**
- * @brief Device descriptor instance.
- *
- * @note
- * Constant part of the device descriptor.
- * Values that must be calculated are updated directly in the buffer
- * just before the transmission.
- */
- static const app_usbd_descriptor_device_t m_device_dsc =
- APP_USBD_CORE_DEVICE_DESCRIPTOR;
- /**
- * @brief Configuration descriptor instance.
- *
- * @note
- * Constant part of the device descriptor.
- * Values that must be calculated are updated directly in the buffer
- * just before the transmission.
- */
- static const app_usbd_descriptor_configuration_t m_configuration_dsc =
- APP_USBD_CORE_CONFIGURATION_DESCRIPTOR;
- /* Required early declaration of event handler function */
- static ret_code_t app_usbd_core_event_handler(app_usbd_class_inst_t const * const p_inst,
- app_usbd_complex_evt_t const * const p_event);
- /**
- * @brief Current USB device state.
- *
- * This variable is updated automatically by core library.
- */
- static app_usbd_state_t m_app_usbd_state = APP_USBD_STATE_Disabled;
- /**
- * @brief Active device features.
- *
- * @note Only @ref APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP is supported for device.
- */
- static uint8_t m_device_features_state;
- /**
- * @brief Remote wake-up pending flag.
- */
- static nrf_atomic_flag_t m_rwu_pending;
- /**
- * @brief Core class methods.
- *
- * Base methods interface for core class.
- * This is quite specific class - it would be only connected into endpoint 0.
- * Not connected into instances list.
- */
- static const app_usbd_class_methods_t m_core_methods = {
- .event_handler = app_usbd_core_event_handler,
- .feed_descriptors = NULL,
- };
- /**
- * @brief Setup transfer buffer.
- */
- static uint8_t m_setup_transfer_buff[NRF_DRV_USBD_EPSIZE];
- /**
- * @brief Handler for outgoing setup data.
- *
- */
- static app_usbd_core_setup_data_handler_desc_t m_ep0_handler_desc;
- #define APP_USBD_CORE_CLASS_INSTANCE_CONFIG ()
- /*lint -u -save -e26 -e40 -e64 -e123 -e505 -e651*/
- /**
- * @brief Core instance.
- *
- * Create instance that would be connected into endpoints in USBD library.
- */
- APP_USBD_CLASS_INST_GLOBAL_DEF(
- app_usbd_core_inst,
- app_usbd_core,
- &m_core_methods,
- APP_USBD_CORE_CLASS_CONFIGURATION,
- () );
- /*lint -restore*/
- /**
- * @brief Set the new USB state.
- *
- * Function changes the internal status of the bus.
- * If the bus status is different than the one configured, an event is passed to all
- * the instances.
- *
- * @param state New state to be set.
- *
- * @sa usbd_core_state_get
- */
- static void usbd_core_state_set(app_usbd_state_t state)
- {
- if (m_app_usbd_state != state)
- {
- m_app_usbd_state = state;
- if(state != APP_USBD_STATE_Configured)
- {
- CLR_BIT(m_device_features_state, APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP);
- }
- static const app_usbd_evt_t evt_data = {
- .type = APP_USBD_EVT_STATE_CHANGED
- };
- app_usbd_event_execute((app_usbd_internal_evt_t const *)&evt_data);
- }
- }
- /**
- * @brief Get the current USB state - internal function.
- *
- * This is just a wrapper for @ref app_usbd_core_state_get
- * to make symmetrical function to the internal @ref usbd_core_state_set.
- *
- * @return Current USB state.
- *
- * @sa usbd_core_state_set
- * @sa app_usbd_core_state_get
- */
- static inline app_usbd_state_t usbd_core_state_get(void)
- {
- return m_app_usbd_state;
- }
- /**
- * @brief Check current USBD power connection status.
- *
- */
- static inline bool usbd_core_power_is_detected(void)
- {
- return 0 != ( (NRF_POWER->USBREGSTATUS) & POWER_USBREGSTATUS_VBUSDETECT_Msk);
- }
- /**
- * @brief Clear current EP0 handler.
- *
- * Function just clears the EP0 handler without calling it.
- */
- static inline void usbd_core_ep0_handler_clear(void)
- {
- m_ep0_handler_desc.handler = NULL;
- }
- /**
- * @brief Safely call EP0 handler.
- *
- * Function calls EP0 handler only if its pointer is non-zero.
- *
- * @param status Status to send as a handler parameter.
- */
- static inline ret_code_t usbd_core_ep0_handler_call_and_clear(nrf_drv_usbd_ep_status_t status)
- {
- app_usbd_core_setup_data_handler_t handler = m_ep0_handler_desc.handler;
- if (NULL != handler)
- {
- usbd_core_ep0_handler_clear();
- return handler(status, m_ep0_handler_desc.p_context);
- }
- return NRF_ERROR_NULL;
- }
- /**
- * @brief Check if EP0 handler is configured.
- *
- * EP0 handler is configured is any instance that has processed SETUP command
- * expects some incoming / outgoing data.
- *
- * EP0 handler should be cleared automatically just before it is called
- * (see @ref usbd_core_ep0_handler_call_and_clear).
- * If instance requires more data - it has to setup EP0 handler once more time
- * (see @ref app_usbd_core_setup_data_handler_set).
- *
- * This function adds small layer of abstraction for checking if EP0 handler
- * is already configured.
- *
- * @retval true EP0 handler is set.
- * @retval false EP0 handler is cleared.
- */
- static inline bool usb_core_ep0_handler_check(void)
- {
- return (NULL != m_ep0_handler_desc.handler);
- }
- /**
- * @brief Empty data handler.
- *
- * Data handler used only to mark that there is requested data during SETUP.
- *
- * @return Always NRF_SUCCESS
- * @sa setup_empty_data_handler_desc
- */
- static ret_code_t setup_data_handler_empty(nrf_drv_usbd_ep_status_t status, void * p_contex)
- {
- UNUSED_PARAMETER(status);
- UNUSED_PARAMETER(p_contex);
- return NRF_SUCCESS;
- }
- /**
- * @brief
- *
- * Empty EP0 transfer transfer handler.
- */
- static app_usbd_core_setup_data_handler_desc_t const m_setup_data_handler_empty_desc =
- {
- .handler = setup_data_handler_empty,
- .p_context = NULL
- };
- /**
- * @brief Structure used as a context for descriptor feeder.
- *
- * Structure with all the data required to process instances to generate descriptor
- * data chunk.
- */
- typedef struct
- {
- app_usbd_class_inst_t const * p_cinst; //!< The class instance that is to be processed next.
- const uint8_t * p_desc; //!< Pointer at current descriptor or NULL if finished.
- /**<
- * If the value passed by @ref p_desc is NULL on transfer function enter it means that ZLP is required.
- * Or it is time to finish the transfer (depending on @c total_left).
- */
- size_t desc_left; //!< Number of bytes left in the current class descriptor to send
- size_t total_left; //!< Number of bytes left that was requested by the host
- app_usbd_class_descriptor_ctx_t feed_thread; //!< Class descriptor context
- } app_usbd_core_descriptor_conf_feed_data_t;
- /**
- * @brief Default data used by the feeder.
- *
- *
- */
- static app_usbd_core_descriptor_conf_feed_data_t m_descriptor_conf_feed_data;
- /**
- * @brief Descriptor feeder.
- *
- * Descriptor feeder is used as an callback function when descriptors are
- * transfered and buffer is ready for next data.
- * It prepares next chunk of data to be sent.
- *
- * @param p_next See @ref nrf_drv_usbd_next_transfer_handler_t documentation.
- * @param p_context Pointer to @ref app_usbd_core_descriptor_feed_data_t data type.
- * @param ep_size The size of the endpoint.
- *
- * @return See @ref nrf_drv_usbd_next_transfer_handler_t documentation.
- */
- static bool usbd_descriptor_conf_feeder(
- nrf_drv_usbd_ep_transfer_t * p_next,
- void * p_context,
- size_t ep_size)
- {
- bool continue_req = true;
- app_usbd_core_descriptor_conf_feed_data_t * p_data = p_context;
- if ((p_data->p_desc == NULL) && (app_usbd_class_next_get(p_data->p_cinst) == NULL)
- && (p_data->desc_left == 0))
- {
- /* ZLP */
- continue_req = false;
- p_next->p_data.tx = NULL;
- p_next->size = 0;
- }
- else
- {
- ASSERT(ep_size <= NRF_DRV_USBD_FEEDER_BUFFER_SIZE);
- uint8_t * p_tx_buff;
- size_t size = 0; /* Currently added number of bytes */
- size_t tx_size; /* Number of bytes to send right now */
- bool feeding = false;
- /* Feeder function can use the USBD driver internal buffer */
- p_tx_buff = nrf_drv_usbd_feeder_buffer_get();
- tx_size = MIN(ep_size, p_data->total_left);
- while (0 != tx_size)
- {
- size_t to_copy = MIN(tx_size, p_data->desc_left);
- /* First transfer */
- if (p_data->p_desc != NULL)
- {
- memcpy(p_tx_buff + size, p_data->p_desc, to_copy);
- p_data->p_desc = NULL;
- }
- /* Starting with second transfer */
- else if (0 < p_data->desc_left)
- {
- UNUSED_RETURN_VALUE(p_data->p_cinst->p_class_methods->feed_descriptors(
- &p_data->feed_thread, p_data->p_cinst,
- (uint8_t *)p_tx_buff + size, to_copy));
- feeding = true;
- }
- else
- {
- ;
- }
- p_data->desc_left -= to_copy;
- p_data->total_left -= to_copy;
- tx_size -= to_copy;
- size += to_copy;
- /* Switch to next class if no descriptor left and first feeding was done */
- if(p_data->desc_left == 0 && feeding)
- {
- p_data->p_cinst = app_usbd_class_next_get(p_data->p_cinst);
- }
- if (0 == p_data->total_left)
- {
- continue_req = false;
- }
- else if (0 == p_data->desc_left)
- {
- if (NULL == p_data->p_cinst)
- {
- p_data->p_desc = NULL;
- /* No more data - check if ZLP is required */
- if (size > 0)
- {
- if (size < ep_size)
- {
- continue_req = false;
- }
- }
- break;
- }
- else
- {
- /* New class - count descriptor size and initialize feeding thread */
- app_usbd_class_descriptor_ctx_t desiz;
- APP_USBD_CLASS_DESCRIPTOR_INIT(&desiz);
- while(p_data->p_cinst->p_class_methods->feed_descriptors(
- &desiz, p_data->p_cinst, NULL, sizeof(uint8_t)))
- {
- p_data->desc_left++;
- }
- APP_USBD_CLASS_DESCRIPTOR_INIT(&p_data->feed_thread);
- }
- }
- else
- {
- /* Nothing to do */
- }
- }
- p_next->p_data.tx = p_tx_buff;
- p_next->size = size;
- }
- return continue_req;
- }
- /**
- * @brief Standard endpoint request handle.
- *
- * @param[in] p_setup_ev Setup event.
- *
- * @return Standard error code.
- */
- static ret_code_t setup_endpoint_req_std(app_usbd_setup_evt_t const * p_setup_ev)
- {
- if (APP_USBD_SETUP_REQTYPE_STD != app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
- {
- return NRF_ERROR_NOT_SUPPORTED;
- }
- nrf_drv_usbd_ep_t ep_addr = (nrf_drv_usbd_ep_t)(p_setup_ev->setup.wIndex.lb);
- app_usbd_state_t usb_state = usbd_core_state_get();
- switch (p_setup_ev->setup.bRequest)
- {
- case APP_USBD_SETUP_STDREQ_GET_STATUS:
- {
- if ((usb_state == APP_USBD_STATE_Configured) || (NRF_USBD_EP_NR_GET(ep_addr) == 0))
- {
- 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));
- }
- else
- {
- return NRF_ERROR_INVALID_STATE;
- }
- }
- case APP_USBD_SETUP_STDREQ_SET_FEATURE:
- {
- if ((!NRF_USBD_EPISO_CHECK(ep_addr)) &&
- (p_setup_ev->setup.wValue.w == APP_USBD_SETUP_STDFEATURE_ENDPOINT_HALT))
- {
- if ((usb_state == APP_USBD_STATE_Configured) || (NRF_USBD_EP_NR_GET(ep_addr) == 0))
- {
- nrf_drv_usbd_ep_stall(ep_addr);
- return NRF_SUCCESS;
- }
- else
- {
- return NRF_ERROR_INVALID_STATE;
- }
- }
- break;
- }
- case APP_USBD_SETUP_STDREQ_CLEAR_FEATURE:
- {
- if ((!NRF_USBD_EPISO_CHECK(ep_addr)) &&
- (p_setup_ev->setup.wValue.w == APP_USBD_SETUP_STDFEATURE_ENDPOINT_HALT))
- {
- if ((usb_state == APP_USBD_STATE_Configured) || (NRF_USBD_EP_NR_GET(ep_addr) == 0))
- {
- nrf_drv_usbd_ep_dtoggle_clear(ep_addr);
- nrf_drv_usbd_ep_stall_clear(ep_addr);
- return NRF_SUCCESS;
- }
- else
- {
- return NRF_ERROR_INVALID_STATE;
- }
- }
- break;
- }
- default:
- break;
- }
- return NRF_ERROR_NOT_SUPPORTED;
- }
- /**
- * @brief Standard interface request handle.
- *
- * @param[in,out] p_class_inst Class instance that holds selected interface.
- * @param[in] iface_idx Index of the interface in class structure.
- * @param[in] p_event Event structure to be processed.
- *
- * @return Operation status.
- */
- static ret_code_t setup_interface_req_std_handle(
- app_usbd_class_inst_t const * const p_class_inst,
- uint8_t iface_idx,
- app_usbd_setup_evt_t const * p_setup_ev)
- {
- if (APP_USBD_SETUP_REQTYPE_STD != app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
- {
- return NRF_ERROR_NOT_SUPPORTED;
- }
- app_usbd_state_t usb_state = usbd_core_state_get();
- if (app_usbd_setup_req_dir(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQDIR_IN)
- {
- switch (p_setup_ev->setup.bRequest)
- {
- case APP_USBD_SETUP_STDREQ_GET_STATUS:
- {
- if (!(usb_state == APP_USBD_STATE_Configured))
- {
- return NRF_ERROR_INVALID_STATE;
- }
- 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));
- }
- case APP_USBD_SETUP_STDREQ_GET_INTERFACE:
- {
- if (!(usb_state == APP_USBD_STATE_Configured))
- {
- return NRF_ERROR_INVALID_STATE;
- }
- size_t tx_size;
- uint8_t * p_tx_buff = app_usbd_core_setup_transfer_buff_get(&tx_size);
- p_tx_buff[0] = app_usbd_iface_selection_get(p_class_inst, iface_idx);
- return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_tx_buff, sizeof(uint8_t));
- }
- }
- }
- else /* APP_USBD_SETUP_REQDIR_OUT */
- {
- switch (p_setup_ev->setup.bRequest)
- {
- case APP_USBD_SETUP_STDREQ_SET_INTERFACE:
- {
- if (!(usb_state == APP_USBD_STATE_Configured))
- {
- return NRF_ERROR_INVALID_STATE;
- }
- if(p_setup_ev->setup.wValue.w > UINT8_MAX)
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- uint8_t alt = p_setup_ev->setup.wValue.lb;
- return app_usbd_iface_select(p_class_inst, iface_idx, alt);
- }
- default:
- break;
- }
- }
- return NRF_ERROR_NOT_SUPPORTED;
- }
- /**
- * @brief
- *
- * Descriptors feeder handle structure.
- */
- static const nrf_drv_usbd_handler_desc_t usbd_descriptor_feeder_desc =
- {
- .handler = { .feeder = usbd_descriptor_conf_feeder },
- .p_context = &m_descriptor_conf_feed_data
- };
- static ret_code_t setup_device_req_get_status(
- app_usbd_class_inst_t const * const p_inst,
- app_usbd_setup_evt_t const * const p_setup_ev)
- {
- size_t max_size;
- uint8_t * p_trans_buff = app_usbd_core_setup_transfer_buff_get(&max_size);
- ASSERT(sizeof(uint16_t) <= max_size);
- memset(p_trans_buff, 0, sizeof(uint16_t));
- if (m_configuration_dsc.bmAttributes &
- APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_SELF_POWERED_MASK)
- {
- SET_BIT(p_trans_buff[0], 0);
- }
- if (IS_SET(m_device_features_state, APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP))
- {
- SET_BIT(p_trans_buff[0], 1);
- }
- return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_trans_buff, sizeof(uint16_t));
- }
- static ret_code_t setup_device_req_get_descriptor(app_usbd_class_inst_t const * const p_inst,
- app_usbd_setup_evt_t const * const p_setup_ev)
- {
- switch (p_setup_ev->setup.wValue.hb)
- {
- case APP_USBD_DESCRIPTOR_DEVICE:
- {
- if(p_setup_ev->setup.wLength.w == 0)
- {
- return NRF_SUCCESS;
- }
- return app_usbd_core_setup_rsp(&(p_setup_ev->setup),
- &m_device_dsc,
- sizeof(m_device_dsc));
- }
- case APP_USBD_DESCRIPTOR_CONFIGURATION:
- {
- if(p_setup_ev->setup.wLength.w == 0)
- {
- return NRF_SUCCESS;
- }
- /* The size equals the size of configuration descriptor and all classes descriptors */
- const size_t size = MIN(
- sizeof(app_usbd_descriptor_configuration_t),
- p_setup_ev->setup.wLength.w);
- size_t total_length = sizeof(app_usbd_descriptor_configuration_t);
- uint8_t iface_count = 0;
- /* Iterate over all registered classes count descriptors and total size */
- app_usbd_class_inst_t const * p_class;
- for (p_class = app_usbd_class_first_get(); p_class != NULL;
- p_class = app_usbd_class_next_get(p_class))
- {
- ASSERT(NULL != (p_class->p_class_methods));
- ASSERT(NULL != (p_class->p_class_methods->feed_descriptors));
- size_t dsc_size = 0;
- app_usbd_class_descriptor_ctx_t siz_desc;
- APP_USBD_CLASS_DESCRIPTOR_INIT(&siz_desc);
- while(p_class->p_class_methods->feed_descriptors(&siz_desc,
- p_class,
- NULL,
- sizeof(uint8_t))
- )
- {
- dsc_size++;
- }
- total_length += dsc_size;
- iface_count += app_usbd_class_iface_count_get(p_class);
- }
- /* Access transmission buffer */
- size_t max_size;
- app_usbd_descriptor_configuration_t * p_trans_buff =
- app_usbd_core_setup_transfer_buff_get(&max_size);
- /* Copy the configuration descriptor and update the fields that require it */
- ASSERT(size <= max_size);
- memcpy(p_trans_buff, &m_configuration_dsc, size);
- p_trans_buff->bNumInterfaces = iface_count;
- p_trans_buff->wTotalLength = total_length;
- if (app_usbd_class_rwu_enabled_check())
- {
- p_trans_buff->bmAttributes |=
- APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_REMOTE_WAKEUP_MASK;
- }
- m_descriptor_conf_feed_data.p_cinst = app_usbd_class_first_get();
- m_descriptor_conf_feed_data.p_desc = (void *)p_trans_buff;
- m_descriptor_conf_feed_data.desc_left = size;
- m_descriptor_conf_feed_data.total_left = p_setup_ev->setup.wLength.w;
- /* Start first transfer */
- ret_code_t ret;
- CRITICAL_REGION_ENTER();
- ret = app_usbd_ep_handled_transfer(
- NRF_DRV_USBD_EPIN0,
- &usbd_descriptor_feeder_desc);
- if (NRF_SUCCESS == ret)
- {
- ret = app_usbd_core_setup_data_handler_set(
- NRF_DRV_USBD_EPIN0,
- &m_setup_data_handler_empty_desc);
- }
- CRITICAL_REGION_EXIT();
- return ret;
- }
- case APP_USBD_DESCRIPTOR_STRING:
- {
- if(p_setup_ev->setup.wLength.w == 0)
- {
- return NRF_SUCCESS;
- }
- app_usbd_string_desc_idx_t id =
- (app_usbd_string_desc_idx_t)(p_setup_ev->setup.wValue.lb);
- uint16_t langid = p_setup_ev->setup.wIndex.w;
- uint16_t const * p_string_dsc = app_usbd_string_desc_get(id, langid);
- if (p_string_dsc == NULL)
- {
- return NRF_ERROR_NOT_SUPPORTED;
- }
- return app_usbd_core_setup_rsp(
- &p_setup_ev->setup,
- p_string_dsc,
- app_usbd_string_desc_length(p_string_dsc));
- }
- default:
- break;
- }
- return NRF_ERROR_NOT_SUPPORTED;
- }
- static ret_code_t setup_device_req_get_configuration(
- app_usbd_class_inst_t const * const p_inst,
- app_usbd_setup_evt_t const * const p_setup_ev)
- {
- size_t max_size;
- uint8_t * p_trans_buff = app_usbd_core_setup_transfer_buff_get(&max_size);
- app_usbd_state_t usb_state = usbd_core_state_get();
- if (usb_state == APP_USBD_STATE_Configured)
- {
- p_trans_buff[0] = 1;
- }
- else if (usb_state == APP_USBD_STATE_Addressed)
- {
- p_trans_buff[0] = 0;
- }
- else
- {
- return NRF_ERROR_NOT_SUPPORTED;
- }
- return app_usbd_core_setup_rsp(&p_setup_ev->setup, p_trans_buff, sizeof(p_trans_buff[0]));
- }
- static ret_code_t setup_device_req_set_configuration(
- app_usbd_class_inst_t const * const p_inst,
- app_usbd_setup_evt_t const * const p_setup_ev)
- {
- app_usbd_state_t usb_state = usbd_core_state_get();
- if (!((usb_state == APP_USBD_STATE_Configured) ||
- (usb_state == APP_USBD_STATE_Addressed)))
- {
- return NRF_ERROR_INVALID_STATE;
- }
- if (p_setup_ev->setup.wValue.lb == 0)
- {
- app_usbd_all_iface_deselect();
- usbd_core_state_set(APP_USBD_STATE_Addressed);
- }
- else if (p_setup_ev->setup.wValue.lb == 1)
- {
- /*Clear all bulk/interrupt endpoint status and set toggle to DATA0*/
- app_usbd_all_iface_select_0();
- usbd_core_state_set(APP_USBD_STATE_Configured);
- }
- else
- {
- /*In this driver only one configuration is supported.*/
- return NRF_ERROR_INVALID_PARAM;
- }
- return NRF_SUCCESS;
- }
- /**
- * @brief Internal SETUP event handler.
- * @param[in] p_inst Instance of the class.
- * @param[in] p_setup_ev Setup request.
- * @return Standard error code.
- * @retval NRF_SUCCESS Request handled correctly.
- * @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
- */
- static ret_code_t setup_device_req_std_handler(app_usbd_class_inst_t const * const p_inst,
- app_usbd_setup_evt_t const * const p_setup_ev)
- {
- ASSERT(p_inst != NULL);
- ASSERT(p_setup_ev != NULL);
- if (APP_USBD_SETUP_REQTYPE_STD != app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
- {
- return NRF_ERROR_NOT_SUPPORTED;
- }
- if (app_usbd_setup_req_dir(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQDIR_IN)
- {
- switch (p_setup_ev->setup.bRequest)
- {
- case APP_USBD_SETUP_STDREQ_GET_STATUS:
- {
- return setup_device_req_get_status(p_inst, p_setup_ev);
- }
- case APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR:
- {
- return setup_device_req_get_descriptor(p_inst, p_setup_ev);
- }
- case APP_USBD_SETUP_STDREQ_GET_CONFIGURATION:
- {
- return setup_device_req_get_configuration(p_inst, p_setup_ev);
- }
- default:
- /*Not supported*/
- break;
- }
- return NRF_ERROR_NOT_SUPPORTED;
- }
- else /* APP_USBD_SETUP_REQDIR_OUT */
- {
- switch (p_setup_ev->setup.bRequest)
- {
- case APP_USBD_SETUP_STDREQ_SET_ADDRESS:
- {
- ASSERT(0); /* should never reach this point */
- break;
- }
- case APP_USBD_SETUP_STDREQ_SET_FEATURE:
- {
- if (p_setup_ev->setup.wValue.w == APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP)
- {
- if (!app_usbd_class_rwu_enabled_check())
- {
- return NRF_ERROR_FORBIDDEN;
- }
- SET_BIT(m_device_features_state, APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP);
- return NRF_SUCCESS;
- }
- break;
- }
- case APP_USBD_SETUP_STDREQ_CLEAR_FEATURE:
- {
- if (p_setup_ev->setup.wValue.w == APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP)
- {
- if (!app_usbd_class_rwu_enabled_check())
- {
- return NRF_ERROR_FORBIDDEN;
- }
- CLR_BIT(m_device_features_state, APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP);
- return NRF_SUCCESS;
- }
- break;
- }
- case APP_USBD_SETUP_STDREQ_SET_CONFIGURATION:
- {
- return setup_device_req_set_configuration(p_inst, p_setup_ev);
- }
- case APP_USBD_SETUP_STDREQ_SET_DESCRIPTOR:
- {
- /*Not supported yet.*/
- break;
- }
- default:
- /*Not supported*/
- break;
- }
- return NRF_ERROR_NOT_SUPPORTED;
- }
- }
- /**
- * @brief Process SETUP command.
- *
- * Auxiliary function for SETUP command processing.
- */
- static inline ret_code_t app_usbd_core_setup_req_handler(app_usbd_class_inst_t const * const p_inst)
- {
- app_usbd_setup_evt_t setup_ev;
- ret_code_t ret = NRF_ERROR_NOT_SUPPORTED; /* Final result of request processing function */
- setup_ev.type = APP_USBD_EVT_DRV_SETUP;
- nrf_drv_usbd_setup_get((nrf_drv_usbd_setup_t *)&(setup_ev.setup));
- NRF_LOG_DEBUG("SETUP: t: 0x%.2x r: 0x%.2x",
- setup_ev.setup.bmRequestType,
- setup_ev.setup.bRequest);
- if (usb_core_ep0_handler_check())
- {
- NRF_LOG_WARNING("Previous setup not finished!");
- }
- /* Clear EP0 handler if there is anything in progress */
- usbd_core_ep0_handler_clear();
- switch (app_usbd_setup_req_rec(setup_ev.setup.bmRequestType))
- {
- case APP_USBD_SETUP_REQREC_DEVICE:
- {
- /* Endpoint 0 has core instance (that process device requests) connected */
- ret = setup_device_req_std_handler(p_inst, &setup_ev);
- if (ret == NRF_ERROR_NOT_SUPPORTED)
- {
- ret = app_usbd_all_until_served_call((app_usbd_complex_evt_t const *)&setup_ev);
- }
- break;
- }
- case APP_USBD_SETUP_REQREC_INTERFACE:
- {
- uint8_t const iface_number = setup_ev.setup.wIndex.lb;
- uint8_t iface_idx;
- app_usbd_class_inst_t const * p_inst_found = app_usbd_iface_find(
- iface_number,
- &iface_idx);
- if (p_inst_found == NULL)
- {
- ret = NRF_ERROR_INVALID_ADDR;
- }
- else
- {
- ret = app_usbd_iface_call(
- p_inst_found, iface_idx,
- (app_usbd_complex_evt_t const *)&setup_ev);
- if (ret == NRF_ERROR_NOT_SUPPORTED)
- {
- ret = setup_interface_req_std_handle(p_inst_found, iface_idx, &setup_ev);
- }
- }
- break;
- }
- case APP_USBD_SETUP_REQREC_ENDPOINT:
- {
- ret = NRF_ERROR_NOT_SUPPORTED;
- nrf_drv_usbd_ep_t ep = (nrf_drv_usbd_ep_t)setup_ev.setup.wIndex.lb;
- if ((NRF_USBD_EP_NR_GET(ep) != 0)) /* For EP0 we would call this function again! */
- {
- ret = app_usbd_ep_call(ep, (app_usbd_complex_evt_t const *)&setup_ev);
- }
- if (ret == NRF_ERROR_NOT_SUPPORTED)
- {
- ret = setup_endpoint_req_std(&setup_ev);
- }
- break;
- }
- case APP_USBD_SETUP_REQREC_OTHER:
- {
- /* Try to process via every instance */
- ret = app_usbd_all_until_served_call((app_usbd_complex_evt_t const *)&setup_ev);
- break;
- }
- default:
- break;
- }
- /* Processing result */
- if (ret == NRF_SUCCESS)
- {
- if (usb_core_ep0_handler_check())
- {
- if (NRF_DRV_USBD_EPOUT0 == nrf_drv_usbd_last_setup_dir_get())
- {
- /* Request processed successfully and requires SETUP data */
- nrf_drv_usbd_setup_data_clear();
- }
- }
- else
- {
- /* Request processed successfully */
- nrf_drv_usbd_setup_clear();
- }
- }
- else
- {
- /* Request finished with error */
- nrf_drv_usbd_setup_stall();
- }
- return ret;
- }
- /**
- * @brief Event handler for core module.
- *
- * The event handler that would process all events directed to device.
- *
- */
- static ret_code_t app_usbd_core_event_handler(app_usbd_class_inst_t const * const p_inst,
- app_usbd_complex_evt_t const * const p_event)
- {
- ret_code_t ret = NRF_ERROR_NOT_SUPPORTED;
- switch (p_event->type)
- {
- case APP_USBD_EVT_DRV_RESET:
- {
- usbd_core_state_set(APP_USBD_STATE_Default);
- break;
- }
- case APP_USBD_EVT_DRV_SUSPEND:
- {
- ret = NRF_SUCCESS;
- break;
- }
- case APP_USBD_EVT_DRV_RESUME:
- {
- if (nrf_atomic_flag_clear_fetch(&m_rwu_pending) != 0)
- {
- nrf_usbd_task_trigger(NRF_USBD_TASK_NODRIVEDPDM);
- }
- ASSERT(usbd_core_state_get() >= APP_USBD_STATE_Unattached);
- ret = NRF_SUCCESS;
- break;
- }
- case APP_USBD_EVT_SETUP_SETADDRESS:
- {
- app_usbd_state_t usb_state = usbd_core_state_get();
- if (usb_state == APP_USBD_STATE_Default)
- {
- usbd_core_state_set(APP_USBD_STATE_Addressed);
- }
- break;
- }
- case APP_USBD_EVT_DRV_SETUP:
- {
- ret = app_usbd_core_setup_req_handler(p_inst);
- break;
- }
- case APP_USBD_EVT_INST_APPEND:
- {
- ASSERT(usbd_core_state_get() == APP_USBD_STATE_Disabled);
- ret = NRF_SUCCESS;
- break;
- }
- case APP_USBD_EVT_INST_REMOVE:
- {
- ASSERT(usbd_core_state_get() == APP_USBD_STATE_Unattached);
- usbd_core_state_set(APP_USBD_STATE_Disabled);
- ret = NRF_SUCCESS;
- break;
- }
- case APP_USBD_EVT_STARTED:
- {
- if (usbd_core_power_is_detected())
- {
- usbd_core_state_set(APP_USBD_STATE_Powered);
- }
- else
- {
- usbd_core_state_set(APP_USBD_STATE_Unattached);
- }
- ret = NRF_SUCCESS;
- break;
- }
- case APP_USBD_EVT_STOPPED:
- {
- ASSERT(usbd_core_state_get() >= APP_USBD_STATE_Powered);
- usbd_core_state_set(APP_USBD_STATE_Unattached);
- ret = NRF_SUCCESS;
- break;
- }
- /* Data transfer on endpoint 0 */
- case APP_USBD_EVT_DRV_EPTRANSFER:
- {
- if (p_event->drv_evt.data.eptransfer.status == NRF_USBD_EP_ABORTED)
- {
- /* Just ignore aborting */
- break;
- }
- /* This EPTRANSFER event has to be called only for EP0 */
- ASSERT((p_event->drv_evt.data.eptransfer.ep == NRF_DRV_USBD_EPOUT0) ||
- (p_event->drv_evt.data.eptransfer.ep == NRF_DRV_USBD_EPIN0));
- ret = usbd_core_ep0_handler_call_and_clear(p_event->drv_evt.data.eptransfer.status);
- /* Processing result */
- if (ret == NRF_SUCCESS)
- {
- if (usb_core_ep0_handler_check())
- {
- if (p_event->drv_evt.data.eptransfer.ep == NRF_DRV_USBD_EPOUT0)
- {
- /* Request processed successfully and requires SETUP data */
- nrf_drv_usbd_setup_data_clear();
- }
- }
- else
- {
- nrf_drv_usbd_setup_clear();
- }
- }
- else
- {
- /* Request finished with error */
- nrf_drv_usbd_setup_stall();
- }
- break;
- }
- default:
- break;
- }
- return ret;
- }
- /** @} */
- void app_usbd_core_ep0_enable(void)
- {
- app_usbd_ep_enable(NRF_DRV_USBD_EPOUT0);
- app_usbd_ep_enable(NRF_DRV_USBD_EPIN0);
- }
- void app_usbd_core_ep0_disable(void)
- {
- app_usbd_ep_disable(NRF_DRV_USBD_EPOUT0);
- app_usbd_ep_disable(NRF_DRV_USBD_EPIN0);
- }
- ret_code_t app_usbd_core_setup_rsp(app_usbd_setup_t const * p_setup,
- void const * p_data,
- size_t size)
- {
- size_t req_size = p_setup->wLength.w;
- size_t tx_size = MIN(req_size, size);
- bool zlp_required = (size < req_size) &&
- (0 == (size % nrf_drv_usbd_ep_max_packet_size_get(NRF_DRV_USBD_EPIN0)));
- NRF_DRV_USBD_TRANSFER_IN_FLAGS(
- transfer,
- p_data,
- tx_size,
- zlp_required ? NRF_DRV_USBD_TRANSFER_ZLP_FLAG : 0);
- ret_code_t ret;
- CRITICAL_REGION_ENTER();
- ret = app_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer);
- if (NRF_SUCCESS == ret)
- {
- ret = app_usbd_core_setup_data_handler_set(NRF_DRV_USBD_EPIN0,
- &m_setup_data_handler_empty_desc);
- }
- CRITICAL_REGION_EXIT();
- return ret;
- }
- ret_code_t app_usbd_core_setup_data_handler_set(
- nrf_drv_usbd_ep_t ep,
- app_usbd_core_setup_data_handler_desc_t const * const p_handler_desc)
- {
- if (nrf_drv_usbd_last_setup_dir_get() != ep)
- {
- return NRF_ERROR_INVALID_ADDR;
- }
- m_ep0_handler_desc = *p_handler_desc;
- return NRF_SUCCESS;
- }
- void * app_usbd_core_setup_transfer_buff_get(size_t * p_size)
- {
- if (p_size != NULL)
- *p_size = sizeof(m_setup_transfer_buff);
- return m_setup_transfer_buff;
- }
- app_usbd_state_t app_usbd_core_state_get(void)
- {
- return usbd_core_state_get();
- }
- bool app_usbd_core_feature_state_get(app_usbd_setup_stdfeature_t feature)
- {
- return IS_SET(m_device_features_state, feature) ? true : false;
- }
- #endif //NRF_MODULE_ENABLED(APP_USBD)
|