SAMV71 Xplained Ultra Software Package 1.5

MSDLun.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- */
00002 /*                  Atmel Microcontroller Software Support                      */
00003 /*                       SAM Software Package License                           */
00004 /* ---------------------------------------------------------------------------- */
00005 /* Copyright (c) 2015, Atmel Corporation                                        */
00006 /*                                                                              */
00007 /* All rights reserved.                                                         */
00008 /*                                                                              */
00009 /* Redistribution and use in source and binary forms, with or without           */
00010 /* modification, are permitted provided that the following condition is met:    */
00011 /*                                                                              */
00012 /* - Redistributions of source code must retain the above copyright notice,     */
00013 /* this list of conditions and the disclaimer below.                            */
00014 /*                                                                              */
00015 /* Atmel's name may not be used to endorse or promote products derived from     */
00016 /* this software without specific prior written permission.                     */
00017 /*                                                                              */
00018 /* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
00028 /* ---------------------------------------------------------------------------- */
00029 
00030 /** \file
00031  * \addtogroup usbd_msd
00032  *@{
00033  */
00034 
00035 /*------------------------------------------------------------------------------
00036  *         Headers
00037  *------------------------------------------------------------------------------*/
00038 
00039 
00040 #include "MSDLun.h"
00041 #include <USBLib_Trace.h>
00042 #include "USBD.h"
00043 
00044 /*------------------------------------------------------------------------------
00045  *         Constants
00046  *------------------------------------------------------------------------------*/
00047 
00048 /** Default LUN block size in bytes */
00049 #define     DEFAULT_LUN_BLOCK_SIZE      512
00050 
00051 /*------------------------------------------------------------------------------
00052  *         Internal variables
00053  *------------------------------------------------------------------------------*/
00054 
00055 /** Inquiry data to return to the host for the Lun. */
00056 static SBCInquiryData inquiryData = {
00057 
00058     SBC_DIRECT_ACCESS_BLOCK_DEVICE, /* Direct-access block device */
00059     SBC_PERIPHERAL_DEVICE_CONNECTED,/* Peripheral device is connected */
00060     0x00,                           /* Reserved bits */
00061     0x01,                           /* Media is removable */
00062     SBC_SPC_VERSION_4,              /* SPC-4 supported */
00063     0x2,                            /* Response data format, must be 0x2 */
00064     0,                              /* Hierarchical addressing not supported */
00065     0,                              /* ACA not supported */
00066     0x0,                            /* Obsolete bits */
00067     sizeof(SBCInquiryData) - 5,     /* Additional length */
00068     0,                              /* No embedded SCC */
00069     0,                              /* No access control coordinator */
00070     SBC_TPGS_NONE,                  /* No target port support group */
00071     0,                              /* Third-party copy not supported */
00072     0x0,                            /* Reserved bits */
00073     0,                              /* Protection information not supported */
00074     0x0,                            /* Obsolete bit */
00075     0,                              /* No embedded enclosure service component */
00076     0x0,                            /* ??? */
00077     0,                              /* Device is not multi-port */
00078     0x0,                            /* Obsolete bits */
00079     0x0,                            /* Unused feature */
00080     0x0,                            /* Unused features */
00081     0,                              /* Task management model not supported */
00082     0x0,                            /* ??? */
00083     {'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '},
00084     {
00085         'M', 'a', 's', 's', ' ',
00086         'S', 't', 'o', 'r', 'a', 'g', 'e', ' ',
00087         'M', 'S', 'D'
00088     },
00089     {'0', '.', '0', '1'},
00090     {
00091         'M', 'a', 's', 's', ' ',
00092         'S', 't', 'o', 'r', 'a', 'g', 'e', ' ',
00093         'E', 'x', 'a', 'm', 'p', 'l', 'e'
00094     },
00095     0x00,                           /* Unused features */
00096     0x00,                           /* Reserved bits */
00097     {SBC_VERSION_DESCRIPTOR_SBC_3}, /* SBC-3 compliant device */
00098     {
00099         0, 0, 0, 0, 0,
00100         0, 0, 0, 0, 0,
00101         0, 0, 0, 0, 0,
00102         0, 0, 0, 0, 0,
00103         0, 0
00104     } /* Reserved */
00105 };
00106 
00107 /*------------------------------------------------------------------------------
00108  *         Exported functions
00109  *------------------------------------------------------------------------------*/
00110 
00111 /**
00112  * \brief  Initializes a LUN instance. Must be invoked at least once even no
00113  *         Media is linked.
00114  * \param  lun          Pointer to the MSDLun instance to initialize
00115  * \param  media        Media on which the LUN is constructed, set to 0 to
00116  *                      disconnect the Media or initialize an ejected LUN.
00117  * \param  ioBuffer     Pointer to a buffer used for read/write operation and
00118  *                      which must be blockSize bytes long.
00119  * \param  ioBufferSize Size of the allocated IO buffer.
00120  * \param  baseAddress  Base address of the LUN in number of media blocks
00121  * \param  size         Total size of the LUN in number of media blocks
00122  * \param  blockSize    One block of the LUN in number of media blocks
00123  * \param  protected    The LUN area is forced to readonly even the media
00124  *                      is writable
00125  * \param  dataMonitor  Pointer to a Monitor Function to analyze the flow of
00126  *                      this LUN.
00127  */
00128 void LUN_Init(MSDLun    *lun,
00129               void      *media,
00130               uint8_t   *ioBuffer,
00131               uint32_t   ioBufferSize,
00132               uint32_t   baseAddress,
00133               uint32_t   size,
00134               uint16_t   blockSize,
00135               uint8_t    protected,
00136               void (*dataMonitor)(uint8_t flowDirection,
00137                                   uint32_t  dataLength,
00138                                   uint32_t  fifoNullCount,
00139                                   uint32_t  fifoFullCount))
00140 {
00141     uint32_t logicalBlockAddress;
00142     TRACE_INFO("LUN init\n\r");
00143 
00144     /* Initialize inquiry data */
00145 
00146     lun->inquiryData = &inquiryData;
00147 
00148     /* Initialize request sense data */
00149 
00150     lun->requestSenseData.bResponseCode = SBC_SENSE_DATA_FIXED_CURRENT;
00151     lun->requestSenseData.isValid = 1;
00152     lun->requestSenseData.bObsolete1 = 0;
00153     lun->requestSenseData.bSenseKey = SBC_SENSE_KEY_NO_SENSE;
00154     lun->requestSenseData.bReserved1 = 0;
00155     lun->requestSenseData.isILI = 0;
00156     lun->requestSenseData.isEOM = 0;
00157     lun->requestSenseData.isFilemark = 0;
00158     lun->requestSenseData.pInformation[0] = 0;
00159     lun->requestSenseData.pInformation[1] = 0;
00160     lun->requestSenseData.pInformation[2] = 0;
00161     lun->requestSenseData.pInformation[3] = 0;
00162     lun->requestSenseData.bAdditionalSenseLength
00163         = sizeof(SBCRequestSenseData) - 8;
00164     lun->requestSenseData.bAdditionalSenseCode = 0;
00165     lun->requestSenseData.bAdditionalSenseCodeQualifier = 0;
00166     lun->requestSenseData.bFieldReplaceableUnitCode = 0;
00167     lun->requestSenseData.bSenseKeySpecific = 0;
00168     lun->requestSenseData.pSenseKeySpecific[0] = 0;
00169     lun->requestSenseData.pSenseKeySpecific[0] = 0;
00170     lun->requestSenseData.isSKSV = 0;
00171 
00172     STORE_DWORDB(0, lun->readCapacityData.pLogicalBlockAddress);
00173     STORE_DWORDB(0, lun->readCapacityData.pLogicalBlockLength);
00174 
00175     /* Initialize LUN */
00176 
00177     lun->media = media;
00178 
00179     if (media == 0) {
00180         lun->status = LUN_NOT_PRESENT;
00181         return;
00182     }
00183 
00184     lun->baseAddress = baseAddress;
00185 
00186     /* Customized block size */
00187 
00188     if (blockSize)
00189         lun->blockSize = blockSize;
00190     else {
00191         uint32_t blkSize = MED_GetBlockSize(media);
00192 
00193         if (blkSize < DEFAULT_LUN_BLOCK_SIZE)
00194             lun->blockSize = DEFAULT_LUN_BLOCK_SIZE / blkSize;
00195         else
00196             lun->blockSize = 1;
00197     }
00198 
00199     if (size)
00200         lun->size = size;
00201     else {
00202         lun->size = MED_GetSize(media);
00203         /*if (blockSize) */
00204 
00205         /*    lun->size = media->size / blockSize; */
00206 
00207         /*else { */
00208 
00209         /*    if (media->blockSize < DEFAULT_LUN_BLOCK_SIZE) */
00210 
00211         /*        lun->size = media->size / lun->blockSize; */
00212 
00213         /*    else */
00214 
00215         /*        lun->size = media->size; */
00216 
00217         /*} */
00218 
00219     }
00220 
00221     TRACE_INFO("LUN: blkSize %d, size %d\n\r", (int)lun->blockSize, (int)lun->size);
00222 
00223     if (protected) lun->protected = 1;
00224     else           lun->protected = MED_IsProtected(media);
00225 
00226     MSDIOFifo_Init(&lun->ioFifo, ioBuffer, ioBufferSize);
00227 
00228     lun->dataMonitor = dataMonitor;
00229 
00230     /* Initialize read capacity data */
00231 
00232     logicalBlockAddress = lun->size / lun->blockSize - 1;
00233     STORE_DWORDB(logicalBlockAddress,
00234                  lun->readCapacityData.pLogicalBlockAddress);
00235     STORE_DWORDB(lun->blockSize * MED_GetBlockSize(media),
00236                  lun->readCapacityData.pLogicalBlockLength);
00237 
00238     /* Indicate media change */
00239 
00240     lun->status = LUN_CHANGED;
00241 }
00242 
00243 /**
00244  * \brief  Eject the media from a LUN
00245  * \param  lun          Pointer to the MSDLun instance to initialize
00246  * \return Operation result code
00247  */
00248 uint32_t LUN_Eject(MSDLun *lun)
00249 {
00250     if (lun->media) {
00251 
00252         /* Avoid any LUN R/W in progress */
00253         if (MED_IsBusy(lun->media))
00254 
00255             return USBD_STATUS_LOCKED;
00256 
00257         /* Remove the link of the media */
00258         lun->media = 0;
00259     }
00260 
00261     /* LUN is removed */
00262     lun->status = LUN_NOT_PRESENT;
00263 
00264     return USBD_STATUS_SUCCESS;
00265 }
00266 
00267 /**
00268  * \brief  Writes data on the a LUN starting at the specified block address.
00269  * \param  lun          Pointer to a MSDLun instance
00270  * \param  blockAddress First block address to write
00271  * \param  data         Pointer to the data to write
00272  * \param  length       Number of blocks to write
00273  * \param  callback     Optional callback to invoke when the write finishes
00274  * \param  argument     Optional callback argument.
00275  * \return Operation result code
00276  */
00277 uint32_t LUN_Write(MSDLun        *lun,
00278                    uint32_t blockAddress,
00279                    void         *data,
00280                    uint32_t length,
00281                    TransferCallback   callback,
00282                    void         *argument)
00283 {
00284     uint32_t  medBlk, medLen;
00285     uint8_t status;
00286 
00287     TRACE_INFO_WP("LUNWrite(%u) ", (unsigned int)blockAddress);
00288 
00289     /* Check that the data is not too big */
00290     if ((length + blockAddress) * lun->blockSize > lun->size) {
00291 
00292         TRACE_WARNING("LUN_Write: Data too big\n\r");
00293         status = USBD_STATUS_ABORTED;
00294     } else if (lun->media == 0 || lun->status != LUN_READY) {
00295 
00296         TRACE_WARNING("LUN_Write: Media not ready\n\r");
00297         status = USBD_STATUS_ABORTED;
00298     } else if (lun->protected) {
00299         TRACE_WARNING("LUN_Write: LUN is readonly\n\r");
00300         status = USBD_STATUS_ABORTED;
00301     } else {
00302 
00303         /* Compute write start address */
00304         medBlk = lun->baseAddress + blockAddress * lun->blockSize;
00305         medLen = length * lun->blockSize;
00306 
00307         /* Start write operation */
00308         status = MED_Write(lun->media,
00309                            medBlk,
00310                            data,
00311                            medLen,
00312                            (fMEDCallback)callback,
00313                            argument);
00314 
00315         /* Check operation result code */
00316         if (status == MED_STATUS_SUCCESS)
00317 
00318             status = USBD_STATUS_SUCCESS;
00319         else {
00320 
00321             TRACE_WARNING("LUN_Write: Cannot write media\n\r");
00322             status = USBD_STATUS_ABORTED;
00323         }
00324     }
00325 
00326     return status;
00327 }
00328 
00329 /**
00330  * \brief  Reads data from a LUN, starting at the specified block address.
00331  * \param  lun          Pointer to a MSDLun instance
00332  * \param  blockAddress First block address to read
00333  * \param  data         Pointer to a data buffer in which to store the data
00334  * \param  length       Number of blocks to read
00335  * \param  callback     Optional callback to invoke when the read finishes
00336  * \param  argument     Optional callback argument.
00337  * \return Operation result code
00338  */
00339 uint32_t LUN_Read(MSDLun        *lun,
00340                   uint32_t blockAddress,
00341                   void     *data,
00342                   uint32_t length,
00343                   TransferCallback   callback,
00344                   void         *argument)
00345 {
00346     uint32_t medBlk, medLen;
00347     uint8_t status;
00348 
00349     /* Check that the data is not too big */
00350     if ((length + blockAddress) * lun->blockSize > lun->size) {
00351 
00352         TRACE_WARNING("LUN_Read: Area: (%d + %d)*%d > %d\n\r",
00353                       (int)length, (int)blockAddress, (int)lun->blockSize, (int)lun->size);
00354         status = USBD_STATUS_ABORTED;
00355     } else if (lun->media == 0 || lun->status != LUN_READY) {
00356 
00357         TRACE_WARNING("LUN_Read: Media not present\n\r");
00358         status = USBD_STATUS_ABORTED;
00359     } else {
00360 
00361         TRACE_INFO_WP("LUNRead(%u) ", (unsigned int)blockAddress);
00362 
00363         /* Compute read start address */
00364         medBlk = lun->baseAddress + (blockAddress * lun->blockSize);
00365         medLen = length * lun->blockSize;
00366 
00367         /* Start write operation */
00368         status = MED_Read(lun->media,
00369                           medBlk,
00370                           data,
00371                           medLen,
00372                           (fMEDCallback)callback,
00373                           argument);
00374 
00375         /* Check result code */
00376         if (status == MED_STATUS_SUCCESS)
00377 
00378             status = USBD_STATUS_SUCCESS;
00379         else {
00380 
00381             TRACE_WARNING("LUN_Read: Cannot read media\n\r");
00382             status = USBD_STATUS_ABORTED;
00383         }
00384     }
00385 
00386     return status;
00387 }
00388 
00389 /**@}*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines