SAMV71 Xplained Ultra Software Package 1.3

MSDLun.c

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