SAMV71 Xplained Ultra Software Package 1.4

SBCMethods.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 #include "SBCMethods.h"
00040 #include "MSDDStateMachine.h"
00041 #include "USBD.h"
00042 
00043 #include "MSDIOFifo.h"
00044 
00045 /*------------------------------------------------------------------------------
00046  *      Global variables
00047  *------------------------------------------------------------------------------*/
00048 
00049 /*------------------------------------------------------------------------------
00050  *      Macros
00051  *------------------------------------------------------------------------------*/
00052 
00053 #ifdef MSDIO_READ10_CHUNK_SIZE
00054 /** READ10 - Read data from specific LUN to FIFO */
00055 #define SBC_READ_CHUNK(pLun, lba, pFifo, pCb, pArg) \
00056     LUN_Read((pLun), (lba), \
00057             &(pFifo)->pBuffer[(pFifo)->inputNdx], \
00058              ((pFifo)->chunkSize/(pFifo)->blockSize), \
00059              (TransferCallback)(pCb), (void*)pArg)
00060 /** READ10 - Transfer data from FIFO to USB */
00061 #define SBC_TX_CHUNK(ep, pFifo, pCb, pArg) \
00062     USBD_Write( (ep), \
00063                &(pFifo)->pBuffer[(pFifo)->outputNdx], \
00064                 (pFifo)->chunkSize, \
00065                 (TransferCallback)(pCb), (void*)(pArg))
00066 #endif
00067 
00068 #ifdef MSDIO_WRITE10_CHUNK_SIZE
00069 /** WRITE10 - Read data from USB to FIFO */
00070 #define SBC_RX_CHUNK(ep, pFifo,pCb,pArg) \
00071     USBD_Read( (ep), \
00072               &(pFifo)->pBuffer[(pFifo)->inputNdx], \
00073                (pFifo)->chunkSize, \
00074                (TransferCallback)(pCb), (void*)(pArg))
00075 /** WRITE10 - Write data from FIFO to LUN */
00076 #define SBC_WRITE_CHUNK(pLun, lba, pFifo, pCb, pArg) \
00077     LUN_Write((pLun), (lba), \
00078              &(pFifo)->pBuffer[(pFifo)->outputNdx], \
00079               ((pFifo)->chunkSize/(pFifo)->blockSize), \
00080               (TransferCallback)(pCb), (void*)(pArg))
00081 #endif
00082 
00083 
00084 /**
00085  * \brief  Header for the mode pages data
00086  * \see    SBCModeParameterHeader6
00087  */
00088 static const SBCModeParameterHeader6 modeParameterHeader6 = {
00089 
00090     sizeof(SBCModeParameterHeader6) - 1,        /*! Length is 0x03 */
00091 
00092     SBC_MEDIUM_TYPE_DIRECT_ACCESS_BLOCK_DEVICE, /*! Direct-access block device */
00093 
00094     0,                                          /*! Reserved bits */
00095 
00096     0,                                          /*! DPO/FUA not supported */
00097 
00098     0,                                          /*! Reserved bits */
00099 
00100     0,                                          /*! not write-protected */
00101 
00102     0                                           /*! No block descriptor */
00103 
00104 };
00105 
00106 /*------------------------------------------------------------------------------
00107  *      Internal functions
00108  *------------------------------------------------------------------------------*/
00109 
00110 /**
00111  * This function is to be used as a callback for USB or LUN transfers.
00112  * \param  transfer    Pointer to the transfer structure to update
00113  * \param  status      Operation result code
00114  * \param  transferred Number of bytes transferred by the command
00115  * \param  remaining   Number of bytes not transferred
00116  */
00117 static void MSDDriver_Callback(MSDTransfer *transfer,
00118                                uint8_t status,
00119                                uint32_t transferred,
00120                                uint32_t remaining)
00121 {
00122     TRACE_DEBUG_WP( "Cbk " ) ;
00123     transfer->semaphore++;
00124     transfer->status = status;
00125     transfer->transferred = transferred;
00126     transfer->remaining = remaining;
00127 }
00128 
00129 /**
00130  * \brief  Check if the LUN is ready.
00131  * \param  lun          Pointer to the LUN affected by the command
00132  * \return 1 if the LUN is ready to be written
00133  * \see    MSDLun
00134  */
00135 static unsigned char SBCLunIsReady(MSDLun *lun)
00136 {
00137     unsigned char lunIsReady = 0;
00138 
00139     if (lun->media == 0 || lun->status < LUN_CHANGED) {
00140         TRACE_INFO("SBCLunIsReady: Not Present!\n\r");
00141         SBC_UpdateSenseData(&(lun->requestSenseData),
00142                             SBC_SENSE_KEY_NOT_READY,
00143                             SBC_ASC_MEDIUM_NOT_PRESENT,
00144                             0);
00145 
00146     }
00147     else if (lun->status < LUN_READY) {
00148         TRACE_INFO("SBCLunIsReady: Changing!\n\r");
00149         SBC_UpdateSenseData(&(lun->requestSenseData),
00150                             SBC_SENSE_KEY_UNIT_ATTENTION,
00151                             SBC_ASC_NOT_READY_TO_READY_CHANGE,
00152                             0);
00153         lun->status = LUN_READY;
00154     }
00155     else {
00156 
00157         lunIsReady = 1;
00158     }
00159 
00160     return lunIsReady;
00161 }
00162 
00163 /**
00164  * \brief  Check if the LUN can write.
00165  * \param  lun          Pointer to the LUN affected by the command
00166  * \return 1 if the LUN is ready to be written
00167  * \see    MSDLun
00168  */
00169 static unsigned char SBCLunCanBeWritten(MSDLun *lun)
00170 {
00171     unsigned char canBeWritten = 0;
00172 
00173     if (!SBCLunIsReady(lun)) {
00174 
00175         TRACE_WARNING("SBCLunCanBeWritten: Not Ready!\n\r");
00176     }
00177     else if (lun->protected) {
00178 
00179         TRACE_WARNING("SBCLunCanBeWritten: Protected!\n\r");
00180         SBC_UpdateSenseData(&(lun->requestSenseData),
00181                             SBC_SENSE_KEY_DATA_PROTECT,
00182                             SBC_ASC_WRITE_PROTECTED,
00183                             0);
00184     }
00185     else {
00186 
00187         canBeWritten = 1;
00188     }
00189 
00190     return canBeWritten;
00191 }
00192 
00193 /**
00194  * \brief  Performs a WRITE (10) command on the specified LUN.
00195  *
00196  *         The data to write is first received from the USB host and then
00197  *         actually written on the media.
00198  *         This function operates asynchronously and must be called multiple
00199  *         times to complete. A result code of MSDDriver_STATUS_INCOMPLETE
00200  *         indicates that at least another call of the method is necessary.
00201  * \param  lun          Pointer to the LUN affected by the command
00202  * \param  commandState Current state of the command
00203  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
00204  * \see    MSDLun
00205  * \see    MSDCommandState
00206  */
00207 static unsigned char SBC_Write10(MSDLun          *lun,
00208                                  MSDCommandState *commandState)
00209 {
00210     unsigned char status;
00211     unsigned char result = MSDD_STATUS_INCOMPLETE;
00212     SBCRead10 *command = (SBCRead10 *) commandState->cbw.pCommand;
00213     MSDTransfer *transfer = &(commandState->transfer);
00214     MSDTransfer *disktransfer = &(commandState->disktransfer);
00215     MSDIOFifo   *fifo = &lun->ioFifo;
00216     unsigned int oldChunkSize, newChunkSize;
00217     /* Init command state */
00218     if (commandState->state == 0) {
00219 
00220         commandState->state = SBC_STATE_WRITE;
00221 
00222         /* The command should not be proceeded if READONLY */
00223         if (!SBCLunCanBeWritten(lun)) {
00224 
00225             return MSDD_STATUS_RW;
00226         }
00227         else {
00228 
00229 
00230             /* Initialize FIFO */
00231             fifo->dataTotal = commandState->length;
00232             fifo->blockSize = lun->blockSize * MED_GetBlockSize(lun->media);
00233           #ifdef MSDIO_WRITE10_CHUNK_SIZE
00234             if ( fifo->blockSize < MSDIO_WRITE10_CHUNK_SIZE)
00235                 fifo->chunkSize = MSDIO_WRITE10_CHUNK_SIZE;
00236             else
00237                 fifo->chunkSize = fifo->blockSize;
00238           #endif
00239             fifo->fullCnt = 0;
00240             fifo->nullCnt = 0;
00241 
00242             /* Initialize FIFO output (Disk) */
00243             fifo->outputNdx = 0;
00244             fifo->outputTotal = 0;
00245             fifo->outputState = MSDIO_IDLE;
00246             transfer->semaphore = 0;
00247 
00248             /* Initialize FIFO input (USB) */
00249             fifo->inputNdx = 0;
00250             fifo->inputTotal = 0;
00251             fifo->inputState = MSDIO_START;
00252             disktransfer->semaphore = 0;
00253         }
00254 
00255     }
00256 
00257     if (commandState->length == 0) {
00258 
00259         /* Perform the callback! */
00260         if (lun->dataMonitor) {
00261 
00262             lun->dataMonitor(0, fifo->dataTotal, fifo->nullCnt, fifo->fullCnt);
00263         }
00264         return MSDD_STATUS_SUCCESS;
00265     }
00266     oldChunkSize = fifo->chunkSize;
00267     if ((fifo->dataTotal - fifo->inputTotal) < fifo->chunkSize) {
00268        newChunkSize = fifo->dataTotal - fifo->inputTotal;
00269        fifo->chunkSize = newChunkSize;
00270     }
00271     /* USB receive task */
00272     switch(fifo->inputState) {
00273 
00274     /*------------------ */
00275     case MSDIO_IDLE:
00276     /*------------------ */
00277 
00278         if (fifo->inputTotal < fifo->dataTotal &&
00279             fifo->inputTotal - fifo->outputTotal < fifo->bufferSize) {
00280 
00281             fifo->inputState = MSDIO_START;
00282         }
00283         break;
00284 
00285     /*------------------ */
00286     case MSDIO_START:
00287     /*------------------ */
00288 
00289         /* Should not start if there is any disk error */
00290         if (fifo->outputState == MSDIO_ERROR) {
00291 
00292             TRACE_INFO_WP("udErr ");
00293             fifo->inputState = MSDIO_ERROR;
00294             break;
00295         }
00296 
00297         /* Read one block of data sent by the host */
00298         if (MED_IsMappedWRSupported(lun->media)) {
00299 
00300             /* Directly read to memory */
00301           #if 1
00302             uint32_t mappedAddr = MED_GetMappedAddress(
00303                                         lun->media,
00304                                         DWORDB(command->pLogicalBlockAddress)
00305                                          * lun->blockSize);
00306             //printf("W(%x,%d)\n\r", mappedAddr, fifo->dataTotal);
00307             status = USBD_Read(commandState->pipeOUT,
00308                                (void*)(mappedAddr),
00309                                //(void*)
00310                                // ((lun->media->baseAddress
00311                                //   + (lun->baseAddress
00312                                //       + DWORDB(command->pLogicalBlockAddress)
00313                                //         * lun->blockSize
00314                                //     )
00315                                //   ) * MED_GetBlockSize(lun->media)
00316                                //),
00317                                 fifo->dataTotal,
00318                                 (TransferCallback) MSDDriver_Callback,
00319                                 (void *) transfer);
00320           #else
00321             status = MSDD_Read((void*)
00322                                 ((lun->media->baseAddress
00323                                   + (lun->baseAddress
00324                                       + DWORDB(command->pLogicalBlockAddress)
00325                                         * lun->blockSize
00326                                     )
00327                                   ) * MED_GetBlockSize(lun->media)
00328                                 ),
00329                                 fifo->dataTotal,
00330                                 (TransferCallback) MSDDriver_Callback,
00331                                 (void *) transfer);
00332           #endif
00333         }
00334         else {
00335           #ifdef MSDIO_WRITE10_CHUNK_SIZE
00336             status = SBC_RX_CHUNK(commandState->pipeOUT,
00337                                   fifo, MSDDriver_Callback, transfer);
00338           #else
00339             /* Read block to buffer */
00340            #if 1
00341             status = USBD_Read(commandState->pipeOUT,
00342                                (void*)&fifo->pBuffer[fifo->inputNdx],
00343                                fifo->blockSize,
00344                                (TransferCallback) MSDDriver_Callback,
00345                                (void *) transfer);
00346            #else
00347             status = MSDD_Read((void*)&fifo->pBuffer[fifo->inputNdx],
00348                                fifo->blockSize,
00349                                (TransferCallback) MSDDriver_Callback,
00350                                (void *) transfer);
00351            #endif
00352           #endif
00353         }
00354 
00355         /* Check operation result code */
00356 
00357         if (status != USBD_STATUS_SUCCESS) {
00358 
00359             TRACE_WARNING(
00360                 "RBC_Write10: Failed to start receiving\n\r");
00361             SBC_UpdateSenseData(&(lun->requestSenseData),
00362                                 SBC_SENSE_KEY_HARDWARE_ERROR,
00363                                 0,
00364                                 0);
00365             result = MSDD_STATUS_ERROR;
00366         }
00367         else {
00368 
00369             TRACE_INFO_WP("uRx ");
00370 
00371             /* Prepare next device state */
00372 
00373             fifo->inputState = MSDIO_WAIT;
00374         }
00375         break; /* MSDIO_START */
00376 
00377 
00378     /*------------------ */
00379 
00380     case MSDIO_WAIT:
00381     /*------------------ */
00382 
00383         TRACE_INFO_WP("uWait ");
00384 
00385         /* Check semaphore */
00386 //        printf("uW%x ",transfer->semaphore);
00387         if (transfer->semaphore > 0) {
00388 
00389             transfer->semaphore--;
00390             fifo->inputState = MSDIO_NEXT;
00391         }
00392         break;
00393 
00394     /*------------------ */
00395 
00396     case MSDIO_NEXT:
00397     /*------------------ */
00398 
00399         /* Check the result code of the read operation */
00400 
00401         if (transfer->status != USBD_STATUS_SUCCESS) {
00402 
00403             TRACE_WARNING(
00404                 "RBC_Write10: Failed to received\n\r");
00405             SBC_UpdateSenseData(&(lun->requestSenseData),
00406                                 SBC_SENSE_KEY_HARDWARE_ERROR,
00407                                 0,
00408                                 0);
00409             result = MSDD_STATUS_ERROR;
00410         }
00411         else {
00412 
00413             TRACE_INFO_WP("uNxt ");
00414 
00415             /* Mapped read, all data done */
00416 
00417             if (MED_IsMappedWRSupported(lun->media)) {
00418 
00419                 fifo->inputTotal = fifo->dataTotal;
00420                 fifo->inputState = MSDIO_IDLE;
00421             }
00422             else {
00423 
00424                 /* Update input index */
00425               #ifdef MSDIO_WRITE10_CHUNK_SIZE
00426                 
00427                 MSDIOFifo_IncNdx(fifo->inputNdx,
00428                                  fifo->chunkSize,
00429                                  fifo->bufferSize);
00430                 fifo->inputTotal += fifo->chunkSize;
00431 
00432               #else
00433                 MSDIOFifo_IncNdx(fifo->inputNdx,
00434                                  fifo->blockSize,
00435                                  fifo->bufferSize);
00436                 fifo->inputTotal += fifo->blockSize;
00437               #endif
00438 
00439                 /* Start Next block */
00440 
00441                 /* - All Data done? */
00442 
00443                 if (fifo->inputTotal >= fifo->dataTotal) {
00444 
00445                     fifo->inputState = MSDIO_IDLE;
00446                 }
00447                 /* - Buffer full? */
00448 
00449                 else if (fifo->inputNdx == fifo->outputNdx) {
00450                     fifo->inputState = MSDIO_IDLE;
00451                     fifo->fullCnt ++;
00452 
00453                     TRACE_DEBUG_WP("ufFull%d ", fifo->inputNdx);
00454                 }
00455                 /* - More data to transfer? */
00456 
00457                 else if (fifo->inputTotal < fifo->dataTotal) {
00458                     fifo->inputState = MSDIO_START;
00459 
00460                     TRACE_INFO_WP("uStart ");
00461                 }
00462                 /* never executed ! */
00463 
00464                 /*else { */
00465 
00466                 /*    fifo->inputState = MSDIO_IDLE; */
00467 
00468                 /*    TRACE_INFO_WP("uDone "); */
00469 
00470                 /*} */
00471 
00472             }
00473 
00474         }
00475         break; /* MSDIO_NEXT */
00476 
00477 
00478     /*------------------ */
00479 
00480     case MSDIO_ERROR:
00481     /*------------------ */
00482 
00483 
00484         TRACE_WARNING_WP("uErr ");
00485         commandState->length -= fifo->inputTotal;
00486         return MSDD_STATUS_RW;
00487 
00488     }
00489     /* Disk write task */
00490     fifo->chunkSize = oldChunkSize ;
00491     if ((fifo->dataTotal - fifo->outputTotal) < fifo->chunkSize) {
00492          newChunkSize = fifo->dataTotal - fifo->outputTotal;
00493          fifo->chunkSize = newChunkSize;
00494     }
00495     switch(fifo->outputState) {
00496 
00497     /*------------------ */
00498 
00499     case MSDIO_IDLE:
00500     /*------------------ */
00501 
00502         if (fifo->outputTotal < fifo->inputTotal) {
00503 
00504             fifo->outputState = MSDIO_START;
00505         }
00506         break;
00507 
00508     /*------------------ */
00509 
00510     case MSDIO_START:
00511     /*------------------ */
00512 
00513 
00514         /* Write the block to the media */
00515 
00516         if (MED_IsMappedWRSupported(lun->media)) {
00517 
00518             MSDDriver_Callback(disktransfer, MED_STATUS_SUCCESS, 0, 0);
00519             status = LUN_STATUS_SUCCESS;
00520         }
00521         else {
00522           #ifdef MSDIO_WRITE10_CHUNK_SIZE
00523             status = SBC_WRITE_CHUNK(lun, DWORDB(command->pLogicalBlockAddress),
00524                                      fifo, MSDDriver_Callback, disktransfer);
00525           #else
00526             status = LUN_Write(lun,
00527                                DWORDB(command->pLogicalBlockAddress),
00528                                &fifo->pBuffer[fifo->outputNdx],
00529                                1,
00530                                (TransferCallback) MSDDriver_Callback,
00531                                (void *) disktransfer);
00532           #endif
00533         }
00534 
00535         /* Check operation result code */
00536 
00537         if (status != USBD_STATUS_SUCCESS) {
00538 
00539             TRACE_WARNING(
00540                 "RBC_Write10: Failed to start write - ");
00541 
00542             if (!SBCLunCanBeWritten(lun)) {
00543 
00544                 TRACE_WARNING("?\n\r");
00545                 SBC_UpdateSenseData(&(lun->requestSenseData),
00546                                     SBC_SENSE_KEY_NOT_READY,
00547                                     0,
00548                                     0);
00549             }
00550 
00551             fifo->outputState = MSDIO_ERROR;
00552         }
00553         else {
00554 
00555             /* Prepare next state */
00556 
00557             fifo->outputState = MSDIO_WAIT;
00558         }
00559         break; /* MSDIO_START */
00560 
00561 
00562     /*------------------ */
00563 
00564     case MSDIO_WAIT:
00565     /*------------------ */
00566 
00567         TRACE_INFO_WP("dWait ");
00568 
00569         /* Check semaphore value */
00570 
00571         if (disktransfer->semaphore > 0) {
00572 
00573             /* Take semaphore and move to next state */
00574 
00575             disktransfer->semaphore--;
00576             fifo->outputState = MSDIO_NEXT;
00577         }
00578         break;
00579 
00580     /*------------------ */
00581 
00582     case MSDIO_NEXT:
00583     /*------------------ */
00584 
00585         /* Check operation result code */
00586 
00587         if (transfer->status != USBD_STATUS_SUCCESS) {
00588 
00589             TRACE_WARNING(
00590                 "RBC_Write10: Failed to write\n\r");
00591             SBC_UpdateSenseData(&(lun->requestSenseData),
00592                                 SBC_SENSE_KEY_RECOVERED_ERROR,
00593                                 SBC_ASC_TOO_MUCH_WRITE_DATA,
00594                                 0);
00595             result = MSDD_STATUS_ERROR;
00596         }
00597         else {
00598 
00599             TRACE_INFO_WP("dNxt ");
00600 
00601             /* Update transfer length and block address */
00602 
00603 
00604             /* Mapped memory, done */
00605 
00606             if (MED_IsMappedWRSupported(lun->media)) {
00607 
00608                 commandState->length = 0;
00609                 fifo->outputState = MSDIO_IDLE;
00610             }
00611             else {
00612 
00613                 /* Update output index */
00614 
00615               #ifdef MSDIO_WRITE10_CHUNK_SIZE
00616                 STORE_DWORDB(DWORDB(command->pLogicalBlockAddress)
00617                                  + fifo->chunkSize/fifo->blockSize,
00618                              command->pLogicalBlockAddress);
00619                 MSDIOFifo_IncNdx(fifo->outputNdx,
00620                                  fifo->chunkSize,
00621                                  fifo->bufferSize);
00622                 fifo->outputTotal += fifo->chunkSize;
00623               #else
00624                 STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + 1,
00625                              command->pLogicalBlockAddress);
00626                 MSDIOFifo_IncNdx(fifo->outputNdx,
00627                                  fifo->blockSize,
00628                                  fifo->bufferSize);
00629                 fifo->outputTotal += fifo->blockSize;
00630               #endif
00631 
00632                 /* Start Next block */
00633 
00634                 /* - All data done? */
00635 
00636                 if (fifo->outputTotal >= fifo->dataTotal) {
00637 
00638                     fifo->outputState = MSDIO_IDLE;
00639                     commandState->length = 0;
00640                     TRACE_INFO_WP("dDone ");
00641                 }
00642                 /* - Send next? */
00643 
00644                 else if (fifo->outputTotal < fifo->inputTotal) {
00645 
00646                     fifo->outputState = MSDIO_START;
00647                     TRACE_INFO_WP("dStart ");
00648                 }
00649                 /* - Buffer Null? */
00650 
00651                 else {
00652                     fifo->outputState = MSDIO_IDLE;
00653                     fifo->nullCnt ++;
00654 
00655                     TRACE_DEBUG_WP("dfNull%d ", fifo->outputNdx);
00656                 }
00657             }
00658         }
00659         break; /* MSDIO_NEXT */
00660 
00661 
00662     /*------------------ */
00663 
00664     case MSDIO_ERROR:
00665     /*------------------ */
00666 
00667         break;
00668     }
00669 
00670     return result;
00671 }
00672 
00673 /**
00674  * \brief  Performs a READ (10) command on specified LUN.
00675  *
00676  *         The data is first read from the media and then sent to the USB host.
00677  *         This function operates asynchronously and must be called multiple
00678  *         times to complete. A result code of MSDDriver_STATUS_INCOMPLETE
00679  *         indicates that at least another call of the method is necessary.
00680  * \param  lun          Pointer to the LUN affected by the command
00681  * \param  commandState Current state of the command
00682  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
00683  * \see    MSDLun
00684  * \see    MSDCommandState
00685  */
00686 static unsigned char SBC_Read10(MSDLun          *lun,
00687                                 MSDCommandState *commandState)
00688 {
00689     unsigned char status;
00690     unsigned char result = MSDD_STATUS_INCOMPLETE;
00691     SBCRead10 *command = (SBCRead10 *) commandState->cbw.pCommand;
00692     MSDTransfer *transfer = &(commandState->transfer);
00693     MSDTransfer *disktransfer = &(commandState->disktransfer);
00694     MSDIOFifo   *fifo = &lun->ioFifo;
00695     unsigned int oldChunkSize, newChunkSize;
00696     /* Init command state */
00697 
00698     if (commandState->state == 0) {
00699 
00700         commandState->state = SBC_STATE_READ;
00701 
00702         if (!SBCLunIsReady(lun)) {
00703 
00704             return MSDD_STATUS_RW;
00705         }
00706         else {
00707 
00708             /* Initialize FIFO */
00709 
00710             fifo->dataTotal = commandState->length;
00711             fifo->blockSize = lun->blockSize * MED_GetBlockSize(lun->media);
00712           #ifdef MSDIO_READ10_CHUNK_SIZE
00713             if (fifo->blockSize < MSDIO_READ10_CHUNK_SIZE){
00714                 fifo->chunkSize = MSDIO_READ10_CHUNK_SIZE;
00715             }
00716             else
00717                 fifo->chunkSize = fifo->blockSize;
00718           #endif
00719             fifo->fullCnt = 0;
00720             fifo->nullCnt = 0;
00721 
00722           #ifdef MSDIO_FIFO_OFFSET
00723             /* Enable offset if total size >= 2*bufferSize */
00724 
00725             if (fifo->dataTotal / fifo->bufferSize >= 2)
00726                 fifo->bufferOffset = MSDIO_FIFO_OFFSET;
00727             else
00728                 fifo->bufferOffset = 0;
00729           #endif
00730 
00731             /* Initialize FIFO output (USB) */
00732 
00733             fifo->outputNdx = 0;
00734             fifo->outputTotal = 0;
00735             fifo->outputState = MSDIO_IDLE;
00736             transfer->semaphore = 0;
00737 
00738             /* Initialize FIFO input (Disk) */
00739 
00740             fifo->inputNdx = 0;
00741             fifo->inputTotal = 0;
00742             fifo->inputState = MSDIO_START;
00743             disktransfer->semaphore = 0;
00744         }
00745     }
00746 
00747     /* Check length */
00748 
00749     if (commandState->length == 0) {
00750 
00751         /* Perform the callback! */
00752 
00753         if (lun->dataMonitor) {
00754 
00755             lun->dataMonitor(1, fifo->dataTotal, fifo->nullCnt, fifo->fullCnt);
00756         }
00757         return MSDD_STATUS_SUCCESS;
00758     }
00759 
00760     /* Disk reading task */
00761     oldChunkSize = fifo->chunkSize;
00762     if ((fifo->dataTotal - fifo->inputTotal) < fifo->chunkSize) {
00763        newChunkSize = fifo->dataTotal - fifo->inputTotal;
00764        fifo->chunkSize = newChunkSize;
00765     }
00766     switch(fifo->inputState) {
00767 
00768     /*------------------ */
00769 
00770     case MSDIO_IDLE:
00771     /*------------------ */
00772 
00773         if (fifo->inputTotal < fifo->dataTotal &&
00774             fifo->inputTotal - fifo->outputTotal < fifo->bufferSize) {
00775 
00776             fifo->inputState = MSDIO_START;
00777         }
00778         break;
00779 
00780     /*------------------ */
00781 
00782     case MSDIO_START:
00783     /*------------------ */
00784         /* Read one block of data from the media */
00785 
00786         if (MED_IsMappedRDSupported(lun->media)) {
00787 
00788             /* Directly write, no read needed */
00789 
00790             MSDDriver_Callback(disktransfer, MED_STATUS_SUCCESS, 0, 0);
00791             status = LUN_STATUS_SUCCESS;
00792         }
00793         else {
00794           #ifdef MSDIO_READ10_CHUNK_SIZE
00795             status = SBC_READ_CHUNK(lun, DWORDB(command->pLogicalBlockAddress),
00796                                     fifo, MSDDriver_Callback, disktransfer);
00797           #else
00798 
00799             status = LUN_Read(lun,
00800                               DWORDB(command->pLogicalBlockAddress),
00801                               &fifo->pBuffer[fifo->inputNdx],
00802                               1,
00803                               (TransferCallback) MSDDriver_Callback,
00804                               (void *)disktransfer);
00805           #endif
00806         }
00807 
00808         /* Check operation result code */
00809 
00810         if (status != LUN_STATUS_SUCCESS) {
00811 
00812             TRACE_WARNING("RBC_Read10: Failed to start reading\n\r");
00813             if (SBCLunIsReady(lun)) {
00814 
00815                 SBC_UpdateSenseData(&(lun->requestSenseData),
00816                                     SBC_SENSE_KEY_NOT_READY,
00817                                     SBC_ASC_LOGICAL_UNIT_NOT_READY,
00818                                     0);
00819             }
00820 
00821             fifo->inputState = MSDIO_ERROR;
00822         }
00823         else {
00824 
00825             TRACE_INFO_WP("dRd ");
00826 
00827             /* Move to next command state */
00828 
00829             fifo->inputState = MSDIO_WAIT;
00830         }
00831         break; /* MSDIO_START */
00832 
00833 
00834     /*------------------ */
00835 
00836     case MSDIO_WAIT:
00837     /*------------------ */
00838 
00839         /* Check semaphore value */
00840 
00841         if (disktransfer->semaphore > 0) {
00842 
00843             TRACE_INFO_WP("dOk ");
00844 
00845             /* Take semaphore and move to next state */
00846 
00847             disktransfer->semaphore--;
00848             fifo->inputState = MSDIO_NEXT;
00849         }
00850         break;
00851 
00852     /*------------------ */
00853 
00854     case MSDIO_NEXT:
00855     /*------------------ */
00856 
00857         /* Check the operation result code */
00858 
00859         if (disktransfer->status != USBD_STATUS_SUCCESS) {
00860 
00861             TRACE_WARNING(
00862                 "RBC_Read10: Failed to read media\n\r");
00863             SBC_UpdateSenseData(&(lun->requestSenseData),
00864                                 SBC_SENSE_KEY_RECOVERED_ERROR,
00865                                 SBC_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,
00866                                 0);
00867             result = MSDD_STATUS_ERROR;
00868         }
00869         else {
00870 
00871             TRACE_INFO_WP("dNxt ");
00872 
00873             if (MED_IsMappedRDSupported(lun->media)) {
00874 
00875                 /* All data is ready */
00876 
00877                 fifo->inputState = MSDIO_IDLE;
00878                 fifo->inputTotal = fifo->dataTotal;
00879             }
00880             else {
00881 
00882                 /* Update block address */
00883 
00884               #ifdef MSDIO_READ10_CHUNK_SIZE
00885                 
00886                 /* Update input index */
00887                 STORE_DWORDB(DWORDB(command->pLogicalBlockAddress)
00888                                  + fifo->chunkSize/fifo->blockSize,
00889                              command->pLogicalBlockAddress);
00890                 MSDIOFifo_IncNdx(fifo->inputNdx,
00891                                  fifo->chunkSize,
00892                                  fifo->bufferSize);
00893                 fifo->inputTotal += fifo->chunkSize;
00894               #else
00895                 /* Update block address */
00896 
00897                 STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + 1,
00898                              command->pLogicalBlockAddress);
00899 
00900                 /* Update input index */
00901 
00902                 MSDIOFifo_IncNdx(fifo->inputNdx,
00903                                  fifo->blockSize,
00904                                  fifo->bufferSize);
00905                 fifo->inputTotal += fifo->blockSize;
00906               #endif
00907 
00908                 /* Start Next block */
00909 
00910                 /* - All Data done? */
00911 
00912                 if (fifo->inputTotal >= fifo->dataTotal) {
00913 
00914                     TRACE_INFO_WP("dDone ");
00915                     fifo->inputState = MSDIO_IDLE;
00916                 }
00917                 /* - Buffer full? */
00918 
00919                 else if (fifo->inputNdx == fifo->outputNdx) {
00920 
00921                     TRACE_INFO_WP("dfFull%d ", (int)fifo->inputNdx);
00922                     fifo->inputState = MSDIO_IDLE;
00923                     fifo->fullCnt ++;
00924                 }
00925                 /* - More data to transfer? */
00926 
00927                 else if (fifo->inputTotal < fifo->dataTotal) {
00928 
00929                     TRACE_DEBUG_WP("dStart ");
00930                     fifo->inputState = MSDIO_START;
00931                 }
00932             }
00933 
00934         }
00935 
00936         break;
00937 
00938     /*------------------ */
00939 
00940     case MSDIO_ERROR:
00941     /*------------------ */
00942         break;
00943     }
00944      fifo->chunkSize = oldChunkSize ;
00945     /* USB sending task */
00946     if ((fifo->dataTotal - fifo->outputTotal) < fifo->chunkSize) {
00947          newChunkSize = fifo->dataTotal - fifo->outputTotal;
00948          fifo->chunkSize = newChunkSize;
00949     }
00950     
00951     switch(fifo->outputState) {
00952 
00953     /*------------------ */
00954 
00955     case MSDIO_IDLE:
00956     /*------------------ */
00957 
00958         if (fifo->outputTotal < fifo->inputTotal) {
00959 
00960           #ifdef MSDIO_FIFO_OFFSET
00961             /* Offset buffer the input data */
00962 
00963             if (fifo->bufferOffset) {
00964                 if (fifo->inputTotal < fifo->bufferOffset) {
00965                     break;
00966                 }
00967                 fifo->bufferOffset = 0;
00968             }
00969           #endif
00970             fifo->outputState = MSDIO_START;
00971         }
00972         break;
00973 
00974     /*------------------ */
00975 
00976     case MSDIO_START:
00977     /*------------------ */
00978         /* Should not start if there is any disk error */
00979 
00980         if (fifo->outputState == MSDIO_ERROR) {
00981 
00982             fifo->inputState = MSDIO_ERROR;
00983             break;
00984         }
00985 
00986         /* Send the block to the host */
00987         if (MED_IsMappedRDSupported(lun->media)) {
00988           #if 1
00989             uint32_t mappedAddr = MED_GetMappedAddress(
00990                                         lun->media,
00991                                         DWORDB(command->pLogicalBlockAddress)
00992                                          * lun->blockSize);
00993             //printf("R(%x,%d)\n\r", mappedAddr, commandState->length);
00994             status = USBD_Write(commandState->pipeIN,
00995                                 (void*)(mappedAddr),
00996                                 //(void*)
00997                                 // ((lun->media->baseAddress
00998                                 //    + (lun->baseAddress
00999                                 //       + DWORDB(command->pLogicalBlockAddress)
01000                                 //         * lun->blockSize
01001                                 //      )
01002                                 //   ) * MED_GetBlockSize(lun->media)
01003                                 // ),
01004                                 commandState->length,
01005                                 (TransferCallback) MSDDriver_Callback,
01006                                 (void *) transfer);
01007           #else
01008             status = MSDD_Write((void*)
01009                                  ((lun->media->baseAddress
01010                                     + (lun->baseAddress
01011                                        + DWORDB(command->pLogicalBlockAddress)
01012                                          * lun->blockSize
01013                                       )
01014                                    ) * MED_GetBlockSize(lun->media)
01015                                  ),
01016                                 commandState->length,
01017                                 (TransferCallback) MSDDriver_Callback,
01018                                 (void *) transfer);
01019           #endif
01020         }
01021         else {
01022           #ifdef MSDIO_READ10_CHUNK_SIZE
01023             status = SBC_TX_CHUNK(commandState->pipeIN,
01024                                   fifo, MSDDriver_Callback, transfer);
01025           #else
01026            #if 1
01027             status = USBD_Write(commandState->pipeIN,
01028                                 &fifo->pBuffer[fifo->outputNdx],
01029                                 fifo->blockSize,
01030                                 (TransferCallback) MSDDriver_Callback,
01031                                 (void *) transfer);
01032            #else
01033             status = MSDD_Write(&fifo->pBuffer[fifo->outputNdx],
01034                                 fifo->blockSize,
01035                                 (TransferCallback) MSDDriver_Callback,
01036                                 (void *) transfer);
01037            #endif
01038           #endif
01039         }
01040         /* Check operation result code */
01041 
01042         if (status != USBD_STATUS_SUCCESS) {
01043 
01044             TRACE_WARNING(
01045                 "RBC_Read10: Failed to start to send\n\r");
01046             SBC_UpdateSenseData(&(lun->requestSenseData),
01047                                 SBC_SENSE_KEY_HARDWARE_ERROR,
01048                                 0,
01049                                 0);
01050             result = MSDD_STATUS_ERROR;
01051         }
01052         else {
01053 
01054             TRACE_INFO_WP("uTx ");
01055 
01056             /* Move to next command state */
01057 
01058             fifo->outputState = MSDIO_WAIT;
01059         }
01060         break; /* MSDIO_START */
01061 
01062 
01063     /*------------------ */
01064 
01065     case MSDIO_WAIT:
01066     /*------------------ */
01067 
01068         /* Check semaphore value */
01069 
01070         if (transfer->semaphore > 0) {
01071 
01072             TRACE_INFO_WP("uOk ");
01073 
01074             /* Take semaphore and move to next state */
01075 
01076             transfer->semaphore--;
01077             fifo->outputState = MSDIO_NEXT;
01078         }
01079         break;
01080 
01081     /*------------------ */
01082 
01083     case MSDIO_NEXT:
01084     /*------------------ */
01085 
01086         /* Check operation result code */
01087 
01088         if (transfer->status != USBD_STATUS_SUCCESS) {
01089 
01090             TRACE_WARNING(
01091                 "RBC_Read10: Failed to send data\n\r");
01092             SBC_UpdateSenseData(&(lun->requestSenseData),
01093                                 SBC_SENSE_KEY_HARDWARE_ERROR,
01094                                 0,
01095                                 0);
01096             result = MSDD_STATUS_ERROR;
01097         }
01098         else {
01099 
01100             TRACE_INFO_WP("uNxt ");
01101 
01102             if (MED_IsMappedRDSupported(lun->media)) {
01103 
01104                 commandState->length = 0;
01105             }
01106             else {
01107 
01108                 /* Update output index */
01109 
01110               #ifdef MSDIO_READ10_CHUNK_SIZE
01111                 MSDIOFifo_IncNdx(fifo->outputNdx,
01112                                  fifo->chunkSize,
01113                                  fifo->bufferSize);
01114                 fifo->outputTotal += fifo->chunkSize;
01115               #else
01116                 MSDIOFifo_IncNdx(fifo->outputNdx,
01117                                  fifo->blockSize,
01118                                  fifo->bufferSize);
01119                 fifo->outputTotal += fifo->blockSize;
01120               #endif
01121 
01122                 /* Start Next block */
01123 
01124                 /* - All data done? */
01125 
01126                 if (fifo->outputTotal >= fifo->dataTotal) {
01127 
01128                     fifo->outputState = MSDIO_IDLE;
01129                     commandState->length = 0;
01130                     TRACE_INFO_WP("uDone ");
01131                 }
01132                 /* - Buffer Null? */
01133 
01134                 else if (fifo->inputNdx == fifo->outputNdx) {
01135 
01136                     TRACE_INFO_WP("ufNull%d ", (int)fifo->outputNdx);
01137                     fifo->outputState = MSDIO_IDLE;
01138                     fifo->nullCnt ++;
01139                 }
01140                 /* - Send next? */
01141 
01142                 else if (fifo->outputTotal < fifo->inputTotal) {
01143 
01144                     TRACE_DEBUG_WP("uStart ");
01145                     fifo->outputState = MSDIO_START;
01146                 }
01147             }
01148 
01149         }
01150         break;
01151 
01152     /*------------------ */
01153 
01154     case MSDIO_ERROR:
01155     /*------------------ */
01156         break;
01157     }
01158 
01159     return result;
01160 }
01161 
01162 /**
01163  * \brief  Performs a READ CAPACITY (10) command.
01164  *
01165  *         This function operates asynchronously and must be called multiple
01166  *         times to complete. A result code of MSDD_STATUS_INCOMPLETE
01167  *         indicates that at least another call of the method is necessary.
01168  * \param  lun          Pointer to the LUN affected by the command
01169  * \param  commandState Current state of the command
01170  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
01171  * \see    MSDLun
01172  * \see    MSDCommandState
01173  */
01174 static unsigned char SBC_ReadCapacity10(MSDLun               *lun,
01175                                         MSDCommandState *commandState)
01176 {
01177     unsigned char result = MSDD_STATUS_INCOMPLETE;
01178     unsigned char status;
01179     MSDTransfer *transfer = &(commandState->transfer);
01180 
01181     if (!SBCLunIsReady(lun)) {
01182 
01183         TRACE_INFO("SBC_ReadCapacity10: Not Ready!\n\r");
01184         return MSDD_STATUS_RW;
01185     }
01186 
01187     /* Initialize command state if needed */
01188     if (commandState->state == 0) {
01189 
01190         commandState->state = SBC_STATE_WRITE;
01191     }
01192 
01193     /* Identify current command state */
01194     switch (commandState->state) {
01195     /*------------------- */
01196     case SBC_STATE_WRITE:
01197     /*------------------- */
01198 
01199         /* Start the write operation */
01200       #if 1
01201         status = USBD_Write(commandState->pipeIN,
01202                             &(lun->readCapacityData),
01203                             commandState->length,
01204                             (TransferCallback) MSDDriver_Callback,
01205                             (void *) transfer);
01206       #else
01207         status = MSDD_Write(&(lun->readCapacityData),
01208                             commandState->length,
01209                             (TransferCallback) MSDDriver_Callback,
01210                             (void *) transfer);
01211       #endif
01212 
01213         /* Check operation result code */
01214         if (status != USBD_STATUS_SUCCESS) {
01215 
01216             TRACE_WARNING(
01217                 "RBC_ReadCapacity: Cannot start sending data\n\r");
01218             result = MSDD_STATUS_ERROR;
01219         }
01220         else {
01221 
01222             /* Proceed to next command state */
01223             TRACE_INFO_WP("Sending ");
01224             commandState->state = SBC_STATE_WAIT_WRITE;
01225         }
01226         break;
01227 
01228     /*------------------------ */
01229     case SBC_STATE_WAIT_WRITE:
01230     /*------------------------ */
01231 
01232         /* Check semaphore value */
01233         if (transfer->semaphore > 0) {
01234 
01235             /* Take semaphore and terminate command */
01236             transfer->semaphore--;
01237 
01238             if (transfer->status != USBD_STATUS_SUCCESS) {
01239 
01240                 TRACE_WARNING("RBC_ReadCapacity: Cannot send data\n\r");
01241                 result = MSDD_STATUS_ERROR;
01242             }
01243             else {
01244 
01245                 TRACE_INFO_WP("Sent ");
01246                 result = MSDD_STATUS_SUCCESS;
01247             }
01248             commandState->length -= transfer->transferred;
01249         }
01250         break;
01251     }
01252 
01253     return result;
01254 }
01255 
01256 /**
01257  * \brief  Handles an INQUIRY command.
01258  *
01259  *         This function operates asynchronously and must be called multiple
01260  *         times to complete. A result code of MSDDriver_STATUS_INCOMPLETE
01261  *         indicates that at least another call of the method is necessary.
01262  * \param  lun          Pointer to the LUN affected by the command
01263  * \param  commandState Current state of the command
01264  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
01265  * \see    MSDLun
01266  * \see    MSDCommandState
01267  */
01268 static unsigned char SBC_Inquiry(MSDLun               *lun,
01269                                  MSDCommandState *commandState)
01270 {
01271     unsigned char  result = MSDD_STATUS_INCOMPLETE;
01272     unsigned char  status;
01273     MSDTransfer *transfer = &(commandState->transfer);
01274 
01275     /* Check if required length is 0 */
01276     if (commandState->length == 0) {
01277 
01278         /* Nothing to do */
01279         result = MSDD_STATUS_SUCCESS;
01280     }
01281     /* Initialize command state if needed */
01282     else if (commandState->state == 0) {
01283 
01284         commandState->state = SBC_STATE_WRITE;
01285 
01286         /* Change additional length field of inquiry data */
01287         lun->inquiryData->bAdditionalLength
01288             = (unsigned char) (commandState->length - 5);
01289     }
01290 
01291     /* Identify current command state */
01292 
01293     switch (commandState->state) {
01294     /*------------------- */
01295     case SBC_STATE_WRITE:
01296     /*------------------- */
01297 
01298         /* Start write operation */
01299       #if 1
01300         status = USBD_Write(commandState->pipeIN,
01301                             (void *) lun->inquiryData,
01302                             commandState->length,
01303                             (TransferCallback) MSDDriver_Callback,
01304                             (void *) transfer);
01305       #else
01306         status = MSDD_Write((void *) lun->inquiryData,
01307                             commandState->length,
01308                             (TransferCallback) MSDDriver_Callback,
01309                             (void *) transfer);
01310       #endif
01311 
01312         /* Check operation result code */
01313         if (status != USBD_STATUS_SUCCESS) {
01314 
01315             TRACE_WARNING(
01316                 "SPC_Inquiry: Cannot start sending data\n\r");
01317             result = MSDD_STATUS_ERROR;
01318         }
01319         else {
01320 
01321             /* Proceed to next state */
01322             TRACE_INFO_WP("Sending ");
01323             commandState->state = SBC_STATE_WAIT_WRITE;
01324         }
01325         break;
01326 
01327     /*------------------------ */
01328     case SBC_STATE_WAIT_WRITE:
01329     /*------------------------ */
01330 
01331         /* Check the semaphore value */
01332         if (transfer->semaphore > 0) {
01333 
01334             /* Take semaphore and terminate command */
01335             transfer->semaphore--;
01336 
01337             if (transfer->status != USBD_STATUS_SUCCESS) {
01338 
01339                 TRACE_WARNING(
01340                     "SPC_Inquiry: Data transfer failed\n\r");
01341                 result = MSDD_STATUS_ERROR;
01342             }
01343             else {
01344 
01345                 TRACE_INFO_WP("Sent ");
01346                 result = MSDD_STATUS_SUCCESS;
01347             }
01348 
01349             /* Update length field */
01350             commandState->length -= transfer->transferred;
01351         }
01352         break;
01353     }
01354 
01355     return result;
01356 }
01357 
01358 /**
01359  * \brief  Performs a REQUEST SENSE command.
01360  *
01361  *         This function operates asynchronously and must be called multiple
01362  *         times to complete. A result code of MSDDriver_STATUS_INCOMPLETE
01363  *         indicates that at least another call of the method is necessary.
01364  * \param  lun          Pointer to the LUN affected by the command
01365  * \param  commandState Current state of the command
01366  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
01367  * \see    MSDLun
01368  * \see    MSDCommandState
01369  */
01370 static unsigned char SBC_RequestSense(MSDLun               *lun,
01371                                       MSDCommandState *commandState)
01372 {
01373     unsigned char result = MSDD_STATUS_INCOMPLETE;
01374     unsigned char status;
01375     MSDTransfer *transfer = &(commandState->transfer);
01376 
01377     /* Check if requested length is zero */
01378     if (commandState->length == 0) {
01379 
01380         /* Nothing to do */
01381 
01382         result = MSDD_STATUS_SUCCESS;
01383     }
01384     /* Initialize command state if needed */
01385     else if (commandState->state == 0) {
01386 
01387         commandState->state = SBC_STATE_WRITE;
01388     }
01389 
01390     /* Identify current command state */
01391     switch (commandState->state) {
01392     /*------------------- */
01393     case SBC_STATE_WRITE:
01394     /*------------------- */
01395 
01396         /* Start transfer */
01397       #if 1
01398         status = USBD_Write(commandState->pipeIN,
01399                             &(lun->requestSenseData),
01400                             commandState->length,
01401                             (TransferCallback) MSDDriver_Callback,
01402                             (void *) transfer);
01403       #else
01404         status = MSDD_Write(&(lun->requestSenseData),
01405                             commandState->length,
01406                             (TransferCallback) MSDDriver_Callback,
01407                             (void *) transfer);
01408       #endif
01409 
01410         /* Check result code */
01411         if (status != USBD_STATUS_SUCCESS) {
01412 
01413             TRACE_WARNING(
01414                 "RBC_RequestSense: Cannot start sending data\n\r");
01415             result = MSDD_STATUS_ERROR;
01416         }
01417         else {
01418 
01419             /* Change state */
01420             commandState->state = SBC_STATE_WAIT_WRITE;
01421         }
01422         break;
01423 
01424     /*------------------------ */
01425     case SBC_STATE_WAIT_WRITE:
01426     /*------------------------ */
01427 
01428         /* Check the transfer semaphore */
01429         if (transfer->semaphore > 0) {
01430 
01431             /* Take semaphore and finish command */
01432             transfer->semaphore--;
01433 
01434             if (transfer->status != USBD_STATUS_SUCCESS) {
01435 
01436                 result = MSDD_STATUS_ERROR;
01437             }
01438             else {
01439 
01440                 result = MSDD_STATUS_SUCCESS;
01441             }
01442 
01443             /* Update length */
01444             commandState->length -= transfer->transferred;
01445         }
01446         break;
01447     }
01448 
01449     return result;
01450 }
01451 
01452 /**
01453  * \brief  Performs a MODE SENSE (6) command.
01454  *
01455  *         This function operates asynchronously and must be called multiple
01456  *         times to complete. A result code of MSDDriver_STATUS_INCOMPLETE
01457  *         indicates that at least another call of the method is necessary.
01458  * \param  lun          Pointer to the LUN affected by the command
01459  * \param  commandState Current state of the command
01460  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
01461  * \see    MSDLun
01462  * \see    MSDCommandState
01463  */
01464 static unsigned char SBC_ModeSense6(MSDLun *lun, MSDCommandState *commandState)
01465 {
01466     unsigned char      result = MSDD_STATUS_INCOMPLETE;
01467     unsigned char      status;
01468     MSDTransfer     *transfer = &(commandState->transfer);
01469     SBCCommand      *pCmd     = (SBCCommand*)commandState->cbw.pCommand;
01470 
01471     if (!SBCLunIsReady(lun)) {
01472 
01473         TRACE_INFO("SBC_ModeSense6: Not Ready!\n\r");
01474         return MSDD_STATUS_RW;
01475     }
01476 
01477     /* Check if mode page is supported */
01478     if (pCmd->modeSense6.bPageCode
01479         != SBC_PAGE_RETURN_ALL) {
01480 
01481         return MSDD_STATUS_PARAMETER;
01482     }
01483 
01484     /* Initialize command state if needed */
01485     if (commandState->state == 0) {
01486 
01487         commandState->state = SBC_STATE_WRITE;
01488     }
01489 
01490     /* Check current command state */
01491     switch (commandState->state) {
01492     /*------------------- */
01493     case SBC_STATE_WRITE:
01494     /*------------------- */
01495 
01496         /* Start transfer */
01497       #if 1
01498         status = USBD_Write(commandState->pipeIN,
01499                             (void *) &modeParameterHeader6,
01500                             commandState->length,
01501                             (TransferCallback) MSDDriver_Callback,
01502                             (void *) transfer);
01503       #else
01504         status = MSDD_Write((void *) &modeParameterHeader6,
01505                             commandState->length,
01506                             (TransferCallback) MSDDriver_Callback,
01507                             (void *) transfer);
01508       #endif
01509 
01510         /* Check operation result code */
01511         if (status != USBD_STATUS_SUCCESS) {
01512 
01513             TRACE_WARNING(
01514                 "SPC_ModeSense6: Cannot start data transfer\n\r");
01515             result = MSDD_STATUS_ERROR;
01516         }
01517         else {
01518 
01519             /* Proceed to next state */
01520             commandState->state = SBC_STATE_WAIT_WRITE;
01521         }
01522         break;
01523 
01524     /*------------------------ */
01525     case SBC_STATE_WAIT_WRITE:
01526     /*------------------------ */
01527 
01528         TRACE_INFO_WP("Wait ");
01529 
01530         /* Check semaphore value */
01531         if (transfer->semaphore > 0) {
01532 
01533             /* Take semaphore and terminate command */
01534             transfer->semaphore--;
01535 
01536             if (transfer->status != USBD_STATUS_SUCCESS) {
01537 
01538                 TRACE_WARNING(
01539                     "SPC_ModeSense6: Data transfer failed\n\r");
01540                 result = MSDD_STATUS_ERROR;
01541             }
01542             else {
01543 
01544                 result = MSDD_STATUS_SUCCESS;
01545             }
01546 
01547             /* Update length field */
01548             commandState->length -= transfer->transferred;
01549 
01550         }
01551         break;
01552     }
01553 
01554     return result;
01555 }
01556 
01557 /**
01558  * \brief  Performs a TEST UNIT READY COMMAND command.
01559  * \param  lun          Pointer to the LUN affected by the command
01560  * \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
01561  * \see    MSDLun
01562  */
01563 static unsigned char SBC_TestUnitReady(MSDLun *lun)
01564 {
01565     unsigned char result = MSDD_STATUS_RW;
01566     unsigned char senseKey = SBC_SENSE_KEY_NO_SENSE,
01567                   addSenseCode = 0,
01568                   addSenseCodeQual = 0;
01569 
01570     /* Check current media state */
01571 
01572     if (lun->status < LUN_CHANGED) {
01573 
01574         TRACE_INFO_WP("Ejc ");
01575         senseKey = SBC_SENSE_KEY_NOT_READY;
01576         addSenseCode = SBC_ASC_MEDIUM_NOT_PRESENT;
01577     }
01578     else if (lun->status == LUN_CHANGED) {
01579 
01580         TRACE_INFO_WP("Chg ");
01581         senseKey = SBC_SENSE_KEY_UNIT_ATTENTION;
01582         addSenseCode = SBC_ASC_NOT_READY_TO_READY_CHANGE;
01583         lun->status = LUN_READY;
01584     }
01585     else {
01586 
01587         switch(MED_GetState(lun->media)) {
01588         /*------------------- */
01589         case MED_STATE_READY:
01590         /*------------------- */
01591 
01592             /* Nothing to do */
01593             TRACE_INFO_WP("Rdy ");
01594             result = MSDD_STATUS_SUCCESS;
01595             break;
01596 
01597         /*------------------ */
01598         case MED_STATE_BUSY:
01599         /*------------------ */
01600 
01601             TRACE_INFO_WP("Bsy ");
01602             senseKey = SBC_SENSE_KEY_NOT_READY;
01603             break;
01604 
01605         /*------ */
01606         default:
01607         /*------ */
01608 
01609             TRACE_INFO_WP("? ");
01610             senseKey = SBC_SENSE_KEY_NOT_READY;
01611             addSenseCode = SBC_ASC_MEDIUM_NOT_PRESENT;
01612             break;
01613         }
01614     }
01615     SBC_UpdateSenseData(&(lun->requestSenseData),
01616                         senseKey,
01617                         addSenseCode,
01618                         addSenseCodeQual);
01619 
01620     return result;
01621 }
01622 
01623 /*------------------------------------------------------------------------------
01624  *      Exported functions
01625  *------------------------------------------------------------------------------*/
01626 /**
01627  * \brief  Updates the sense data of a LUN with the given key and codes
01628  * \param  requestSenseData             Pointer to the sense data to update
01629  * \param  senseKey                     Sense key
01630  * \param  additionalSenseCode          Additional sense code
01631  * \param  additionalSenseCodeQualifier Additional sense code qualifier
01632  */
01633 void SBC_UpdateSenseData(SBCRequestSenseData *requestSenseData,
01634                          unsigned char senseKey,
01635                          unsigned char additionalSenseCode,
01636                          unsigned char additionalSenseCodeQualifier)
01637 {
01638     requestSenseData->bSenseKey = senseKey;
01639     requestSenseData->bAdditionalSenseCode = additionalSenseCode;
01640     requestSenseData->bAdditionalSenseCodeQualifier
01641         = additionalSenseCodeQualifier;
01642 }
01643 
01644 /**
01645  * \brief  Return information about the transfer length and direction expected
01646  *         by the device for a particular command.
01647  * \param  command Pointer to a buffer holding the command to evaluate
01648  * \param  length  Expected length of the data transfer
01649  * \param  type    Expected direction of data transfer
01650  * \param  lun     Pointer to the LUN affected by the command
01651  */
01652 unsigned char SBC_GetCommandInformation(void          *command,
01653                                unsigned int  *length,
01654                                unsigned char *type,
01655                                MSDLun         *lun)
01656 {
01657     SBCCommand *sbcCommand = (SBCCommand *) command;
01658     unsigned char          isCommandSupported = 1;
01659 
01660     /* Identify command */
01661 
01662     switch (sbcCommand->bOperationCode) {
01663     /*--------------- */
01664 
01665     case SBC_INQUIRY:
01666     /*--------------- */
01667 
01668         (*type) = MSDD_DEVICE_TO_HOST;
01669 
01670         /* Allocation length is stored in big-endian format */
01671 
01672         (*length) = WORDB(sbcCommand->inquiry.pAllocationLength);
01673         break;
01674 
01675     /*-------------------- */
01676 
01677     case SBC_MODE_SENSE_6:
01678     /*-------------------- */
01679 
01680         (*type) = MSDD_DEVICE_TO_HOST;
01681         if (sbcCommand->modeSense6.bAllocationLength >
01682             sizeof(SBCModeParameterHeader6)) {
01683 
01684             *length = sizeof(SBCModeParameterHeader6);
01685         }
01686         else {
01687 
01688             *length = sbcCommand->modeSense6.bAllocationLength;
01689         }
01690         break;
01691 
01692     /*------------------------------------ */
01693 
01694     case SBC_PREVENT_ALLOW_MEDIUM_REMOVAL:
01695     /*------------------------------------ */
01696 
01697         (*type) = MSDD_NO_TRANSFER;
01698         break;
01699 
01700     /*--------------------- */
01701 
01702     case SBC_REQUEST_SENSE:
01703     /*--------------------- */
01704 
01705         (*type) = MSDD_DEVICE_TO_HOST;
01706         (*length) = sbcCommand->requestSense.bAllocationLength;
01707         break;
01708 
01709     /*----------------------- */
01710 
01711     case SBC_TEST_UNIT_READY:
01712     /*----------------------- */
01713 
01714         (*type) = MSDD_NO_TRANSFER;
01715         break;
01716 
01717     /*--------------------- */
01718 
01719     case SBC_READ_CAPACITY_10:
01720     /*--------------------- */
01721 
01722         (*type) = MSDD_DEVICE_TO_HOST;
01723         (*length) = sizeof(SBCReadCapacity10Data);
01724         break;
01725 
01726     /*--------------- */
01727 
01728     case SBC_READ_10:
01729     /*--------------- */
01730 
01731         (*type) = MSDD_DEVICE_TO_HOST;
01732         (*length) = WORDB(sbcCommand->read10.pTransferLength)
01733                      * lun->blockSize * MED_GetBlockSize(lun->media);
01734         break;
01735 
01736     /*---------------- */
01737 
01738     case SBC_WRITE_10:
01739     /*---------------- */
01740 
01741         (*type) = MSDD_HOST_TO_DEVICE;
01742         (*length) = WORDB(sbcCommand->write10.pTransferLength)
01743                      * lun->blockSize * MED_GetBlockSize(lun->media);
01744         break;
01745 
01746     /*----------------- */
01747 
01748     case SBC_VERIFY_10:
01749     /*----------------- */
01750 
01751         (*type) = MSDD_NO_TRANSFER;
01752         break;
01753     /*------ */
01754 
01755     default:
01756     /*------ */
01757 
01758         isCommandSupported = 0;
01759     }
01760 
01761     /* If length is 0, no transfer is expected */
01762 
01763     if ((*length) == 0) {
01764 
01765         (*type) = MSDD_NO_TRANSFER;
01766     }
01767 
01768     return isCommandSupported;
01769 }
01770 
01771 /**
01772  * \brief  Processes a SBC command by dispatching it to a subfunction.
01773  * \param  lun          Pointer to the affected LUN
01774  * \param  commandState Pointer to the current command state
01775  * \return Operation result code
01776  */
01777 unsigned char SBC_ProcessCommand(MSDLun               *lun,
01778                                  MSDCommandState *commandState)
01779 {
01780     unsigned char result = MSDD_STATUS_INCOMPLETE;
01781     SBCCommand *command = (SBCCommand *) commandState->cbw.pCommand;
01782 
01783     /* Identify command */
01784 
01785     switch (command->bOperationCode) {
01786     /*--------------- */
01787     case SBC_READ_10:
01788     /*--------------- */
01789 
01790         //TRACE_DEBUG_WP("Read(10) ");
01791         /* Perform the Read10 command */
01792 
01793         result = SBC_Read10(lun, commandState);
01794         break;
01795 
01796     /*---------------- */
01797     case SBC_WRITE_10:
01798     /*---------------- */
01799 
01800         //TRACE_DEBUG_WP("Write(10) ");
01801         /* Perform the Write10 command */
01802 
01803         result = SBC_Write10(lun, commandState);
01804         break;
01805 
01806     /*--------------------- */
01807     case SBC_READ_CAPACITY_10:
01808     /*--------------------- */
01809 
01810         //TRACE_INFO_WP("RdCapacity(10) ");
01811         /* Perform the ReadCapacity command */
01812 
01813         result = SBC_ReadCapacity10(lun, commandState);
01814         break;
01815 
01816     /*--------------------- */
01817     case SBC_VERIFY_10:
01818     /*--------------------- */
01819 
01820         //TRACE_INFO_WP("Verify(10) ");
01821         /* Flush media */
01822 
01823         MED_Flush(lun->media);
01824         result = MSDD_STATUS_SUCCESS;
01825         break;
01826 
01827     /*--------------- */
01828     case SBC_INQUIRY:
01829     /*--------------- */
01830 
01831         //TRACE_INFO_WP("Inquiry ");
01832         /* Process Inquiry command */
01833         result = SBC_Inquiry(lun, commandState);
01834         break;
01835 
01836     /*-------------------- */
01837     case SBC_MODE_SENSE_6:
01838     /*-------------------- */
01839 
01840         TRACE_INFO_WP("ModeSense(6) ");
01841         /* Process ModeSense6 command */
01842         result = SBC_ModeSense6(lun, commandState);
01843         break;       
01844    
01845 
01846     /*----------------------- */
01847     case SBC_TEST_UNIT_READY:
01848     /*----------------------- */
01849 
01850         TRACE_INFO_WP("TstUnitRdy ");
01851         /* Process TestUnitReady command */
01852         /*MED_Flush(lun->media); */
01853         result = SBC_TestUnitReady(lun);
01854         break;
01855 
01856     /*--------------------- */
01857     case SBC_REQUEST_SENSE:
01858     /*--------------------- */
01859         TRACE_INFO_WP("ReqSense ");
01860 
01861         /* Perform the RequestSense command */
01862         result = SBC_RequestSense(lun, commandState);
01863         break;
01864 
01865     /*------------------------------------ */
01866     case SBC_PREVENT_ALLOW_MEDIUM_REMOVAL:
01867     /*------------------------------------ */
01868         TRACE_INFO_WP("PrevAllowRem ");
01869 
01870         /* Check parameter */
01871 
01872         result = command->mediumRemoval.bPrevent ?
01873                     MSDD_STATUS_PARAMETER : MSDD_STATUS_SUCCESS;
01874         break;
01875            
01876      /*------------------------------------ */
01877     case SBC_READ_FORMAT_CAPACITIES:
01878     /*------------------------------------ */
01879       
01880       result = MSDD_STATUS_PARAMETER;
01881       break;
01882     /*------ */
01883     default:
01884     /*------ */
01885         result = MSDD_STATUS_PARAMETER;
01886     }
01887 
01888     return result;
01889 }
01890 
01891 /**@}*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines