2907 lines
132 KiB
C
2907 lines
132 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/USB-Host
|
|
* The Embedded USB Host Stack
|
|
*
|
|
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
|
|
*
|
|
* SPDX-License-Identifier: APACHE-2.0
|
|
*
|
|
* This software is subject to an open source license and is distributed by
|
|
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
|
|
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* NOTICE
|
|
*
|
|
* Semidrive modified this file to adapt it for ssdk platform.
|
|
* The modifications are only intended for use with Semidrive chips.
|
|
* Copyright of all the modifications belongs to Semidrive Semiconductor.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* MASS STORAGE CLASS (MSC)
|
|
*
|
|
* Filename : usbh_msc.c
|
|
* Version : V3.42.01
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_MODULE
|
|
#define MICRIUM_SOURCE
|
|
#include "usbh_msc.h"
|
|
#include "../../Source/usbh_core.h"
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* MODULE
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_SIG_CBW 0x43425355u
|
|
#define USBH_MSC_SIG_CSW 0x53425355u
|
|
|
|
#define USBH_MSC_LEN_CBW 31u
|
|
#define USBH_MSC_LEN_CSW 13u
|
|
|
|
#define USBH_MSC_MAX_TRANSFER_RETRY 1000u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* SUBCLASS CODES
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class Specification Overview', Revision 1.2, Section 2.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_SUBCLASS_CODE_RBC 0x01u
|
|
#define USBH_MSC_SUBCLASS_CODE_SFF_8020i 0x02u
|
|
#define USBH_MSC_SUBCLASS_CODE_MMC_2 0x02u
|
|
#define USBH_MSC_SUBCLASS_CODE_QIC_157 0x03u
|
|
#define USBH_MSC_SUBCLASS_CODE_UFI 0x04u
|
|
#define USBH_MSC_SUBCLASS_CODE_SFF_8070i 0x05u
|
|
#define USBH_MSC_SUBCLASS_CODE_SCSI 0x06u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* PROTOCOL CODES
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class Specification Overview', Revision 1.2, Section 3.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_PROTOCOL_CODE_CTRL_BULK_INTR_CMD_INTR 0x00u
|
|
#define USBH_MSC_PROTOCOL_CODE_CTRL_BULK_INTR 0x01u
|
|
#define USBH_MSC_PROTOCOL_CODE_BULK_ONLY 0x50u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* CLASS-SPECIFIC REQUESTS
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class - Bulk Only Transport', Section 3.
|
|
*
|
|
* (2) The 'bRequest' field of a class-specific setup request may contain one of these values.
|
|
*
|
|
* (3) The mass storage reset request is "used to reset the mass storage device and its
|
|
* associated interface". The setup request packet will consist of :
|
|
*
|
|
* (a) bmRequestType = 00100001b (class, interface, host-to-device)
|
|
* (b) bRequest = 0xFF
|
|
* (c) wValue = 0x0000
|
|
* (d) wIndex = Interface number
|
|
* (e) wLength = 0x0000
|
|
*
|
|
* (4) The get max LUN is used to determine the number of LUN's supported by the device. The
|
|
* setup request packet will consist of :
|
|
*
|
|
* (a) bmRequestType = 10100001b (class, interface, device-to-host)
|
|
* (b) bRequest = 0xFE
|
|
* (c) wValue = 0x0000
|
|
* (d) wIndex = Interface number
|
|
* (e) wLength = 0x0001
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_REQ_MASS_STORAGE_RESET 0xFFu /* See Note #3. */
|
|
#define USBH_MSC_REQ_GET_MAX_LUN 0xFEu /* See Note #4. */
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* COMMAND BLOCK FLAG VALUES
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class - Bulk Only Transport', Section 5.1.
|
|
*
|
|
* (2) The 'bmCBWFlags' field of a command block wrapper may contain one of these values.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_BMCBWFLAGS_DIR_HOST_TO_DEVICE 0x00u
|
|
#define USBH_MSC_BMCBWFLAGS_DIR_DEVICE_TO_HOST 0x80u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* COMMAND BLOCK STATUS VALUES
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class - Bulk Only Transport', Section 5.3, Table 5.3.
|
|
*
|
|
* (2) The 'bCSWStatus' field of a command status wrapper may contain one of these values.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBH_MSC_BCSWSTATUS_CMD_PASSED 0x00u
|
|
#define USBH_MSC_BCSWSTATUS_CMD_FAILED 0x01u
|
|
#define USBH_MSC_BCSWSTATUS_PHASE_ERROR 0x02u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* SCSI DEFINES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* ------------------ SCSI OPCODES ------------------------ */
|
|
#define USBH_SCSI_CMD_TEST_UNIT_READY 0x00u
|
|
#define USBH_SCSI_CMD_REWIND 0x01u
|
|
#define USBH_SCSI_CMD_REZERO_UNIT 0x01u
|
|
#define USBH_SCSI_CMD_REQUEST_SENSE 0x03u
|
|
#define USBH_SCSI_CMD_FORMAT_UNIT 0x04u
|
|
#define USBH_SCSI_CMD_FORMAT_MEDIUM 0x04u
|
|
#define USBH_SCSI_CMD_FORMAT 0x04u
|
|
#define USBH_SCSI_CMD_READ_BLOCK_LIMITS 0x05u
|
|
#define USBH_SCSI_CMD_REASSIGN_BLOCKS 0x07u
|
|
#define USBH_SCSI_CMD_INITIALIZE_ELEMENT_STATUS 0x07u
|
|
#define USBH_SCSI_CMD_READ_06 0x08u
|
|
#define USBH_SCSI_CMD_RECEIVE 0x08u
|
|
#define USBH_SCSI_CMD_GET_MESSAGE_06 0x08u
|
|
#define USBH_SCSI_CMD_WRITE_06 0x0Au
|
|
#define USBH_SCSI_CMD_SEND_06 0x0Au
|
|
#define USBH_SCSI_CMD_SEND_MESSAGE_06 0x0Au
|
|
#define USBH_SCSI_CMD_PRINT 0x0Au
|
|
#define USBH_SCSI_CMD_SEEK_06 0x0Bu
|
|
#define USBH_SCSI_CMD_SET_CAPACITY 0x0Bu
|
|
#define USBH_SCSI_CMD_SLEW_AND_PRINT 0x0Bu
|
|
#define USBH_SCSI_CMD_READ_REVERSE_06 0x0Fu
|
|
|
|
#define USBH_SCSI_CMD_WRITE_FILEMARKS_06 0x10u
|
|
#define USBH_SCSI_CMD_SYNCHRONIZE_BUFFER 0x10u
|
|
#define USBH_SCSI_CMD_SPACE_06 0x11u
|
|
#define USBH_SCSI_CMD_INQUIRY 0x12u
|
|
#define USBH_SCSI_CMD_VERIFY_06 0x13u
|
|
#define USBH_SCSI_CMD_RECOVER_BUFFERED_DATA 0x14u
|
|
#define USBH_SCSI_CMD_MODE_SELECT_06 0x15u
|
|
#define USBH_SCSI_CMD_RESERVE_06 0x16u
|
|
#define USBH_SCSI_CMD_RESERVE_ELEMENT_06 0x16u
|
|
#define USBH_SCSI_CMD_RELEASE_06 0x17u
|
|
#define USBH_SCSI_CMD_RELEASE_ELEMENT_06 0x17u
|
|
#define USBH_SCSI_CMD_COPY 0x18u
|
|
#define USBH_SCSI_CMD_ERASE_06 0x19u
|
|
#define USBH_SCSI_CMD_MODE_SENSE_06 0x1Au
|
|
#define USBH_SCSI_CMD_START_STOP_UNIT 0x1Bu
|
|
#define USBH_SCSI_CMD_LOAD_UNLOAD 0x1Bu
|
|
#define USBH_SCSI_CMD_SCAN_06 0x1Bu
|
|
#define USBH_SCSI_CMD_STOP_PRINT 0x1Bu
|
|
#define USBH_SCSI_CMD_OPEN_CLOSE_IMPORT_EXPORT_ELEMENT 0x1Bu
|
|
#define USBH_SCSI_CMD_RECEIVE_DIAGNOSTIC_RESULTS 0x1Cu
|
|
#define USBH_SCSI_CMD_SEND_DIAGNOSTIC 0x1Du
|
|
#define USBH_SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1Eu
|
|
|
|
#define USBH_SCSI_CMD_READ_FORMAT_CAPACITIES 0x23u
|
|
#define USBH_SCSI_CMD_SET_WINDOW 0x24u
|
|
#define USBH_SCSI_CMD_READ_CAPACITY_10 0x25u
|
|
#define USBH_SCSI_CMD_READ_CAPACITY 0x25u
|
|
#define USBH_SCSI_CMD_READ_CARD_CAPACITY 0x25u
|
|
#define USBH_SCSI_CMD_GET_WINDOW 0x25u
|
|
#define USBH_SCSI_CMD_READ_10 0x28u
|
|
#define USBH_SCSI_CMD_GET_MESSAGE_10 0x28u
|
|
#define USBH_SCSI_CMD_READ_GENERATION 0x29u
|
|
#define USBH_SCSI_CMD_WRITE_10 0x2Au
|
|
#define USBH_SCSI_CMD_SEND_10 0x2Au
|
|
#define USBH_SCSI_CMD_SEND_MESSAGE_10 0x2Au
|
|
#define USBH_SCSI_CMD_SEEK_10 0x2Bu
|
|
#define USBH_SCSI_CMD_LOCATE_10 0x2Bu
|
|
#define USBH_SCSI_CMD_POSITION_TO_ELEMENT 0x2Bu
|
|
#define USBH_SCSI_CMD_ERASE_10 0x2Cu
|
|
#define USBH_SCSI_CMD_READ_UPDATED_BLOCK 0x2Du
|
|
#define USBH_SCSI_CMD_WRITE_AND_VERIFY_10 0x2Eu
|
|
#define USBH_SCSI_CMD_VERIFY_10 0x2Fu
|
|
|
|
#define USBH_SCSI_CMD_SEARCH_DATA_HIGH_10 0x30u
|
|
#define USBH_SCSI_CMD_SEARCH_DATA_EQUAL_10 0x31u
|
|
#define USBH_SCSI_CMD_OBJECT_POSITION 0x31u
|
|
#define USBH_SCSI_CMD_SEARCH_DATA_LOW_10 0x32u
|
|
#define USBH_SCSI_CMD_SET_LIMITS_10 0x33u
|
|
#define USBH_SCSI_CMD_PRE_FETCH_10 0x34u
|
|
#define USBH_SCSI_CMD_READ_POSITION 0x34u
|
|
#define USBH_SCSI_CMD_GET_DATA_BUFFER_STATUS 0x34u
|
|
#define USBH_SCSI_CMD_SYNCHRONIZE_CACHE_10 0x35u
|
|
#define USBH_SCSI_CMD_LOCK_UNLOCK_CACHE_10 0x36u
|
|
#define USBH_SCSI_CMD_READ_DEFECT_DATA_10 0x37u
|
|
#define USBH_SCSI_CMD_INIT_ELEMENT_STATUS_WITH_RANGE 0x37u
|
|
#define USBH_SCSI_CMD_MEDIUM_SCAN 0x38u
|
|
#define USBH_SCSI_CMD_COMPARE 0x39u
|
|
#define USBH_SCSI_CMD_COPY_AND_VERIFY 0x3Au
|
|
#define USBH_SCSI_CMD_WRITE_BUFFER 0x3Bu
|
|
#define USBH_SCSI_CMD_READ_BUFFER 0x3Cu
|
|
#define USBH_SCSI_CMD_UPDATE_BLOCK 0x3Du
|
|
#define USBH_SCSI_CMD_READ_LONG_10 0x3Eu
|
|
#define USBH_SCSI_CMD_WRITE_LONG_10 0x3Fu
|
|
|
|
#define USBH_SCSI_CMD_CHANGE_DEFINITION 0x40u
|
|
#define USBH_SCSI_CMD_WRITE_SAME_10 0x41u
|
|
#define USBH_SCSI_CMD_READ_SUBCHANNEL 0x42u
|
|
#define USBH_SCSI_CMD_READ_TOC_PMA_ATIP 0x43u
|
|
#define USBH_SCSI_CMD_REPORT_DENSITY_SUPPORT 0x44u
|
|
#define USBH_SCSI_CMD_READ_HEADER 0x44u
|
|
#define USBH_SCSI_CMD_PLAY_AUDIO_10 0x45u
|
|
#define USBH_SCSI_CMD_GET_CONFIGURATION 0x46u
|
|
#define USBH_SCSI_CMD_PLAY_AUDIO_MSF 0x47u
|
|
#define USBH_SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4Au
|
|
#define USBH_SCSI_CMD_PAUSE_RESUME 0x4Bu
|
|
#define USBH_SCSI_CMD_LOG_SELECT 0x4Cu
|
|
#define USBH_SCSI_CMD_LOG_SENSE 0x4Du
|
|
#define USBH_SCSI_CMD_STOP_PLAY_SCAN 0x4Eu
|
|
|
|
#define USBH_SCSI_CMD_XDWRITE_10 0x50u
|
|
#define USBH_SCSI_CMD_XPWRITE_10 0x51u
|
|
#define USBH_SCSI_CMD_READ_DISC_INFORMATION 0x51u
|
|
#define USBH_SCSI_CMD_XDREAD_10 0x52u
|
|
#define USBH_SCSI_CMD_READ_TRACK_INFORMATION 0x52u
|
|
#define USBH_SCSI_CMD_RESERVE_TRACK 0x53u
|
|
#define USBH_SCSI_CMD_SEND_OPC_INFORMATION 0x54u
|
|
#define USBH_SCSI_CMD_MODE_SELECT_10 0x55u
|
|
#define USBH_SCSI_CMD_RESERVE_10 0x56u
|
|
#define USBH_SCSI_CMD_RESERVE_ELEMENT_10 0x56u
|
|
#define USBH_SCSI_CMD_RELEASE_10 0x57u
|
|
#define USBH_SCSI_CMD_RELEASE_ELEMENT_10 0x57u
|
|
#define USBH_SCSI_CMD_REPAIR_TRACK 0x58u
|
|
#define USBH_SCSI_CMD_MODE_SENSE_10 0x5Au
|
|
#define USBH_SCSI_CMD_CLOSE_TRACK_SESSION 0x5Bu
|
|
#define USBH_SCSI_CMD_READ_BUFFER_CAPACITY 0x5Cu
|
|
#define USBH_SCSI_CMD_SEND_CUE_SHEET 0x5Du
|
|
#define USBH_SCSI_CMD_PERSISTENT_RESERVE_IN 0x5Eu
|
|
#define USBH_SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5Fu
|
|
|
|
#define USBH_SCSI_CMD_EXTENDED_CDB 0x7Eu
|
|
#define USBH_SCSI_CMD_VARIABLE_LENGTH_CDB 0x7Fu
|
|
|
|
#define USBH_SCSI_CMD_XDWRITE_EXTENDED_16 0x80u
|
|
#define USBH_SCSI_CMD_WRITE_FILEMARKS_16 0x80u
|
|
#define USBH_SCSI_CMD_REBUILD_16 0x81u
|
|
#define USBH_SCSI_CMD_READ_REVERSE_16 0x81u
|
|
#define USBH_SCSI_CMD_REGENERATE_16 0x82u
|
|
#define USBH_SCSI_CMD_EXTENDED_COPY 0x83u
|
|
#define USBH_SCSI_CMD_RECEIVE_COPY_RESULTS 0x84u
|
|
#define USBH_SCSI_CMD_ATA_COMMAND_PASS_THROUGH_16 0x85u
|
|
#define USBH_SCSI_CMD_ACCESS_CONTROL_IN 0x86u
|
|
#define USBH_SCSI_CMD_ACCESS_CONTROL_OUT 0x87u
|
|
#define USBH_SCSI_CMD_READ_16 0x88u
|
|
#define USBH_SCSI_CMD_WRITE_16 0x8Au
|
|
#define USBH_SCSI_CMD_ORWRITE 0x8Bu
|
|
#define USBH_SCSI_CMD_READ_ATTRIBUTE 0x8Cu
|
|
#define USBH_SCSI_CMD_WRITE_ATTRIBUTE 0x8Du
|
|
#define USBH_SCSI_CMD_WRITE_AND_VERIFY_16 0x8Eu
|
|
#define USBH_SCSI_CMD_VERIFY_16 0x8Fu
|
|
|
|
#define USBH_SCSI_CMD_PREFETCH_16 0x90u
|
|
#define USBH_SCSI_CMD_SYNCHRONIZE_CACHE_16 0x91u
|
|
#define USBH_SCSI_CMD_SPACE_16 0x91u
|
|
#define USBH_SCSI_CMD_LOCK_UNLOCK_CACHE_16 0x92u
|
|
#define USBH_SCSI_CMD_LOCATE_16 0x92u
|
|
#define USBH_SCSI_CMD_WRITE_SAME_16 0x93u
|
|
#define USBH_SCSI_CMD_ERASE_16 0x93u
|
|
#define USBH_SCSI_CMD_SERVICE_ACTION_IN_16 0x9Eu
|
|
#define USBH_SCSI_CMD_SERVICE_ACTION_OUT_16 0x9Fu
|
|
|
|
#define USBH_SCSI_CMD_REPORT_LUNS 0xA0u
|
|
#define USBH_SCSI_CMD_BLANK 0xA1u
|
|
#define USBH_SCSI_CMD_ATA_COMMAND_PASS_THROUGH_12 0xA1u
|
|
#define USBH_SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2u
|
|
#define USBH_SCSI_CMD_MAINTENANCE_IN 0xA3u
|
|
#define USBH_SCSI_CMD_SEND_KEY 0xA3u
|
|
#define USBH_SCSI_CMD_MAINTENANCE_OUT 0xA4u
|
|
#define USBH_SCSI_CMD_REPORT_KEY 0xA4u
|
|
#define USBH_SCSI_CMD_MOVE_MEDIUM 0xA5u
|
|
#define USBH_SCSI_CMD_PLAY_AUDIO_12 0xA5u
|
|
#define USBH_SCSI_CMD_EXCHANGE_MEDIUM 0xA6u
|
|
#define USBH_SCSI_CMD_LOAD_UNLOAD_CDVD 0xA6u
|
|
#define USBH_SCSI_CMD_MOVE_MEDIUM_ATTACHED 0xA7u
|
|
#define USBH_SCSI_CMD_SET_READ_AHEAD 0xA7u
|
|
#define USBH_SCSI_CMD_READ_12 0xA8u
|
|
#define USBH_SCSI_CMD_GET_MESSAGE_12 0xA8u
|
|
#define USBH_SCSI_CMD_SERVICE_ACTION_OUT_12 0xA9u
|
|
#define USBH_SCSI_CMD_WRITE_12 0xAAu
|
|
#define USBH_SCSI_CMD_SEND_MESSAGE_12 0xAAu
|
|
#define USBH_SCSI_CMD_SERVICE_ACTION_IN_12 0xABu
|
|
#define USBH_SCSI_CMD_ERASE_12 0xACu
|
|
#define USBH_SCSI_CMD_GET_PERFORMANCE 0xACu
|
|
#define USBH_SCSI_CMD_READ_DVD_STRUCTURE 0xADu
|
|
#define USBH_SCSI_CMD_WRITE_AND_VERIFY_12 0xAEu
|
|
#define USBH_SCSI_CMD_VERIFY_12 0xAFu
|
|
|
|
#define USBH_SCSI_CMD_SEARCH_DATA_HIGH_12 0xB0u
|
|
#define USBH_SCSI_CMD_SEARCH_DATA_EQUAL_12 0xB1u
|
|
#define USBH_SCSI_CMD_SEARCH_DATA_LOW_12 0xB2u
|
|
#define USBH_SCSI_CMD_SET_LIMITS_12 0xB3u
|
|
#define USBH_SCSI_CMD_READ_ELEMENT_STATUS_ATTACHED 0xB4u
|
|
#define USBH_SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5u
|
|
#define USBH_SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDRESS 0xB5u
|
|
#define USBH_SCSI_CMD_SEND_VOLUME_TAG 0xB6u
|
|
#define USBH_SCSI_CMD_SET_STREAMING 0xB6u
|
|
#define USBH_SCSI_CMD_READ_DEFECT_DATA_12 0xB7u
|
|
#define USBH_SCSI_CMD_READ_ELEMENT_STATUS 0xB8u
|
|
#define USBH_SCSI_CMD_READ_CD_MSF 0xB9u
|
|
#define USBH_SCSI_CMD_REDUNDANCY_GROUP_IN 0xBAu
|
|
#define USBH_SCSI_CMD_SCAN 0xBAu
|
|
#define USBH_SCSI_CMD_REDUNDANCY_GROUP_OUT 0xBBu
|
|
#define USBH_SCSI_CMD_SET_CD_SPEED 0xBBu
|
|
#define USBH_SCSI_CMD_SPARE_IN 0xBCu
|
|
#define USBH_SCSI_CMD_SPARE_OUT 0xBDu
|
|
#define USBH_SCSI_CMD_MECHANISM_STATUS 0xBDu
|
|
#define USBH_SCSI_CMD_VOLUME_SET_IN 0xBEu
|
|
#define USBH_SCSI_CMD_READ_CD 0xBEu
|
|
#define USBH_SCSI_CMD_VOLUME_SET_OUT 0xBFu
|
|
#define USBH_SCSI_CMD_SEND_DVD_STRUCTURE 0xBFu
|
|
|
|
/* ------------------- SCSI STATUS CODES ------------------ */
|
|
#define USBH_SCSI_STATUS_GOOD 0x00u
|
|
#define USBH_SCSI_STATUS_CHECK_CONDITION 0x02u
|
|
#define USBH_SCSI_STATUS_CONDITION_MET 0x04u
|
|
#define USBH_SCSI_STATUS_BUSY 0x08u
|
|
#define USBH_SCSI_STATUS_RESERVATION_CONFLICT 0x18u
|
|
#define USBH_SCSI_STATUS_TASK_SET_FULL 0x28u
|
|
#define USBH_SCSI_STATUS_ACA_ACTIVE 0x30u
|
|
#define USBH_SCSI_STATUS_TASK_ABORTED 0x40u
|
|
|
|
/* ------------------- SCSI SENSE KEYS -------------------- */
|
|
#define USBH_SCSI_SENSE_KEY_NO_SENSE 0x00u
|
|
#define USBH_SCSI_SENSE_KEY_RECOVERED_ERROR 0x01u
|
|
#define USBH_SCSI_SENSE_KEY_NOT_RDY 0x02u
|
|
#define USBH_SCSI_SENSE_KEY_MEDIUM_ERROR 0x03u
|
|
#define USBH_SCSI_SENSE_KEY_HARDWARE_ERROR 0x04u
|
|
#define USBH_SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05u
|
|
#define USBH_SCSI_SENSE_KEY_UNIT_ATTENTION 0x06u
|
|
#define USBH_SCSI_SENSE_KEY_DATA_PROTECT 0x07u
|
|
#define USBH_SCSI_SENSE_KEY_BLANK_CHECK 0x08u
|
|
#define USBH_SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09u
|
|
#define USBH_SCSI_SENSE_KEY_COPY_ABORTED 0x0Au
|
|
#define USBH_SCSI_SENSE_KEY_ABORTED_COMMAND 0x0Bu
|
|
#define USBH_SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0Du
|
|
#define USBH_SCSI_SENSE_KEY_MISCOMPARE 0x0Eu
|
|
|
|
/* ------------- SCSI ADDITIONAL SENSE CODES -------------- */
|
|
#define USBH_SCSI_ASC_NO_ADDITIONAL_SENSE_INFO 0x00u
|
|
#define USBH_SCSI_ASC_NO_INDEX_SECTOR_SIGNAL 0x01u
|
|
#define USBH_SCSI_ASC_NO_SEEK_COMPLETE 0x02u
|
|
#define USBH_SCSI_ASC_PERIPHERAL_DEV_WR_FAULT 0x03u
|
|
#define USBH_SCSI_ASC_LOG_UNIT_NOT_RDY 0x04u
|
|
#define USBH_SCSI_ASC_LOG_UNIT_NOT_RESPOND_TO_SELECTION 0x05u
|
|
#define USBH_SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06u
|
|
#define USBH_SCSI_ASC_MULTIPLE_PERIPHERAL_DEVS_SELECTED 0x07u
|
|
#define USBH_SCSI_ASC_LOG_UNIT_COMMUNICATION_FAIL 0x08u
|
|
#define USBH_SCSI_ASC_TRACK_FOLLOWING_ERR 0x09u
|
|
#define USBH_SCSI_ASC_ERR_LOG_OVERFLOW 0x0Au
|
|
#define USBH_SCSI_ASC_WARNING 0x0Bu
|
|
#define USBH_SCSI_ASC_WR_ERR 0x0Cu
|
|
#define USBH_SCSI_ASC_ERR_DETECTED_BY_THIRD_PARTY 0x0Du
|
|
#define USBH_SCSI_ASC_INVALID_INFO_UNIT 0x0Eu
|
|
|
|
#define USBH_SCSI_ASC_ID_CRC_OR_ECC_ERR 0x10u
|
|
#define USBH_SCSI_ASC_UNRECOVERED_RD_ERR 0x11u
|
|
#define USBH_SCSI_ASC_ADDR_MARK_NOT_FOUND_FOR_ID 0x12u
|
|
#define USBH_SCSI_ASC_ADDR_MARK_NOT_FOUND_FOR_DATA 0x13u
|
|
#define USBH_SCSI_ASC_RECORDED_ENTITY_NOT_FOUND 0x14u
|
|
#define USBH_SCSI_ASC_RANDOM_POSITIONING_ERR 0x15u
|
|
#define USBH_SCSI_ASC_DATA_SYNCHRONIZATION_MARK_ERR 0x16u
|
|
#define USBH_SCSI_ASC_RECOVERED_DATA_NO_ERR_CORRECT 0x17u
|
|
#define USBH_SCSI_ASC_RECOVERED_DATA_ERR_CORRECT 0x18u
|
|
#define USBH_SCSI_ASC_DEFECT_LIST_ERR 0x19u
|
|
#define USBH_SCSI_ASC_PARAMETER_LIST_LENGTH_ERR 0x1Au
|
|
#define USBH_SCSI_ASC_SYNCHRONOUS_DATA_TRANSFER_ERR 0x1Bu
|
|
#define USBH_SCSI_ASC_DEFECT_LIST_NOT_FOUND 0x1Cu
|
|
#define USBH_SCSI_ASC_MISCOMPARE_DURING_VERIFY_OP 0x1Du
|
|
#define USBH_SCSI_ASC_RECOVERED_ID_WITH_ECC_CORRECTION 0x1Eu
|
|
#define USBH_SCSI_ASC_PARTIAL_DEFECT_LIST_TRANSFER 0x1Fu
|
|
|
|
#define USBH_SCSI_ASC_INVALID_CMD_OP_CODE 0x20u
|
|
#define USBH_SCSI_ASC_LOG_BLOCK_ADDR_OUT_OF_RANGE 0x21u
|
|
#define USBH_SCSI_ASC_ILLEGAL_FUNCTION 0x22u
|
|
#define USBH_SCSI_ASC_INVALID_FIELD_IN_CDB 0x24u
|
|
#define USBH_SCSI_ASC_LOG_UNIT_NOT_SUPPORTED 0x25u
|
|
#define USBH_SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26u
|
|
#define USBH_SCSI_ASC_WR_PROTECTED 0x27u
|
|
#define USBH_SCSI_ASC_NOT_RDY_TO_RDY_CHANGE 0x28u
|
|
#define USBH_SCSI_ASC_POWER_ON_OR_BUS_DEV_RESET 0x29u
|
|
#define USBH_SCSI_ASC_PARAMETERS_CHANGED 0x2Au
|
|
#define USBH_SCSI_ASC_CANNOT_COPY_CANNOT_DISCONNECT 0x2Bu
|
|
#define USBH_SCSI_ASC_CMD_SEQUENCE_ERR 0x2Cu
|
|
#define USBH_SCSI_ASC_OVERWR_ERR_ON_UPDATE_IN_PLACE 0x2Du
|
|
#define USBH_SCSI_ASC_INSUFFICIENT_TIME_FOR_OP 0x2Eu
|
|
#define USBH_SCSI_ASC_CMDS_CLEARED_BY_ANOTHER_INIT 0x2Fu
|
|
|
|
#define USBH_SCSI_ASC_INCOMPATIBLE_MEDIUM_INSTALLED 0x30u
|
|
#define USBH_SCSI_ASC_MEDIUM_FORMAT_CORRUPTED 0x31u
|
|
#define USBH_SCSI_ASC_NO_DEFECT_SPARE_LOCATION_AVAIL 0x32u
|
|
#define USBH_SCSI_ASC_TAPE_LENGTH_ERR 0x33u
|
|
#define USBH_SCSI_ASC_ENCLOSURE_FAIL 0x34u
|
|
#define USBH_SCSI_ASC_ENCLOSURE_SERVICES_FAIL 0x35u
|
|
#define USBH_SCSI_ASC_RIBBON_INK_OR_TONER_FAIL 0x36u
|
|
#define USBH_SCSI_ASC_ROUNDED_PARAMETER 0x37u
|
|
#define USBH_SCSI_ASC_EVENT_STATUS_NOTIFICATION 0x38u
|
|
#define USBH_SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39u
|
|
#define USBH_SCSI_ASC_MEDIUM_NOT_PRESENT 0x3Au
|
|
#define USBH_SCSI_ASC_SEQUENTIAL_POSITIONING_ERR 0x3Bu
|
|
#define USBH_SCSI_ASC_INVALID_BITS_IN_IDENTIFY_MSG 0x3Du
|
|
#define USBH_SCSI_ASC_LOG_UNIT_HAS_NOT_SELF_CFG_YET 0x3Eu
|
|
#define USBH_SCSI_ASC_TARGET_OP_CONDITIONS_HAVE_CHANGED 0x3Fu
|
|
|
|
#define USBH_SCSI_ASC_RAM_FAIL 0x40u
|
|
#define USBH_SCSI_ASC_DATA_PATH_FAIL 0x41u
|
|
#define USBH_SCSI_ASC_POWER_ON_SELF_TEST_FAIL 0x42u
|
|
#define USBH_SCSI_ASC_MSG_ERR 0x43u
|
|
#define USBH_SCSI_ASC_INTERNAL_TARGET_FAIL 0x44u
|
|
#define USBH_SCSI_ASC_SELECT_OR_RESELECT_FAIL 0x45u
|
|
#define USBH_SCSI_ASC_UNSUCCESSFUL_SOFT_RESET 0x46u
|
|
#define USBH_SCSI_ASC_SCSI_PARITY_ERR 0x47u
|
|
#define USBH_SCSI_ASC_INIT_DETECTED_ERR_MSG_RECEIVED 0x48u
|
|
#define USBH_SCSI_ASC_INVALID_MSG_ERR 0x49u
|
|
#define USBH_SCSI_ASC_CMD_PHASE_ERR 0x4Au
|
|
#define USBH_SCSI_ASC_DATA_PHASE_ERR 0x4Bu
|
|
#define USBH_SCSI_ASC_LOG_UNIT_FAILED_SELF_CFG 0x4Cu
|
|
#define USBH_SCSI_ASC_OVERLAPPED_CMDS_ATTEMPTED 0x4Eu
|
|
|
|
#define USBH_SCSI_ASC_WR_APPEND_ERR 0x50u
|
|
#define USBH_SCSI_ASC_ERASE_FAIL 0x51u
|
|
#define USBH_SCSI_ASC_CARTRIDGE_FAULT 0x52u
|
|
#define USBH_SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED 0x53u
|
|
#define USBH_SCSI_ASC_SCSI_TO_HOST_SYSTEM_IF_FAIL 0x54u
|
|
#define USBH_SCSI_ASC_SYSTEM_RESOURCE_FAIL 0x55u
|
|
#define USBH_SCSI_ASC_UNABLE_TO_RECOVER_TOC 0x57u
|
|
#define USBH_SCSI_ASC_GENERATION_DOES_NOT_EXIST 0x58u
|
|
#define USBH_SCSI_ASC_UPDATED_BLOCK_RD 0x59u
|
|
#define USBH_SCSI_ASC_OP_REQUEST_OR_STATE_CHANGE_INPUT 0x5Au
|
|
#define USBH_SCSI_ASC_LOG_EXCEPT 0x5Bu
|
|
#define USBH_SCSI_ASC_RPL_STATUS_CHANGE 0x5Cu
|
|
#define USBH_SCSI_ASC_FAIL_PREDICTION_TH_EXCEEDED 0x5Du
|
|
#define USBH_SCSI_ASC_LOW_POWER_CONDITION_ON 0x5Eu
|
|
|
|
#define USBH_SCSI_ASC_LAMP_FAIL 0x60u
|
|
#define USBH_SCSI_ASC_VIDEO_ACQUISITION_ERR 0x61u
|
|
#define USBH_SCSI_ASC_SCAN_HEAD_POSITIONING_ERR 0x62u
|
|
#define USBH_SCSI_ASC_END_OF_USER_AREA_ENCOUNTERED 0x63u
|
|
#define USBH_SCSI_ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64u
|
|
#define USBH_SCSI_ASC_VOLTAGE_FAULT 0x65u
|
|
#define USBH_SCSI_ASC_AUTO_DOCUMENT_FEEDER_COVER_UP 0x66u
|
|
#define USBH_SCSI_ASC_CONFIGURATION_FAIL 0x67u
|
|
#define USBH_SCSI_ASC_LOG_UNIT_NOT_CONFIGURED 0x68u
|
|
#define USBH_SCSI_ASC_DATA_LOSS_ON_LOG_UNIT 0x69u
|
|
#define USBH_SCSI_ASC_INFORMATIONAL_REFER_TO_LOG 0x6Au
|
|
#define USBH_SCSI_ASC_STATE_CHANGE_HAS_OCCURRED 0x6Bu
|
|
#define USBH_SCSI_ASC_REBUILD_FAIL_OCCURRED 0x6Cu
|
|
#define USBH_SCSI_ASC_RECALCULATE_FAIL_OCCURRED 0x6Du
|
|
#define USBH_SCSI_ASC_CMD_TO_LOG_UNIT_FAILED 0x6Eu
|
|
#define USBH_SCSI_ASC_COPY_PROTECTION_KEY_EXCHANGE_FAIL 0x6Fu
|
|
#define USBH_SCSI_ASC_DECOMPRESSION_EXCEPT_LONG_ALGO_ID 0x71u
|
|
#define USBH_SCSI_ASC_SESSION_FIXATION_ERR 0x72u
|
|
#define USBH_SCSI_ASC_CD_CONTROL_ERR 0x73u
|
|
#define USBH_SCSI_ASC_SECURITY_ERR 0x74u
|
|
|
|
/* ----------------- SCSI PAGE PARAMETERS ----------------- */
|
|
#define USBH_SCSI_PAGE_CODE_READ_WRITE_ERROR_RECOVERY 0x01u
|
|
#define USBH_SCSI_PAGE_CODE_FORMAT_DEVICE 0x03u
|
|
#define USBH_SCSI_PAGE_CODE_FLEXIBLE_DISK 0x05u
|
|
#define USBH_SCSI_PAGE_CODE_INFORMATIONAL_EXCEPTIONS 0x1Cu
|
|
#define USBH_SCSI_PAGE_CODE_ALL 0x3Fu
|
|
|
|
#define USBH_SCSI_PAGE_LENGTH_INFORMATIONAL_EXCEPTIONS 0x0Au
|
|
#define USBH_SCSI_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY 0x0Au
|
|
#define USBH_SCSI_PAGE_LENGTH_FLEXIBLE_DISK 0x1Eu
|
|
#define USBH_SCSI_PAGE_LENGTH_FORMAT_DEVICE 0x16u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONSTANTS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL DATA TYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* COMMAND BLOCK WRAPPER DATA TYPE
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class - Bulk Only Transport', Section 5.1.
|
|
*
|
|
* (2) The 'bmCBWFlags' field is a bit-mapped datum with three subfields :
|
|
*
|
|
* (a) Bit 7 : Data transfer direction :
|
|
*
|
|
* (1) 0 = Data-out from host to device.
|
|
* (2) 1 = Data-in from device to host.
|
|
*
|
|
* (b) Bit 6 : Obsolete. Should be set to zero.
|
|
* (c) Bits 5-0: Reserved. Should be set to zero.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbh_msc_cbw {
|
|
CPU_INT32U dCBWSignature; /* Signature to identify this data pkt as CBW. */
|
|
CPU_INT32U dCBWTag; /* Command block tag sent by host. */
|
|
CPU_INT32U dCBWDataTransferLength; /* Number of bytes of data that host expects to xfer. */
|
|
CPU_INT08U bmCBWFlags; /* Flags (see Notes #2). */
|
|
CPU_INT08U bCBWLUN; /* LUN to which the command block is being sent. */
|
|
CPU_INT08U bCBWCBLength; /* Length of CBWCB in bytes. */
|
|
CPU_INT08U CBWCB[16]; /* Command block to be executed by device. */
|
|
} USBH_MSC_CBW;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* COMMAND STATUS WRAPPER DATA TYPE
|
|
*
|
|
* Note(s) : (1) See 'USB Mass Storage Class - Bulk Only Transport', Section 5.2.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
typedef struct usbh_msc_csw {
|
|
CPU_INT32U dCSWSignature; /* Signature to identify this data pkt as CSW. */
|
|
CPU_INT32U dCSWTag; /* Device shall set this to value in CBW's dCBWTag. */
|
|
CPU_INT32U dCSWDataResidue; /* Difference between expected & actual nbr data bytes. */
|
|
CPU_INT08U bCSWStatus; /* Indicates success or failure of command. */
|
|
} USBH_MSC_CSW;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL TABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL GLOBAL VARIABLES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_MSC_DEV USBH_MSC_DevArr[USBH_MSC_CFG_MAX_DEV];
|
|
static MEM_POOL USBH_MSC_DevPool;
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_GlobalInit (USBH_ERR *p_err);
|
|
|
|
static void *USBH_MSC_ProbeIF (USBH_DEV *p_dev,
|
|
USBH_IF *p_if,
|
|
USBH_ERR *p_err);
|
|
|
|
static void USBH_MSC_Disconn (void *p_class_dev);
|
|
|
|
static void USBH_MSC_Suspend (void *p_class_dev);
|
|
|
|
static void USBH_MSC_Resume (void *p_class_dev);
|
|
|
|
static void USBH_MSC_DevClr (USBH_MSC_DEV *p_msc_dev);
|
|
|
|
static USBH_ERR USBH_MSC_EP_Open (USBH_MSC_DEV *p_msc_dev);
|
|
|
|
static void USBH_MSC_EP_Close (USBH_MSC_DEV *p_msc_dev);
|
|
|
|
static CPU_INT32U USBH_MSC_XferCmd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
USBH_MSC_DATA_DIR dir,
|
|
void *p_cb,
|
|
CPU_INT08U cb_len,
|
|
void *p_arg,
|
|
CPU_INT32U data_len,
|
|
USBH_ERR *p_err);
|
|
|
|
static USBH_ERR USBH_MSC_TxCBW (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_CBW *p_msc_cbw);
|
|
|
|
static USBH_ERR USBH_MSC_RxCSW (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_CSW *p_msc_csw);
|
|
|
|
static USBH_ERR USBH_MSC_TxData (USBH_MSC_DEV *p_msc_dev,
|
|
void *p_arg,
|
|
CPU_INT32U data_len);
|
|
|
|
static USBH_ERR USBH_MSC_RxData (USBH_MSC_DEV *p_msc_dev,
|
|
void *p_arg,
|
|
CPU_INT32U data_len);
|
|
|
|
static USBH_ERR USBH_MSC_ResetRecovery (USBH_MSC_DEV *p_msc_dev);
|
|
|
|
static USBH_ERR USBH_MSC_BulkOnlyReset (USBH_MSC_DEV *p_msc_dev);
|
|
|
|
static void USBH_MSC_FmtCBW (USBH_MSC_CBW *p_cbw,
|
|
void *p_buf_dest);
|
|
|
|
static void USBH_MSC_ParseCSW (USBH_MSC_CSW *p_csw,
|
|
void *p_buf_src);
|
|
|
|
static USBH_ERR USBH_SCSI_CMD_TestUnitReady (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun);
|
|
|
|
static USBH_ERR USBH_SCSI_CMD_StdInquiry (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_INQUIRY_INFO *p_msc_inquiry_info,
|
|
CPU_INT08U lun);
|
|
|
|
static CPU_INT32U USBH_SCSI_CMD_ReqSense (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT08U *p_arg,
|
|
CPU_INT32U data_len,
|
|
USBH_ERR *p_err);
|
|
|
|
static USBH_ERR USBH_SCSI_GetSenseInfo (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT08U *p_sense_key,
|
|
CPU_INT08U *p_asc,
|
|
CPU_INT08U *p_ascq);
|
|
|
|
static USBH_ERR USBH_SCSI_CMD_CapacityRd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U *p_nbr_blks,
|
|
CPU_INT32U *p_blk_size);
|
|
|
|
static CPU_INT32U USBH_SCSI_Rd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U blk_addr,
|
|
CPU_INT16U nbr_blks,
|
|
CPU_INT32U blk_size,
|
|
void *p_arg,
|
|
USBH_ERR *p_err);
|
|
|
|
static CPU_INT32U USBH_SCSI_Wr (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U blk_addr,
|
|
CPU_INT16U nbr_blks,
|
|
CPU_INT32U blk_size,
|
|
const void *p_arg,
|
|
USBH_ERR *p_err);
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* LOCAL CONFIGURATION ERRORS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* INITIALIZED GLOBAL VARIABLES ACCESSES BY OTHER MODULES/OBJECTS
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_CLASS_DRV USBH_MSC_ClassDrv = {
|
|
(CPU_INT08U *)"MASS STORAGE",
|
|
USBH_MSC_GlobalInit,
|
|
0,
|
|
USBH_MSC_ProbeIF,
|
|
USBH_MSC_Suspend,
|
|
USBH_MSC_Resume,
|
|
USBH_MSC_Disconn
|
|
};
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* GLOBAL FUNCTION
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_Init()
|
|
*
|
|
* Description : Initialize a mass storage device instance.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Device logical unit number to initialize.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if MSC device initialization is successful.
|
|
* USBH_ERR_INVALID_ARG, if invalid argument passed to 'p_msc_dev'.
|
|
* USBH_ERR_DEV_NOT_READY, if MSC device not ready for communication.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_SCSI_CMD_TestUnitReady -----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_SCSI_GetSenseInfo -----
|
|
* USBH_ERR_UNKNOWN, if unknown error occured.
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : (1) This block of code will send TEST_UNIT_READY SCSI command to know if MSC device is
|
|
* ready for communication. Host will try up to 20 times in case of MSC device not ready.
|
|
* If MSC device is not ready, host sends REQUEST_SENSE SCSI command to know
|
|
* exactly why device is not ready.
|
|
*
|
|
* (2) SENSE KEY, ADDITIONAL SENSE CODE (ASC) and ADDITIONAL SENSE CODE QUALIFIER (ASCQ)
|
|
* fields provide a hierarchy of information.
|
|
* See "SCSI Primary Commands - 4 (SPC-4)", section "4.5.2.1 Descriptor format sense
|
|
* data overview" for more details about REQUEST_SENSE response. Document is
|
|
* available at http://www.t10.org/drafts.htm#SPC_Family.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_MSC_Init (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun)
|
|
{
|
|
CPU_INT08U retry;
|
|
CPU_INT08U sense_key;
|
|
CPU_INT08U asc;
|
|
CPU_INT08U ascq;
|
|
CPU_BOOLEAN unit_ready;
|
|
USBH_ERR err;
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_msc_dev->HMutex); /* Acquire MSC dev lock to avoid multiple access. */
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
/* See Note #1. */
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN) &&
|
|
(p_msc_dev->RefCnt > 0u )) {
|
|
|
|
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
|
|
USBH_PRINT_LOG("Mass Storage device (LUN %d) is initializing ...\r\n", lun);
|
|
#endif
|
|
retry = 40u; /* Host attempts 20 times to know if MSC dev ready. */
|
|
unit_ready = DEF_FALSE;
|
|
|
|
while (retry > 0u) {
|
|
/* --------------- TEST_UNIT_READY CMD ---------------- */
|
|
err = USBH_SCSI_CMD_TestUnitReady(p_msc_dev, lun);
|
|
if (err == USBH_ERR_NONE) { /* MSC dev ready for comm. */
|
|
unit_ready = DEF_TRUE;
|
|
break;
|
|
} else if (err == USBH_ERR_MSC_IO) { /* Bulk xfers for the BOT protocol failed. */
|
|
USBH_PRINT_ERR(err);
|
|
break;
|
|
} else {
|
|
if (err != USBH_ERR_MSC_CMD_FAILED) { /* MSC dev not ready ... */
|
|
USBH_PRINT_ERR(err);
|
|
}
|
|
|
|
err = USBH_SCSI_GetSenseInfo(p_msc_dev, /* ...determine reason of failure. */
|
|
lun,
|
|
&sense_key,
|
|
&asc,
|
|
&ascq);
|
|
if (err == USBH_ERR_NONE) {
|
|
switch (sense_key) { /* See Note #2. */
|
|
case USBH_SCSI_SENSE_KEY_UNIT_ATTENTION:/* MSC dev is initializing internally but not rdy. */
|
|
switch (asc) {
|
|
case USBH_SCSI_ASC_MEDIUM_NOT_PRESENT:
|
|
USBH_OS_DlyMS(500u);
|
|
break;
|
|
/* MSC dev changed its internal state to ready. */
|
|
case USBH_SCSI_ASC_NOT_RDY_TO_RDY_CHANGE:
|
|
USBH_OS_DlyMS(500u);
|
|
break;
|
|
|
|
default: /* Other Additional Sense Code values not supported. */
|
|
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
|
|
USBH_PRINT_LOG("SENSE KEY1 : %02X, ASC : %02X, ASCQ : %02X\r\n", sense_key, asc, ascq);
|
|
#endif
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case USBH_SCSI_SENSE_KEY_NOT_RDY: /* MSC dev not ready. */
|
|
USBH_OS_DlyMS(500u);
|
|
break;
|
|
|
|
default: /* Other Sense Key values not supported. */
|
|
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
|
|
USBH_PRINT_LOG("SENSE KEY2 : %02X, ASC : %02X, ASCQ : %02X\r\n", sense_key, asc, ascq);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
retry--;
|
|
} else {
|
|
USBH_PRINT_ERR(err);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (unit_ready == DEF_FALSE) {
|
|
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
|
|
USBH_PRINT_LOG("Device is not ready\r\n");
|
|
#endif
|
|
err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
} else {
|
|
err = USBH_ERR_DEV_NOT_READY; /* MSC dev enum not completed by host. */
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex); /* Unlock access to MSC dev. */
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_MaxLUN_Get()
|
|
*
|
|
* Description : Get maximum logical unit number (LUN) supported by MSC device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBH_ERR_NONE Maximum LUN successfully retrieved.
|
|
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_msc_dev'.
|
|
* USBH_ERR_DEV_NOT_READY If device enumeration not completed.
|
|
*
|
|
* ----- RETURNED BY USBH_CtrlRx() : -----
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* Return(s) : Maximum number of logical unit.
|
|
*
|
|
* Note(s) : (1) The "GET MAX LUN" is an MSC specific command and is documented in "USB MSC Bulk Only
|
|
* Transport specification", Section 3.2.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBH_MSC_MaxLUN_Get (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT08U if_nbr;
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, lun_nbr, 1);
|
|
|
|
/* ------------------ VALIDATE ARG -------------------- */
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
/* --------------- GET_MAX_LUN REQUEST ---------------- */
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN) &&
|
|
(p_msc_dev->RefCnt > 0u )) {
|
|
|
|
if_nbr = USBH_IF_NbrGet(p_msc_dev->IF_Ptr); /* Get IF nbr matching to MSC dev. */
|
|
|
|
USBH_CtrlRx( p_msc_dev->DevPtr, /* Send GET_MAX_LUN request via a Ctrl xfer. */
|
|
USBH_MSC_REQ_GET_MAX_LUN, /* See Note #1. */
|
|
(USBH_REQ_DIR_DEV_TO_HOST | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
0u,
|
|
if_nbr,
|
|
(void *) lun_nbr,
|
|
1u,
|
|
USBH_MSC_TIMEOUT,
|
|
p_err);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
(void)USBH_EP_Reset( p_msc_dev->DevPtr, /* Reset dflt EP if ctrl xfer failed. */
|
|
(USBH_EP *)0);
|
|
|
|
if (*p_err == USBH_ERR_EP_STALL) { /* Device may stall if no multiple LUNs support. */
|
|
lun_nbr[0] = 0u;
|
|
*p_err = USBH_ERR_NONE;
|
|
}
|
|
}
|
|
} else { /* MSC dev enumeration not completed by host. */
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
if (*p_err == USBH_ERR_NONE)
|
|
return (lun_nbr[0]);
|
|
else
|
|
return (0u);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_UnitRdyTest()
|
|
*
|
|
* Description : Test if a certain logical unit within the MSC device is ready for communication.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBH_ERR_NONE Maximum LUN successfully retrieved.
|
|
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_msc_dev'.
|
|
* USBH_ERR_DEV_NOT_READY If device enumeration not completed.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* ---- RETURNED BY USBH_SCSI_CMD_TestUnitReady() ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : DEF_YES, if logical unit ready.
|
|
*
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBH_MSC_UnitRdyTest (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN unit_rdy = DEF_NO;
|
|
|
|
/* ------------------- VALIDATE PTR ------------------- */
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (unit_rdy);
|
|
}
|
|
|
|
*p_err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (unit_rdy);
|
|
}
|
|
/* --------------- TEST_UNIT_READY REQ ---------------- */
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN) &&
|
|
(p_msc_dev->RefCnt > 0u )) {
|
|
|
|
*p_err = USBH_SCSI_CMD_TestUnitReady(p_msc_dev, 0u);
|
|
if (*p_err == USBH_ERR_NONE) {
|
|
unit_rdy = DEF_YES;
|
|
} else if (*p_err == USBH_ERR_MSC_CMD_FAILED) {
|
|
*p_err = USBH_ERR_NONE; /* CSW reporting cmd failed for this req NOT an err. */
|
|
unit_rdy = DEF_NO;
|
|
} else {
|
|
/* Empty Else Statement */
|
|
}
|
|
} else { /* MSC dev enumeration not completed by host. */
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
return (unit_rdy);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_CapacityRd()
|
|
*
|
|
* Description : Read mass storage device capacity (i.e number of blocks and block size) of specified LUN
|
|
* by sending READ_CAPACITY SCSI command.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* p_nbr_blks Pointer to variable that receives number of blocks.
|
|
*
|
|
* p_blk_size Pointer to variable that receives block size.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If capacity of MSC device retrieved successfully.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_msc_dev' / 'p_nbr_blks' /
|
|
* 'p_blk_size'.
|
|
* USBH_ERR_DEV_NOT_READY, If device enumeration not completed.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
* List error codes from USBH_SCSI_CMD_CapacityRd
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_MSC_CapacityRd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U *p_nbr_blks,
|
|
CPU_INT32U *p_blk_size)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
/* ------------------- VALIDATE PTR ------------------- */
|
|
if ((p_msc_dev == (USBH_MSC_DEV *)0) ||
|
|
(p_nbr_blks == (CPU_INT32U *)0) ||
|
|
(p_blk_size == (CPU_INT32U *)0)) {
|
|
err = USBH_ERR_INVALID_ARG;
|
|
return (err);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
/* -------------- READ_CAPACITY REQUEST --------------- */
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN) &&
|
|
(p_msc_dev->RefCnt > 0u )) {
|
|
|
|
err = USBH_SCSI_CMD_CapacityRd(p_msc_dev, /* Issue READ_CAPACITY SCSI cmd using bulk xfers. */
|
|
lun,
|
|
p_nbr_blks,
|
|
p_blk_size);
|
|
} else { /* MSC dev enumeration not completed by host. */
|
|
err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex); /* Unlock access to MSC dev. */
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_StdInquiry()
|
|
*
|
|
* Description : Retrieve various information about a specific logical unit inside mass storage device
|
|
* such as device type, if device is removable, vendor/product identification, etc.
|
|
* INQUIRY SCSI command is used.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_msc_inquiry_info Pointer to structure that will receive the informations.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If information about logical unit retrieved successfully.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_msc_dev' / 'p_msc_inquiry_info'.
|
|
* USBH_ERR_NOT_SUPPORTED, If INQUIRY command has failed.
|
|
* USBH_ERR_DEV_NOT_READY, If device enumeration not completed.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_MSC_StdInquiry (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_INQUIRY_INFO *p_msc_inquiry_info,
|
|
CPU_INT08U lun)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
/* ------------------- VALIDATE PTR ------------------- */
|
|
if ((p_msc_dev == (USBH_MSC_DEV *)0) ||
|
|
(p_msc_inquiry_info == (USBH_MSC_INQUIRY_INFO *)0)) {
|
|
err = USBH_ERR_INVALID_ARG;
|
|
return (err);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
/* ----------------- INQUIRY REQUEST ------------------ */
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN) &&
|
|
(p_msc_dev->RefCnt > 0u )) {
|
|
|
|
err = USBH_SCSI_CMD_StdInquiry(p_msc_dev, /* Issue INQUIRY SCSI command using Bulk xfers. */
|
|
p_msc_inquiry_info,
|
|
lun);
|
|
if (err == USBH_ERR_NONE) {
|
|
err = USBH_ERR_NONE;
|
|
} else {
|
|
err = USBH_ERR_NOT_SUPPORTED;
|
|
}
|
|
} else {
|
|
err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_RefAdd()
|
|
*
|
|
* Description : Increment counter of connected mass storage devices.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If counter successfully incremented.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_msc_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_MSC_RefAdd (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
p_msc_dev->RefCnt++;
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_RefRel()
|
|
*
|
|
* Description : Decrement counter of connected mass storage devices and free device if counter = 0.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If counter successfully decremented.
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'p_msc_dev'.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
USBH_ERR USBH_MSC_RefRel (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
USBH_ERR err;
|
|
LIB_ERR err_lib;
|
|
|
|
/* ------------------- VALIDATE PTR ------------------- */
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
return (USBH_ERR_INVALID_ARG);
|
|
}
|
|
|
|
err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
if (p_msc_dev->RefCnt > 0u) {
|
|
p_msc_dev->RefCnt--;
|
|
|
|
if ((p_msc_dev->RefCnt == 0u) &&
|
|
(p_msc_dev->State == USBH_CLASS_DEV_STATE_DISCONN)) {
|
|
/* Release MSC dev if no more ref on it. */
|
|
Mem_PoolBlkFree( &USBH_MSC_DevPool,
|
|
(void *)p_msc_dev,
|
|
&err_lib);
|
|
}
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_Rd()
|
|
*
|
|
* Description : Read specified number of blocks from device using READ_10 SCSI command.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* blk_addr Block address.
|
|
*
|
|
* nbr_blks Number of blocks to read.
|
|
*
|
|
* blk_size Block size.
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBH_ERR_NONE Block(s) read successfully.
|
|
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_msc_dev'.
|
|
* USBH_ERR_DEV_NOT_READY If device enumeration not completed.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_SCSI_Rd -----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets read.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT32U USBH_MSC_Rd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U blk_addr,
|
|
CPU_INT16U nbr_blks,
|
|
CPU_INT32U blk_size,
|
|
void *p_arg,
|
|
USBH_ERR *p_err)
|
|
|
|
{
|
|
CPU_INT32U xfer_len;
|
|
|
|
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN) &&
|
|
(p_msc_dev->RefCnt > 0u )) {
|
|
xfer_len = USBH_SCSI_Rd(p_msc_dev,
|
|
lun,
|
|
blk_addr,
|
|
nbr_blks,
|
|
blk_size,
|
|
p_arg,
|
|
p_err);
|
|
} else {
|
|
xfer_len = 0u;
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_Wr()
|
|
*
|
|
* Description : Write specified number of blocks to the device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to mass storage device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* blk_addr Block address.
|
|
*
|
|
* nbr_blks Number of blocks to write.
|
|
*
|
|
* blk_size Block size.
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBH_ERR_NONE Block(s) write successfully.
|
|
* USBH_ERR_INVALID_ARG If invalid argument passed to 'p_msc_dev'.
|
|
* USBH_ERR_DEV_NOT_READY If device enumeration not completed.
|
|
*
|
|
* ----- RETURNED BY USBH_OS_MutexLock() : -----
|
|
* USBH_ERR_INVALID_ARG, If invalid argument passed to 'mutex'.
|
|
* USBH_ERR_OS_ABORT, If mutex wait aborted.
|
|
* USBH_ERR_OS_FAIL, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_SCSI_Rd -----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets written.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT32U USBH_MSC_Wr ( USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U blk_addr,
|
|
CPU_INT16U nbr_blks,
|
|
CPU_INT32U blk_size,
|
|
const void *p_arg,
|
|
USBH_ERR *p_err)
|
|
|
|
{
|
|
CPU_INT32U xfer_len;
|
|
|
|
|
|
if (p_msc_dev == (USBH_MSC_DEV *)0) {
|
|
*p_err = USBH_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
if ((p_msc_dev->State == USBH_CLASS_DEV_STATE_CONN ) &&
|
|
(p_msc_dev->RefCnt > 0 )) {
|
|
xfer_len = USBH_SCSI_Wr(p_msc_dev,
|
|
lun,
|
|
blk_addr,
|
|
nbr_blks,
|
|
blk_size,
|
|
p_arg,
|
|
p_err);
|
|
} else {
|
|
xfer_len = 0u;
|
|
*p_err = USBH_ERR_DEV_NOT_READY;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_GlobalInit()
|
|
*
|
|
* Description : Initialize MSC.
|
|
*
|
|
* Argument(s) : p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBH_ERR_NONE MSC successfully initalized.
|
|
* USBH_ERR_ALLOC If MSC device cannot be allocated.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_GlobalInit (USBH_ERR *p_err)
|
|
{
|
|
|
|
CPU_INT08U ix;
|
|
CPU_SIZE_T octets_reqd;
|
|
LIB_ERR err_lib;
|
|
|
|
/* --------------- INIT MSC DEV STRUCT ---------------- */
|
|
for (ix = 0u; ix < USBH_MSC_CFG_MAX_DEV; ix++) {
|
|
USBH_MSC_DevClr(&USBH_MSC_DevArr[ix]);
|
|
USBH_OS_MutexCreate(&USBH_MSC_DevArr[ix].HMutex);
|
|
}
|
|
|
|
Mem_PoolCreate ( &USBH_MSC_DevPool, /* POOL for managing MSC dev struct. */
|
|
(void *)USBH_MSC_DevArr,
|
|
(sizeof(USBH_MSC_DEV) * USBH_MSC_CFG_MAX_DEV),
|
|
USBH_MSC_CFG_MAX_DEV,
|
|
sizeof(USBH_MSC_DEV),
|
|
sizeof(CPU_ALIGN),
|
|
&octets_reqd,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
|
|
USBH_PRINT_LOG("%d octets required\r\n", octets_reqd);
|
|
#endif
|
|
*p_err = USBH_ERR_ALLOC;
|
|
} else {
|
|
*p_err = USBH_ERR_NONE;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_ProbeIF()
|
|
*
|
|
* Description : Determine if interface is mass storage class interface.
|
|
*
|
|
* Argument(s) : p_dev Pointer to USB device.
|
|
*
|
|
* p_if Pointer to interface.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBH_ERR_NONE MSC successfully initalized.
|
|
* USBH_ERR_DEV_ALLOC MSC device cannot be allocated.
|
|
* USBH_ERR_CLASS_DRV_NOT_FOUND IF type is not MSC.
|
|
*
|
|
* ----- RETURNED BY USBH_IF_DescGet() : -----
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'alt_ix'.
|
|
*
|
|
* ----- RETURNED BY USBH_MSC_EP_Open -----
|
|
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
|
|
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
|
|
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
|
|
* Host controller drivers error, Otherwise.
|
|
*
|
|
* Return(s) : p_msc_dev, if device has a mass storage class interface.
|
|
* 0, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void *USBH_MSC_ProbeIF (USBH_DEV *p_dev,
|
|
USBH_IF *p_if,
|
|
USBH_ERR *p_err)
|
|
{
|
|
USBH_IF_DESC p_if_desc;
|
|
USBH_MSC_DEV *p_msc_dev;
|
|
LIB_ERR err_lib;
|
|
|
|
|
|
p_msc_dev = (USBH_MSC_DEV *)0;
|
|
*p_err = USBH_IF_DescGet(p_if, 0u, &p_if_desc);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return ((void *)0);
|
|
}
|
|
/* Chk for class, sub class and protocol. */
|
|
if ((p_if_desc.bInterfaceClass == USBH_CLASS_CODE_MASS_STORAGE) &&
|
|
((p_if_desc.bInterfaceSubClass == USBH_MSC_SUBCLASS_CODE_SCSI) ||
|
|
(p_if_desc.bInterfaceSubClass == USBH_MSC_SUBCLASS_CODE_SFF_8070i)) &&
|
|
(p_if_desc.bInterfaceProtocol == USBH_MSC_PROTOCOL_CODE_BULK_ONLY)) {
|
|
|
|
/* Alloc dev from MSC dev pool. */
|
|
p_msc_dev = (USBH_MSC_DEV *)Mem_PoolBlkGet(&USBH_MSC_DevPool,
|
|
sizeof(USBH_MSC_DEV),
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBH_ERR_DEV_ALLOC;
|
|
return ((void *)0);
|
|
}
|
|
|
|
USBH_MSC_DevClr(p_msc_dev);
|
|
p_msc_dev->RefCnt = (CPU_INT08U )0;
|
|
p_msc_dev->State = USBH_CLASS_DEV_STATE_CONN;
|
|
p_msc_dev->DevPtr = p_dev;
|
|
p_msc_dev->IF_Ptr = p_if;
|
|
|
|
*p_err = USBH_MSC_EP_Open(p_msc_dev); /* Open Bulk in/out EPs. */
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
Mem_PoolBlkFree( &USBH_MSC_DevPool,
|
|
(void *)p_msc_dev,
|
|
&err_lib);
|
|
}
|
|
} else {
|
|
*p_err = USBH_ERR_CLASS_DRV_NOT_FOUND;
|
|
}
|
|
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
p_msc_dev = (void *)0;
|
|
}
|
|
|
|
return ((void *)p_msc_dev);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_Disconn()
|
|
*
|
|
* Description : Handle disconnection of mass storage device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_Disconn (void *p_class_dev)
|
|
{
|
|
LIB_ERR err_lib;
|
|
USBH_MSC_DEV *p_msc_dev;
|
|
|
|
|
|
p_msc_dev = (USBH_MSC_DEV *)p_class_dev;
|
|
|
|
(void)USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
|
|
p_msc_dev->State = USBH_CLASS_DEV_STATE_DISCONN;
|
|
USBH_MSC_EP_Close(p_msc_dev); /* Close bulk in/out EPs. */
|
|
|
|
if (p_msc_dev->RefCnt == 0u) { /* Release MSC dev. */
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
Mem_PoolBlkFree( &USBH_MSC_DevPool,
|
|
(void *)p_msc_dev,
|
|
&err_lib);
|
|
return;
|
|
}
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_Suspend()
|
|
*
|
|
* Description : Suspend MSC device. Waits for completion of any pending I/O.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_Suspend (void *p_class_dev)
|
|
{
|
|
USBH_MSC_DEV *p_msc_dev;
|
|
|
|
|
|
p_msc_dev = (USBH_MSC_DEV *)p_class_dev;
|
|
|
|
(void)USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
|
|
p_msc_dev->State = USBH_CLASS_DEV_STATE_SUSPEND;
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_Resume()
|
|
*
|
|
* Description : Resume MSC device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_Resume (void *p_class_dev)
|
|
{
|
|
USBH_MSC_DEV *p_msc_dev;
|
|
|
|
|
|
p_msc_dev = (USBH_MSC_DEV *)p_class_dev;
|
|
|
|
(void)USBH_OS_MutexLock(p_msc_dev->HMutex);
|
|
|
|
p_msc_dev->State = USBH_CLASS_DEV_STATE_CONN;
|
|
|
|
(void)USBH_OS_MutexUnlock(p_msc_dev->HMutex);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_DevClr()
|
|
*
|
|
* Description : Clear USBH_MSC_DEV structure.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_DevClr (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
p_msc_dev->DevPtr = (USBH_DEV *)0;
|
|
p_msc_dev->IF_Ptr = (USBH_IF *)0;
|
|
p_msc_dev->State = USBH_CLASS_DEV_STATE_NONE;
|
|
p_msc_dev->RefCnt = 0u;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_EP_Open()
|
|
*
|
|
* Description : Open bulk IN & OUT endpoints.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if endpoints successfully opened.
|
|
*
|
|
* ---- RETURNED BY USBH_BulkInOpen ----
|
|
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
|
|
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
|
|
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
|
|
* Host controller drivers error, Otherwise.
|
|
*
|
|
* ---- RETURNED BY USBH_BulkOutOpen ----
|
|
* USBH_ERR_EP_ALLOC, If USBH_CFG_MAX_NBR_EPS reached.
|
|
* USBH_ERR_EP_NOT_FOUND, If endpoint with given type and direction not found.
|
|
* USBH_ERR_OS_SIGNAL_CREATE, if mutex or semaphore creation failed.
|
|
* Host controller drivers error, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_EP_Open (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
err = USBH_BulkInOpen(p_msc_dev->DevPtr,
|
|
p_msc_dev->IF_Ptr,
|
|
&p_msc_dev->BulkInEP);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
err = USBH_BulkOutOpen(p_msc_dev->DevPtr,
|
|
p_msc_dev->IF_Ptr,
|
|
&p_msc_dev->BulkOutEP);
|
|
if (err != USBH_ERR_NONE) {
|
|
USBH_MSC_EP_Close(p_msc_dev);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_EP_Close()
|
|
*
|
|
* Description : Close bulk IN & OUT endpoints.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_EP_Close (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
USBH_EP_Close(&p_msc_dev->BulkInEP);
|
|
USBH_EP_Close(&p_msc_dev->BulkOutEP);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_XferCmd()
|
|
*
|
|
* Description : Executes MSC command cycle. Sends command (CBW), followed by data stage (if present),
|
|
* and then receive status (CSW).
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical Unit Number.
|
|
*
|
|
* dir Direction of data transfer, if present.
|
|
*
|
|
* p_cb Pointer to command block.
|
|
*
|
|
* cb_len Command block length, in octets.
|
|
*
|
|
* p_arg Pointer to data buffer, if data stage present.
|
|
*
|
|
* data_len Length of data buffer in octets, if data stage present.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
* USBH_ERR_NONE Command successfully transmitted.
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
*
|
|
* ----- RETURNED BY USBH_MSC_RxCSW() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_MSC_RxData() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_MSC_TxCBW() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not OUT.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_MSC_TxData() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not OUT.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets transferred.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT32U USBH_MSC_XferCmd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
USBH_MSC_DATA_DIR dir,
|
|
void *p_cb,
|
|
CPU_INT08U cb_len,
|
|
void *p_arg,
|
|
CPU_INT32U data_len,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT32U xfer_len;
|
|
USBH_MSC_CBW msc_cbw;
|
|
USBH_MSC_CSW msc_csw;
|
|
|
|
/* Prepare CBW. */
|
|
msc_cbw.dCBWSignature = USBH_MSC_SIG_CBW;
|
|
msc_cbw.dCBWTag = 0u;
|
|
msc_cbw.dCBWDataTransferLength = data_len;
|
|
msc_cbw.bmCBWFlags = (dir == USBH_MSC_DATA_DIR_NONE) ? 0u : dir;
|
|
msc_cbw.bCBWLUN = lun;
|
|
msc_cbw.bCBWCBLength = cb_len;
|
|
|
|
Mem_Copy((void *)msc_cbw.CBWCB,
|
|
p_cb,
|
|
cb_len);
|
|
|
|
*p_err = USBH_MSC_TxCBW(p_msc_dev, &msc_cbw); /* Send CBW to dev. */
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
switch (dir) {
|
|
case USBH_MSC_DATA_DIR_OUT:
|
|
*p_err = USBH_MSC_TxData(p_msc_dev,
|
|
p_arg,
|
|
data_len); /* Send data to dev. */
|
|
break;
|
|
|
|
case USBH_MSC_DATA_DIR_IN:
|
|
*p_err = USBH_MSC_RxData(p_msc_dev,
|
|
p_arg,
|
|
data_len); /* Receive data from dev. */
|
|
break;
|
|
|
|
default:
|
|
*p_err = USBH_ERR_NONE;
|
|
break;
|
|
}
|
|
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
Mem_Set((void *)&msc_csw,
|
|
0u,
|
|
USBH_MSC_LEN_CSW);
|
|
|
|
*p_err = USBH_MSC_RxCSW(p_msc_dev, &msc_csw); /* Receive CSW. */
|
|
|
|
if ((msc_csw.dCSWSignature != USBH_MSC_SIG_CSW ) ||
|
|
(msc_csw.bCSWStatus == USBH_MSC_BCSWSTATUS_PHASE_ERROR) ||
|
|
(msc_csw.dCSWTag != msc_cbw.dCBWTag )) {
|
|
USBH_MSC_ResetRecovery(p_msc_dev); /* Invalid CSW, issue reset recovery. */
|
|
}
|
|
|
|
if (*p_err == USBH_ERR_NONE) {
|
|
switch (msc_csw.bCSWStatus) {
|
|
case USBH_MSC_BCSWSTATUS_CMD_PASSED:
|
|
*p_err = USBH_ERR_NONE;
|
|
break;
|
|
|
|
case USBH_MSC_BCSWSTATUS_CMD_FAILED:
|
|
*p_err = USBH_ERR_MSC_CMD_FAILED;
|
|
break;
|
|
|
|
case USBH_MSC_BCSWSTATUS_PHASE_ERROR:
|
|
*p_err = USBH_ERR_MSC_CMD_PHASE;
|
|
break;
|
|
|
|
default:
|
|
*p_err = USBH_ERR_MSC_CMD_FAILED;
|
|
break;
|
|
}
|
|
} else {
|
|
*p_err = USBH_ERR_MSC_IO;
|
|
}
|
|
|
|
/* Actual len of data xfered to dev. */
|
|
xfer_len = msc_cbw.dCBWDataTransferLength - msc_csw.dCSWDataResidue;
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_TxCBW()
|
|
*
|
|
* Description : Send Command Block Wrapper (CBW) to device through bulk OUT endpoint.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_msc_cbw Pointer to Command Block Wrapper (CBW).
|
|
*
|
|
* Return(s) : USBH_ERR_NONE If CBW successfully transmitted.
|
|
*
|
|
* ----- RETURNED BY USBH_BulkTx() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not OUT.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_TxCBW (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_CBW *p_msc_cbw)
|
|
{
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, cmd_buf, USBH_MSC_LEN_CBW);
|
|
USBH_ERR err;
|
|
CPU_INT32U len;
|
|
|
|
|
|
Mem_Clr((void *)cmd_buf,
|
|
USBH_MSC_LEN_CBW);
|
|
|
|
USBH_MSC_FmtCBW(p_msc_cbw, cmd_buf); /* Format CBW. */
|
|
|
|
len = USBH_BulkTx( &p_msc_dev->BulkOutEP, /* Send CBW through bulk OUT EP. */
|
|
(void *)&cmd_buf[0],
|
|
USBH_MSC_LEN_CBW,
|
|
USBH_MSC_TIMEOUT,
|
|
&err);
|
|
if (len != USBH_MSC_LEN_CBW) {
|
|
if (err != USBH_ERR_NONE) {
|
|
USBH_PRINT_ERR(err);
|
|
USBH_EP_Reset(p_msc_dev->DevPtr,
|
|
&p_msc_dev->BulkOutEP); /* Clear EP err on host side. */
|
|
}
|
|
|
|
if (err == USBH_ERR_EP_STALL) {
|
|
USBH_MSC_ResetRecovery(p_msc_dev);
|
|
}
|
|
} else {
|
|
err = USBH_ERR_NONE;
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_RxCSW()
|
|
*
|
|
* Description : Receive Command Status Word (CSW) from device through bulk IN endpoint.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_msc_csw Pointer to Command Status Word (CSW).
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If CSW successfully received.
|
|
*
|
|
* ----- RETURNED BY USBH_BulkRx() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_RxCSW (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_CSW *p_msc_csw)
|
|
{
|
|
CPU_INT32U retry;
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, status_buf, USBH_MSC_LEN_CSW);
|
|
USBH_ERR err;
|
|
CPU_INT32U len;
|
|
|
|
|
|
err = USBH_ERR_NONE;
|
|
retry = 2u;
|
|
|
|
/* Receive CSW from dev through bulk IN EP. */
|
|
while (retry > 0u) {
|
|
len = USBH_BulkRx( &p_msc_dev->BulkInEP,
|
|
(void *)&status_buf[0],
|
|
USBH_MSC_LEN_CSW,
|
|
USBH_MSC_TIMEOUT,
|
|
&err);
|
|
if (len != USBH_MSC_LEN_CSW) {
|
|
USBH_EP_Reset(p_msc_dev->DevPtr,
|
|
&p_msc_dev->BulkInEP); /* Clear err on host side. */
|
|
|
|
if (err == USBH_ERR_EP_STALL) {
|
|
(void)USBH_EP_StallClr(&p_msc_dev->BulkInEP);
|
|
retry--;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
err = USBH_ERR_NONE;
|
|
USBH_MSC_ParseCSW(p_msc_csw, status_buf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_TxData()
|
|
*
|
|
* Description : Send data to device through bulk OUT endpoint.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* data_len Length of data buffer in octets.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if data successfully transmitted.
|
|
*
|
|
* ----- RETURNED BY USBH_BulkTx() : -----
|
|
* USBH_ERR_NONE Bulk transfer successfully transmitted.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not OUT.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_NONE, URB is successfully submitted to host controller.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_TxData (USBH_MSC_DEV *p_msc_dev,
|
|
void *p_arg,
|
|
CPU_INT32U data_len)
|
|
{
|
|
USBH_ERR err;
|
|
CPU_BOOLEAN retry;
|
|
CPU_INT08U *p_data_08;
|
|
CPU_INT16U retry_cnt;
|
|
CPU_INT32U p_data_ix;
|
|
CPU_INT32U data_len_rem;
|
|
CPU_INT32U data_len_tx;
|
|
|
|
|
|
err = USBH_ERR_NONE;
|
|
p_data_ix = 0u;
|
|
p_data_08 = (CPU_INT08U *)p_arg;
|
|
data_len_rem = data_len;
|
|
retry_cnt = 0u;
|
|
retry = DEF_TRUE;
|
|
|
|
while ((data_len_rem > 0u ) &&
|
|
(retry == DEF_TRUE)) {
|
|
|
|
data_len_tx = USBH_BulkTx( &p_msc_dev->BulkOutEP,
|
|
(void *)(p_data_08 + p_data_ix),
|
|
data_len_rem,
|
|
USBH_MSC_TIMEOUT,
|
|
&err);
|
|
switch (err) {
|
|
case USBH_ERR_DEV_NOT_RESPONDING:
|
|
case USBH_ERR_HC_IO:
|
|
retry_cnt++;
|
|
if (retry_cnt >= USBH_MSC_MAX_TRANSFER_RETRY) {
|
|
retry = DEF_FALSE;
|
|
}
|
|
break;
|
|
|
|
case USBH_ERR_NONE:
|
|
if (data_len_tx < data_len_rem) {
|
|
data_len_rem -= data_len_tx;
|
|
p_data_ix += data_len_tx;
|
|
} else {
|
|
data_len_rem = 0u;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
retry = DEF_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err != USBH_ERR_NONE) {
|
|
USBH_PRINT_ERR(err);
|
|
|
|
USBH_EP_Reset(p_msc_dev->DevPtr,
|
|
&p_msc_dev->BulkOutEP);
|
|
if (err == USBH_ERR_EP_STALL) {
|
|
(void)USBH_EP_StallClr(&p_msc_dev->BulkOutEP);
|
|
} else {
|
|
(void)USBH_MSC_ResetRecovery(p_msc_dev);
|
|
}
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_RxData()
|
|
*
|
|
* Description : Receive data from device through bulk IN endpoint.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* data_len Length of data buffer in octets.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if data successfully received.
|
|
*
|
|
* ----- RETURNED BY USBH_BulkRx() : -----
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type is not Bulk or direction is not IN.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_RxData (USBH_MSC_DEV *p_msc_dev,
|
|
void *p_arg,
|
|
CPU_INT32U data_len)
|
|
|
|
{
|
|
USBH_ERR err;
|
|
CPU_BOOLEAN retry;
|
|
CPU_INT08U *p_data_08;
|
|
CPU_INT16U retry_cnt;
|
|
CPU_INT32U p_data_ix;
|
|
CPU_INT32U data_len_rem;
|
|
CPU_INT32U data_len_rx;
|
|
|
|
|
|
err = USBH_ERR_NONE;
|
|
p_data_ix = 0u;
|
|
p_data_08 = (CPU_INT08U *)p_arg;
|
|
data_len_rem = data_len;
|
|
retry_cnt = 0u;
|
|
retry = DEF_TRUE;
|
|
|
|
while ((data_len_rem > 0u ) &&
|
|
(retry == DEF_TRUE)) {
|
|
|
|
data_len_rx = USBH_BulkRx( &p_msc_dev->BulkInEP,
|
|
(void *)(p_data_08 + p_data_ix),
|
|
data_len_rem,
|
|
USBH_MSC_TIMEOUT,
|
|
&err);
|
|
switch (err) {
|
|
case USBH_ERR_DEV_NOT_RESPONDING:
|
|
case USBH_ERR_HC_IO:
|
|
retry_cnt++;
|
|
if (retry_cnt >= USBH_MSC_MAX_TRANSFER_RETRY) {
|
|
retry = DEF_FALSE;
|
|
}
|
|
break;
|
|
|
|
case USBH_ERR_NONE:
|
|
if (data_len_rx < data_len_rem) {
|
|
data_len_rem -= data_len_rx; /* Update remaining nbr of octets to read. */
|
|
p_data_ix += data_len_rx; /* Update buf ix. */
|
|
} else {
|
|
data_len_rem = 0u;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
retry = DEF_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err != USBH_ERR_NONE) {
|
|
USBH_PRINT_ERR(err);
|
|
|
|
(void)USBH_EP_Reset(p_msc_dev->DevPtr,
|
|
&p_msc_dev->BulkInEP); /* Clr err on host side EP. */
|
|
if (err == USBH_ERR_EP_STALL) {
|
|
(void)USBH_EP_StallClr(&p_msc_dev->BulkInEP);
|
|
err = USBH_ERR_NONE;
|
|
} else {
|
|
(void)USBH_MSC_ResetRecovery(p_msc_dev);
|
|
err = USBH_ERR_MSC_IO;
|
|
}
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_ResetRecovery()
|
|
*
|
|
* Description : Apply bulk-only reset recovery to device on phase error & clear stalled endpoints.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, If reset recovery procedure is successful.
|
|
*
|
|
* ----- RETURNED BY USBH_MSC_BulkOnlyReset -----
|
|
* USBH_ERR_UNKNOWN, Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG, Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE, Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* ----- RETURNED BY USBH_EP_StallClr -----
|
|
* USBH_ERR_UNKNOWN Unknown error occurred.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* USBH_ERR_HC_IO, Root hub input/output error.
|
|
* USBH_ERR_EP_STALL, Root hub does not support request.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_ResetRecovery (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
USBH_ERR err;
|
|
|
|
|
|
err = USBH_MSC_BulkOnlyReset(p_msc_dev);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
err = USBH_EP_StallClr(&p_msc_dev->BulkInEP);
|
|
if (err != USBH_ERR_NONE) {
|
|
return (err);
|
|
}
|
|
|
|
err = USBH_EP_StallClr(&p_msc_dev->BulkOutEP);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_BulkOnlyReset()
|
|
*
|
|
* Description : Issue bulk-only reset.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* Return(s) : Specific error code.
|
|
*
|
|
* Note(s) : (1)The "BULK ONLY MASS STORAGE RESET" is an MSC specific request is documented in USB
|
|
MSC Bulk only transport specification, section 3.1
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_MSC_BulkOnlyReset (USBH_MSC_DEV *p_msc_dev)
|
|
{
|
|
USBH_ERR err;
|
|
CPU_INT08U if_nbr;
|
|
|
|
|
|
err = USBH_ERR_NONE;
|
|
if_nbr = USBH_IF_NbrGet(p_msc_dev->IF_Ptr);
|
|
|
|
USBH_CtrlTx( p_msc_dev->DevPtr,
|
|
USBH_MSC_REQ_MASS_STORAGE_RESET, /* See Note(s) #1 */
|
|
(USBH_REQ_DIR_HOST_TO_DEV | USBH_REQ_TYPE_CLASS | USBH_REQ_RECIPIENT_IF),
|
|
0u,
|
|
if_nbr,
|
|
(void *)0,
|
|
0u,
|
|
USBH_MSC_TIMEOUT,
|
|
&err);
|
|
if (err != USBH_ERR_NONE) {
|
|
USBH_PRINT_ERR(err);
|
|
USBH_EP_Reset( p_msc_dev->DevPtr,
|
|
(USBH_EP *)0);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_CMD_StdInquiry()
|
|
*
|
|
* Description : Read inquiry data of device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* p_msc_inquiry_info Pointer to inquiry info structure.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if command is successful.
|
|
*
|
|
* ---- RETURNED BY USBH_MSC_XferCmd ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : (1) The SCSI "INQUIRY" command is documented in 'SCSI Primary Commands - 3
|
|
* (SPC-3)', Section 6.33.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_SCSI_CMD_StdInquiry (USBH_MSC_DEV *p_msc_dev,
|
|
USBH_MSC_INQUIRY_INFO *p_msc_inquiry_info,
|
|
CPU_INT08U lun)
|
|
{
|
|
USBH_ERR err;
|
|
CPU_INT08U cmd[6];
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, inq_data, 0x24);
|
|
|
|
/* ------- PREPARE SCSI CMD BLOCK (SEE NOTE #1) ------- */
|
|
cmd[0] = USBH_SCSI_CMD_INQUIRY; /* Operation code (0x12). */
|
|
cmd[1] = 0u; /* Std inquiry data. */
|
|
cmd[2] = 0u; /* Page code. */
|
|
cmd[3] = 0u; /* Alloc len. */
|
|
cmd[4] = 0x24u; /* Alloc len. */
|
|
cmd[5] = 0u; /* Ctrl. */
|
|
|
|
/* ------------------ SEND SCSI CMD ------------------- */
|
|
USBH_MSC_XferCmd( p_msc_dev,
|
|
lun,
|
|
USBH_MSC_DATA_DIR_IN,
|
|
(void *)&cmd[0],
|
|
6u,
|
|
(void *) inq_data,
|
|
0x24u,
|
|
&err);
|
|
if (err == USBH_ERR_NONE) {
|
|
p_msc_inquiry_info->DevType = inq_data[0] & 0x1Fu;
|
|
p_msc_inquiry_info->IsRemovable = inq_data[1] >> 7u;
|
|
|
|
Mem_Copy((void *) p_msc_inquiry_info->Vendor_ID,
|
|
(void *)&inq_data[8],
|
|
8u);
|
|
|
|
Mem_Copy((void *) p_msc_inquiry_info->Product_ID,
|
|
(void *)&inq_data[16],
|
|
16u);
|
|
|
|
p_msc_inquiry_info->ProductRevisionLevel = MEM_VAL_GET_INT32U(&inq_data[32]);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_CMD_TestUnitReady()
|
|
*
|
|
* Description : Read number of sectors & sector size.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if the command is successful.
|
|
*
|
|
* ---- RETURNED BY USBH_MSC_XferCmd ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : (1) The SCSI "TEST UNIT READY" command is documented in 'SCSI Primary Commands - 3
|
|
* (SPC-3)', Section 6.33.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_SCSI_CMD_TestUnitReady (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun)
|
|
{
|
|
USBH_ERR err;
|
|
CPU_INT08U cmd[6];
|
|
/* See Note #1. */
|
|
/* ------------ PREPARE SCSI COMMAND BLOCK ------------ */
|
|
cmd[0] = USBH_SCSI_CMD_TEST_UNIT_READY; /* Operation code (0x00). */
|
|
cmd[1] = 0u; /* Reserved. */
|
|
cmd[2] = 0u; /* Reserved. */
|
|
cmd[3] = 0u; /* Reserved. */
|
|
cmd[4] = 0u; /* Reserved. */
|
|
cmd[5] = 0u; /* Control. */
|
|
|
|
USBH_MSC_XferCmd( p_msc_dev, /* ---------------- SEND SCSI COMMAND ----------------- */
|
|
lun,
|
|
USBH_MSC_DATA_DIR_NONE,
|
|
(void *)&cmd[0],
|
|
6u,
|
|
(void *) 0,
|
|
0u,
|
|
&err);
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_CMD_ReqSense()
|
|
*
|
|
* Description : Issue command to obtain sense data.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to USBH_MSC_DEV device.
|
|
*
|
|
* lun Logical unit number
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* data_len Number of data bytes to receive.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
* USBH_ERR_NONE Command successfully transmitted.
|
|
*
|
|
* ---- RETURNED BY USBH_MSC_XferCmd ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets sent.
|
|
*
|
|
* Note(s) : (1) The SCSI "REQUEST SENSE" command is documented in 'SCSI Primary Commands - 3
|
|
* (SPC-3)', Section 6.27.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT32U USBH_SCSI_CMD_ReqSense (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT08U *p_arg,
|
|
CPU_INT32U data_len,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT08U cmd[6];
|
|
CPU_INT32U xfer_len;
|
|
|
|
/* See Note(s) #1 */
|
|
/* ------------ PREPARE SCSI COMMAND BLOCK ------------ */
|
|
cmd[0] = USBH_SCSI_CMD_REQUEST_SENSE; /* Operation code (0x03). */
|
|
cmd[1] = 0u; /* Reserved. */
|
|
cmd[2] = 0u; /* Reserved. */
|
|
cmd[3] = 0u; /* Reserved. */
|
|
cmd[4] = (CPU_INT08U)data_len; /* Allocation length. */
|
|
cmd[5] = 0u; /* Ctrl. */
|
|
|
|
/* ------------------ SEND SCSI CMD ------------------- */
|
|
xfer_len = USBH_MSC_XferCmd( p_msc_dev,
|
|
lun,
|
|
USBH_MSC_DATA_DIR_IN,
|
|
(void *)cmd,
|
|
6u,
|
|
(void *)p_arg,
|
|
data_len,
|
|
p_err);
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_GetSenseInfo()
|
|
*
|
|
* Description : Obtain sense data.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* p_sense_key Pointer to variable that will receive sense key.
|
|
*
|
|
* p_asc Pointer to variable that will receive additional sense code.
|
|
*
|
|
* p_ascq Pointer to variable that will receive additional sense code qualifier.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if command is successful.
|
|
* USBH_ERR_UNKNOWN, if unknown error occured.
|
|
*
|
|
* ---- RETURNED BY USBH_SCSI_CMD_ReqSense ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : (1) The SCSI "REQUEST SENSE" command is documented in 'SCSI Primary Commands - 3
|
|
* (SPC-3)', Section 6.27.
|
|
*
|
|
* (2) The format of the sense data is documented in 'SCSI Primary Commands - 3 (SPC-3)',
|
|
* Section 4.5.3. :
|
|
* (a) The response code in the 0th byte of the sense data should be either 0x70 or 0x71.
|
|
* (b) The lower nibble of the 2nd byte of the sense data is the sense key.
|
|
* (c) The 12th byte of the sense data is the additional sense code (ASC).
|
|
* (d) The 13th byte of the sense data is the additional sense code (ASC) qualifier.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_SCSI_GetSenseInfo (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT08U *p_sense_key,
|
|
CPU_INT08U *p_asc,
|
|
CPU_INT08U *p_ascq)
|
|
{
|
|
USBH_ERR err;
|
|
CPU_INT32U xfer_len;
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, sense_data, 18);
|
|
CPU_INT08U resp_code;
|
|
|
|
|
|
xfer_len = USBH_SCSI_CMD_ReqSense(p_msc_dev, /* Issue SCSI request sense cmd. */
|
|
lun,
|
|
sense_data,
|
|
18u,
|
|
&err);
|
|
if (err == USBH_ERR_NONE) {
|
|
resp_code = sense_data[0] & 0x7Fu;
|
|
|
|
if ( (xfer_len >= 13u) &&
|
|
((resp_code == 0x70u) || (resp_code == 0x71u))) {
|
|
*p_sense_key = sense_data[2] & 0x0Fu;
|
|
*p_asc = sense_data[12];
|
|
*p_ascq = sense_data[13];
|
|
err = USBH_ERR_NONE;
|
|
|
|
} else {
|
|
*p_sense_key = 0u;
|
|
*p_asc = 0u;
|
|
*p_ascq = 0u;
|
|
err = USBH_ERR_UNKNOWN;
|
|
#if (USBH_CFG_PRINT_LOG == DEF_ENABLED)
|
|
USBH_PRINT_LOG("ERROR Invalid SENSE response from device - ");
|
|
USBH_PRINT_LOG("xfer_len : %d, sense_data[0] : %02X\r\n", xfer_len, sense_data[0]);
|
|
#endif
|
|
}
|
|
|
|
} else {
|
|
*p_sense_key = 0u;
|
|
*p_asc = 0u;
|
|
*p_ascq = 0u;
|
|
USBH_PRINT_ERR(err);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_CMD_CapacityRd()
|
|
*
|
|
* Description : Read number of sectors & sector size.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* p_nbr_blks Pointer to variable that will receive number of blocks.
|
|
*
|
|
* p_blk_size Pointer to variable that will receive block size.
|
|
*
|
|
* Return(s) : USBH_ERR_NONE, if command is successful.
|
|
*
|
|
* ---- RETURNED BY USBH_MSC_XferCmd ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Note(s) : (1) The SCSI "READ CAPAPITY (10)" command is documented in 'SCSI Block Commands - 2
|
|
* (SBC-2)', Section 5.10.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBH_ERR USBH_SCSI_CMD_CapacityRd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U *p_nbr_blks,
|
|
CPU_INT32U *p_blk_size)
|
|
{
|
|
CPU_INT08U cmd[10];
|
|
ALLOC_CACHE_ALIGN_BUFFER(CPU_INT08U, cap_data, 8);
|
|
USBH_ERR err;
|
|
/* See Note #1. */
|
|
/* -------------- PREPARE SCSI CMD BLOCK -------------- */
|
|
cmd[0] = USBH_SCSI_CMD_READ_CAPACITY; /* Operation code (0x25). */
|
|
cmd[1] = 0u; /* Reserved. */
|
|
cmd[2] = 0u; /* Logical Block Address (MSB). */
|
|
cmd[3] = 0u; /* Logical Block Address. */
|
|
cmd[4] = 0u; /* Logical Block Address. */
|
|
cmd[5] = 0u; /* Logical Block Address (LSB). */
|
|
cmd[6] = 0u; /* Reserved. */
|
|
cmd[7] = 0u; /* Reserved. */
|
|
cmd[8] = 0u; /* ----------------------- PMI. ----------------------- */
|
|
cmd[9] = 0u; /* Control. */
|
|
|
|
USBH_MSC_XferCmd ( p_msc_dev, /* ------------------ SEND SCSI CMD ------------------- */
|
|
lun,
|
|
USBH_MSC_DATA_DIR_IN,
|
|
(void *)cmd,
|
|
10u,
|
|
(void *)cap_data,
|
|
8u,
|
|
&err);
|
|
if (err == USBH_ERR_NONE) { /* -------------- HANDLE DEVICE RESPONSE -------------- */
|
|
MEM_VAL_COPY_GET_INT32U_BIG(p_nbr_blks, &cap_data[0]);
|
|
*p_nbr_blks += 1u;
|
|
MEM_VAL_COPY_GET_INT32U_BIG(p_blk_size, &cap_data[4]);
|
|
}
|
|
|
|
return (err);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_Rd()
|
|
*
|
|
* Description : Read specified number of blocks from device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* blk_addr Block address.
|
|
*
|
|
* nbr_blks Number of blocks to read.
|
|
*
|
|
* blk_size Block size.
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
* USBH_ERR_NONE Data successfully received.
|
|
*
|
|
* ---- RETURNED BY USBH_MSC_XferCmd ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of bytes read.
|
|
*
|
|
* Note(s) : (1) The SCSI "READ (10): command is documented in 'SCSI Block Commands - 2 (SBC-2)',
|
|
* Section 5.6.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT32U USBH_SCSI_Rd (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U blk_addr,
|
|
CPU_INT16U nbr_blks,
|
|
CPU_INT32U blk_size,
|
|
void *p_arg,
|
|
USBH_ERR *p_err)
|
|
{
|
|
CPU_INT08U cmd[10];
|
|
CPU_INT32U data_len;
|
|
CPU_INT32U xfer_len;
|
|
|
|
|
|
data_len = nbr_blks * blk_size;
|
|
/* See Note #1. */
|
|
/* -------------- PREPARE SCSI CMD BLOCK -------------- */
|
|
cmd[0] = USBH_SCSI_CMD_READ_10; /* Operation code (0x28). */
|
|
cmd[1] = 0u; /* Reserved. */
|
|
MEM_VAL_COPY_SET_INT32U_BIG(&cmd[2], &blk_addr); /* Logcal Block Address (LBA). */
|
|
cmd[6] = 0u; /* Reserved. */
|
|
MEM_VAL_COPY_SET_INT16U_BIG(&cmd[7], &nbr_blks); /* Transfer length (number of logical blocks). */
|
|
cmd[9] = 0u; /* Control. */
|
|
|
|
xfer_len = USBH_MSC_XferCmd( p_msc_dev, /* ---------------- SEND SCSI COMMAND ----------------- */
|
|
lun,
|
|
USBH_MSC_DATA_DIR_IN,
|
|
(void *)&cmd[0],
|
|
10u,
|
|
p_arg,
|
|
data_len,
|
|
p_err);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
xfer_len = (CPU_INT32U)0;
|
|
}
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_SCSI_Wr()
|
|
*
|
|
* Description : Write specified number of blocks to device.
|
|
*
|
|
* Argument(s) : p_msc_dev Pointer to MSC device.
|
|
*
|
|
* lun Logical unit number.
|
|
*
|
|
* blk_addr Block address.
|
|
*
|
|
* nbr_blks Number of blocks to write.
|
|
*
|
|
* blk_size Block size.
|
|
*
|
|
* p_arg Pointer to data buffer.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
* USBH_ERR_NONE Data successfully transmitted.
|
|
*
|
|
* ---- RETURNED BY USBH_MSC_XferCmd ----
|
|
* USBH_ERR_MSC_CMD_FAILED Device reports command failed.
|
|
* USBH_ERR_MSC_CMD_PHASE Device reports command phase error.
|
|
* USBH_ERR_MSC_IO Unable to receive CSW.
|
|
* USBH_ERR_INVALID_ARG Invalid argument passed to 'p_ep'.
|
|
* USBH_ERR_EP_INVALID_TYPE Endpoint type or direction is incorrect.
|
|
* USBH_ERR_EP_INVALID_STATE Endpoint is not opened.
|
|
* Host controller drivers error code, Otherwise.
|
|
*
|
|
* Return(s) : Number of octets written.
|
|
*
|
|
* Note(s) : (1) The SCSI "WRITE (10)" command is documented in 'SCSI Block Commands - 2 (SBC-2)',
|
|
* Section 5.25.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT32U USBH_SCSI_Wr (USBH_MSC_DEV *p_msc_dev,
|
|
CPU_INT08U lun,
|
|
CPU_INT32U blk_addr,
|
|
CPU_INT16U nbr_blks,
|
|
CPU_INT32U blk_size,
|
|
const void *p_arg,
|
|
USBH_ERR *p_err)
|
|
|
|
{
|
|
CPU_INT08U cmd[10];
|
|
CPU_INT32U data_len;
|
|
CPU_INT32U xfer_len;
|
|
|
|
|
|
data_len = nbr_blks * blk_size;
|
|
/* See Note #1. */
|
|
/* -------------- PREPARE SCSI CMD BLOCK -------------- */
|
|
cmd[0] = USBH_SCSI_CMD_WRITE_10; /* Operation code (0x2A). */
|
|
cmd[1] = 0u; /* Reserved. */
|
|
MEM_VAL_COPY_SET_INT32U_BIG(&cmd[2], &blk_addr); /* Logical Block Address (LBA). */
|
|
cmd[6] = 0u; /* Reserved. */
|
|
MEM_VAL_COPY_SET_INT16U_BIG(&cmd[7], &nbr_blks); /* Transfer length (number of logical blocks). */
|
|
cmd[9] = 0u; /* Control. */
|
|
|
|
xfer_len = USBH_MSC_XferCmd( p_msc_dev, /* ------------------ SEND SCSI CMD ------------------- */
|
|
lun,
|
|
USBH_MSC_DATA_DIR_OUT,
|
|
(void *)&cmd[0],
|
|
10u,
|
|
(void *) p_arg,
|
|
data_len,
|
|
p_err);
|
|
if (*p_err != USBH_ERR_NONE) {
|
|
xfer_len = 0u;
|
|
}
|
|
|
|
return (xfer_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_FmtCBW()
|
|
*
|
|
* Description : Format CBW from CBW structure.
|
|
*
|
|
* Argument(s) : p_cbw Variable that contains CBW information.
|
|
*
|
|
* p_buf_dest Pointer to buffer that will receive CBW content.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_FmtCBW (USBH_MSC_CBW *p_cbw,
|
|
void *p_buf_dest)
|
|
{
|
|
CPU_INT08U i;
|
|
USBH_MSC_CBW *p_buf_dest_cbw;
|
|
|
|
|
|
p_buf_dest_cbw = (USBH_MSC_CBW *)p_buf_dest;
|
|
|
|
p_buf_dest_cbw->dCBWSignature = MEM_VAL_GET_INT32U_LITTLE(&p_cbw->dCBWSignature);
|
|
p_buf_dest_cbw->dCBWTag = MEM_VAL_GET_INT32U_LITTLE(&p_cbw->dCBWTag);
|
|
p_buf_dest_cbw->dCBWDataTransferLength = MEM_VAL_GET_INT32U_LITTLE(&p_cbw->dCBWDataTransferLength);
|
|
p_buf_dest_cbw->bmCBWFlags = p_cbw->bmCBWFlags;
|
|
p_buf_dest_cbw->bCBWLUN = p_cbw->bCBWLUN;
|
|
p_buf_dest_cbw->bCBWCBLength = p_cbw->bCBWCBLength;
|
|
|
|
for (i = 0u; i < 16u; i++) {
|
|
p_buf_dest_cbw->CBWCB[i] = p_cbw->CBWCB[i];
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBH_MSC_ParseCSW()
|
|
*
|
|
* Description : Parse CSW into CSW structure.
|
|
*
|
|
* Argument(s) : p_csw Variable that will receive CSW parsed in this function.
|
|
*
|
|
* p_buf_src Pointer to buffer that contains CSW.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBH_MSC_ParseCSW (USBH_MSC_CSW *p_csw,
|
|
void *p_buf_src)
|
|
{
|
|
USBH_MSC_CSW *p_buf_src_cbw;
|
|
|
|
|
|
p_buf_src_cbw = (USBH_MSC_CSW *)p_buf_src;
|
|
|
|
p_csw->dCSWSignature = MEM_VAL_GET_INT32U_LITTLE(&p_buf_src_cbw->dCSWSignature);
|
|
p_csw->dCSWTag = MEM_VAL_GET_INT32U_LITTLE(&p_buf_src_cbw->dCSWTag);
|
|
p_csw->dCSWDataResidue = MEM_VAL_GET_INT32U_LITTLE(&p_buf_src_cbw->dCSWDataResidue);
|
|
p_csw->bCSWStatus = p_buf_src_cbw->bCSWStatus;
|
|
}
|