/** * 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. * */ #ifndef APP_USBD_MSC_INTERNAL_H__ #define APP_USBD_MSC_INTERNAL_H__ #include "app_util.h" #ifdef __cplusplus extern "C" { #endif /** * @defgroup app_usbd_msc_internals USB MSC internals * @ingroup app_usbd_msc * * @brief @tagAPI52840 Internals of the USB MSC class. * @{ */ /** * @brief Minimal serial string descriptor length. * */ #define APP_USBD_MSC_MINIMAL_SERIAL_STRING_SIZE (12 + 1) /** * @brief Number of block buffers * * Number of buffers used for the transfer. * The library is designed to work with double buffering. * Not tested with other configuration. */ #define APP_USBD_MSC_BUFFER_CNT 2 /** * @brief Create the name of the block buffer * * @param instance_name The name of the MSC instance * * @return The name of the block buffer used with the instance */ #define APP_USBD_MSC_BUFFER_NAME(instance_name) CONCAT_2(instance_name, _block) /** * @brief Create the name of the block device list * * @param instance_name The name of the MSC instance * * @return The name of the block device list */ #define APP_USBD_MSC_BLKDEVS_NAME(instance_name) CONCAT_2(instance_name, _blkdevs) /** * @brief Forward declaration of Mass Storage Class type. * */ APP_USBD_CLASS_FORWARD(app_usbd_msc); /*lint -save -e165*/ /** * @brief Forward declaration of @ref app_usbd_msc_user_event_e * */ enum app_usbd_msc_user_event_e; /*lint -restore*/ /** * @brief User event handler. * * @param[in] p_inst Class instance. * @param[in] event User event. * * */ typedef void (*app_usbd_msc_user_ev_handler_t)(app_usbd_class_inst_t const * p_inst, enum app_usbd_msc_user_event_e event); /** * @brief MSC part of class instance data. */ typedef struct { void * p_block_buff; //!< Block buffer size_t block_buff_size; //!< Block buffer size (typically 512 bytes) size_t block_buff_count; //!< Number of buffers (typically 2) nrf_block_dev_t const ** pp_block_devs; //!< Block devices list size_t block_devs_count; //!< Block device list size app_usbd_msc_user_ev_handler_t user_ev_handler; //!< User event handler app_usbd_msc_subclass_t subclass; //!< MSC subclass app_usbd_msc_protocol_t protocol; //!< MSC protocol } app_usbd_msc_inst_t; /** * @brief Internal module state. */ typedef enum { APP_USBD_MSC_STATE_DISABLED, /**< Internal module state DISABLED */ APP_USBD_MSC_STATE_IDLE, /**< Internal module state IDLE */ APP_USBD_MSC_STATE_CBW, /**< Internal module state CBW */ APP_USBD_MSC_STATE_CMD_IN, /**< Internal module state CMD_IN */ APP_USBD_MSC_STATE_DATA_IN, /**< Internal module state DATA_IN */ APP_USBD_MSC_STATE_DATA_OUT, /**< Internal module state DATA_OUT */ APP_USBD_MSC_STATE_CSW, /**< Internal module state CSW */ APP_USBD_MSC_STATE_UNSUPPORTED, /**< Internal module state UNSUPPORTED */ APP_USBD_MSC_STATE_CBW_INVALID, /**< Endpoint is stalled until * the command @ref APP_USBD_MSC_REQ_BULK_RESET */ APP_USBD_MSC_STATE_DEVICE_ERROR, /**< Endpoint is stalled and it is required * to send PE error when clearing */ } app_usbd_msc_state_t; /** * @brief MSC context. * * */ typedef struct { app_usbd_msc_state_t state; //!< Internal module state app_usbd_msc_cbw_t cbw; //!< SCSI command block wrapper app_usbd_msc_csw_t csw; //!< SCSI Command status wrapper /** @brief Currently processed command with data */ struct { /** @brief Buffer data */ struct { uint8_t rd_idx; //!< Buffer read index uint8_t d_count; //!< Number of blocks inside the buffer ready to process uint8_t a_count; //!< Number of blocks allocated in the buffer } buff; /** @brief Currently transfered block */ struct { size_t size_left; //!< Number of bytes left to transfer size_t datalen_left; //!< Number of bytes left that was requested by the host bool pending; //!< The flag marking the pending transfer bool abort; //!< Something fails during reading - abort transfer and mark an error, //!< Used for read access. } transfer; /** @brief The block currently processed by block device */ struct { uint8_t lun; //!< The logical unit for current transfer block size_t blk_size; //!< The size of the block of the selected lun size_t size_left; //!< Number of bytes left to be processed by block device size_t datalen_left; //!< Number of bytes left that was requested by the host uint32_t blk_idx; //!< Current block index bool pending; //!< The flag marking the pending transfer bool abort; //!< Something fails during transfer - abort processing and mark an error, //!< Used for write access. } process; } current; /** @brief SCSI response container*/ union { app_usbd_scsi_cmd_inquiry_resp_t inquiry; //!< @ref APP_USBD_SCSI_CMD_INQUIRY response app_usbd_scsi_cmd_requestsense_resp_t requestsense; //!< @ref APP_USBD_SCSI_CMD_REQUESTSENSE response app_usbd_scsi_cmd_readcapacity10_resp_t readcapacity10; //!< @ref APP_USBD_SCSI_CMD_READCAPACITY10 response app_usbd_scsi_cmd_modesense6_resp_t modesense6; //!< @ref APP_USBD_SCSI_CMD_MODESENSE6 response app_usbd_scsi_cmd_modesense10_resp_t modesense10; //!< @ref APP_USBD_SCSI_CMD_MODESENSE10 response } scsi_resp; uint16_t blk_dev_init_mask; //!< Block devices init mask } app_usbd_msc_ctx_t; /** * @brief MSC configuration macro. * * Used by @ref APP_USBD_MSC_GLOBAL_DEF * * @param iface Interface number. * @param endpoints Endpoint list. * */ #define APP_USBD_MSC_CONFIG(iface, endpoints) ((iface, BRACKET_EXTRACT(endpoints))) /** * @brief Specific class constant data for MSC. * * @ref app_usbd_msc_inst_t */ #define APP_USBD_MSC_INSTANCE_SPECIFIC_DEC app_usbd_msc_inst_t inst; /** * @brief Configures MSC instance. * * @param p_devs Block devices list that is array of pointers of @ref nrf_block_dev_t type. * @param devs_cnt Number of block devices connected. * @param p_buff Block buffer. * @param block_size Total size of the single block in the buffer. * @param block_cnt Number of available block buffers. * @param user_event_handler User event handler. */ #define APP_USBD_MSC_INST_CONFIG(p_devs, \ devs_cnt, \ p_buff, \ block_size, \ block_cnt, \ user_event_handler) \ .inst = { \ .pp_block_devs = (p_devs), \ .block_devs_count = (devs_cnt), \ .p_block_buff = (p_buff), \ .block_buff_size = (block_size), \ .block_buff_count = (block_cnt), \ .user_ev_handler = (user_event_handler), \ .subclass = APP_USBD_MSC_SUBCLASS_TRANSPARENT, \ .protocol = APP_USBD_MSC_PROTOCOL_BULK, \ } /** * @brief Specific class data for MSC. * * @ref app_usbd_msc_ctx_t * */ #define APP_USBD_MSC_DATA_SPECIFIC_DEC app_usbd_msc_ctx_t ctx; /** * @brief MSC descriptors config macro. * * @param interface_number Interface number. * @param ... Extracted endpoint list. * */ #define APP_USBD_MSC_DSC_CONFIG(interface_number, ...) { \ APP_USBD_MSC_INTERFACE_DSC(interface_number, \ APP_USBD_MSC_SUBCLASS_TRANSPARENT, \ APP_USBD_MSC_PROTOCOL_BULK) \ APP_USBD_MSC_EP_DSC(GET_VA_ARG_1(__VA_ARGS__), \ GET_VA_ARG_1(GET_ARGS_AFTER_1(__VA_ARGS__)), \ 64) \ } /** * @brief Public MSC class interface. * * */ extern const app_usbd_class_methods_t app_usbd_msc_class_methods; /** * @brief Global definition of mass storage class instance. */ #define APP_USBD_MSC_GLOBAL_DEF_INTERNAL(instance_name, \ interface_number, \ user_ev_handler, \ endpoint_list, \ blockdev_list, \ workbuffer_size) \ static const nrf_block_dev_t * APP_USBD_MSC_BLKDEVS_NAME(instance_name)[] = \ { BRACKET_EXTRACT(blockdev_list) }; \ static uint32_t APP_USBD_MSC_BUFFER_NAME(instance_name) \ [APP_USBD_MSC_BUFFER_CNT * CEIL_DIV(workbuffer_size, sizeof(uint32_t))]; \ APP_USBD_CLASS_INST_GLOBAL_DEF( \ instance_name, \ app_usbd_msc, \ &app_usbd_msc_class_methods, \ APP_USBD_MSC_CONFIG(interface_number, endpoint_list), \ (APP_USBD_MSC_INST_CONFIG(APP_USBD_MSC_BLKDEVS_NAME(instance_name), \ ARRAY_SIZE(APP_USBD_MSC_BLKDEVS_NAME(instance_name)), \ APP_USBD_MSC_BUFFER_NAME (instance_name), \ sizeof(APP_USBD_MSC_BUFFER_NAME(instance_name)) \ / APP_USBD_MSC_BUFFER_CNT, \ APP_USBD_MSC_BUFFER_CNT, \ user_ev_handler)) \ ) /** @} */ #ifdef __cplusplus } #endif #endif /* APP_USBD_MSC_INTERNAL_H__ */