mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 05:38:33 +03:00
390 lines
13 KiB
C
390 lines
13 KiB
C
/* ----------------------------------------------------------------------------
|
|
* ATMEL Microcontroller Software Support
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2008, Atmel Corporation
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the disclaimer below.
|
|
*
|
|
* Atmel's name may not be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/** \file
|
|
* \addtogroup usbd_msd
|
|
*@{
|
|
*/
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Headers
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
|
|
#include "MSDLun.h"
|
|
#include <USBLib_Trace.h>
|
|
#include <USBD.h>
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Constants
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/** Default LUN block size in bytes */
|
|
#define DEFAULT_LUN_BLOCK_SIZE 512
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Internal variables
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/** Inquiry data to return to the host for the Lun. */
|
|
static SBCInquiryData inquiryData = {
|
|
|
|
SBC_DIRECT_ACCESS_BLOCK_DEVICE, /* Direct-access block device */
|
|
SBC_PERIPHERAL_DEVICE_CONNECTED,/* Peripheral device is connected */
|
|
0x00, /* Reserved bits */
|
|
0x01, /* Media is removable */
|
|
SBC_SPC_VERSION_4, /* SPC-4 supported */
|
|
0x2, /* Response data format, must be 0x2 */
|
|
0, /* Hierarchical addressing not supported */
|
|
0, /* ACA not supported */
|
|
0x0, /* Obsolete bits */
|
|
sizeof(SBCInquiryData) - 5, /* Additional length */
|
|
0, /* No embedded SCC */
|
|
0, /* No access control coordinator */
|
|
SBC_TPGS_NONE, /* No target port support group */
|
|
0, /* Third-party copy not supported */
|
|
0x0, /* Reserved bits */
|
|
0, /* Protection information not supported */
|
|
0x0, /* Obsolete bit */
|
|
0, /* No embedded enclosure service component */
|
|
0x0, /* ??? */
|
|
0, /* Device is not multi-port */
|
|
0x0, /* Obsolete bits */
|
|
0x0, /* Unused feature */
|
|
0x0, /* Unused features */
|
|
0, /* Task management model not supported */
|
|
0x0, /* ??? */
|
|
{'A','T','M','E','L',' ',' ',' '},
|
|
{'M','a','s','s',' ',
|
|
'S','t','o','r','a','g','e',' ',
|
|
'M','S','D'},
|
|
{'0','.','0','1'},
|
|
{'M','a','s','s',' ',
|
|
'S','t','o','r','a','g','e',' ',
|
|
'E','x','a','m','p','l','e'},
|
|
0x00, /* Unused features */
|
|
0x00, /* Reserved bits */
|
|
{SBC_VERSION_DESCRIPTOR_SBC_3}, /* SBC-3 compliant device */
|
|
{0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0,
|
|
0, 0} /* Reserved */
|
|
};
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Exported functions
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* \brief Initializes a LUN instance. Must be invoked at least once even no
|
|
* Media is linked.
|
|
* \param lun Pointer to the MSDLun instance to initialize
|
|
* \param media Media on which the LUN is constructed, set to 0 to
|
|
* disconnect the Media or initialize an ejected LUN.
|
|
* \param ioBuffer Pointer to a buffer used for read/write operation and
|
|
* which must be blockSize bytes long.
|
|
* \param ioBufferSize Size of the allocated IO buffer.
|
|
* \param baseAddress Base address of the LUN in number of media blocks
|
|
* \param size Total size of the LUN in number of media blocks
|
|
* \param blockSize One block of the LUN in number of media blocks
|
|
* \param protected The LUN area is forced to readonly even the media
|
|
* is writable
|
|
* \param dataMonitor Pointer to a Monitor Function to analyze the flow of
|
|
* this LUN.
|
|
*/
|
|
void LUN_Init(MSDLun *lun,
|
|
Media *media,
|
|
uint8_t *ioBuffer,
|
|
uint32_t ioBufferSize,
|
|
uint32_t baseAddress,
|
|
uint32_t size,
|
|
uint16_t blockSize,
|
|
uint8_t protected,
|
|
void (*dataMonitor)(uint8_t flowDirection,
|
|
uint32_t dataLength,
|
|
uint32_t fifoNullCount,
|
|
uint32_t fifoFullCount))
|
|
{
|
|
uint32_t logicalBlockAddress;
|
|
TRACE_INFO("LUN init\n\r");
|
|
|
|
/* Initialize inquiry data */
|
|
|
|
lun->inquiryData = &inquiryData;
|
|
|
|
/* Initialize request sense data */
|
|
|
|
lun->requestSenseData.bResponseCode = SBC_SENSE_DATA_FIXED_CURRENT;
|
|
lun->requestSenseData.isValid = 1;
|
|
lun->requestSenseData.bObsolete1 = 0;
|
|
lun->requestSenseData.bSenseKey = SBC_SENSE_KEY_NO_SENSE;
|
|
lun->requestSenseData.bReserved1 = 0;
|
|
lun->requestSenseData.isILI = 0;
|
|
lun->requestSenseData.isEOM = 0;
|
|
lun->requestSenseData.isFilemark = 0;
|
|
lun->requestSenseData.pInformation[0] = 0;
|
|
lun->requestSenseData.pInformation[1] = 0;
|
|
lun->requestSenseData.pInformation[2] = 0;
|
|
lun->requestSenseData.pInformation[3] = 0;
|
|
lun->requestSenseData.bAdditionalSenseLength
|
|
= sizeof(SBCRequestSenseData) - 8;
|
|
lun->requestSenseData.bAdditionalSenseCode = 0;
|
|
lun->requestSenseData.bAdditionalSenseCodeQualifier = 0;
|
|
lun->requestSenseData.bFieldReplaceableUnitCode = 0;
|
|
lun->requestSenseData.bSenseKeySpecific = 0;
|
|
lun->requestSenseData.pSenseKeySpecific[0] = 0;
|
|
lun->requestSenseData.pSenseKeySpecific[0] = 0;
|
|
lun->requestSenseData.isSKSV = 0;
|
|
|
|
STORE_DWORDB(0, lun->readCapacityData.pLogicalBlockAddress);
|
|
STORE_DWORDB(0, lun->readCapacityData.pLogicalBlockLength);
|
|
|
|
/* Initialize LUN */
|
|
|
|
lun->media = media;
|
|
if (media == 0) {
|
|
lun->status = LUN_NOT_PRESENT;
|
|
return;
|
|
}
|
|
|
|
lun->baseAddress = baseAddress;
|
|
|
|
/* Customized block size */
|
|
|
|
if (blockSize) {
|
|
lun->blockSize = blockSize;
|
|
}
|
|
else {
|
|
if (media->blockSize < DEFAULT_LUN_BLOCK_SIZE)
|
|
lun->blockSize = DEFAULT_LUN_BLOCK_SIZE / media->blockSize;
|
|
else
|
|
lun->blockSize = 1;
|
|
}
|
|
|
|
if (size) {
|
|
lun->size = size;
|
|
}
|
|
else {
|
|
lun->size = media->size;
|
|
/*if (blockSize) */
|
|
|
|
/* lun->size = media->size / blockSize; */
|
|
|
|
/*else { */
|
|
|
|
/* if (media->blockSize < DEFAULT_LUN_BLOCK_SIZE) */
|
|
|
|
/* lun->size = media->size / lun->blockSize; */
|
|
|
|
/* else */
|
|
|
|
/* lun->size = media->size; */
|
|
|
|
/*} */
|
|
|
|
}
|
|
|
|
TRACE_INFO("LUN: blkSize %d, size %d\n\r", (int)lun->blockSize, (int)lun->size);
|
|
if (protected) lun->protected = 1;
|
|
else lun->protected = media->protected;
|
|
|
|
lun->ioFifo.pBuffer = ioBuffer;
|
|
lun->ioFifo.bufferSize = ioBufferSize;
|
|
|
|
lun->dataMonitor = dataMonitor;
|
|
|
|
/* Initialize read capacity data */
|
|
|
|
logicalBlockAddress = lun->size / lun->blockSize - 1;
|
|
STORE_DWORDB(logicalBlockAddress,
|
|
lun->readCapacityData.pLogicalBlockAddress);
|
|
STORE_DWORDB(lun->blockSize * media->blockSize,
|
|
lun->readCapacityData.pLogicalBlockLength);
|
|
|
|
/* Indicate media change */
|
|
|
|
lun->status = LUN_CHANGED;
|
|
}
|
|
|
|
/**
|
|
* \brief Eject the media from a LUN
|
|
* \param lun Pointer to the MSDLun instance to initialize
|
|
* \return Operation result code
|
|
*/
|
|
uint32_t LUN_Eject(MSDLun *lun)
|
|
{
|
|
if (lun->media) {
|
|
|
|
/* Avoid any LUN R/W in progress */
|
|
if (lun->media->state == MED_STATE_BUSY) {
|
|
|
|
return USBD_STATUS_LOCKED;
|
|
}
|
|
|
|
/* Remove the link of the media */
|
|
lun->media = 0;
|
|
}
|
|
/* LUN is removed */
|
|
lun->status = LUN_NOT_PRESENT;
|
|
|
|
return USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* \brief Writes data on the a LUN starting at the specified block address.
|
|
* \param lun Pointer to a MSDLun instance
|
|
* \param blockAddress First block address to write
|
|
* \param data Pointer to the data to write
|
|
* \param length Number of blocks to write
|
|
* \param callback Optional callback to invoke when the write finishes
|
|
* \param argument Optional callback argument.
|
|
* \return Operation result code
|
|
*/
|
|
uint32_t LUN_Write(MSDLun *lun,
|
|
uint32_t blockAddress,
|
|
void *data,
|
|
uint32_t length,
|
|
TransferCallback callback,
|
|
void *argument)
|
|
{
|
|
uint32_t medBlk, medLen;
|
|
uint8_t status;
|
|
|
|
TRACE_INFO_WP("LUNWrite(%u) ", blockAddress);
|
|
|
|
/* Check that the data is not too big */
|
|
if ((length + blockAddress) * lun->blockSize > lun->size) {
|
|
|
|
TRACE_WARNING("LUN_Write: Data too big\n\r");
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
else if (lun->media == 0 || lun->status != LUN_READY) {
|
|
|
|
TRACE_WARNING("LUN_Write: Media not ready\n\r");
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
else if (lun->protected) {
|
|
TRACE_WARNING("LUN_Write: LUN is readonly\n\r");
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
else {
|
|
|
|
/* Compute write start address */
|
|
medBlk = lun->baseAddress + blockAddress * lun->blockSize;
|
|
medLen = length * lun->blockSize;
|
|
|
|
/* Start write operation */
|
|
status = MED_Write(lun->media,
|
|
medBlk,
|
|
data,
|
|
medLen,
|
|
(MediaCallback) callback,
|
|
argument);
|
|
|
|
/* Check operation result code */
|
|
if (status == MED_STATUS_SUCCESS) {
|
|
|
|
status = USBD_STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
|
|
TRACE_WARNING("LUN_Write: Cannot write media\n\r");
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* \brief Reads data from a LUN, starting at the specified block address.
|
|
* \param lun Pointer to a MSDLun instance
|
|
* \param blockAddress First block address to read
|
|
* \param data Pointer to a data buffer in which to store the data
|
|
* \param length Number of blocks to read
|
|
* \param callback Optional callback to invoke when the read finishes
|
|
* \param argument Optional callback argument.
|
|
* \return Operation result code
|
|
*/
|
|
uint32_t LUN_Read(MSDLun *lun,
|
|
uint32_t blockAddress,
|
|
void *data,
|
|
uint32_t length,
|
|
TransferCallback callback,
|
|
void *argument)
|
|
{
|
|
uint32_t medBlk, medLen;
|
|
uint8_t status;
|
|
|
|
/* Check that the data is not too big */
|
|
if ((length + blockAddress) * lun->blockSize > lun->size) {
|
|
|
|
TRACE_WARNING("LUN_Read: Area: (%d + %d)*%d > %d\n\r",
|
|
(int)length, (int)blockAddress, (int)lun->blockSize, (int)lun->size);
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
else if (lun->media == 0 || lun->status != LUN_READY) {
|
|
|
|
TRACE_WARNING("LUN_Read: Media not present\n\r");
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
else {
|
|
|
|
TRACE_INFO_WP("LUNRead(%u) ", blockAddress);
|
|
|
|
/* Compute read start address */
|
|
medBlk = lun->baseAddress + (blockAddress * lun->blockSize);
|
|
medLen = length * lun->blockSize;
|
|
|
|
/* Start write operation */
|
|
status = MED_Read(lun->media,
|
|
medBlk,
|
|
data,
|
|
medLen,
|
|
(MediaCallback) callback,
|
|
argument);
|
|
|
|
/* Check result code */
|
|
if (status == MED_STATUS_SUCCESS) {
|
|
|
|
status = USBD_STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
|
|
TRACE_WARNING("LUN_Read: Cannot read media\n\r");
|
|
status = USBD_STATUS_ABORTED;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**@}*/
|