diff options
| author | hathach <[email protected]> | 2014-03-12 14:08:52 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2014-03-12 14:10:38 +0700 |
| commit | 9ba209cda074289bbbe51dc79b4231404c8089ba (patch) | |
| tree | 66e5b6590773b8466bf251000ec425ddcd6a1789 /tinyusb/class | |
| parent | 8f03dea95a5d8cb4ebd72b0da74cd51365c8d936 (diff) | |
IAR line ending warning
Diffstat (limited to 'tinyusb/class')
| -rw-r--r-- | tinyusb/class/msc_device.c | 12 | ||||
| -rw-r--r-- | tinyusb/class/msc_host.c | 858 |
2 files changed, 434 insertions, 436 deletions
diff --git a/tinyusb/class/msc_device.c b/tinyusb/class/msc_device.c index 997145499..2196a0164 100644 --- a/tinyusb/class/msc_device.c +++ b/tinyusb/class/msc_device.c @@ -52,17 +52,15 @@ // MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
typedef struct {
- uint8_t interface_number;
- endpoint_handle_t edpt_in, edpt_out;
-
- // must be in USB ram
- ATTR_USB_MIN_ALIGNMENT uint8_t max_lun; // can STALL for one LUN
-
ATTR_USB_MIN_ALIGNMENT msc_cmd_block_wrapper_t cbw;
ATTR_USB_MIN_ALIGNMENT msc_cmd_status_wrapper_t csw;
+ ATTR_USB_MIN_ALIGNMENT uint8_t max_lun; // can STALL for one LUN
+
+ uint8_t interface_number;
+ endpoint_handle_t edpt_in, edpt_out;
}mscd_interface_t;
-TUSB_CFG_ATTR_USBRAM STATIC_VAR mscd_interface_t mscd_data;
+ATTR_USB_MIN_ALIGNMENT TUSB_CFG_ATTR_USBRAM STATIC_VAR mscd_interface_t mscd_data;
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
diff --git a/tinyusb/class/msc_host.c b/tinyusb/class/msc_host.c index dcb3fff6f..1380b1e03 100644 --- a/tinyusb/class/msc_host.c +++ b/tinyusb/class/msc_host.c @@ -1,429 +1,429 @@ -/**************************************************************************/ -/*! - @file msc_host.c - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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 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 the copyright holders nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. - - This file is part of the tinyusb stack. -*/ -/**************************************************************************/ - -#include "tusb_option.h" - -#if MODE_HOST_SUPPORTED & TUSB_CFG_HOST_MSC - -#define _TINY_USB_SOURCE_FILE_ - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "common/common.h" -#include "msc_host.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -TUSB_CFG_ATTR_USBRAM STATIC_VAR msch_interface_t msch_data[TUSB_CFG_HOST_DEVICE_MAX]; - - -//------------- Initalization Data -------------// -OSAL_SEM_DEF(msch_semaphore); -static osal_semaphore_handle_t msch_sem_hdl; - -// buffer used to read scsi information when mounted, largest response data currently is inquiry -TUSB_CFG_ATTR_USBRAM ATTR_ALIGNED(4) STATIC_VAR uint8_t msch_buffer[sizeof(scsi_inquiry_data_t)]; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - -//--------------------------------------------------------------------+ -// PUBLIC API -//--------------------------------------------------------------------+ -bool tusbh_msc_is_mounted(uint8_t dev_addr) -{ - return tusbh_device_is_configured(dev_addr) && // is configured can be omitted - msch_data[dev_addr-1].is_initialized; -} - -bool tusbh_msc_is_busy(uint8_t dev_addr) -{ - return msch_data[dev_addr-1].is_initialized && - hcd_pipe_is_busy(msch_data[dev_addr-1].bulk_in); -} - -uint8_t const* tusbh_msc_get_vendor_name(uint8_t dev_addr) -{ - return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].vendor_id : NULL; -} - -uint8_t const* tusbh_msc_get_product_name(uint8_t dev_addr) -{ - return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].product_id : NULL; -} - -tusb_error_t tusbh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size) -{ - if ( !msch_data[dev_addr-1].is_initialized ) return TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED; - ASSERT(p_last_lba != NULL && p_block_size != NULL, TUSB_ERROR_INVALID_PARA); - - (*p_last_lba) = msch_data[dev_addr-1].last_lba; - (*p_block_size) = (uint32_t) msch_data[dev_addr-1].block_size; - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// PUBLIC API: SCSI COMMAND -//--------------------------------------------------------------------+ -static inline void msc_cbw_add_signature(msc_cmd_block_wrapper_t *p_cbw, uint8_t lun) ATTR_ALWAYS_INLINE; -static inline void msc_cbw_add_signature(msc_cmd_block_wrapper_t *p_cbw, uint8_t lun) -{ - p_cbw->signature = MSC_CBW_SIGNATURE; - p_cbw->tag = 0xCAFECAFE; - p_cbw->lun = lun; -} - -static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer) ATTR_WARN_UNUSED_RESULT; -static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer) -{ - if ( NULL != p_buffer) - { // there is data phase - if (p_msch->cbw.dir & TUSB_DIR_DEV_TO_HOST_MASK) - { - ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t), false) ); - ASSERT_STATUS( hcd_pipe_queue_xfer(p_msch->bulk_in , p_buffer, p_msch->cbw.xfer_bytes) ); - }else - { - ASSERT_STATUS( hcd_pipe_queue_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t)) ); - ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out , p_buffer, p_msch->cbw.xfer_bytes, false) ); - } - } - - ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_in , (uint8_t*) &p_msch->csw, sizeof(msc_cmd_status_wrapper_t), true) ); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - p_msch->cbw.xfer_bytes = sizeof(scsi_inquiry_data_t); - p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_inquiry_t); - - //------------- SCSI command -------------// - scsi_inquiry_t cmd_inquiry = - { - .cmd_code = SCSI_CMD_INQUIRY, - .alloc_length = sizeof(scsi_inquiry_data_t) - }; - - memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len); - - ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) ); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - p_msch->cbw.xfer_bytes = sizeof(scsi_read_capacity10_data_t); - p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_read_capacity10_t); - - //------------- SCSI command -------------// - scsi_read_capacity10_t cmd_read_capacity10 = - { - .cmd_code = SCSI_CMD_READ_CAPACITY_10, - .lba = 0, - .partial_medium_indicator = 0 - }; - - memcpy(p_msch->cbw.command, &cmd_read_capacity10, p_msch->cbw.cmd_len); - - ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) ); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - p_msch->cbw.xfer_bytes = 18; - p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_request_sense_t); - - //------------- SCSI command -------------// - scsi_request_sense_t cmd_request_sense = - { - .cmd_code = SCSI_CMD_REQUEST_SENSE, - .alloc_length = 18 - }; - - memcpy(p_msch->cbw.command, &cmd_request_sense, p_msch->cbw.cmd_len); - - ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) ); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_cmd_status_wrapper_t * p_csw) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - - p_msch->cbw.xfer_bytes = 0; // Number of bytes - p_msch->cbw.dir = TUSB_DIR_HOST_TO_DEV; - p_msch->cbw.cmd_len = sizeof(scsi_test_unit_ready_t); - - //------------- SCSI command -------------// - scsi_test_unit_ready_t cmd_test_unit_ready = - { - .cmd_code = SCSI_CMD_TEST_UNIT_READY, - .lun = lun // according to wiki - }; - - memcpy(p_msch->cbw.command, &cmd_test_unit_ready, p_msch->cbw.cmd_len); - - // TODO MSCH refractor test uinit ready - ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t), false) ); - ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_in , (uint8_t*) p_csw, sizeof(msc_cmd_status_wrapper_t), true) ); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - - p_msch->cbw.xfer_bytes = p_msch->block_size*block_count; // Number of bytes - p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_read10_t); - - //------------- SCSI command -------------// - scsi_read10_t cmd_read10 = - { - .cmd_code = SCSI_CMD_READ_10, - .lba = __n2be(lba), - .block_count = u16_le2be(block_count) - }; - - memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len); - - ASSERT_STATUS ( msch_command_xfer(p_msch, p_buffer)); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tusbh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - - p_msch->cbw.xfer_bytes = p_msch->block_size*block_count; // Number of bytes - p_msch->cbw.dir = TUSB_DIR_HOST_TO_DEV; - p_msch->cbw.cmd_len = sizeof(scsi_write10_t); - - //------------- SCSI command -------------// - scsi_write10_t cmd_write10 = - { - .cmd_code = SCSI_CMD_WRITE_10, - .lba = __n2be(lba), - .block_count = u16_le2be(block_count) - }; - - memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len); - - ASSERT_STATUS ( msch_command_xfer(p_msch, (void*) p_buffer)); - - return TUSB_ERROR_NONE; -} - -//--------------------------------------------------------------------+ -// CLASS-USBH API (don't require to verify parameters) -//--------------------------------------------------------------------+ -void msch_init(void) -{ - memclr_(msch_data, sizeof(msch_interface_t)*TUSB_CFG_HOST_DEVICE_MAX); - msch_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(msch_semaphore) ); -} - -tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length) -{ - tusb_error_t error; - - OSAL_SUBTASK_BEGIN - - if (! ( MSC_SUBCLASS_SCSI == p_interface_desc->bInterfaceSubClass && - MSC_PROTOCOL_BOT == p_interface_desc->bInterfaceProtocol ) ) - { - return TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL; - } - - //------------- Open Data Pipe -------------// - tusb_descriptor_endpoint_t const *p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_interface_desc ); - for(uint32_t i=0; i<2; i++) - { - SUBTASK_ASSERT(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->bDescriptorType); - SUBTASK_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer); - - pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_DEV_TO_HOST_MASK ) ? - &msch_data[dev_addr-1].bulk_in : &msch_data[dev_addr-1].bulk_out; - - (*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_MSC); - SUBTASK_ASSERT( pipehandle_is_valid(*p_pipe_hdl) ); - - p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_endpoint ); - } - - msch_data[dev_addr-1].interface_number = p_interface_desc->bInterfaceNumber; - (*p_length) += sizeof(tusb_descriptor_interface_t) + 2*sizeof(tusb_descriptor_endpoint_t); - - - //------------- Get Max Lun -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE), - MSC_REQUEST_GET_MAX_LUN, 0, msch_data[dev_addr-1].interface_number, - 1, msch_buffer ), - error - ); - - SUBTASK_ASSERT( TUSB_ERROR_NONE == error /* && TODO STALL means zero */); - msch_data[dev_addr-1].max_lun = msch_buffer[0]; - -#if 0 - //------------- Reset -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE), - MSC_REQUEST_RESET, 0, msch_data[dev_addr-1].interface_number, - 0, NULL ), - error - ); -#endif - - enum { SCSI_XFER_TIMEOUT = 2000 }; - //------------- SCSI Inquiry -------------// - tusbh_msc_inquiry(dev_addr, 0, msch_buffer); - osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); - SUBTASK_ASSERT_STATUS(error); - - memcpy(msch_data[dev_addr-1].vendor_id , ((scsi_inquiry_data_t*) msch_buffer)->vendor_id , 8); - memcpy(msch_data[dev_addr-1].product_id, ((scsi_inquiry_data_t*) msch_buffer)->product_id, 16); - - //------------- SCSI Read Capacity 10 -------------// - tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer); - osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); - SUBTASK_ASSERT_STATUS(error); - - // NOTE: my toshiba thumb-drive stall the first Read Capacity and require the sequence - // Read Capacity --> Stalled --> Clear Stall --> Request Sense --> Read Capacity (2) to work - if ( hcd_pipe_is_stalled(msch_data[dev_addr-1].bulk_in) ) - { // clear stall TODO abstract clear stall function - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_ENDPOINT), - TUSB_REQUEST_CLEAR_FEATURE, 0, hcd_pipe_get_endpoint_addr(msch_data[dev_addr-1].bulk_in), - 0, NULL ), - error - ); - SUBTASK_ASSERT_STATUS(error); - - hcd_pipe_clear_stall(msch_data[dev_addr-1].bulk_in); - osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); // wait for SCSI status - SUBTASK_ASSERT_STATUS(error); - - //------------- SCSI Request Sense -------------// - tusbh_msc_request_sense(dev_addr, 0, msch_buffer); - osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); - SUBTASK_ASSERT_STATUS(error); - - //------------- Re-read SCSI Read Capactity -------------// - tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer); - osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); - SUBTASK_ASSERT_STATUS(error); - } - - msch_data[dev_addr-1].last_lba = __be2n( ((scsi_read_capacity10_data_t*)msch_buffer)->last_lba ); - msch_data[dev_addr-1].block_size = (uint16_t) __be2n( ((scsi_read_capacity10_data_t*)msch_buffer)->block_size ); - - msch_data[dev_addr-1].is_initialized = true; - tusbh_msc_mounted_cb(dev_addr); - - OSAL_SUBTASK_END -} - -void msch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes) -{ - if ( pipehandle_is_equal(pipe_hdl, msch_data[pipe_hdl.dev_addr-1].bulk_in) ) - { - if (msch_data[pipe_hdl.dev_addr-1].is_initialized) - { - tusbh_msc_isr(pipe_hdl.dev_addr, event, xferred_bytes); - }else - { // still initializing under open subtask - osal_semaphore_post(msch_sem_hdl); - } - } -} - -void msch_close(uint8_t dev_addr) -{ - (void) hcd_pipe_close(msch_data[dev_addr-1].bulk_in); - (void) hcd_pipe_close(msch_data[dev_addr-1].bulk_out); - - memclr_(&msch_data[dev_addr-1], sizeof(msch_interface_t)); - osal_semaphore_reset(msch_sem_hdl); - - tusbh_msc_unmounted_cb(dev_addr); // invoke Application Callback -} - -//--------------------------------------------------------------------+ -// INTERNAL & HELPER -//--------------------------------------------------------------------+ - - -#endif +/**************************************************************************/
+/*!
+ @file msc_host.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2013, hathach (tinyusb.org)
+ 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 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 the copyright holders nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
+
+ This file is part of the tinyusb stack.
+*/
+/**************************************************************************/
+
+#include "tusb_option.h"
+
+#if MODE_HOST_SUPPORTED & TUSB_CFG_HOST_MSC
+
+#define _TINY_USB_SOURCE_FILE_
+
+//--------------------------------------------------------------------+
+// INCLUDE
+//--------------------------------------------------------------------+
+#include "common/common.h"
+#include "msc_host.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF
+//--------------------------------------------------------------------+
+TUSB_CFG_ATTR_USBRAM STATIC_VAR msch_interface_t msch_data[TUSB_CFG_HOST_DEVICE_MAX];
+
+
+//------------- Initalization Data -------------//
+OSAL_SEM_DEF(msch_semaphore);
+static osal_semaphore_handle_t msch_sem_hdl;
+
+// buffer used to read scsi information when mounted, largest response data currently is inquiry
+TUSB_CFG_ATTR_USBRAM ATTR_ALIGNED(4) STATIC_VAR uint8_t msch_buffer[sizeof(scsi_inquiry_data_t)];
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+
+//--------------------------------------------------------------------+
+// PUBLIC API
+//--------------------------------------------------------------------+
+bool tusbh_msc_is_mounted(uint8_t dev_addr)
+{
+ return tusbh_device_is_configured(dev_addr) && // is configured can be omitted
+ msch_data[dev_addr-1].is_initialized;
+}
+
+bool tusbh_msc_is_busy(uint8_t dev_addr)
+{
+ return msch_data[dev_addr-1].is_initialized &&
+ hcd_pipe_is_busy(msch_data[dev_addr-1].bulk_in);
+}
+
+uint8_t const* tusbh_msc_get_vendor_name(uint8_t dev_addr)
+{
+ return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].vendor_id : NULL;
+}
+
+uint8_t const* tusbh_msc_get_product_name(uint8_t dev_addr)
+{
+ return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].product_id : NULL;
+}
+
+tusb_error_t tusbh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size)
+{
+ if ( !msch_data[dev_addr-1].is_initialized ) return TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED;
+ ASSERT(p_last_lba != NULL && p_block_size != NULL, TUSB_ERROR_INVALID_PARA);
+
+ (*p_last_lba) = msch_data[dev_addr-1].last_lba;
+ (*p_block_size) = (uint32_t) msch_data[dev_addr-1].block_size;
+
+ return TUSB_ERROR_NONE;
+}
+
+//--------------------------------------------------------------------+
+// PUBLIC API: SCSI COMMAND
+//--------------------------------------------------------------------+
+static inline void msc_cbw_add_signature(msc_cmd_block_wrapper_t *p_cbw, uint8_t lun) ATTR_ALWAYS_INLINE;
+static inline void msc_cbw_add_signature(msc_cmd_block_wrapper_t *p_cbw, uint8_t lun)
+{
+ p_cbw->signature = MSC_CBW_SIGNATURE;
+ p_cbw->tag = 0xCAFECAFE;
+ p_cbw->lun = lun;
+}
+
+static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer) ATTR_WARN_UNUSED_RESULT;
+static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer)
+{
+ if ( NULL != p_buffer)
+ { // there is data phase
+ if (p_msch->cbw.dir & TUSB_DIR_DEV_TO_HOST_MASK)
+ {
+ ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t), false) );
+ ASSERT_STATUS( hcd_pipe_queue_xfer(p_msch->bulk_in , p_buffer, p_msch->cbw.xfer_bytes) );
+ }else
+ {
+ ASSERT_STATUS( hcd_pipe_queue_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t)) );
+ ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out , p_buffer, p_msch->cbw.xfer_bytes, false) );
+ }
+ }
+
+ ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_in , (uint8_t*) &p_msch->csw, sizeof(msc_cmd_status_wrapper_t), true) );
+
+ return TUSB_ERROR_NONE;
+}
+
+tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
+{
+ msch_interface_t* p_msch = &msch_data[dev_addr-1];
+
+ //------------- Command Block Wrapper -------------//
+ msc_cbw_add_signature(&p_msch->cbw, lun);
+ p_msch->cbw.xfer_bytes = sizeof(scsi_inquiry_data_t);
+ p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
+ p_msch->cbw.cmd_len = sizeof(scsi_inquiry_t);
+
+ //------------- SCSI command -------------//
+ scsi_inquiry_t cmd_inquiry =
+ {
+ .cmd_code = SCSI_CMD_INQUIRY,
+ .alloc_length = sizeof(scsi_inquiry_data_t)
+ };
+
+ memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len);
+
+ ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) );
+
+ return TUSB_ERROR_NONE;
+}
+
+tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
+{
+ msch_interface_t* p_msch = &msch_data[dev_addr-1];
+
+ //------------- Command Block Wrapper -------------//
+ msc_cbw_add_signature(&p_msch->cbw, lun);
+ p_msch->cbw.xfer_bytes = sizeof(scsi_read_capacity10_data_t);
+ p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
+ p_msch->cbw.cmd_len = sizeof(scsi_read_capacity10_t);
+
+ //------------- SCSI command -------------//
+ scsi_read_capacity10_t cmd_read_capacity10 =
+ {
+ .cmd_code = SCSI_CMD_READ_CAPACITY_10,
+ .lba = 0,
+ .partial_medium_indicator = 0
+ };
+
+ memcpy(p_msch->cbw.command, &cmd_read_capacity10, p_msch->cbw.cmd_len);
+
+ ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) );
+
+ return TUSB_ERROR_NONE;
+}
+
+tusb_error_t tusbh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
+{
+ msch_interface_t* p_msch = &msch_data[dev_addr-1];
+
+ //------------- Command Block Wrapper -------------//
+ p_msch->cbw.xfer_bytes = 18;
+ p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
+ p_msch->cbw.cmd_len = sizeof(scsi_request_sense_t);
+
+ //------------- SCSI command -------------//
+ scsi_request_sense_t cmd_request_sense =
+ {
+ .cmd_code = SCSI_CMD_REQUEST_SENSE,
+ .alloc_length = 18
+ };
+
+ memcpy(p_msch->cbw.command, &cmd_request_sense, p_msch->cbw.cmd_len);
+
+ ASSERT_STATUS ( msch_command_xfer(p_msch, p_data) );
+
+ return TUSB_ERROR_NONE;
+}
+
+tusb_error_t tusbh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_cmd_status_wrapper_t * p_csw)
+{
+ msch_interface_t* p_msch = &msch_data[dev_addr-1];
+
+ //------------- Command Block Wrapper -------------//
+ msc_cbw_add_signature(&p_msch->cbw, lun);
+
+ p_msch->cbw.xfer_bytes = 0; // Number of bytes
+ p_msch->cbw.dir = TUSB_DIR_HOST_TO_DEV;
+ p_msch->cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
+
+ //------------- SCSI command -------------//
+ scsi_test_unit_ready_t cmd_test_unit_ready =
+ {
+ .cmd_code = SCSI_CMD_TEST_UNIT_READY,
+ .lun = lun // according to wiki
+ };
+
+ memcpy(p_msch->cbw.command, &cmd_test_unit_ready, p_msch->cbw.cmd_len);
+
+ // TODO MSCH refractor test uinit ready
+ ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cmd_block_wrapper_t), false) );
+ ASSERT_STATUS( hcd_pipe_xfer(p_msch->bulk_in , (uint8_t*) p_csw, sizeof(msc_cmd_status_wrapper_t), true) );
+
+ return TUSB_ERROR_NONE;
+}
+
+tusb_error_t tusbh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count)
+{
+ msch_interface_t* p_msch = &msch_data[dev_addr-1];
+
+ //------------- Command Block Wrapper -------------//
+ msc_cbw_add_signature(&p_msch->cbw, lun);
+
+ p_msch->cbw.xfer_bytes = p_msch->block_size*block_count; // Number of bytes
+ p_msch->cbw.dir = TUSB_DIR_DEV_TO_HOST_MASK;
+ p_msch->cbw.cmd_len = sizeof(scsi_read10_t);
+
+ //------------- SCSI command -------------//
+ scsi_read10_t cmd_read10 =
+ {
+ .cmd_code = SCSI_CMD_READ_10,
+ .lba = __n2be(lba),
+ .block_count = u16_le2be(block_count)
+ };
+
+ memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len);
+
+ ASSERT_STATUS ( msch_command_xfer(p_msch, p_buffer));
+
+ return TUSB_ERROR_NONE;
+}
+
+tusb_error_t tusbh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count)
+{
+ msch_interface_t* p_msch = &msch_data[dev_addr-1];
+
+ //------------- Command Block Wrapper -------------//
+ msc_cbw_add_signature(&p_msch->cbw, lun);
+
+ p_msch->cbw.xfer_bytes = p_msch->block_size*block_count; // Number of bytes
+ p_msch->cbw.dir = TUSB_DIR_HOST_TO_DEV;
+ p_msch->cbw.cmd_len = sizeof(scsi_write10_t);
+
+ //------------- SCSI command -------------//
+ scsi_write10_t cmd_write10 =
+ {
+ .cmd_code = SCSI_CMD_WRITE_10,
+ .lba = __n2be(lba),
+ .block_count = u16_le2be(block_count)
+ };
+
+ memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len);
+
+ ASSERT_STATUS ( msch_command_xfer(p_msch, (void*) p_buffer));
+
+ return TUSB_ERROR_NONE;
+}
+
+//--------------------------------------------------------------------+
+// CLASS-USBH API (don't require to verify parameters)
+//--------------------------------------------------------------------+
+void msch_init(void)
+{
+ memclr_(msch_data, sizeof(msch_interface_t)*TUSB_CFG_HOST_DEVICE_MAX);
+ msch_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(msch_semaphore) );
+}
+
+tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length)
+{
+ tusb_error_t error;
+
+ OSAL_SUBTASK_BEGIN
+
+ if (! ( MSC_SUBCLASS_SCSI == p_interface_desc->bInterfaceSubClass &&
+ MSC_PROTOCOL_BOT == p_interface_desc->bInterfaceProtocol ) )
+ {
+ return TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL;
+ }
+
+ //------------- Open Data Pipe -------------//
+ tusb_descriptor_endpoint_t const *p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_interface_desc );
+ for(uint32_t i=0; i<2; i++)
+ {
+ SUBTASK_ASSERT(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->bDescriptorType);
+ SUBTASK_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer);
+
+ pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_DEV_TO_HOST_MASK ) ?
+ &msch_data[dev_addr-1].bulk_in : &msch_data[dev_addr-1].bulk_out;
+
+ (*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_MSC);
+ SUBTASK_ASSERT( pipehandle_is_valid(*p_pipe_hdl) );
+
+ p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_endpoint );
+ }
+
+ msch_data[dev_addr-1].interface_number = p_interface_desc->bInterfaceNumber;
+ (*p_length) += sizeof(tusb_descriptor_interface_t) + 2*sizeof(tusb_descriptor_endpoint_t);
+
+
+ //------------- Get Max Lun -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE),
+ MSC_REQUEST_GET_MAX_LUN, 0, msch_data[dev_addr-1].interface_number,
+ 1, msch_buffer ),
+ error
+ );
+
+ SUBTASK_ASSERT( TUSB_ERROR_NONE == error /* && TODO STALL means zero */);
+ msch_data[dev_addr-1].max_lun = msch_buffer[0];
+
+#if 0
+ //------------- Reset -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_INTERFACE),
+ MSC_REQUEST_RESET, 0, msch_data[dev_addr-1].interface_number,
+ 0, NULL ),
+ error
+ );
+#endif
+
+ enum { SCSI_XFER_TIMEOUT = 2000 };
+ //------------- SCSI Inquiry -------------//
+ tusbh_msc_inquiry(dev_addr, 0, msch_buffer);
+ osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
+ SUBTASK_ASSERT_STATUS(error);
+
+ memcpy(msch_data[dev_addr-1].vendor_id , ((scsi_inquiry_data_t*) msch_buffer)->vendor_id , 8);
+ memcpy(msch_data[dev_addr-1].product_id, ((scsi_inquiry_data_t*) msch_buffer)->product_id, 16);
+
+ //------------- SCSI Read Capacity 10 -------------//
+ tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
+ osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
+ SUBTASK_ASSERT_STATUS(error);
+
+ // NOTE: my toshiba thumb-drive stall the first Read Capacity and require the sequence
+ // Read Capacity --> Stalled --> Clear Stall --> Request Sense --> Read Capacity (2) to work
+ if ( hcd_pipe_is_stalled(msch_data[dev_addr-1].bulk_in) )
+ { // clear stall TODO abstract clear stall function
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_ENDPOINT),
+ TUSB_REQUEST_CLEAR_FEATURE, 0, hcd_pipe_get_endpoint_addr(msch_data[dev_addr-1].bulk_in),
+ 0, NULL ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS(error);
+
+ hcd_pipe_clear_stall(msch_data[dev_addr-1].bulk_in);
+ osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error); // wait for SCSI status
+ SUBTASK_ASSERT_STATUS(error);
+
+ //------------- SCSI Request Sense -------------//
+ tusbh_msc_request_sense(dev_addr, 0, msch_buffer);
+ osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
+ SUBTASK_ASSERT_STATUS(error);
+
+ //------------- Re-read SCSI Read Capactity -------------//
+ tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer);
+ osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT, &error);
+ SUBTASK_ASSERT_STATUS(error);
+ }
+
+ msch_data[dev_addr-1].last_lba = __be2n( ((scsi_read_capacity10_data_t*)msch_buffer)->last_lba );
+ msch_data[dev_addr-1].block_size = (uint16_t) __be2n( ((scsi_read_capacity10_data_t*)msch_buffer)->block_size );
+
+ msch_data[dev_addr-1].is_initialized = true;
+ tusbh_msc_mounted_cb(dev_addr);
+
+ OSAL_SUBTASK_END
+}
+
+void msch_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
+{
+ if ( pipehandle_is_equal(pipe_hdl, msch_data[pipe_hdl.dev_addr-1].bulk_in) )
+ {
+ if (msch_data[pipe_hdl.dev_addr-1].is_initialized)
+ {
+ tusbh_msc_isr(pipe_hdl.dev_addr, event, xferred_bytes);
+ }else
+ { // still initializing under open subtask
+ osal_semaphore_post(msch_sem_hdl);
+ }
+ }
+}
+
+void msch_close(uint8_t dev_addr)
+{
+ (void) hcd_pipe_close(msch_data[dev_addr-1].bulk_in);
+ (void) hcd_pipe_close(msch_data[dev_addr-1].bulk_out);
+
+ memclr_(&msch_data[dev_addr-1], sizeof(msch_interface_t));
+ osal_semaphore_reset(msch_sem_hdl);
+
+ tusbh_msc_unmounted_cb(dev_addr); // invoke Application Callback
+}
+
+//--------------------------------------------------------------------+
+// INTERNAL & HELPER
+//--------------------------------------------------------------------+
+
+
+#endif
|
