From 9ba209cda074289bbbe51dc79b4231404c8089ba Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 12 Mar 2014 14:08:52 +0700 Subject: IAR line ending warning --- tinyusb/class/msc_device.c | 12 +- tinyusb/class/msc_host.c | 858 ++++++++++++++++++++++----------------------- 2 files changed, 434 insertions(+), 436 deletions(-) (limited to 'tinyusb/class') 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 -- cgit v1.3.1