SAMV71 Xplained Ultra Software Package 1.5

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