SAMV71 Xplained Ultra Software Package 1.3

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