/* * Copyright (c) 2016 - 2023, Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /* This file is undergoing transition towards native Zephyr nrf USB driver. */ /** @cond INTERNAL_HIDDEN */ #ifndef NRF_USBD_COMMON_H__ #define NRF_USBD_COMMON_H__ #include #ifdef __cplusplus extern "C" { #endif /** * @defgroup nrf_usbd_common USBD driver * @{ * @ingroup nrf_usbd * @brief Universal Serial Bus Device (USBD) peripheral driver. */ /** * @brief Number of bytes in the endpoint. */ #define NRF_USBD_COMMON_EPSIZE 64 /** * @brief Number of bytes for isochronous endpoints. * * Number of bytes for isochronous endpoints in total. * This number would be shared between IN and OUT endpoint. * It may be also assigned totaly to one endpoint. * @sa nrf_usbd_isosplit_set * @sa nrf_usbd_isosplit_get */ #define NRF_USBD_COMMON_ISOSIZE 1023 /** * @name Macros for creating endpoint identifiers. * * Auxiliary macros for creating endpoint identifiers compatible with the USB specification. * @{ */ /** * @brief Create identifier for IN endpoint. * * Simple macro to create IN endpoint identifier for given endpoint number. * * @param[in] n Endpoint number. * * @return Endpoint identifier that connects endpoint number and endpoint direction. */ #define NRF_USBD_COMMON_EPIN(n) ((nrf_usbd_common_ep_t)(0x80 | n)) /** * @brief Create identifier for OUT endpoint. * * Simple macro to create OUT endpoint identifier for given endpoint number. * * @param[in] n Endpoint number. * * @return Endpoint identifier that connects endpoint number and endpoint direction. */ #define NRF_USBD_COMMON_EPOUT(n) ((nrf_usbd_common_ep_t)(n)) /** @} */ /** * @brief Endpoint identifier. * * Endpoint identifier used in the driver. * This endpoint number is consistent with USB 2.0 specification. */ typedef enum { NRF_USBD_COMMON_EPOUT0 = 0x00, /**< Endpoint OUT 0 */ NRF_USBD_COMMON_EPOUT1 = 0x01, /**< Endpoint OUT 1 */ NRF_USBD_COMMON_EPOUT2 = 0x02, /**< Endpoint OUT 2 */ NRF_USBD_COMMON_EPOUT3 = 0x03, /**< Endpoint OUT 3 */ NRF_USBD_COMMON_EPOUT4 = 0x04, /**< Endpoint OUT 4 */ NRF_USBD_COMMON_EPOUT5 = 0x05, /**< Endpoint OUT 5 */ NRF_USBD_COMMON_EPOUT6 = 0x06, /**< Endpoint OUT 6 */ NRF_USBD_COMMON_EPOUT7 = 0x07, /**< Endpoint OUT 7 */ NRF_USBD_COMMON_EPOUT8 = 0x08, /**< Endpoint OUT 8 */ NRF_USBD_COMMON_EPIN0 = 0x80, /**< Endpoint IN 0 */ NRF_USBD_COMMON_EPIN1 = 0x81, /**< Endpoint IN 1 */ NRF_USBD_COMMON_EPIN2 = 0x82, /**< Endpoint IN 2 */ NRF_USBD_COMMON_EPIN3 = 0x83, /**< Endpoint IN 3 */ NRF_USBD_COMMON_EPIN4 = 0x84, /**< Endpoint IN 4 */ NRF_USBD_COMMON_EPIN5 = 0x85, /**< Endpoint IN 5 */ NRF_USBD_COMMON_EPIN6 = 0x86, /**< Endpoint IN 6 */ NRF_USBD_COMMON_EPIN7 = 0x87, /**< Endpoint IN 7 */ NRF_USBD_COMMON_EPIN8 = 0x88, /**< Endpoint IN 8 */ } nrf_usbd_common_ep_t; /** * @brief Events generated by the driver. * * Enumeration of possible events that may be generated by the driver. */ typedef enum { NRF_USBD_COMMON_EVT_SOF, /**< Start Of Frame event on USB bus detected. */ NRF_USBD_COMMON_EVT_RESET, /**< Reset condition on USB bus detected. */ NRF_USBD_COMMON_EVT_SUSPEND, /**< This device should go to suspend mode now. */ NRF_USBD_COMMON_EVT_RESUME, /**< This device should resume from suspend now. */ /** Wakeup request - the USBD peripheral is ready to generate * WAKEUP signal after exiting low power mode. */ NRF_USBD_COMMON_EVT_WUREQ, NRF_USBD_COMMON_EVT_SETUP, /**< Setup frame received and decoded. */ /** For Rx (OUT: Host->Device): * 1. The packet has been received but there is no buffer * prepared for transfer already. * 2. Whole transfer has been finished. * * For Tx (IN: Device->Host): * The last packet from requested transfer has been transferred * over USB bus and acknowledged. */ NRF_USBD_COMMON_EVT_EPTRANSFER, NRF_USBD_COMMON_EVT_CNT /**< Number of defined events. */ } nrf_usbd_common_event_type_t; /** * @brief Endpoint status codes. * * Status codes that may be returned by @ref nrf_usbd_common_ep_status_get or, except for * @ref NRF_USBD_COMMON_EP_BUSY, reported together with @ref NRF_USBD_COMMON_EVT_EPTRANSFER. */ typedef enum { /** No error occurred. */ NRF_USBD_COMMON_EP_OK, /** Data received, no buffer prepared already - waiting for configured transfer. */ NRF_USBD_COMMON_EP_WAITING, /** Received number of bytes cannot fit given buffer. * This error would also be returned when next_transfer function * has been defined but currently received data cannot fit completely * in current buffer. No data split from single endpoint transmission * is supported. * * When this error is reported - data is left inside endpoint * buffer. Clear endpoint or prepare new buffer and read it. */ NRF_USBD_COMMON_EP_OVERLOAD, /** EP0 transfer can be aborted when new setup comes. * Any other transfer can be aborted by USB reset or driver stopping. */ NRF_USBD_COMMON_EP_ABORTED, /** Transfer is in progress. */ NRF_USBD_COMMON_EP_BUSY, } nrf_usbd_common_ep_status_t; /** * @brief Event structure. * * Structure passed to event handler. */ typedef struct { nrf_usbd_common_event_type_t type; /**< Event type. */ union { struct { uint16_t framecnt; /**< Current value of frame counter. */ } sof; /**< Data available for @ref NRF_USBD_COMMON_EVT_SOF. */ struct { nrf_usbd_common_ep_t ep; /**< Endpoint number. */ } isocrc; /**< Isochronouns channel endpoint number. */ struct { nrf_usbd_common_ep_t ep; /**< Endpoint number. */ nrf_usbd_common_ep_status_t status; /**< Status for the endpoint. */ } eptransfer; /**< Endpoint transfer status. */ } data; /**< Union to store event data. */ } nrf_usbd_common_evt_t; /** * @brief USBD event callback function type. * * @param[in] p_event Event information structure. */ typedef void (*nrf_usbd_common_event_handler_t)(nrf_usbd_common_evt_t const *p_event); /** * @brief Universal data pointer. * * Universal data pointer that can be used for any type of transfer. */ typedef union { void const *tx; /*!< Constant TX buffer pointer. */ void *rx; /*!< Writable RX buffer pointer. */ uint32_t addr; /*!< Numeric value used internally by the driver. */ } nrf_usbd_common_data_ptr_t; /** * @brief Structure to be filled with information about the next transfer. * * This is used mainly for transfer feeders and consumers. * It describes a single endpoint transfer and therefore the size of the buffer * can never be higher than the endpoint size. */ typedef struct { /** Union with available data pointers used by the driver. */ nrf_usbd_common_data_ptr_t p_data; /** Size of the requested transfer. */ size_t size; } nrf_usbd_common_ep_transfer_t; /** * @brief Flags for the current transfer. * * Flags configured for the transfer that can be merged using the bitwise 'or' operator (|). */ typedef enum { NRF_USBD_COMMON_TRANSFER_ZLP_FLAG = 1U << 0, /*!< Add a zero-length packet. */ } nrf_usbd_common_transfer_flags_t; /** * @brief Total transfer configuration. * * This structure is used to configure total transfer information. * It is used by internal built-in feeders and consumers. */ typedef struct { /** Union with available data pointers used by the driver. */ nrf_usbd_common_data_ptr_t p_data; /** Total size of the requested transfer. */ size_t size; /*!< Transfer flags. Use the @ref nrf_usbd_common_transfer_flags_t values. */ uint32_t flags; } nrf_usbd_common_transfer_t; /** * @brief Auxiliary macro for declaring IN transfer description with optional flags. * * The base macro for creating transfers with any configuration option. * * @param name Instance name. * @param tx_buff Buffer to transfer. * @param tx_size Transfer size. * @param tx_flags Flags for the transfer (see @ref nrf_usbd_common_transfer_flags_t). * * @return Configured variable with total transfer description. */ #define NRF_USBD_COMMON_TRANSFER_IN(name, tx_buff, tx_size, tx_flags) \ const nrf_usbd_common_transfer_t name = { \ .p_data = {.tx = (tx_buff)}, .size = (tx_size), .flags = (tx_flags)} /** * @brief Helper macro for declaring OUT transfer item (@ref nrf_usbd_common_transfer_t). * * @param name Instance name. * @param rx_buff Buffer to transfer. * @param rx_size Transfer size. */ #define NRF_USBD_COMMON_TRANSFER_OUT(name, rx_buff, rx_size) \ const nrf_usbd_common_transfer_t name = { \ .p_data = {.rx = (rx_buff)}, .size = (rx_size), .flags = 0} /** * @brief Setup packet structure. * * Structure that contains interpreted SETUP packet as described in USB specification. */ typedef struct { uint8_t bmRequestType; /*!< byte 0 */ uint8_t bRequest; /*!< byte 1 */ uint16_t wValue; /*!< byte 2, 3 */ uint16_t wIndex; /*!< byte 4, 5 */ uint16_t wLength; /*!< byte 6, 7 */ } nrf_usbd_common_setup_t; /** * @brief Driver initialization. * * @param[in] event_handler Event handler provided by the user. Cannot be null. * * @retval NRFX_SUCCESS Initialization successful. * @retval NRFX_ERROR_INVALID_STATE Driver was already initialized. */ nrfx_err_t nrf_usbd_common_init(nrf_usbd_common_event_handler_t event_handler); /** * @brief Driver deinitialization. */ void nrf_usbd_common_uninit(void); /** * @brief Enable the USBD port. * * After calling this function USBD peripheral would be enabled. * The USB LDO would be enabled. * Enabled USBD peripheral would request HFCLK. * This function does not enable external oscillator, so if it is not enabled by other part of the * program after enabling USBD driver HFINT would be used for the USBD peripheral. * It is perfectly fine until USBD is started. See @ref nrf_usbd_common_start. * * In normal situation this function should be called in reaction to USBDETECTED * event from POWER peripheral. * * Interrupts and USB pins pull-up would stay disabled until @ref nrf_usbd_common_start * function is called. */ void nrf_usbd_common_enable(void); /** * @brief Disable the USBD port. * * After calling this function USBD peripheral would be disabled. * No events would be detected or processed by the driver. * Clock for the peripheral would be disconnected. */ void nrf_usbd_common_disable(void); /** * @brief Start USB functionality. * * After calling this function USBD peripheral should be fully functional * and all new incoming events / interrupts would be processed by the driver. * * Also only after calling this function host sees new connected device. * * Call this function when USBD power LDO regulator is ready - on USBPWRRDY event * from POWER peripheral. * * Before USBD interrupts are enabled, external HFXO is requested. * * @param enable_sof The flag that is used to enable SOF processing. * If it is false, SOF interrupt is left disabled and will not be generated. * This improves power saving if SOF is not required. * * @note If the isochronous endpoints are going to be used, * it is required to enable the SOF. * In other case any isochronous endpoint would stay busy * after first transmission. */ void nrf_usbd_common_start(bool enable_sof); /** * @brief Check if driver is initialized. * * @retval false Driver is not initialized. * @retval true Driver is initialized. */ bool nrf_usbd_common_is_initialized(void); /** * @brief Check if driver is enabled. * * @retval false Driver is disabled. * @retval true Driver is enabled. */ bool nrf_usbd_common_is_enabled(void); /** * @brief Check if driver is started. * * @retval false Driver is not started. * @retval true Driver is started (fully functional). * @note The USBD peripheral interrupt state is checked. */ bool nrf_usbd_common_is_started(void); /** * @brief Suspend USBD operation. * * The USBD peripheral is forced to go into the low power mode. * The function has to be called in the reaction to @ref NRF_USBD_COMMON_EVT_SUSPEND event * when the firmware is ready. * * After successful call of this function most of the USBD registers would be unavailable. * * @note Check returned value for the feedback if suspending was successful. * * @retval true USBD peripheral successfully suspended. * @retval false USBD peripheral was not suspended due to resume detection. */ bool nrf_usbd_common_suspend(void); /** * @brief Start wake up procedure. * * The USBD peripheral is forced to quit the low power mode. * After calling this function all the USBD registers would be available. * * The hardware starts measuring time when wake up is possible. * This may take 0-5 ms depending on how long the SUSPEND state was kept on the USB line. * When NRF_USBD_COMMON_EVT_WUREQ event is generated it means that Wake Up signaling has just been * started on the USB lines. * * @note Do not expect only @ref NRF_USBD_COMMON_EVT_WUREQ event. * There always may appear @ref NRF_USBD_COMMON_EVT_RESUME event. * @note NRF_USBD_COMMON_EVT_WUREQ event means that Remote WakeUp signal * has just begun to be generated. * This may take up to 20 ms for the bus to become active. * * @retval true WakeUp procedure started. * @retval false No WakeUp procedure started - bus is already active. */ bool nrf_usbd_common_wakeup_req(void); /** * @brief Check if USBD is in SUSPEND mode. * * @note This is the information about peripheral itself, not about the bus state. * * @retval true USBD peripheral is suspended. * @retval false USBD peripheral is active. */ bool nrf_usbd_common_suspend_check(void); /** * @brief Check the bus state. * * This function checks if the bus state is suspended. * * @note The value returned by this function changes on SUSPEND and RESUME event processing. * * @retval true USBD bus is suspended. * @retval false USBD bus is active. */ bool nrf_usbd_common_bus_suspend_check(void); /** * @brief Force the bus state to active */ void nrf_usbd_common_force_bus_wakeup(void); /** * @brief Configure packet size that should be supported by the endpoint. * * The real endpoint buffer size is always the same. * This value sets max packet size that would be transmitted over the endpoint. * This is required by the driver. * * @param[in] ep Endpoint number. * @param[in] size Required maximum packet size. * * @note Endpoint size is always set to @ref NRF_USBD_COMMON_EPSIZE * or @ref NRF_USBD_COMMON_ISOSIZE / 2 * when @ref nrf_usbd_common_ep_enable function is called. */ void nrf_usbd_common_ep_max_packet_size_set(nrf_usbd_common_ep_t ep, uint16_t size); /** * @brief Get configured endpoint packet size. * * Function to get configured endpoint size on the buffer. * * @param[in] ep Endpoint number. * * @return Maximum pocket size configured on selected endpoint. */ uint16_t nrf_usbd_common_ep_max_packet_size_get(nrf_usbd_common_ep_t ep); /** * @brief Check if the selected endpoint is enabled. * * @param[in] ep Endpoint number to check. * * @retval true Endpoint is enabled. * @retval false Endpoint is disabled. */ bool nrf_usbd_common_ep_enable_check(nrf_usbd_common_ep_t ep); /** * @brief Enable selected endpoint. * * This function enables endpoint itself and its interrupts. * * @param[in] ep Endpoint number to enable. * * @note * Max packet size is set to endpoint default maximum value. * * @sa nrf_usbd_common_ep_max_packet_size_set */ void nrf_usbd_common_ep_enable(nrf_usbd_common_ep_t ep); /** * @brief Disable selected endpoint. * * This function disables endpoint itself and its interrupts. * * @param[in] ep Endpoint number to disable. */ void nrf_usbd_common_ep_disable(nrf_usbd_common_ep_t ep); /** * @brief Start sending data over endpoint. * * Function initializes endpoint transmission. * This is asynchronous function - it finishes immediately after configuration * for transmission is prepared. * * @note Data buffer pointed by p_data have to be kept active till * @ref NRF_USBD_COMMON_EVT_EPTRANSFER event is generated. * * @param[in] ep Endpoint number. * For IN endpoint sending would be initiated. * For OUT endpoint receiving would be initiated. * @param[in] p_transfer Transfer parameters. * * @retval NRFX_SUCCESS Transfer queued or started. * @retval NRFX_ERROR_BUSY Selected endpoint is pending. * @retval NRFX_ERROR_INVALID_ADDR Unexpected transfer on EPIN0 or EPOUT0. */ nrfx_err_t nrf_usbd_common_ep_transfer(nrf_usbd_common_ep_t ep, nrf_usbd_common_transfer_t const *p_transfer); /** * @brief Get the information about last finished or current transfer. * * Function returns the status of the last buffer set for transfer on selected endpoint. * The status considers last buffer set by @ref nrf_usbd_common_ep_transfer function or * by transfer callback function. * * @param[in] ep Endpoint number. * @param[out] p_size Information about the current/last transfer size. * * @return Endpoint status. * * @sa nrf_usbd_common_ep_status_t */ nrf_usbd_common_ep_status_t nrf_usbd_common_ep_status_get(nrf_usbd_common_ep_t ep, size_t *p_size); /** * @brief Get number of received bytes. * * Get the number of received bytes. * The function behavior is undefined when called on IN endpoint. * * @param[in] ep Endpoint number. * * @return Number of received bytes. */ size_t nrf_usbd_common_epout_size_get(nrf_usbd_common_ep_t ep); /** * @brief Check if endpoint buffer is ready or is under USB IP control. * * Function to test if endpoint is busy. * Endpoint that is busy cannot be accessed by MCU. * It means that: * - OUT (TX) endpoint: Last uploaded data is still in endpoint and is waiting * to be received by the host. * - IN (RX) endpoint: Endpoint is ready to receive data from the host * and the endpoint does not have any data. * When endpoint is not busy: * - OUT (TX) endpoint: New data can be uploaded. * - IN (RX) endpoint: New data can be downloaded using @ref nrf_usbd_common_ep_transfer * function. * * @param[in] ep Endpoint number. * * @retval false Endpoint is not busy. * @retval true Endpoint is busy. */ bool nrf_usbd_common_ep_is_busy(nrf_usbd_common_ep_t ep); /** * @brief Stall endpoint * * Stall endpoit to send error information during next transfer request from * the host. * * @note To stall endpoint it is safer to use @ref nrf_usbd_common_setup_stall * @note Stalled endpoint would not be cleared when DMA transfer finishes. * * @param[in] ep Endpoint number to stall. */ void nrf_usbd_common_ep_stall(nrf_usbd_common_ep_t ep); /** * @brief Clear stall flag on endpoint. * * This function clears endpoint that is stalled. * @note * If it is OUT endpoint (receiving) it would be also prepared for reception. * It means that busy flag would be set. * @note * In endpoint (transmitting) would not be cleared - it gives possibility to * write new data before transmitting. * * @param[in] ep Endpoint number. */ void nrf_usbd_common_ep_stall_clear(nrf_usbd_common_ep_t ep); /** * @brief Check if endpoint is stalled. * * This function gets stall state of selected endpoint. * * @param[in] ep Endpoint number to check. * * @retval false Endpoint is not stalled. * @retval true Endpoint is stalled. */ bool nrf_usbd_common_ep_stall_check(nrf_usbd_common_ep_t ep); /** * @brief Clear current endpoint data toggle. * * @param[in] ep Endpoint number to clear. */ void nrf_usbd_common_ep_dtoggle_clear(nrf_usbd_common_ep_t ep); /** * @brief Get parsed setup data. * * Function fills the parsed setup data structure. * * @param[out] p_setup Pointer to data structure that would be filled by * parsed data. */ void nrf_usbd_common_setup_get(nrf_usbd_common_setup_t *p_setup); /** * @brief Clear the control endpoint for packet reception during DATA stage. * * This function may be called if any more data in control write transfer is expected. * Clears only OUT endpoint to be able to take another OUT data token. * It does not allow STATUS stage. * @sa nrf_usbd_common_setup_clear */ void nrf_usbd_common_setup_data_clear(void); /** * @brief Clear setup endpoint. * * This function acknowledges setup when SETUP command was received and processed. * It has to be called if no data respond for the SETUP command is sent. */ void nrf_usbd_common_setup_clear(void); /** * @brief Stall setup endpoint. * * Mark an error on setup endpoint. */ void nrf_usbd_common_setup_stall(void); /** * @brief Abort pending transfer on selected endpoint. * * @param[in] ep Endpoint number. */ void nrf_usbd_common_ep_abort(nrf_usbd_common_ep_t ep); /** * @brief Get the information about expected transfer SETUP data direction. * * Function returns the information about last expected transfer direction. * * @retval NRF_USBD_COMMON_EPOUT0 Expecting OUT (Host->Device) direction or no data. * @retval NRF_USBD_COMMON_EPIN0 Expecting IN (Device->Host) direction. */ nrf_usbd_common_ep_t nrf_usbd_common_last_setup_dir_get(void); /** * @brief Drop transfer on OUT endpoint. * * @param[in] ep OUT endpoint ID. */ void nrf_usbd_common_transfer_out_drop(nrf_usbd_common_ep_t ep); /** @} */ void nrf_usbd_common_irq_handler(void); #ifdef __cplusplus } #endif #endif /* NRF_USBD_COMMON_H__ */ /** @endcond */