SAM3S8/SD8 Software Package: libraries/usb/device/massstorage/SBCMethods.c Source File

SAM3S8/SD8 Software Package 1.2

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

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines