From 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 23 Aug 2018 17:08:59 +0200 Subject: o Initial import. --- .../libraries/usbd/class/msc/app_usbd_msc.c | 2365 ++++++++++++++++++++ .../libraries/usbd/class/msc/app_usbd_msc.h | 193 ++ .../libraries/usbd/class/msc/app_usbd_msc_desc.h | 104 + .../usbd/class/msc/app_usbd_msc_internal.h | 259 +++ .../libraries/usbd/class/msc/app_usbd_msc_scsi.h | 329 +++ .../libraries/usbd/class/msc/app_usbd_msc_types.h | 141 ++ 6 files changed, 3391 insertions(+) create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.c create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_desc.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_internal.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_scsi.h create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_types.h (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc') diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.c new file mode 100644 index 0000000..a19de11 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.c @@ -0,0 +1,2365 @@ +/** + * Copyright (c) 2016 - 2018, 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_MSC) + +#include +#include +#include "app_usbd.h" +#include "app_usbd_msc.h" +#include "app_usbd_string_desc.h" + +/** + * @defgroup app_usbd_msc_internal USBD MSC internals + * @{ + * @ingroup app_usbd_msc + * @internal + */ + +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_requestsense_t) == 6); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_requestsense_resp_t) == 18); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_inquiry_t) == 6); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_inquiry_resp_t) == 36); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_read6_t) == 6); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_write6_t) == 6); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_modesense6_t) == 6); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_modesense6_resp_t) == 4); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_readcapacity10_t) == 10); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_readcapacity10_resp_t) == 8); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_read10_t) == 10); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_write10_t) == 10); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_modesense10_t) == 10); +STATIC_ASSERT(sizeof(app_usbd_scsi_cmd_modesense10_resp_t) == 8); + +STATIC_ASSERT(sizeof(app_usbd_msc_cbw_t) == 31); +STATIC_ASSERT(sizeof(app_usbd_msc_csw_t) == 13); + +#define NRF_LOG_MODULE_NAME usbd_msc + +#if APP_USBD_MSC_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL APP_USBD_MSC_CONFIG_LOG_LEVEL +#define NRF_LOG_INFO_COLOR APP_USBD_MSC_CONFIG_INFO_COLOR +#define NRF_LOG_DEBUG_COLOR APP_USBD_MSC_CONFIG_DEBUG_COLOR +#else // APP_USBD_MSC_CONFIG_LOG_ENABLED +#define NRF_LOG_LEVEL 0 +#endif // APP_USBD_MSC_CONFIG_LOG_ENABLED +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define APP_USBD_MSC_IFACE_IDX 0 /**< Mass storage class interface index */ +#define APP_USBD_MSC_EPIN_IDX 0 /**< Mass storage class endpoint IN index */ +#define APP_USBD_MSC_EPOUT_IDX 1 /**< Mass storage class endpoint OUT index */ + +/** + * @brief Set request buffer busy flag + * + * @param[in] val Bitmask to set + * @param[in] id Buffer id + * */ +#define APP_USBD_MSC_REQ_BUSY_SET(val, id) SET_BIT(val, id) + +/** + * @brief Clear request buffer busy flag + * + * @param[in] val Bitmask to set + * @param[in] id Buffer id + * */ +#define APP_USBD_MSC_REQ_BUSY_CLR(val, id) CLR_BIT(val, id) + +#define APP_USBD_MSC_REQ_BUSY_FULL_MASK (0x03) /**< Request busy mask */ + +static void msc_blockdev_ev_handler(nrf_block_dev_t const * p_blk_dev, + nrf_block_dev_event_t const * p_event); + +/** + * @brief Auxiliary function to access MSC instance data + * + * @param[in] p_inst Class instance data + * + * @return MSC instance data @ref app_usbd_msc_t + */ +static inline app_usbd_msc_t const * msc_get(app_usbd_class_inst_t const * p_inst) +{ + ASSERT(p_inst != NULL); + return (app_usbd_msc_t const *)p_inst; +} + + +/** + * @brief Auxiliary function to access MSC context data + * + * @param[in] p_msc MSC instance data + * @return MSC context data @ref app_usbd_msc_ctx_t + */ +static inline app_usbd_msc_ctx_t * msc_ctx_get(app_usbd_msc_t const * p_msc) +{ + ASSERT(p_msc != NULL); + ASSERT(p_msc->specific.p_data != NULL); + return &p_msc->specific.p_data->ctx; +} + + +/** + * @brief Auxiliary function to access MSC IN endpoint address + * + * @param[in] p_inst Class instance data + * + * @return IN endpoint address + */ +static inline nrf_drv_usbd_ep_t ep_in_addr_get(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_class_iface_conf_t const * class_iface; + + class_iface = app_usbd_class_iface_get(p_inst, APP_USBD_MSC_IFACE_IDX); + + app_usbd_class_ep_conf_t const * ep_cfg; + ep_cfg = app_usbd_class_iface_ep_get(class_iface, APP_USBD_MSC_EPIN_IDX); + + return app_usbd_class_ep_address_get(ep_cfg); +} + + +/** + * @brief Auxiliary function to access MSC OUT endpoint address + * + * @param[in] p_inst Class instance data + * + * @return OUT endpoint address + */ +static inline nrf_drv_usbd_ep_t ep_out_addr_get(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_class_iface_conf_t const * class_iface; + + class_iface = app_usbd_class_iface_get(p_inst, APP_USBD_MSC_IFACE_IDX); + + app_usbd_class_ep_conf_t const * ep_cfg; + ep_cfg = app_usbd_class_iface_ep_get(class_iface, APP_USBD_MSC_EPOUT_IDX); + + return app_usbd_class_ep_address_get(ep_cfg); +} + + +/** + * @brief Command Block Wrapper trigger + * + * @param[in] p_inst Generic class instance + * @param[in] state Next state transition + * + * @return Standard error code + * */ +static ret_code_t cbw_wait_start(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + nrf_drv_usbd_ep_t ep_addr_out = ep_out_addr_get(p_inst); + + NRF_LOG_DEBUG("cbw_wait_start"); + memset(&p_msc_ctx->cbw, 0, sizeof(app_usbd_msc_cbw_t)); + NRF_DRV_USBD_TRANSFER_OUT(cbw, &p_msc_ctx->cbw, sizeof(app_usbd_msc_cbw_t)); + ret_code_t ret = app_usbd_ep_transfer(ep_addr_out, &cbw); + if (ret == NRF_SUCCESS) + { + p_msc_ctx->state = APP_USBD_MSC_STATE_CBW; + } + + return ret; +} + + +/** + * @brief Command Status Wrapper trigger + * + * @param[in] p_inst Generic class instance + * @param[in] state Next state transition + * + * @return Standard error code + * */ +static ret_code_t csw_wait_start(app_usbd_class_inst_t const * p_inst, uint8_t status) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + nrf_drv_usbd_ep_t ep_addr_in = ep_in_addr_get(p_inst); + + memset(&p_msc_ctx->csw, 0, sizeof(app_usbd_msc_csw_t)); + memcpy(p_msc_ctx->csw.signature, APP_USBD_MSC_CSW_SIGNATURE, sizeof(p_msc_ctx->csw.signature)); + memcpy(p_msc_ctx->csw.tag, p_msc_ctx->cbw.tag, sizeof(p_msc_ctx->csw.tag)); + memcpy(p_msc_ctx->csw.residue, &p_msc_ctx->current.residue, sizeof(uint32_t)); + p_msc_ctx->csw.status = status; + + NRF_DRV_USBD_TRANSFER_IN(csw, &p_msc_ctx->csw, sizeof(app_usbd_msc_csw_t)); + ret_code_t ret = app_usbd_ep_transfer(ep_addr_in, &csw); + if (ret == NRF_SUCCESS) + { + p_msc_ctx->state = APP_USBD_MSC_STATE_CSW; + } + + return ret; +} + + +/** + * @brief IN transfer trigger + * + * @param[in] p_inst Generic class instance + * @param[in] p_buff IN transfer data buffer + * @param[in] size IN transfer size + * @param[in] state Next state transition + * + * @return Standard error code + * */ +static ret_code_t transfer_in_start(app_usbd_class_inst_t const * p_inst, + void const * p_buff, + size_t size, + app_usbd_msc_state_t state) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + NRF_LOG_DEBUG("transfer_in_start: p_buff: %p, size: %u", (uint32_t)p_buff, size); + + nrf_drv_usbd_ep_t ep_addr_in = ep_in_addr_get(p_inst); + + NRF_DRV_USBD_TRANSFER_IN(resp, p_buff, size); + ret_code_t ret = app_usbd_ep_transfer(ep_addr_in, &resp); + if (ret == NRF_SUCCESS) + { + p_msc_ctx->state = state; + } + return ret; +} + + +/** + * @brief MSC reset request handler @ref APP_USBD_MSC_REQ_BULK_RESET + * + * @param[in] p_inst Generic class instance + * + * */ +static void bulk_ep_reset(app_usbd_class_inst_t const * p_inst) +{ + nrf_drv_usbd_ep_t ep_addr_in = ep_in_addr_get(p_inst); + nrf_drv_usbd_ep_t ep_addr_out = ep_out_addr_get(p_inst); + + nrf_drv_usbd_ep_abort(ep_addr_in); + nrf_drv_usbd_ep_abort(ep_addr_out); +} + + +/** + * @brief OUT transfer trigger + * + * @param[in] p_inst Generic class instance + * @param[in] p_buff OUT transfer data buffer + * @param[in] size OUT transfer size + * @param[in] state Next state transition + * + * @return Standard error code + * */ +static ret_code_t transfer_out_start(app_usbd_class_inst_t const * p_inst, + void * p_buff, + size_t size, + app_usbd_msc_state_t state) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + NRF_LOG_DEBUG("transfer_out_start: p_buff: %p, size: %u", (uint32_t)p_buff, size); + nrf_drv_usbd_ep_t ep_addr_out = ep_out_addr_get(p_inst); + + NRF_DRV_USBD_TRANSFER_OUT(resp, p_buff, size); + ret_code_t ret = app_usbd_ep_transfer(ep_addr_out, &resp); + if (ret == NRF_SUCCESS) + { + p_msc_ctx->state = state; + } + return ret; +} + + +/** + * @brief Generic function to stall communication endpoints and mark error state + * + * Function used internally to stall all communication endpoints and mark current state. + * + * @param p_inst Generic class instance + * @param state State to set + */ +static void status_generic_error_stall(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_state_t state) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + nrf_drv_usbd_ep_t ep_in = ep_in_addr_get(p_inst); + nrf_drv_usbd_ep_t ep_out = ep_out_addr_get(p_inst); + + nrf_drv_usbd_ep_stall(ep_in); + nrf_drv_usbd_ep_stall(ep_out); + nrf_drv_usbd_ep_abort(ep_in); + nrf_drv_usbd_ep_abort(ep_out); + + p_msc_ctx->state = state; +} + + +/** + * @brief Start status stage of unsupported SCSI command + * + * @param[in,out] p_inst Generic class instance + * + * @return Standard error code + * + * @sa status_generic_error_stall + */ +static ret_code_t status_unsupported_start(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + bool data_stage = uint32_decode(p_msc_ctx->cbw.datlen) != 0; + + if (!data_stage) + { + /* Try to transfer the response now */ + ret_code_t ret; + ret = csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_FAIL); + if (ret == NRF_SUCCESS) + { + return ret; + } + } + + /* Cannot transfer failed response in current command - stall the endpoints and postpone the answer */ + status_generic_error_stall(p_inst, APP_USBD_MSC_STATE_UNSUPPORTED); + if (data_stage) + { + if (!(p_msc_ctx->cbw.flags & APP_USBD_MSC_CBW_DIRECTION_IN)) + { + nrf_drv_usbd_transfer_out_drop(ep_out_addr_get(p_inst)); + } + /* Unsupported command so we did not process any data - mark it in current residue value */ + p_msc_ctx->current.residue = uint32_decode(p_msc_ctx->cbw.datlen); + } + return NRF_SUCCESS; +} + + +/** + * @brief Start status stage of CBW invalid + * + * @param[in,out] p_inst Generic class instance + * + * @sa status_generic_error_stall + */ +static void status_cbwinvalid_start(app_usbd_class_inst_t const * p_inst) +{ + status_generic_error_stall(p_inst, APP_USBD_MSC_STATE_CBW_INVALID); +} + + +/** + * @brief Start status stage of internal device error + * + * Kind of error that requires bulk reset but does not stall endpoint permanently - the correct + * answer is possible. + * + * @param[in] p_inst Generic class instance + * + * @sa status_generic_error_stall + */ +static void status_deverror_start(app_usbd_class_inst_t const * p_inst) +{ + status_generic_error_stall(p_inst, APP_USBD_MSC_STATE_DEVICE_ERROR); +} + + +/** + * @brief Internal SETUP standard IN request handler + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t setup_req_std_in(app_usbd_class_inst_t const * p_inst, + app_usbd_setup_evt_t const * p_setup_ev) +{ + /* Only Get Descriptor standard IN request is supported by MSC class */ + if ((app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQREC_INTERFACE) + && + (p_setup_ev->setup.bmRequest == APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR)) + { + size_t dsc_len = 0; + size_t max_size; + + uint8_t * p_trans_buff = app_usbd_core_setup_transfer_buff_get(&max_size); + + /* Try to find descriptor in class internals*/ + ret_code_t ret = app_usbd_class_descriptor_find( + p_inst, + p_setup_ev->setup.wValue.hb, + p_setup_ev->setup.wValue.lb, + p_trans_buff, + &dsc_len); + + if (ret != NRF_ERROR_NOT_FOUND) + { + ASSERT(dsc_len < NRF_DRV_USBD_EPSIZE); + return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_trans_buff, dsc_len); + } + } + return NRF_ERROR_NOT_SUPPORTED; +} + + +/** + * @brief Internal SETUP standard OUT request handler + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + * @retval NRF_ERROR_FORBIDDEN if endpoint stall cannot be cleared because of internal state + */ +static ret_code_t setup_req_std_out(app_usbd_class_inst_t const * p_inst, + app_usbd_setup_evt_t const * p_setup_ev) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + app_usbd_setup_reqrec_t req_rec = app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType); + + if ((req_rec == APP_USBD_SETUP_REQREC_ENDPOINT) && + (p_setup_ev->setup.bmRequest == APP_USBD_SETUP_STDREQ_CLEAR_FEATURE) && + (p_setup_ev->setup.wValue.w == APP_USBD_SETUP_STDFEATURE_ENDPOINT_HALT)) + { + if (p_msc_ctx->state == APP_USBD_MSC_STATE_CBW_INVALID) + { + return NRF_ERROR_FORBIDDEN; + } + ret_code_t ret = NRF_SUCCESS; + /* Clearing endpoint here. It is done normally inside app_usbd, but we are overwritting this functionality */ + nrf_drv_usbd_ep_t ep_addr = (nrf_drv_usbd_ep_t)(p_setup_ev->setup.wIndex.lb); + nrf_drv_usbd_ep_dtoggle_clear(ep_addr); + nrf_drv_usbd_ep_stall_clear(ep_addr); + if (NRF_USBD_EPIN_CHECK(ep_addr)) + { + switch (p_msc_ctx->state) + { + case APP_USBD_MSC_STATE_UNSUPPORTED: + { + nrf_drv_usbd_ep_stall_clear(ep_out_addr_get(p_inst)); + /*Unsupported command handle: status stage*/ + ret = csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_FAIL); + if (ret != NRF_SUCCESS) + { + NRF_LOG_ERROR("Unexpected csw_wait_start on ep clear: %d", ret); + } + break; + } + + case APP_USBD_MSC_STATE_DEVICE_ERROR: + { + nrf_drv_usbd_ep_stall_clear(ep_out_addr_get(p_inst)); + /*Unsupported command handle: status stage*/ + ret = csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PE); + if (ret != NRF_SUCCESS) + { + NRF_LOG_ERROR("Unexpected csw_wait_start on ep clear: %d", ret); + } + break; + } + + default: + break; + } + } + return ret; + } + return NRF_ERROR_NOT_SUPPORTED; +} + + +/** + * @brief Internal SETUP class IN request handler + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t setup_req_class_in(app_usbd_class_inst_t const * p_inst, + app_usbd_setup_evt_t const * p_setup_ev) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + + switch (p_setup_ev->setup.bmRequest) + { + case APP_USBD_MSC_REQ_GET_MAX_LUN: + { + + if (p_setup_ev->setup.wValue.w != 0) + { + break; + } + + if (p_setup_ev->setup.wLength.w != 1) + { + break; + } + + size_t tx_size; + uint16_t * p_tx_buff = app_usbd_core_setup_transfer_buff_get(&tx_size); + ASSERT(p_msc->specific.inst.block_devs_count != 0); + p_tx_buff[0] = p_msc->specific.inst.block_devs_count - 1; + + ret_code_t ret = cbw_wait_start(p_inst); + UNUSED_VARIABLE(ret); + return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_tx_buff, sizeof(uint8_t)); + } + + default: + break; + + } + + return NRF_ERROR_NOT_SUPPORTED; +} + + +/** + * @brief Internal SETUP class OUT request handler + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t setup_req_class_out(app_usbd_class_inst_t const * p_inst, + app_usbd_setup_evt_t const * p_setup_ev) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + switch (p_setup_ev->setup.bmRequest) + { + case APP_USBD_MSC_REQ_BULK_RESET: + { + if (p_setup_ev->setup.wValue.w != 0) + { + break; + } + + if (p_setup_ev->setup.wLength.w != 0) + { + break; + } + + /* + * Reset internal state to be ready for next CBW + */ + NRF_LOG_DEBUG("bulk ep reset"); + bulk_ep_reset(p_inst); + + if (p_msc_ctx->state != APP_USBD_MSC_STATE_CBW) + { + ret_code_t ret = cbw_wait_start(p_inst); + UNUSED_VARIABLE(ret); + } + + return NRF_SUCCESS; + } + + default: + break; + } + + return NRF_ERROR_NOT_SUPPORTED; +} + + +/** + * @brief Control endpoint handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t setup_event_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_setup_evt_t const * p_setup_ev) +{ + ASSERT(p_inst != NULL); + ASSERT(p_setup_ev != NULL); + + if (app_usbd_setup_req_dir(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQDIR_IN) + { + switch (app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType)) + { + case APP_USBD_SETUP_REQTYPE_STD: + return setup_req_std_in(p_inst, p_setup_ev); + + case APP_USBD_SETUP_REQTYPE_CLASS: + return setup_req_class_in(p_inst, p_setup_ev); + + default: + break; + } + } + else /* APP_USBD_SETUP_REQDIR_OUT */ + { + switch (app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType)) + { + case APP_USBD_SETUP_REQTYPE_STD: + return setup_req_std_out(p_inst, p_setup_ev); + + case APP_USBD_SETUP_REQTYPE_CLASS: + return setup_req_class_out(p_inst, p_setup_ev); + + default: + break; + } + } + + return NRF_ERROR_NOT_SUPPORTED; +} + + +/** + * @brief Handle read6/read10 command data stage + * + * @param[in] p_inst Generic class instance + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t state_data_in_handle(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + ret_code_t ret = NRF_SUCCESS; + + p_msc_ctx->current.trans_in_progress = false; + APP_USBD_MSC_REQ_BUSY_CLR(p_msc_ctx->current.req_busy_mask, p_msc_ctx->current.trans_req_id); + + if (p_msc_ctx->current.blk_datasize == 0 && p_msc_ctx->current.req_busy_mask == 0) + { + p_msc_ctx->current.blk_idx = p_msc_ctx->current.blk_size = 0; + ret = csw_wait_start(p_inst, p_msc_ctx->current.csw_status); + return ret; + } + + ASSERT(p_msc_ctx->current.blk_size != 0); + + if (p_msc_ctx->current.req_busy_mask == 0) + { + nrf_block_dev_t const * p_blkd = + p_msc->specific.inst.pp_block_devs[p_msc_ctx->current.lun]; + + /*Trigger new block read request*/ + p_msc_ctx->current.workbuff_pos ^= p_msc->specific.inst.block_buff_size; + uint32_t req_pos = p_msc_ctx->current.workbuff_pos != 0 ? 1 : 0; + APP_USBD_MSC_REQ_BUSY_SET(p_msc_ctx->current.req_busy_mask, req_pos); + + NRF_BLOCK_DEV_REQUEST(req, + p_msc_ctx->current.blk_idx, + p_msc_ctx->current.blk_count, + ((uint8_t *)p_msc->specific.inst.p_block_buff + + p_msc_ctx->current.workbuff_pos)); + + NRF_LOG_DEBUG("nrf_blk_dev_read_req 3: id: %u, count: %u, left: %u, ptr: %p", + req.blk_id, + req.blk_count, + p_msc_ctx->current.blk_datasize, + (uint32_t)req.p_buff); + + ret = nrf_blk_dev_read_req(p_blkd, &req); + NRF_LOG_DEBUG("nrf_blk_dev_read_req 3: ret: %u", ret); + return ret; + } + + uint32_t blk_size = p_msc_ctx->current.blk_size; + p_msc_ctx->current.trans_req_id ^= 1; + + nrf_block_req_t * p_req = &p_msc_ctx->current.req; + if (p_req->p_buff == NULL) + { + p_msc_ctx->current.trans_req_id ^= 1; + return NRF_SUCCESS; + } + + ret = transfer_in_start(p_inst, + p_req->p_buff, + p_req->blk_count * blk_size, + APP_USBD_MSC_STATE_DATA_IN); + + if (ret == NRF_SUCCESS) + { + /*Clear processed block request.*/ + memset(p_req, 0, sizeof(nrf_block_req_t)); + p_msc_ctx->current.trans_in_progress = true; + } + + return ret; +} + + +/** + * @brief Endpoint IN event handler + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t endpoint_in_event_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_complex_evt_t const * p_event) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + NRF_LOG_DEBUG("state: %d, ep in event, status: %d", + p_msc_ctx->state, + p_event->drv_evt.data.eptransfer.status); + + if (p_event->drv_evt.data.eptransfer.status != NRF_USBD_EP_OK) + { + return NRF_SUCCESS; + } + + ret_code_t ret = NRF_SUCCESS; + + switch (p_msc_ctx->state) + { + case APP_USBD_MSC_STATE_CMD_IN: + { + ret = csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); + break; + } + + case APP_USBD_MSC_STATE_DATA_IN: + { + ret = state_data_in_handle(p_inst); + break; + } + + case APP_USBD_MSC_STATE_CSW: + { + break; + } + + case APP_USBD_MSC_STATE_DATA_OUT: + { + break; + } + + case APP_USBD_MSC_STATE_UNSUPPORTED: + { + ret = NRF_ERROR_NOT_SUPPORTED; + break; + } + + default: + { + ret = NRF_ERROR_INTERNAL; + break; + } + } + + return ret; +} + + +/** + * @brief Helper function to calculate next block transfer block count + * + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * + * @return Blocks to transfer + * */ +static uint32_t next_transfer_blkcnt_calc(app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + uint32_t blkcnt = p_msc->specific.inst.block_buff_size / p_msc_ctx->current.blk_size; + + if (blkcnt > (p_msc_ctx->current.blk_datasize / p_msc_ctx->current.blk_size)) + { + blkcnt = p_msc_ctx->current.blk_datasize / p_msc_ctx->current.blk_size; + } + + return blkcnt; +} + + +/** + * @brief Helper function to calculate next transfer size + * + * @param[in] p_msc_ctx MSC context + * + * @return Blocks to transfer + * */ +static uint32_t next_transfer_size_calc(app_usbd_msc_ctx_t * p_msc_ctx) +{ + uint32_t blk_cnt = p_msc_ctx->current.blk_count; + uint32_t blk_size = p_msc_ctx->current.blk_size; + + return p_msc_ctx->current.blk_datasize > blk_size * blk_cnt ? + blk_size * blk_cnt : p_msc_ctx->current.blk_datasize; +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_TESTUNITREADY handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_testunitready(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: TESTUNITREADY"); + if (uint32_decode(p_msc_ctx->cbw.datlen) != 0) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.cdb_length != APP_USBD_SCSI_CMD_TESTUNITREADY_LEN) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_REQUESTSENSE handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_requestsense(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: REQUESTSENSE"); + app_usbd_scsi_cmd_requestsense_t const * p_reqs = (const void *)p_msc_ctx->cbw.cdb; + UNUSED_VARIABLE(p_reqs); + + if ((p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_requestsense_t))) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) > sizeof(app_usbd_scsi_cmd_requestsense_resp_t)) + { + return status_unsupported_start(p_inst); + } + + p_msc_ctx->resp_len = uint32_decode(p_msc_ctx->cbw.datlen); + + if (p_msc_ctx->resp_len == 0) + { + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); + } + + memset(&p_msc_ctx->scsi_resp, 0, sizeof(app_usbd_scsi_cmd_requestsense_resp_t)); + p_msc_ctx->scsi_resp.requestsense.code = APP_USBD_SCSI_CMD_REQSENSE_CODE_VALID | + APP_USBD_SCSI_CMD_REQSENSE_CODE_CURRENT; + + p_msc_ctx->scsi_resp.requestsense.len = sizeof(app_usbd_scsi_cmd_requestsense_resp_t) - + offsetof(app_usbd_scsi_cmd_requestsense_resp_t, len); + + return transfer_in_start(p_inst, + &p_msc_ctx->scsi_resp, + p_msc_ctx->resp_len, + APP_USBD_MSC_STATE_CMD_IN); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_FORMAT_UNIT handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_formatunit(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: FORMAT_UNIT"); + return status_unsupported_start(p_inst); +} + + +static ret_code_t cmd_read_start(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + + p_msc_ctx->current.trans_in_progress = false; + p_msc_ctx->current.req_busy_mask = 0; + p_msc_ctx->current.workbuff_pos = 0; + + APP_USBD_MSC_REQ_BUSY_SET(p_msc_ctx->current.req_busy_mask, 0); + NRF_BLOCK_DEV_REQUEST(req, + p_msc_ctx->current.blk_idx, + p_msc_ctx->current.blk_count, + ((uint8_t *)p_msc->specific.inst.p_block_buff + + p_msc_ctx->current.workbuff_pos)); + + NRF_LOG_DEBUG("cmd_read_start"); + NRF_LOG_DEBUG("nrf_blk_dev_read_req 1: id: %u, count: %u, left: %u, ptr: %p", + req.blk_id, + req.blk_count, + p_msc_ctx->current.blk_datasize, + (uint32_t)req.p_buff); + + ret_code_t ret = nrf_blk_dev_read_req(p_blkd, &req); + NRF_LOG_DEBUG("nrf_blk_dev_read_req 1: ret: %u", ret); + + return ret; +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_READ6 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_read6(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: READ6"); + app_usbd_scsi_cmd_read6_t const * p_read6 = (const void *)p_msc_ctx->cbw.cdb; + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_read6_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + + p_msc_ctx->current.lun = p_msc_ctx->cbw.lun; + p_msc_ctx->current.blk_idx = ((p_read6->mslba & 0x1F) << 16) | + uint16_big_decode(p_read6->lslba); + p_msc_ctx->current.blk_datasize = uint32_decode(p_msc_ctx->cbw.datlen); + p_msc_ctx->current.blk_size = nrf_blk_dev_geometry(p_blkd)->blk_size; + p_msc_ctx->current.blk_count = next_transfer_blkcnt_calc(p_msc, p_msc_ctx); + + if (p_msc_ctx->current.blk_datasize > p_msc_ctx->current.blk_size * p_read6->xfrlen) + { + p_msc_ctx->current.residue = p_msc_ctx->current.blk_datasize - + p_msc_ctx->current.blk_size * p_read6->xfrlen; + } + + return cmd_read_start(p_inst, p_msc, p_msc_ctx); +} + + +static ret_code_t cmd_write_start(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("cmd_write_start"); + ret_code_t ret = transfer_out_start(p_inst, + ((uint8_t *)p_msc->specific.inst.p_block_buff + + p_msc_ctx->current.workbuff_pos), + next_transfer_size_calc(p_msc_ctx), + APP_USBD_MSC_STATE_DATA_OUT); + + if (ret == NRF_SUCCESS) + { + p_msc_ctx->current.trans_req_id = 0; + APP_USBD_MSC_REQ_BUSY_SET(p_msc_ctx->current.req_busy_mask, + p_msc_ctx->current.trans_req_id); + p_msc_ctx->current.workbuff_pos ^= p_msc->specific.inst.block_buff_size; + p_msc_ctx->current.trans_in_progress = true; + } + + return ret; +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_WRITE6 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_write6(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: WRITE6"); + app_usbd_scsi_cmd_write6_t const * p_write6 = (const void *)p_msc_ctx->cbw.cdb; + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_write6_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + + p_msc_ctx->current.lun = p_msc_ctx->cbw.lun; + p_msc_ctx->current.blk_idx = (p_write6->mslba & 0x1F << 16) | + uint16_big_decode(p_write6->lslba); + p_msc_ctx->current.blk_datasize = uint32_decode(p_msc_ctx->cbw.datlen); + p_msc_ctx->current.blk_size = nrf_blk_dev_geometry(p_blkd)->blk_size; + p_msc_ctx->current.blk_count = next_transfer_blkcnt_calc(p_msc, p_msc_ctx); + + if (p_msc_ctx->current.blk_datasize > p_msc_ctx->current.blk_size * p_write6->xfrlen) + { + p_msc_ctx->current.residue = p_msc_ctx->current.blk_datasize - + p_msc_ctx->current.blk_size * p_write6->xfrlen; + } + + return cmd_write_start(p_inst, p_msc, p_msc_ctx); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_INQUIRY handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_inquiry(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: INQUIRY"); + app_usbd_scsi_cmd_inquiry_t const * p_inq = (const void *)p_msc_ctx->cbw.cdb; + if (p_inq->pagecode != 0) + { + NRF_LOG_WARNING("unsupported pagecode"); + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + NRF_LOG_WARNING("unsupported LUN"); + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) > sizeof(app_usbd_scsi_cmd_inquiry_resp_t)) + { + return status_unsupported_start(p_inst); + } + + p_msc_ctx->resp_len = uint32_decode(p_msc_ctx->cbw.datlen); + + if (p_msc_ctx->resp_len == 0) + { + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); + } + + + p_msc_ctx->scsi_resp.inquiry.qualtype = APP_USBD_MSC_SCSI_INQ_QUAL_CONNECTED | + APP_USBD_MSC_SCSI_INQ_TYPE_DIR_ACCESS; + p_msc_ctx->scsi_resp.inquiry.flags1 = APP_USBD_MSC_SCSI_INQ_FLAG1_RMB; + p_msc_ctx->scsi_resp.inquiry.version = APP_USBD_SCSI_INQ_VER_SPC4; + p_msc_ctx->scsi_resp.inquiry.flags2 = APP_USBD_MSC_SCSI_INQ_FLAG2_RSP_SPC2 | + APP_USBD_MSC_SCSI_INQ_FLAG2_HISUP; + p_msc_ctx->scsi_resp.inquiry.len = sizeof(app_usbd_scsi_cmd_inquiry_resp_t) - + offsetof(app_usbd_scsi_cmd_inquiry_resp_t, len); + + nrf_block_dev_t const * p_blkd = + p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + nrf_block_dev_info_strings_t * p_strings = NULL; + UNUSED_RETURN_VALUE(nrf_blk_dev_ioctl(p_blkd, + NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS, + &p_strings)); + + if (p_strings) + { + UNUSED_RETURN_VALUE(strncpy((char *)p_msc_ctx->scsi_resp.inquiry.vendorid, + p_strings->p_vendor, + sizeof(p_msc_ctx->scsi_resp.inquiry.vendorid))); + + UNUSED_RETURN_VALUE(strncpy((char *)p_msc_ctx->scsi_resp.inquiry.productid, + p_strings->p_product, + sizeof(p_msc_ctx->scsi_resp.inquiry.productid))); + + UNUSED_RETURN_VALUE(strncpy((char *)p_msc_ctx->scsi_resp.inquiry.revision, + p_strings->p_revision, + sizeof(p_msc_ctx->scsi_resp.inquiry.revision))); + } + else + { + memset(p_msc_ctx->scsi_resp.inquiry.vendorid, + 0, + sizeof(p_msc_ctx->scsi_resp.inquiry.vendorid)); + memset(p_msc_ctx->scsi_resp.inquiry.productid, + 0, + sizeof(p_msc_ctx->scsi_resp.inquiry.productid)); + memset(p_msc_ctx->scsi_resp.inquiry.revision, + 0, + sizeof(p_msc_ctx->scsi_resp.inquiry.revision)); + } + + return transfer_in_start(p_inst, + &p_msc_ctx->scsi_resp, + p_msc_ctx->resp_len, + APP_USBD_MSC_STATE_CMD_IN); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_MODESELECT6 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_modeselect6(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: MODESELECT6"); + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_MODESENSE6 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_modesense6(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: MODESENSE6"); + app_usbd_scsi_cmd_modesense6_t const * p_sense6 = (const void *)p_msc_ctx->cbw.cdb; + UNUSED_VARIABLE(p_sense6); + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_modesense6_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) > sizeof(app_usbd_scsi_cmd_modesense6_resp_t)) + { + return status_unsupported_start(p_inst); + } + + p_msc_ctx->resp_len = uint32_decode(p_msc_ctx->cbw.datlen); + + app_usbd_scsi_cmd_modesense6_resp_t * p_resp = &p_msc_ctx->scsi_resp.modesense6; + p_resp->mdlen = sizeof(app_usbd_scsi_cmd_modesense6_resp_t) - 1; + p_resp->type = 0; + p_resp->param = 0; + p_resp->bdlen = 0; + + return transfer_in_start(p_inst, + &p_msc_ctx->scsi_resp, + p_msc_ctx->resp_len, + APP_USBD_MSC_STATE_CMD_IN); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_STARTSTOPUNIT handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_startstopunit(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: STARTSTOPUNIT"); + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_SENDDIAGNOSTIC handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_senddiagnostic(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: SENDDIAGNOSTIC"); + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_PREVENTMEDIAREMOVAL handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_preventremoval(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: PREVENTMEDIAREMOVAL"); + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_READCAPACITY10 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_readcapacity10(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: READCAPACITY10"); + + app_usbd_scsi_cmd_readcapacity10_t const * p_cap10 = (const void *)p_msc_ctx->cbw.cdb; + UNUSED_VARIABLE(p_cap10); + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_readcapacity10_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) > sizeof(app_usbd_scsi_cmd_readcapacity10_resp_t)) + { + return status_unsupported_start(p_inst); + } + + p_msc_ctx->resp_len = uint32_decode(p_msc_ctx->cbw.datlen); + + if (p_msc_ctx->resp_len == 0) + { + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); + } + + nrf_block_dev_t const * p_blkd = + p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + nrf_block_dev_geometry_t const * p_geometry = nrf_blk_dev_geometry(p_blkd); + + (void)uint32_big_encode(p_geometry->blk_count - 1, p_msc_ctx->scsi_resp.readcapacity10.lba); + (void)uint32_big_encode(p_geometry->blk_size, p_msc_ctx->scsi_resp.readcapacity10.blklen); + + return transfer_in_start(p_inst, + &p_msc_ctx->scsi_resp, + p_msc_ctx->resp_len, + APP_USBD_MSC_STATE_CMD_IN); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_READ10 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_read10(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: READ10"); + app_usbd_scsi_cmd_read10_t const * p_read10 = (const void *)p_msc_ctx->cbw.cdb; + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_read10_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) == 0) + { + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_FAIL); + } + + if ((p_msc_ctx->cbw.flags & APP_USBD_MSC_CBW_DIRECTION_IN) == 0) + { + return status_unsupported_start(p_inst); + } + + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + + p_msc_ctx->current.lun = p_msc_ctx->cbw.lun; + p_msc_ctx->current.blk_idx = uint32_big_decode(p_read10->lba); + p_msc_ctx->current.blk_datasize = uint32_decode(p_msc_ctx->cbw.datlen); + p_msc_ctx->current.blk_size = nrf_blk_dev_geometry(p_blkd)->blk_size; + p_msc_ctx->current.blk_count = next_transfer_blkcnt_calc(p_msc, p_msc_ctx); + + uint16_t blocks = uint16_big_decode(p_read10->xfrlen); + p_msc_ctx->current.csw_status = + uint32_decode(p_msc_ctx->cbw.datlen) < p_msc_ctx->current.blk_size * blocks ? + APP_USBD_MSC_CSW_STATUS_FAIL : APP_USBD_MSC_CSW_STATUS_PASS; + + if (p_msc_ctx->current.blk_datasize > p_msc_ctx->current.blk_size * blocks) + { + p_msc_ctx->current.residue = p_msc_ctx->current.blk_datasize - + p_msc_ctx->current.blk_size * blocks; + } + + return cmd_read_start(p_inst, p_msc, p_msc_ctx); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_WRITE10 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_write10(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: WRITE10"); + app_usbd_scsi_cmd_write10_t const * p_write10 = (const void *)p_msc_ctx->cbw.cdb; + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_write10_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) == 0) + { + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_FAIL); + } + + + if ((p_msc_ctx->cbw.flags & APP_USBD_MSC_CBW_DIRECTION_IN) != 0) + { + return status_unsupported_start(p_inst); + } + + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[p_msc_ctx->cbw.lun]; + + p_msc_ctx->current.lun = p_msc_ctx->cbw.lun; + p_msc_ctx->current.blk_idx = uint32_big_decode(p_write10->lba); + p_msc_ctx->current.blk_datasize = uint32_decode(p_msc_ctx->cbw.datlen); + p_msc_ctx->current.blk_size = nrf_blk_dev_geometry(p_blkd)->blk_size; + p_msc_ctx->current.blk_count = next_transfer_blkcnt_calc(p_msc, p_msc_ctx); + + uint16_t blocks = uint16_big_decode(p_write10->xfrlen); + p_msc_ctx->current.csw_status = + uint32_decode(p_msc_ctx->cbw.datlen) < p_msc_ctx->current.blk_size * blocks ? + APP_USBD_MSC_CSW_STATUS_FAIL : APP_USBD_MSC_CSW_STATUS_PASS; + + if (p_msc_ctx->current.blk_datasize > p_msc_ctx->current.blk_size * blocks) + { + p_msc_ctx->current.residue = p_msc_ctx->current.blk_datasize - + p_msc_ctx->current.blk_size * blocks; + } + + return cmd_write_start(p_inst, p_msc, p_msc_ctx); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_MODESELECT10 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_modeselect10(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: MODESELECT10"); + return csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); +} + + +/** + * @brief SCSI Command: @ref APP_USBD_SCSI_CMD_MODESENSE10 handle + * + * @param[in] p_inst Generic class instance + * @param[in] p_msc MSC instance + * @param[in] p_msc_ctx MSC context + * @return Standard error code + * */ +static ret_code_t cmd_modesense10(app_usbd_class_inst_t const * p_inst, + app_usbd_msc_t const * p_msc, + app_usbd_msc_ctx_t * p_msc_ctx) +{ + NRF_LOG_DEBUG("CMD: MODESENSE10"); + app_usbd_scsi_cmd_modesense10_t const * p_sense10 = (const void *)p_msc_ctx->cbw.cdb; + UNUSED_VARIABLE(p_sense10); + if (p_msc_ctx->cbw.cdb_length < sizeof(app_usbd_scsi_cmd_modesense10_t)) + { + return status_unsupported_start(p_inst); + } + + if (p_msc_ctx->cbw.lun >= p_msc->specific.inst.block_devs_count) + { + return status_unsupported_start(p_inst); + } + + if (uint32_decode(p_msc_ctx->cbw.datlen) > sizeof(app_usbd_scsi_cmd_modesense6_resp_t)) + { + return status_unsupported_start(p_inst); + } + + p_msc_ctx->resp_len = uint32_decode(p_msc_ctx->cbw.datlen); + + app_usbd_scsi_cmd_modesense10_resp_t * p_resp = &p_msc_ctx->scsi_resp.modesense10; + + memset(p_resp, 0, sizeof(app_usbd_scsi_cmd_modesense10_resp_t)); + uint16_t len = sizeof(app_usbd_scsi_cmd_modesense10_resp_t) - sizeof(p_resp->mdlen); + p_resp->mdlen[1] = len & 0xff; + p_resp->mdlen[0] = (len >> 8) & 0xff; + + return transfer_in_start(p_inst, + &p_msc_ctx->scsi_resp, + p_msc_ctx->resp_len, + APP_USBD_MSC_STATE_CMD_IN); +} + + +/** + * @brief Get the size of the last OUT transfer + * + * @param p_inst Generic class instance + * + * @return Number of received bytes or 0 if none. + */ +static size_t get_last_out_size(app_usbd_class_inst_t const * p_inst) +{ + nrf_drv_usbd_ep_t ep = ep_out_addr_get(p_inst); + size_t size; + ret_code_t ret = nrf_drv_usbd_ep_status_get(ep, &size); + + if (ret != NRF_SUCCESS) + { + size = 0; + } + + return size; +} + + +/** + * @brief SCSI Command Block Wrapper handler + * + * @param[in] p_inst Generic class instance + * @return Standard error code + * */ +static ret_code_t state_cbw(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + memset(&p_msc_ctx->current, 0, sizeof(p_msc_ctx->current)); + + /*Verify the transfer size*/ + if (get_last_out_size(p_inst) != sizeof(app_usbd_msc_cbw_t)) + { + NRF_LOG_DEBUG("CMD: size error: %u", get_last_out_size(p_inst)); + status_cbwinvalid_start(p_inst); + return NRF_SUCCESS; + } + + /*Verify CBW signature*/ + if (memcmp(p_msc_ctx->cbw.signature, + APP_USBD_MSC_CBW_SIGNATURE, + sizeof(p_msc_ctx->cbw.signature)) != 0) + { + NRF_LOG_DEBUG("CMD: header error: 0x%02x%02x%02x%02x", + p_msc_ctx->cbw.signature[0], p_msc_ctx->cbw.signature[1], + p_msc_ctx->cbw.signature[2], p_msc_ctx->cbw.signature[3]); + + status_cbwinvalid_start(p_inst); + return NRF_SUCCESS; + } + + ret_code_t ret = NRF_SUCCESS; + + switch (p_msc_ctx->cbw.cdb[0]) + { + case APP_USBD_SCSI_CMD_TESTUNITREADY: + ret = cmd_testunitready(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_REQUESTSENSE: + ret = cmd_requestsense(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_FORMAT_UNIT: + ret = cmd_formatunit(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_READ6: + ret = cmd_read6(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_WRITE6: + ret = cmd_write6(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_INQUIRY: + ret = cmd_inquiry(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_MODESELECT6: + ret = cmd_modeselect6(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_MODESENSE6: + ret = cmd_modesense6(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_STARTSTOPUNIT: + ret = cmd_startstopunit(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_SENDDIAGNOSTIC: + ret = cmd_senddiagnostic(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_PREVENTMEDIAREMOVAL: + ret = cmd_preventremoval(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_READCAPACITY10: + ret = cmd_readcapacity10(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_READ10: + ret = cmd_read10(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_WRITE10: + ret = cmd_write10(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_MODESELECT10: + ret = cmd_modeselect10(p_inst, p_msc, p_msc_ctx); + break; + + case APP_USBD_SCSI_CMD_MODESENSE10: + ret = cmd_modesense10(p_inst, p_msc, p_msc_ctx); + break; + + default: + NRF_LOG_DEBUG("CMD: UNSUPPORTED"); + NRF_LOG_HEXDUMP_DEBUG(&(p_msc_ctx->cbw), sizeof(p_msc_ctx->cbw)); + if (uint32_decode(p_msc_ctx->cbw.datlen) != 0) + { + ret = status_unsupported_start(p_inst); + } + else + { + ret = csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_FAIL); + } + break; + } + + return ret; +} + + +/** + * @brief Handle write6/write10 command data stage + * + * @param[in] p_inst Generic class instance + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t state_data_out_handle(app_usbd_class_inst_t const * p_inst) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + ret_code_t ret = NRF_SUCCESS; + uint32_t blk_size = p_msc_ctx->current.blk_size; + + NRF_LOG_DEBUG("APP_USBD_MSC_STATE_DATA_OUT"); + + p_msc_ctx->current.trans_in_progress = false; + if ((p_msc_ctx->current.req_busy_mask != APP_USBD_MSC_REQ_BUSY_FULL_MASK) && + (p_msc_ctx->current.blk_datasize > p_msc_ctx->current.blk_count * blk_size)) + { + size_t size = p_msc_ctx->current.blk_datasize - p_msc_ctx->current.blk_count * blk_size; + if (size > p_msc_ctx->current.blk_count * blk_size) + { + size = p_msc_ctx->current.blk_count * blk_size; + } + + if (size) + { + ret = transfer_out_start(p_inst, + ((uint8_t *)p_msc->specific.inst.p_block_buff + + p_msc_ctx->current.workbuff_pos), + size, + APP_USBD_MSC_STATE_DATA_OUT); + if (ret == NRF_SUCCESS) + { + p_msc_ctx->current.trans_req_id ^= 1; + APP_USBD_MSC_REQ_BUSY_SET(p_msc_ctx->current.req_busy_mask, + p_msc_ctx->current.trans_req_id); + p_msc_ctx->current.workbuff_pos ^= p_msc->specific.inst.block_buff_size; + p_msc_ctx->current.trans_in_progress = true; + } + } + } + + if (!p_msc_ctx->current.block_req_in_progress) + { + nrf_block_dev_t const * p_blkd = + p_msc->specific.inst.pp_block_devs[p_msc_ctx->current.lun]; + + size_t pos = p_msc_ctx->current.workbuff_pos; + if (p_msc_ctx->current.req_busy_mask != APP_USBD_MSC_REQ_BUSY_FULL_MASK) + { + pos ^= p_msc->specific.inst.block_buff_size; + } + + NRF_BLOCK_DEV_REQUEST(req, + p_msc_ctx->current.blk_idx, + p_msc_ctx->current.blk_count, + ((uint8_t *)p_msc->specific.inst.p_block_buff + pos)); + + NRF_LOG_DEBUG("nrf_blk_dev_write_req 1: id: %u, count: %u, left: %u, ptr: %p", + req.blk_id, + req.blk_count, + p_msc_ctx->current.blk_datasize, + (uint32_t)req.p_buff); + + p_msc_ctx->current.block_req_in_progress = true; + ret = nrf_blk_dev_write_req(p_blkd, &req); + NRF_LOG_DEBUG("nrf_blk_dev_write_req 1: ret: %u", ret); + } + + return ret; +} + + +/** + * @brief Endpoint OUT event handler + * + * @param[in] p_inst Generic class instance + * @param[in] p_setup_ev Setup event + * + * @return Standard error code + * @retval NRF_SUCCESS if request handled correctly + * @retval NRF_ERROR_NOT_SUPPORTED if request is not supported + */ +static ret_code_t endpoint_out_event_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_complex_evt_t const * p_event) +{ + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + NRF_LOG_DEBUG("state: %d, ep out event, status: %d", + p_msc_ctx->state, + p_event->drv_evt.data.eptransfer.status); + + ret_code_t ret = NRF_SUCCESS; + if (p_event->drv_evt.data.eptransfer.status == NRF_USBD_EP_WAITING) + { + if (p_msc_ctx->state == APP_USBD_MSC_STATE_DATA_OUT) + { + NRF_LOG_DEBUG("NRF_USBD_EP_WAITING"); + } + else if (p_msc_ctx->state == APP_USBD_MSC_STATE_CSW || + p_msc_ctx->state == APP_USBD_MSC_STATE_IDLE) + { + ret = cbw_wait_start(p_inst); + } + + return ret; + } + else if (p_event->drv_evt.data.eptransfer.status == NRF_USBD_EP_ABORTED) + { + p_msc_ctx->state = APP_USBD_MSC_STATE_IDLE; + return NRF_SUCCESS; + } + else if (p_event->drv_evt.data.eptransfer.status == NRF_USBD_EP_OVERLOAD) + { + NRF_LOG_ERROR("Data overload"); + + switch (p_msc_ctx->state) + { + case APP_USBD_MSC_STATE_DATA_OUT: + { + status_deverror_start(p_inst); + } + + /* Default action is the same like CBW - stall totally until bulk reset */ + case APP_USBD_MSC_STATE_CBW: + default: + { + status_cbwinvalid_start(p_inst); + } + } + return NRF_SUCCESS; + } + else /*NRF_USBD_EP_OK*/ + { + switch (p_msc_ctx->state) + { + case APP_USBD_MSC_STATE_CBW: + { + ret = state_cbw(p_inst); + break; + } + + case APP_USBD_MSC_STATE_CMD_OUT: + { + ret = csw_wait_start(p_inst, APP_USBD_MSC_CSW_STATUS_PASS); + break; + } + + case APP_USBD_MSC_STATE_DATA_OUT: + { + CRITICAL_REGION_ENTER(); + ret = state_data_out_handle(p_inst); + CRITICAL_REGION_EXIT(); + break; + } + + case APP_USBD_MSC_STATE_UNSUPPORTED: + { + ret = NRF_ERROR_NOT_SUPPORTED; + break; + } + + case APP_USBD_MSC_STATE_CSW: + break; + + default: + { + ASSERT(0); + ret = NRF_ERROR_NOT_SUPPORTED; + break; + } + } + } + + NRF_LOG_DEBUG("Ep proc status: %d", ret); + return ret; +} + + +/** + * @brief @ref app_usbd_class_methods_t::event_handler + */ +static ret_code_t msc_event_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_complex_evt_t const * p_event) +{ + ASSERT(p_inst != NULL); + ASSERT(p_event != NULL); + + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + UNUSED_VARIABLE(p_msc); + UNUSED_VARIABLE(p_msc_ctx); + + ret_code_t ret = NRF_SUCCESS; + + switch (p_event->app_evt.type) + { + case APP_USBD_EVT_DRV_SOF: + break; + + case APP_USBD_EVT_DRV_RESET: + break; + + case APP_USBD_EVT_DRV_SETUP: + ret = setup_event_handler(p_inst, (app_usbd_setup_evt_t const *)p_event); + break; + + case APP_USBD_EVT_DRV_EPTRANSFER: + if (NRF_USBD_EPIN_CHECK(p_event->drv_evt.data.eptransfer.ep)) + { + ret = endpoint_in_event_handler(p_inst, p_event); + } + else + { + ret = endpoint_out_event_handler(p_inst, p_event); + } + + break; + + case APP_USBD_EVT_DRV_SUSPEND: + { + /*Flush all block devices cache on suspend*/ + + for (size_t i = 0; i < p_msc->specific.inst.block_devs_count; ++i) + { + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[i]; + (void)nrf_blk_dev_ioctl(p_blkd, NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH, NULL); + } + + break; + } + + case APP_USBD_EVT_DRV_RESUME: + break; + + case APP_USBD_EVT_INST_APPEND: + { + /*Verify serial number string*/ + uint16_t const * p_serial_str = app_usbd_string_desc_get(APP_USBD_STRING_ID_SERIAL, 0); + if (p_serial_str == NULL) + { + return NRF_ERROR_NOT_SUPPORTED; + } + + size_t len = app_usbd_string_desc_length(p_serial_str) / sizeof(uint16_t); + if (len < APP_USBD_MSC_MINIMAL_SERIAL_STRING_SIZE) + { + return NRF_ERROR_NOT_SUPPORTED; + } + + for (size_t i = 1; i < len; ++i) + { + if (isxdigit(p_serial_str[i]) == 0) + { + return NRF_ERROR_NOT_SUPPORTED; + } + } + + break; + } + + case APP_USBD_EVT_INST_REMOVE: + { + break; + } + + case APP_USBD_EVT_STARTED: + { + /*Initialize all block devices*/ + ASSERT(p_msc->specific.inst.block_devs_count <= 16); + + for (size_t i = 0; i < p_msc->specific.inst.block_devs_count; ++i) + { + nrf_block_dev_t const * p_blk_dev = p_msc->specific.inst.pp_block_devs[i]; + ret = nrf_blk_dev_init(p_blk_dev, msc_blockdev_ev_handler, p_msc); + if (ret != NRF_SUCCESS) + { + continue; + } + + p_msc_ctx->blk_dev_init_mask |= 1u << i; + ASSERT(nrf_blk_dev_geometry(p_blk_dev)->blk_size <= + p_msc->specific.inst.block_buff_size); + } + + break; + } + + case APP_USBD_EVT_STOPPED: + { + /*Un-initialize all block devices*/ + ASSERT(p_msc->specific.inst.block_devs_count <= 16); + size_t i; + + for (i = 0; i < p_msc->specific.inst.block_devs_count; ++i) + { + nrf_block_dev_t const * p_blk_dev = p_msc->specific.inst.pp_block_devs[i]; + ret = nrf_blk_dev_uninit(p_blk_dev); + if (ret != NRF_SUCCESS) + { + continue; + } + + p_msc_ctx->blk_dev_init_mask &= ~(1u << i); + } + + break; + } + + default: + ret = NRF_ERROR_NOT_SUPPORTED; + break; + } + + return ret; +} + + +/** + * @brief @ref app_usbd_class_methods_t::feed_descriptors + */ + +static bool msc_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx, + app_usbd_class_inst_t const * p_inst, + uint8_t * p_buff, + size_t max_size) +{ + static uint8_t ifaces = 0; + ifaces = app_usbd_class_iface_count_get(p_inst); + app_usbd_msc_t const * p_msc = msc_get(p_inst); + + APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size); + + static uint8_t i = 0; + + for (i = 0; i < ifaces; i++) + { + /* INTERFACE DESCRIPTOR */ + APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength + APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface + + static app_usbd_class_iface_conf_t const * p_cur_iface = NULL; + p_cur_iface = app_usbd_class_iface_get(p_inst, i); + + APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber + APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting + APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints + APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_MSC_CLASS); // bInterfaceClass = MSC + APP_USBD_CLASS_DESCRIPTOR_WRITE(p_msc->specific.inst.subclass); // bInterfaceSubclass (Industry Standard Command Block) + APP_USBD_CLASS_DESCRIPTOR_WRITE(p_msc->specific.inst.protocol); // bInterfaceProtocol + APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface + + + static uint8_t endpoints = 0; + endpoints = app_usbd_class_iface_ep_count_get(p_cur_iface); + + static uint8_t j = 0; + + for (j = 0; j < endpoints; j++) + { + // ENDPOINT DESCRIPTOR + APP_USBD_CLASS_DESCRIPTOR_WRITE(0x07); // bLength + APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_ENDPOINT); // bDescriptorType = Endpoint + + static app_usbd_class_ep_conf_t const * p_cur_ep = NULL; + p_cur_ep = app_usbd_class_iface_ep_get(p_cur_iface, j); + APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_ep_address_get(p_cur_ep)); // bEndpointAddress + APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_BULK); // bmAttributes + APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize LSB + APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize MSB + APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bInterval + } + + } + + APP_USBD_CLASS_DESCRIPTOR_END(); +} + +const app_usbd_class_methods_t app_usbd_msc_class_methods = { + .event_handler = msc_event_handler, + .feed_descriptors = msc_feed_descriptors, +}; + + +/** + * @brief Block device read done event handler. + * + * @ref NRF_BLOCK_DEV_EVT_BLK_READ_DONE + * + * @param p_blk_dev Block device handle + * @param p_event Block device event + * + * */ +static void msc_blockdev_read_done_handler(nrf_block_dev_t const * p_blk_dev, + nrf_block_dev_event_t const * p_event) +{ + ret_code_t ret; + + app_usbd_class_inst_t const * p_inst = p_event->p_context; + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + uint32_t blk_cnt = p_msc_ctx->current.blk_count; + uint32_t blk_size = p_msc_ctx->current.blk_size; + + /*Save actual request*/ + size_t req_pos = (p_msc_ctx->current.workbuff_pos != 0) ? 1 : 0; + + p_msc_ctx->current.req = *p_event->p_blk_req; + + p_msc_ctx->current.block_req_in_progress = false; + + /*Decrement transfer counter*/ + p_msc_ctx->current.blk_idx += blk_cnt; + if (p_msc_ctx->current.blk_datasize > blk_size * blk_cnt) + { + p_msc_ctx->current.blk_datasize -= blk_size * blk_cnt; + } + else + { + p_msc_ctx->current.blk_datasize = 0; + } + + NRF_LOG_DEBUG("read_done_handler: p_buff: %p, size: %u data size: %u req_pos: %u", + (uint32_t)p_event->p_blk_req->p_buff, + p_event->p_blk_req->blk_count, + p_msc_ctx->current.blk_datasize, + req_pos); + + /*Calculate next block request size*/ + p_msc_ctx->current.blk_count = next_transfer_blkcnt_calc(p_msc, p_msc_ctx); + + if (!p_msc_ctx->current.trans_in_progress) + { + /*Trigger new transfer.*/ + p_msc_ctx->current.trans_req_id = req_pos; + nrf_block_req_t * p_req = &p_msc_ctx->current.req; + + ret = transfer_in_start(p_inst, + p_req->p_buff, + p_req->blk_count * blk_size, + APP_USBD_MSC_STATE_DATA_IN); + if (ret != NRF_SUCCESS) + { + UNUSED_RETURN_VALUE(status_unsupported_start(p_inst)); + } + else + { + /*Clear processed block request.*/ + memset(p_req, 0, sizeof(nrf_block_req_t)); + p_msc_ctx->current.trans_in_progress = true; + } + + } + + if (p_msc_ctx->current.req_busy_mask == APP_USBD_MSC_REQ_BUSY_FULL_MASK) + { + /* No need to perform next block read request. USB transfers need to catch-up + * block device readings */ + return; + } + + if (p_msc_ctx->current.blk_count == 0) + { + /*All data has been read. No need to trigger new block request.*/ + return; + } + + /*Trigger new block read request*/ + p_msc_ctx->current.workbuff_pos ^= p_msc->specific.inst.block_buff_size; + req_pos = p_msc_ctx->current.workbuff_pos != 0 ? 1 : 0; + + APP_USBD_MSC_REQ_BUSY_SET(p_msc_ctx->current.req_busy_mask, req_pos); + + NRF_BLOCK_DEV_REQUEST(req, + p_msc_ctx->current.blk_idx, + p_msc_ctx->current.blk_count, + ((uint8_t *)p_msc->specific.inst.p_block_buff + + p_msc_ctx->current.workbuff_pos)); + + + NRF_LOG_DEBUG("nrf_blk_dev_read_req 2: id: %u, count: %u, left: %u, ptr: %p", + req.blk_id, + req.blk_count, + p_msc_ctx->current.blk_datasize, + (uint32_t)req.p_buff); + + ret = nrf_blk_dev_read_req(p_blk_dev, &req); + NRF_LOG_DEBUG("nrf_blk_dev_read_req 2: ret: %u", ret); + + if (ret != NRF_SUCCESS) + { + UNUSED_RETURN_VALUE(status_unsupported_start(p_inst)); + } +} + + +/** + * @brief Block device write done event handler. + * + * @ref NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE + * + * @param p_blk_dev Block device handle + * @param p_event Block device event + * + * */ +static void msc_blockdev_write_done_handler(nrf_block_dev_t const * p_blk_dev, + nrf_block_dev_event_t const * p_event) +{ + app_usbd_class_inst_t const * p_inst = p_event->p_context; + app_usbd_msc_t const * p_msc = msc_get(p_inst); + app_usbd_msc_ctx_t * p_msc_ctx = msc_ctx_get(p_msc); + + uint32_t blk_cnt = p_msc_ctx->current.blk_count; + uint32_t blk_size = p_msc_ctx->current.blk_size; + + /*Save actual request*/ + size_t req_pos = (p_event->p_blk_req->p_buff == p_msc->specific.inst.p_block_buff) ? 0 : 1; + + p_msc_ctx->current.req = *p_event->p_blk_req; + + APP_USBD_MSC_REQ_BUSY_CLR(p_msc_ctx->current.req_busy_mask, req_pos); + p_msc_ctx->current.block_req_in_progress = false; + + p_msc_ctx->current.blk_idx += blk_cnt; + + if (p_msc_ctx->current.blk_datasize > blk_size * blk_cnt) + { + p_msc_ctx->current.blk_datasize -= blk_size * blk_cnt; + } + else + { + p_msc_ctx->current.blk_datasize = 0; + } + + NRF_LOG_DEBUG("write_done_handler: p_buff: %p, size: %u data size: %u req_pos: %u", + (uint32_t)p_event->p_blk_req->p_buff, + p_event->p_blk_req->blk_count, + p_msc_ctx->current.blk_datasize, + req_pos); + + if (p_msc_ctx->current.blk_datasize == 0) + { + p_msc_ctx->current.blk_idx = p_msc_ctx->current.blk_size = 0; + UNUSED_RETURN_VALUE(csw_wait_start(p_inst, p_msc_ctx->current.csw_status)); + return; + } + + if (p_msc_ctx->current.blk_datasize <= p_msc_ctx->current.blk_count * blk_size) + { + size_t pos = p_msc_ctx->current.workbuff_pos; + if (p_msc_ctx->current.req_busy_mask != APP_USBD_MSC_REQ_BUSY_FULL_MASK) + { + pos ^= p_msc->specific.inst.block_buff_size; + } + + NRF_BLOCK_DEV_REQUEST(req, + p_msc_ctx->current.blk_idx, + p_msc_ctx->current.blk_count, + ((uint8_t *)p_msc->specific.inst.p_block_buff + pos)); + + NRF_LOG_DEBUG("nrf_blk_dev_write_req 2: id: %u, count: %u, left: %u, ptr: %p", + req.blk_id, + req.blk_count, + p_msc_ctx->current.blk_datasize, + (uint32_t)req.p_buff); + + p_msc_ctx->current.block_req_in_progress = true; + ret_code_t ret = nrf_blk_dev_write_req(p_blk_dev, &req); + NRF_LOG_DEBUG("nrf_blk_dev_write_req 2: ret: %u", ret); + + if (ret != NRF_SUCCESS) + { + UNUSED_RETURN_VALUE(status_unsupported_start(p_inst)); + } + + return; + } + + if (!p_msc_ctx->current.trans_in_progress && + (p_msc_ctx->current.blk_datasize > p_msc_ctx->current.blk_count * blk_size)) + { + size_t size = p_msc_ctx->current.blk_datasize - p_msc_ctx->current.blk_count * blk_size; + if (size > p_msc_ctx->current.blk_count * blk_size) + { + size = p_msc_ctx->current.blk_count * blk_size; + } + + if (size > 0) + { + /*Trigger new transfer.*/ + p_msc_ctx->current.blk_count = next_transfer_blkcnt_calc(p_msc, p_msc_ctx); + ret_code_t ret = transfer_out_start(p_inst, + ((uint8_t *)p_msc->specific.inst.p_block_buff + + p_msc_ctx->current.workbuff_pos), + size, + APP_USBD_MSC_STATE_DATA_OUT); + if (ret == NRF_SUCCESS) + { + p_msc_ctx->current.trans_req_id ^= 1; + APP_USBD_MSC_REQ_BUSY_SET(p_msc_ctx->current.req_busy_mask, + p_msc_ctx->current.trans_req_id); + p_msc_ctx->current.workbuff_pos ^= p_msc->specific.inst.block_buff_size; + p_msc_ctx->current.trans_in_progress = true; + } + else + { + UNUSED_RETURN_VALUE(status_unsupported_start(p_inst)); + } + } + } +} + + +/** + * @brief Block device event handler. + * + * Mass storage block device event handler. Need to be pined to all block devices + * from initializer list. + * + * @param p_blk_dev Block device handle + * @param p_event Block device event + * + * */ +static void msc_blockdev_ev_handler(nrf_block_dev_t const * p_blk_dev, + nrf_block_dev_event_t const * p_event) +{ + switch (p_event->ev_type) + { + case NRF_BLOCK_DEV_EVT_INIT: + break; + + case NRF_BLOCK_DEV_EVT_UNINIT: + break; + + case NRF_BLOCK_DEV_EVT_BLK_READ_DONE: + CRITICAL_REGION_ENTER(); + msc_blockdev_read_done_handler(p_blk_dev, p_event); + CRITICAL_REGION_EXIT(); + break; + + case NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE: + CRITICAL_REGION_ENTER(); + msc_blockdev_write_done_handler(p_blk_dev, p_event); + CRITICAL_REGION_EXIT(); + break; + + default: + break; + } +} + +/** @} */ + +bool app_usbd_msc_sync(app_usbd_msc_t const * p_msc) +{ + bool rc = true; + ret_code_t ret = NRF_SUCCESS; + + for (size_t i = 0; i < p_msc->specific.inst.block_devs_count; ++i) + { + nrf_block_dev_t const * p_blkd = p_msc->specific.inst.pp_block_devs[i]; + bool flush_in_progress = true; + + ret = nrf_blk_dev_ioctl(p_blkd, + NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH, + &flush_in_progress); + + if ((ret != NRF_SUCCESS) || flush_in_progress) + { + rc = false; + } + } + + return rc; +} + + +#endif //NRF_MODULE_ENABLED(APP_USBD_MSC) diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.h new file mode 100644 index 0000000..b7fcb6a --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc.h @@ -0,0 +1,193 @@ +/** + * Copyright (c) 2016 - 2018, 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_H__ +#define APP_USBD_MSC_H__ + +#include +#include + +#include "nrf_drv_usbd.h" +#include "nrf_block_dev.h" +#include "app_usbd_class_base.h" +#include "app_usbd.h" +#include "app_usbd_core.h" +#include "app_usbd_descriptor.h" + +#include "app_usbd_msc_types.h" +#include "app_usbd_msc_desc.h" +#include "app_usbd_msc_scsi.h" +#include "app_usbd_msc_internal.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup app_usbd_msc USB MSC class + * @ingroup app_usbd + * + * @brief @tagAPI52840 Module with types, definitions, and API used by the USB MSC class. + * + * @details References: + * - "Universal Serial Bus Mass Storage Class, Specification Overview," + * Revision 1.2, USB Implementer's Forum, June 23, 2003. + * - "Universal Serial Bus Mass Storage Class, Bulk-Only Transport," + * Revision 1.0, USB Implementer's Forum, September 31, 1999. + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Mass storage class instance type + * + * @ref APP_USBD_CLASS_TYPEDEF + */ +typedef struct { } app_usbd_msc_t; +#else +/*lint -save -e10 -e26 -e123 -e505 */ +APP_USBD_CLASS_TYPEDEF(app_usbd_msc, \ + APP_USBD_MSC_CONFIG(0, (NRF_DRV_USBD_EPIN1, NRF_DRV_USBD_EPOUT1)), \ + APP_USBD_MSC_INSTANCE_SPECIFIC_DEC, \ + APP_USBD_MSC_DATA_SPECIFIC_DEC \ +); +#endif + +/*lint -restore*/ + + +/*lint -save -e407 */ + +/** + * @brief Events passed to user event handler + * + * @note Example prototype of user event handler: + * + * void msc_user_ev_handler(app_usbd_class_inst_t const * p_inst, + * app_usbd_msc_user_event_t event); + */ +typedef enum app_usbd_msc_user_event_e { + APP_USBD_MSC_USER_EVT_NONE, /**< Dummy event to satisfy compilers. */ +} app_usbd_msc_user_event_t; + +/*lint -restore*/ + +/** + * @brief Helper macro for defining MSC endpoints + * + * @param in_number Input endpoint number + * @param out_number Output endpoint number + * */ +#define APP_USBD_MSC_ENDPOINT_LIST(in_number, out_number) ( \ + CONCAT_2(NRF_DRV_USBD_EPIN, in_number), \ + CONCAT_2(NRF_DRV_USBD_EPOUT, out_number) \ +) + +/** + * @brief Global definition of app_usbd_msc_t class + * + * @param instance_name Name of global instance + * @param interface_number Unique interface number + * @param user_ev_handler User event handler (optional) + * @param endpoint_list Input endpoint list (@ref nrf_drv_usbd_ep_t) + * @param blockdev_list Block device list + * @param workbuffer_size Work buffer size (need to fit into all block devices from + * block device list) + * + * @note This macro is just simplified version of @ref APP_USBD_MSC_GLOBAL_DEF_INTERNAL + * + */ +#define APP_USBD_MSC_GLOBAL_DEF(instance_name, \ + interface_number, \ + user_ev_handler, \ + endpoint_list, \ + blockdev_list, \ + workbuffer_size) \ + APP_USBD_MSC_GLOBAL_DEF_INTERNAL(instance_name, \ + interface_number, \ + user_ev_handler, \ + endpoint_list, \ + blockdev_list, \ + workbuffer_size) + + +/** + * @@brief Helper function to get class instance from MSC + * + * @param[in] p_msc MSC instance (declared by @ref APP_USBD_MSC_GLOBAL_DEF) + * + * @return Base class instance + */ +static inline app_usbd_class_inst_t const * +app_usbd_msc_class_inst_get(app_usbd_msc_t const * p_msc) +{ + return &p_msc->base; +} + +/** + * @brief Helper function to get MSC from base class instance + * + * @param[in] p_inst Base class instance + * + * @return MSC class handle + */ +static inline app_usbd_msc_t const * app_usbd_msc_class_get(app_usbd_class_inst_t const * p_inst) +{ + return (app_usbd_msc_t const *)p_inst; +} + +/** + * @brief Synchronization of all block devices pined to MSC + * + * @param[in] p_msc MSC instance (declared by @ref APP_USBD_MSC_GLOBAL_DEF) + * + * @retval true All block devices flushed data + * @retval false At least one block device has not flushed data + */ +bool app_usbd_msc_sync(app_usbd_msc_t const * p_msc); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APP_USBD_MSC_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_desc.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_desc.h new file mode 100644 index 0000000..83c3916 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_desc.h @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2016 - 2018, 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_DESC_H__ +#define APP_USBD_MSC_DESC_H__ + +#include "app_usbd_descriptor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup app_usbd_msc_desc USB MSC descriptors + * @ingroup app_usbd_msc + * + * @brief @tagAPI52840 Descriptors for the USB MSC class. + * @{ + */ + +/** + * @brief Initializer of interface descriptor for MSC class + * + * @param interface_number Interface number + * @param subclass Subclass, @ref app_usbd_msc_subclass_t + * @param protocol Protocol, @ref app_usbd_msc_protocol_t + * */ +#define APP_USBD_MSC_INTERFACE_DSC(interface_number, subclass, protocol) \ + /*.bLength = */ sizeof(app_usbd_descriptor_iface_t), \ + /*.bDescriptorType = */ APP_USBD_DESCRIPTOR_INTERFACE, \ + /*.bInterfaceNumber = */ interface_number, \ + /*.bAlternateSetting = */ 0x00, \ + /*.bNumEndpoints = */ 2, \ + /*.bInterfaceClass = */ APP_USBD_MSC_CLASS, \ + /*.bInterfaceSubClass = */ subclass, \ + /*.bInterfaceProtocol = */ protocol, \ + /*.iInterface = 0, */ 0x00, \ + + +/** + * @brief Initializer of endpoint descriptors for MSC class + * + * @param endpoint_in IN endpoint + * @param endpoint_out OUT endpoint + * @param ep_size Endpoint size + * */ +#define APP_USBD_MSC_EP_DSC(endpoint_in, endpoint_out, ep_size) \ + /*.bLength = */ sizeof(app_usbd_descriptor_ep_t), \ + /*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \ + /*.bEndpointAddress = */ endpoint_in, \ + /*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_BULK, \ + /*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \ + /*.bInterval = */ 0, \ + /*.bLength = */ sizeof(app_usbd_descriptor_ep_t), \ + /*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \ + /*.bEndpointAddress = */ endpoint_out, \ + /*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_BULK, \ + /*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \ + /*.bInterval = */ 0, \ + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APP_USBD_MSC_DESC_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_internal.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_internal.h new file mode 100644 index 0000000..c7036fa --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_internal.h @@ -0,0 +1,259 @@ +/** + * Copyright (c) 2016 - 2018, 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__ + +#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 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) + + 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_CMD_OUT, /**< Internal module state CMD_OUT */ + 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_DATA_OUT_WAIT, /**< Internal module state DATA_OUT_WAIT */ + 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_cbw_t cbw; //!< SCSI command block wrapper + app_usbd_msc_csw_t csw; //!< SCSI Command status wrapper + + app_usbd_msc_state_t state; //!< Internal module state + + struct { + uint8_t lun; //!< Current transfer blocks: logical unit + uint8_t csw_status; //!< Current CSW status + uint32_t blk_idx; //!< Current transfer: block index + uint32_t blk_datasize; //!< Current transfer: data size to transfer + uint32_t blk_size; //!< Current transfer: block size + uint32_t blk_count; //!< Current transfer: block count + uint32_t residue; //!< @ref app_usbd_msc_csw_t::residue + + bool trans_in_progress; //!< Transfer in progress flag + bool block_req_in_progress; //!< Block request in progress flag + size_t workbuff_pos; //!< Current buffer offset (double buffering mode) + uint8_t req_busy_mask; //!< Request bust mask (double buffering mode) + uint8_t trans_req_id; //!< Current transfered request (double buffering mode) + + nrf_block_req_t req; //!< Last processed block req (double buffering mode) + } current; + + size_t resp_len; //!< Response length + + /*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 block_devs Block devices list + * @param block_buff Block buffer + * @param user_event_handler User event handler + */ +#define APP_USBD_MSC_INST_CONFIG(block_devs, block_buff, user_event_handler) \ + .inst = { \ + .pp_block_devs = block_devs, \ + .block_devs_count = ARRAY_SIZE(block_devs), \ + .p_block_buff = block_buff, \ + .block_buff_size = sizeof(block_buff) / 2, \ + .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 * CONCAT_2(instance_name, _blkdevs)[] = \ + { BRACKET_EXTRACT(blockdev_list) }; \ + static uint32_t CONCAT_2(instance_name, _block)[2 *(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(CONCAT_2(instance_name, _blkdevs), \ + CONCAT_2(instance_name, _block), \ + user_ev_handler)) \ + ) + + +/** @} */ + + +#ifdef __cplusplus +} +#endif + +#endif /* APP_USBD_MSC_INTERNAL_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_scsi.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_scsi.h new file mode 100644 index 0000000..8379a8c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_scsi.h @@ -0,0 +1,329 @@ +/** + * Copyright (c) 2016 - 2018, 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_SCSI_H__ +#define APP_USBD_MSC_SCSI_H__ + +#include "app_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup app_usbd_msc_scsi USB MSC SCSI data structures + * @ingroup app_usbd_msc + * + * @brief @tagAPI52840 USB MSC SCSI data structures. + * + * @details Reference specifications: + * - "Reduced Block Commands (Revision 10a)" American National Standard + * for Information Technology, August 18, 1999 + * - "SCSI Primary Commands - 4 (SPC-4)," American National Standard + * for Information Technology, July 19, 2008 + * - "SCSI Block Commands -2 (SBC-2)," American National Standard + * for Information Technology, November 13, 2004 + * - NuttX source code - Real-time Operating System: http://nuttx.org/ + * Gregory Nutt + * + * @{ + */ + +/** + * @brief SCSI command set + * + * Mandatory (and some optional) commands required by SBC-2. + * + */ +typedef enum { + APP_USBD_SCSI_CMD_TESTUNITREADY = 0x00, /**< TESTUNITREADY */ + APP_USBD_SCSI_CMD_REQUESTSENSE = 0x03, /**< REQUESTSENSE */ + APP_USBD_SCSI_CMD_FORMAT_UNIT = 0x04, /**< FORMAT_UNIT */ + APP_USBD_SCSI_CMD_READ6 = 0x08, /**< READ6 */ + APP_USBD_SCSI_CMD_WRITE6 = 0x0a, /**< WRITE6 */ + APP_USBD_SCSI_CMD_INQUIRY = 0x12, /**< INQUIRY */ + APP_USBD_SCSI_CMD_MODESELECT6 = 0x15, /**< MODESELECT6 */ + APP_USBD_SCSI_CMD_MODESENSE6 = 0x1a, /**< MODESENSE6 */ + APP_USBD_SCSI_CMD_STARTSTOPUNIT = 0x1b, /**< STARTSTOPUNIT */ + APP_USBD_SCSI_CMD_SENDDIAGNOSTIC = 0x1d, /**< SENDDIAGNOSTIC */ + APP_USBD_SCSI_CMD_PREVENTMEDIAREMOVAL = 0x1e, /**< PREVENTMEDIAREMOVAL */ + APP_USBD_SCSI_CMD_READCAPACITY10 = 0x25, /**< READCAPACITY10 */ + APP_USBD_SCSI_CMD_READ10 = 0x28, /**< READ10 */ + APP_USBD_SCSI_CMD_WRITE10 = 0x2a, /**< WRITE10 */ + APP_USBD_SCSI_CMD_MODESELECT10 = 0x55, /**< MODESELECT10 */ + APP_USBD_SCSI_CMD_MODESENSE10 = 0x5a, /**< MODESENSE10 */ +} app_usbd_scsi_cmd_t; + + +#pragma pack(push, 1) + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_REQUESTSENSE command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_REQUESTSENSE + uint8_t flags; //!< Flags + uint8_t reserved[2]; //!< Reserved + uint8_t alloclen; //!< Allocation length + uint8_t control; //!< Control +} app_usbd_scsi_cmd_requestsense_t; + +#define APP_USBD_SCSI_CMD_REQSENSE_CODE_VALID 0x80 /**< @ref app_usbd_scsi_cmd_requestsense_resp_t::code */ +#define APP_USBD_SCSI_CMD_REQSENSE_CODE_CURRENT 0x70 /**< @ref app_usbd_scsi_cmd_requestsense_resp_t::code */ +#define APP_USBD_SCSI_CMD_REQSENSE_CODE_DEFERRED 0x71 /**< @ref app_usbd_scsi_cmd_requestsense_resp_t::code */ +#define APP_USBD_SCSI_CMD_REQSENSE_CODE_CURRENTDESC 0x72 /**< @ref app_usbd_scsi_cmd_requestsense_resp_t::code */ +#define APP_USBD_SCSI_CMD_REQSENSE_CODE_DEFERREDDESC 0x73 /**< @ref app_usbd_scsi_cmd_requestsense_resp_t::code */ + +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_FILEMARK 0x80 /**< Bits 7 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_EOM 0x40 /**< Bits 6 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_ILI 0x20 /**< Bits 5 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_RESERVED 0x10 /**< Bits 4 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ + +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_NOSENSE 0x00 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_RECOVEREDERROR 0x01 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_NOTREADY 0x02 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_MEDIUMERROR 0x03 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_HARDWAREERROR 0x04 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_ILLEGALREQUEST 0x05 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_UNITATTENTION 0x06 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_DATAPROTECT 0x07 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_BLANKCHECK 0x08 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_VENDORSPECIFIC 0x09 /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ +#define APP_USBD_SCSI_CMD_REQSENSE_FLAG_ABORTEDCOMMAND 0x0b /**< Bits 3...0 @ref app_usbd_scsi_cmd_requestsense_resp_t::flags */ + + +#define APP_USBD_SCSI_CMD_TESTUNITREADY_LEN 6 /**< @ref APP_USBD_SCSI_CMD_TESTUNITREADY command length*/ + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_REQUESTSENSE response + */ +typedef struct { + uint8_t code; //!< Response code: APP_USBD_SCSI_CMD_REQSENSE_CODE_* + uint8_t obsolete; //!< Obsolete + uint8_t flags; //!< APP_USBD_SCSI_CMD_REQSENSE_FLAG_* + uint8_t info[4]; //!< Information + uint8_t len; //!< Additional length + uint8_t cmdinfo[4]; //!< Command-specific information + uint8_t code2; //!< Additional sense code + uint8_t qual2; //!< Additional sense code qualifier + uint8_t fru; //!< Field replacement unit code + uint8_t key[3]; //!< Sense key specific +} app_usbd_scsi_cmd_requestsense_resp_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_INQUIRY command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_INQUIRY + uint8_t flags; //!< Command flags + uint8_t pagecode; //!< Page code + uint8_t alloclen[2]; //!< Allocation length + uint8_t control; //!< Control +} app_usbd_scsi_cmd_inquiry_t; + +#define APP_USBD_MSC_SCSI_INQ_QUAL_CONNECTED 0x00 /**< Peripheral connected */ +#define APP_USBD_MSC_SCSI_INQ_QUAL_NOT_CONN 0x20 /**< Peripheral not connected */ +#define APP_USBD_MSC_SCSI_INQ_QUAL_NOT_SUPP 0x60 /**< Peripheral not supported */ + +#define APP_USBD_MSC_SCSI_INQ_TYPE_DIR_ACCESS 0x00 /**< Direct Access (SBC) */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_SEQ_ACCESS 0x01 /**< Sequential Access */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_PRINTER 0x02 /**< Printer */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_PROCESSOR 0x03 /**< Processor device */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_WRITE_ONCE 0x04 /**< Write-once device */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_CD_DVD 0x05 /**< CD/DVD device */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_OPTICAL 0x07 /**< Optical Memory */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_MC 0x08 /**< Medium Changer */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_ARRAY 0x0c /**< Storage Array Controller */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_ENCLOSURE 0x0d /**< Enclosure Services */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_RBC 0x0e /**< Simplified Direct Access */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_OCRW 0x0f /**< Optical card reader/writer */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_BCC 0x10 /**< Bridge Controller Commands */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_OSD 0x11 /**< Object-based Storage */ +#define APP_USBD_MSC_SCSI_INQ_TYPE_NONE 0x1f /**< No Peripheral */ + + +#define APP_USBD_MSC_SCSI_INQ_FLAG1_RMB 0x80 /**< Removable Medium */ + +#define APP_USBD_SCSI_INQ_VER_NONE 0x00 /**< No standards conformance */ +#define APP_USBD_SCSI_INQ_VER_SPC 0x03 /**< SCSI Primary Commands (link to SBC) */ +#define APP_USBD_SCSI_INQ_VER_SPC2 0x04 /**< SCSI Primary Commands - 2 (link to SBC-2)*/ +#define APP_USBD_SCSI_INQ_VER_SPC3 0x05 /**< SCSI Primary Commands - 3 (link to SBC-2)*/ +#define APP_USBD_SCSI_INQ_VER_SPC4 0x06 /**< SCSI Primary Commands - 4 (link to SBC-3)*/ + +#define APP_USBD_MSC_SCSI_INQ_FLAG2_NORMACA 0x20 /**< Normal ACA Supported */ +#define APP_USBD_MSC_SCSI_INQ_FLAG2_HISUP 0x10 /**< Hierarchal LUN addressing */ +#define APP_USBD_MSC_SCSI_INQ_FLAG2_RSP_SPC2 0x02 /**< SPC-2 / SPC-3 response format*/ +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_INQUIRY response + */ +typedef struct { + uint8_t qualtype; //!< Bits 5-7: Peripheral qualifier; Bits 0-4: Peripheral device type + uint8_t flags1; //!< Flags 1 + uint8_t version; //!< Version + uint8_t flags2; //!< Flags 2 + uint8_t len; //!< Additional length + uint8_t flags3; //!< Flags 3 + uint8_t flags4; //!< Flags 4 + uint8_t flags5; //!< Flags 5 + uint8_t vendorid[8]; //!< T10 Vendor Identification + uint8_t productid[16]; //!< Product Identification + uint8_t revision[4]; //!< Product Revision Level +} app_usbd_scsi_cmd_inquiry_resp_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_READ6 command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_READ6 + uint8_t mslba; //!< Bits 5-7: reserved; Bits 0-6: MS Logical Block Address (LBA) + uint8_t lslba[2]; //!< LS Logical Block Address (LBA) + uint8_t xfrlen; //!< Transfer length (in contiguous logical blocks) + uint8_t control; //!< Control +} app_usbd_scsi_cmd_read6_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_WRITE6 command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_WRITE6 + uint8_t mslba; //!< Bits 5-7: reserved; Bits 0-6: MS Logical Block Address (LBA) + uint8_t lslba[2]; //!< LS Logical Block Address (LBA) + uint8_t xfrlen; //!< Transfer length (in contiguous logical blocks) + uint8_t control; //!< Control +} app_usbd_scsi_cmd_write6_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_MODESENSE6 command + */ +typedef struct { + uint8_t opcode; //!<* @ref APP_USBD_SCSI_CMD_MODESENSE6 + uint8_t flags; //!<* Flags + uint8_t pcpgcode; //!<* Bits 6-7: PC, bits 0-5: page code + uint8_t subpgcode; //!<* subpage code + uint8_t alloclen; //!<* Allocation length + uint8_t control; //!<* Control +} app_usbd_scsi_cmd_modesense6_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_MODESENSE6 response + */ +typedef struct { + uint8_t mdlen; //!< Mode data length + uint8_t type; //!< Medium type + uint8_t param; //!< Device-specific parameter + uint8_t bdlen; //!< Block descriptor length +} app_usbd_scsi_cmd_modesense6_resp_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_READCAPACITY10 command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_READCAPACITY10 + uint8_t reserved1; //!< Reserved field + uint8_t lba[4]; //!< Logical block address (LBA) + uint8_t reserved2[2]; //!< Reserved field + uint8_t pmi; //!< Bits 1-7 Reserved; Bit 0: PMI + uint8_t control; //!< Control +} app_usbd_scsi_cmd_readcapacity10_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_READCAPACITY10 response + */ +typedef struct { + uint8_t lba[4]; //!< Returned logical block address (LBA) + uint8_t blklen[4]; //!< Logical block length (in bytes) +} app_usbd_scsi_cmd_readcapacity10_resp_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_READ10 command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_READ10 + uint8_t flags; //!< Command flags + uint8_t lba[4]; //!< Logical Block Address (LBA) + uint8_t groupno; //!< Bits 5-7: reserved; Bits 0-6: group number + uint8_t xfrlen[2]; //!< Transfer length (in contiguous logical blocks) + uint8_t control; //!< Control +} app_usbd_scsi_cmd_read10_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_WRITE10 command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_WRITE10 + uint8_t flags; //!< Command flags + uint8_t lba[4]; //!< Logical Block Address (LBA) + uint8_t groupno; //!< Bits 5-7: reserved; Bits 0-6: group number + uint8_t xfrlen[2]; //!< Transfer length (in contiguous logical blocks) + uint8_t control; //!< Control +} app_usbd_scsi_cmd_write10_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_MODESENSE10 command + */ +typedef struct { + uint8_t opcode; //!< @ref APP_USBD_SCSI_CMD_MODESENSE10 + uint8_t flags; //!< Flags + uint8_t pcpgcode; //!< Bits 6-7: PC, bits 0-5: page code + uint8_t subpgcode; //!< Subpage code + uint8_t reserved[3]; //!< Reserved + uint8_t alloclen[2]; //!< Allocation length + uint8_t control; //!< Control +} app_usbd_scsi_cmd_modesense10_t; + +/** + * @brief Payload of @ref APP_USBD_SCSI_CMD_MODESENSE10 response + */ +typedef struct { + uint8_t mdlen[2]; //!< Mode data length + uint8_t type; //!< Medium type + uint8_t param; //!< Device-specific parameter + uint8_t reserved[2]; //!< Reserved + uint8_t bdlen[2]; //!< Block descriptor length +} app_usbd_scsi_cmd_modesense10_resp_t; + +#pragma pack(pop) + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APP_USBD_MSC_SCSI_H__ */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_types.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_types.h new file mode 100644 index 0000000..96a6431 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/usbd/class/msc/app_usbd_msc_types.h @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2016 - 2018, 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_TYPES_H__ +#define APP_USBD_MSC_TYPES_H__ + +#include "app_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup app_usbd_msc_types USB MSC types + * @ingroup app_usbd_msc + * + * @brief @tagAPI52840 Types used in the USB MSC class. + * @{ + */ + +/** @brief MSC class definition in interface descriptor + * + * @ref app_usbd_descriptor_iface_t::bInterfaceClass + * */ +#define APP_USBD_MSC_CLASS 0x08 + +/** + * @brief MSC subclass possible value + */ +typedef enum { + APP_USBD_MSC_SUBCLASS_RBC = 0x01, /**< Reduced Block Commands */ + APP_USBD_MSC_SUBCLASS_ATAPI = 0x02, /**< CD/DVD devices */ + APP_USBD_MSC_SUBCLASS_QIC_157 = 0x03, /**< Tape devices */ + APP_USBD_MSC_SUBCLASS_UFI = 0x04, /**< Floppy disk drives */ + APP_USBD_MSC_SUBCLASS_SFF_8070I = 0x05, /**< Floppy disk drives */ + APP_USBD_MSC_SUBCLASS_TRANSPARENT = 0x06, /**< Determined by INQUIRY */ +} app_usbd_msc_subclass_t; + +/** + * @brief MSC protocol possible value + * + * @note The USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport specification is approved + * for use only with full-speed floppy disk drives. CBI shall not be used in high-speed + * capable devices. + */ +typedef enum { + APP_USBD_MSC_PROTOCOL_CBI = 0x00, /**< Command/Bulk/Interrupt */ + APP_USBD_MSC_PROTOCOL_CBI_ALT = 0x01, /**< W/o command completion */ + APP_USBD_MSC_PROTOCOL_BULK = 0x50, /**< Bulk-only */ +} app_usbd_msc_protocol_t; + +/** + * @brief MSC USB requests @ref nrf_drv_usbd_setup_t::bmRequestType + * + * @note Requests are limited only to @ref APP_USBD_MSC_PROTOCOL_BULK protocol type. + */ +typedef enum { + APP_USBD_MSC_REQ_BULK_RESET = 0xFF, /**< Mass Storage Reset */ + APP_USBD_MSC_REQ_GET_MAX_LUN = 0xFE, /**< Get Max LUN */ +} app_usbd_msc_req_t; + +#pragma pack(push, 1) + +#define APP_USBD_MSC_CBW_SIGNATURE "USBC" /**< CBW signature */ +#define APP_USBD_MSC_CBW_DIRECTION_IN (1u <<7) /**< CBW direction flag */ + +/** + * @brief Command Block Wrapper (CBW) + */ +typedef struct { + uint8_t signature[4]; /**< "USBC" (hex: 0x43425355 little-endian) */ + uint8_t tag[4]; /**< Unique command tag */ + uint8_t datlen[4]; /**< Number of bytes that host expects to transfer */ + uint8_t flags; /**< Bit 7: Direction=IN */ + uint8_t lun; /**< Logical Unit Number, equals to @ref app_usbd_msc_inst_t :: block_devs_count*/ + uint8_t cdb_length; /**< Length of cdb field */ + uint8_t cdb[16]; /**< Command Data Block payload */ +} app_usbd_msc_cbw_t; + +#define APP_USBD_MSC_CSW_SIGNATURE "USBS" /**< CSW signature */ + +#define APP_USBD_MSC_CSW_STATUS_PASS 0x00 /**< CSW status: Command Passed */ +#define APP_USBD_MSC_CSW_STATUS_FAIL 0x01 /**< CSW status: Command Failed */ +#define APP_USBD_MSC_CSW_STATUS_PE 0x02 /**< CSW status: Phase Error */ + +/** + * @brief Command Status Wrapper (CSW) + */ +typedef struct { + uint8_t signature[4]; /**< "USBS" (hex: 0x53425355 little-endian) */ + uint8_t tag[4]; /**< Unique command tag (@ref app_usbd_msc_cbw_t :: tag) */ + uint8_t residue[4]; /**< Amount not transferred */ + uint8_t status; /**< Status of transfer */ +} app_usbd_msc_csw_t; + +#pragma pack(pop) + + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* APP_USBD_MSC_TYPES_H__ */ -- cgit v1.2.3