Tag the LUFA 120730 release.
[pub/lufa.git] / Demos / Host / LowLevel / MassStorageHost / Lib / MassStoreCommands.c
index b25a37e..e2887f5 100644 (file)
@@ -1,13 +1,13 @@
 /*
              LUFA Library
-     Copyright (C) Dean Camera, 2011.
+     Copyright (C) Dean Camera, 2012.
 
   dean [at] fourwalledcubicle [dot] com
            www.lufa-lib.org
 */
 
 /*
-  Copyright 2011  Dean Camera (dean [at] fourwalledcubicle [dot] com)
+  Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 
   Permission to use, copy, modify, distribute, and sell this
   software and its documentation for any purpose is hereby granted
@@ -68,13 +68,13 @@ static uint8_t MassStore_SendCommand(MS_CommandBlockWrapper_t* const SCSICommand
 {
        uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
 
-       /* Each transmission should have a unique tag value, increment before use */
-       SCSICommandBlock->Tag = ++MassStore_Tag;
-
        /* Wrap Tag value when invalid - MS class defines tag values of 0 and 0xFFFFFFFF to be invalid */
-       if (MassStore_Tag == 0xFFFFFFFF)
+       if (++MassStore_Tag == 0xFFFFFFFF)
          MassStore_Tag = 1;
 
+       /* Each transmission should have a unique tag value, increment before use */
+       SCSICommandBlock->Tag = MassStore_Tag;
+
        /* Select the OUT data pipe for CBW transmission */
        Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE);
        Pipe_Unfreeze();
@@ -83,6 +83,7 @@ static uint8_t MassStore_SendCommand(MS_CommandBlockWrapper_t* const SCSICommand
        if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t), NULL)) !=
                                              PIPE_RWSTREAM_NoError)
        {
+               Pipe_Freeze();
                return ErrorCode;
        }
 
@@ -95,15 +96,22 @@ static uint8_t MassStore_SendCommand(MS_CommandBlockWrapper_t* const SCSICommand
        /* Freeze pipe after use */
        Pipe_Freeze();
 
-       /* Send data if any */
-       if ((BufferPtr != NULL) &&
-           ((ErrorCode = MassStore_SendReceiveData(SCSICommandBlock, BufferPtr)) != PIPE_READYWAIT_NoError))
+       if (BufferPtr != NULL)
        {
-               Pipe_Freeze();
-               return ErrorCode;
+               /* Transfer the requested data (if any) to or from the device */
+               ErrorCode = MassStore_SendReceiveData(SCSICommandBlock, (void*)BufferPtr);
+
+               /* Only fail completely if the transfer fails without a STALL, as a logical STALL can be recovered from */
+               if ((ErrorCode != PIPE_RWSTREAM_NoError) && (ErrorCode != PIPE_RWSTREAM_PipeStalled))
+               {
+                       Pipe_Freeze();
+                       return ErrorCode;
+               }
        }
 
-       return ErrorCode;
+       /* Retrieve the returned SCSI status from the device */
+       MS_CommandStatusWrapper_t SCSIStatusBlock;
+       return MassStore_GetReturnedStatus(&SCSIStatusBlock);
 }
 
 /** Waits until the attached device is ready to accept data following a CBW, checking
@@ -145,7 +153,7 @@ static uint8_t MassStore_WaitForDataReceived(void)
                if (Pipe_IsStalled())
                {
                        /* Clear the stall condition on the OUT pipe */
-                       USB_Host_ClearPipeStall(MASS_STORE_DATA_OUT_PIPE);
+                       USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
 
                        return PIPE_RWSTREAM_PipeStalled;
                }
@@ -158,7 +166,7 @@ static uint8_t MassStore_WaitForDataReceived(void)
                if (Pipe_IsStalled())
                {
                        /* Clear the stall condition on the IN pipe */
-                       USB_Host_ClearPipeStall(MASS_STORE_DATA_IN_PIPE);
+                       USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
 
                        return PIPE_RWSTREAM_PipeStalled;
                }
@@ -259,7 +267,7 @@ static uint8_t MassStore_GetReturnedStatus(MS_CommandStatusWrapper_t* const SCSI
        {
                return ErrorCode;
        }
-       
+
        /* Clear the data ready for next reception */
        Pipe_ClearIN();
 
@@ -274,12 +282,15 @@ static uint8_t MassStore_GetReturnedStatus(MS_CommandStatusWrapper_t* const SCSI
 }
 
 /** Issues a Mass Storage class specific request to reset the attached device's Mass Storage interface,
- *  readying the device for the next CBW.
+ *  readying the device for the next CBW. The Data endpoints are cleared of any STALL condition once this
+ *  command completes successfully.
  *
  *  \return A value from the USB_Host_SendControlErrorCodes_t enum, or MASS_STORE_SCSI_COMMAND_FAILED if the SCSI command fails
  */
 uint8_t MassStore_MassStorageReset(void)
 {
+       uint8_t ErrorCode;
+
        USB_ControlRequest = (USB_Request_Header_t)
                {
                        .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
@@ -292,7 +303,22 @@ uint8_t MassStore_MassStorageReset(void)
        /* Select the control pipe for the request transfer */
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
 
-       return USB_Host_SendControlRequest(NULL);
+       if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
+         return ErrorCode;
+
+       /* Select first data pipe to clear STALL condition if one exists */
+       Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE);
+
+       if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
+         return ErrorCode;
+
+       /* Select second data pipe to clear STALL condition if one exists */
+       Pipe_SelectPipe(MASS_STORE_DATA_OUT_PIPE);
+
+       if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
+         return ErrorCode;
+
+       return HOST_SENDCONTROL_Successful;
 }
 
 /** Issues a Mass Storage class specific request to determine the index of the highest numbered Logical
@@ -308,7 +334,7 @@ uint8_t MassStore_MassStorageReset(void)
  */
 uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex)
 {
-       uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
+       uint8_t ErrorCode;
 
        USB_ControlRequest = (USB_Request_Header_t)
                {
@@ -348,8 +374,6 @@ uint8_t MassStore_GetMaxLUN(uint8_t* const MaxLUNIndex)
 uint8_t MassStore_Inquiry(const uint8_t LUNIndex,
                           SCSI_Inquiry_Response_t* const InquiryPtr)
 {
-       uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
        /* Create a CBW with a SCSI command to issue INQUIRY command */
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
                {
@@ -369,23 +393,8 @@ uint8_t MassStore_Inquiry(const uint8_t LUNIndex,
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
-       if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, InquiryPtr)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       return ErrorCode;
+       return MassStore_SendCommand(&SCSICommandBlock, InquiryPtr);
 }
 
 /** Issues a SCSI Request Sense command to the attached device, to determine the current SCSI sense information. This
@@ -399,8 +408,6 @@ uint8_t MassStore_Inquiry(const uint8_t LUNIndex,
 uint8_t MassStore_RequestSense(const uint8_t LUNIndex,
                                SCSI_Request_Sense_Response_t* const SensePtr)
 {
-       uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
        /* Create a CBW with a SCSI command to issue REQUEST SENSE command */
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
                {
@@ -420,23 +427,8 @@ uint8_t MassStore_RequestSense(const uint8_t LUNIndex,
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
-       if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, SensePtr)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       return ErrorCode;
+       return MassStore_SendCommand(&SCSICommandBlock, SensePtr);
 }
 
 /** Issues a SCSI Device Block Read command to the attached device, to read in one or more data blocks from the
@@ -456,8 +448,6 @@ uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex,
                                   const uint16_t BlockSize,
                                   void* BufferPtr)
 {
-       uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
        /* Create a CBW with a SCSI command to read in the given blocks from the device */
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
                {
@@ -481,23 +471,8 @@ uint8_t MassStore_ReadDeviceBlock(const uint8_t LUNIndex,
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
-       if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, BufferPtr)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       return ErrorCode;
+       return MassStore_SendCommand(&SCSICommandBlock, BufferPtr);
 }
 
 /** Issues a SCSI Device Block Write command to the attached device, to write one or more data blocks to the
@@ -517,8 +492,6 @@ uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex,
                                    const uint16_t BlockSize,
                                    void* BufferPtr)
 {
-       uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
        /* Create a CBW with a SCSI command to write the given blocks to the device */
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
                {
@@ -542,23 +515,8 @@ uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex,
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
-       if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, BufferPtr)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       return ErrorCode;
+       return MassStore_SendCommand(&SCSICommandBlock, BufferPtr);
 }
 
 /** Issues a SCSI Device Test Unit Ready command to the attached device, to determine if the device is ready to accept
@@ -570,8 +528,6 @@ uint8_t MassStore_WriteDeviceBlock(const uint8_t LUNIndex,
  */
 uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex)
 {
-       uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
        /* Create a CBW with a SCSI command to issue TEST UNIT READY command */
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
                {
@@ -591,23 +547,8 @@ uint8_t MassStore_TestUnitReady(const uint8_t LUNIndex)
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
-       if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       return ErrorCode;
+       return MassStore_SendCommand(&SCSICommandBlock, NULL);
 }
 
 /** Issues a SCSI Device Read Capacity command to the attached device, to determine the capacity of the
@@ -646,26 +587,14 @@ uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex,
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
        if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, CapacityPtr)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
+         return ErrorCode;
 
        /* Endian-correct the read data */
        CapacityPtr->Blocks    = SwapEndian_32(CapacityPtr->Blocks);
        CapacityPtr->BlockSize = SwapEndian_32(CapacityPtr->BlockSize);
 
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
        return ErrorCode;
 }
 
@@ -681,8 +610,6 @@ uint8_t MassStore_ReadCapacity(const uint8_t LUNIndex,
 uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex,
                                             const bool PreventRemoval)
 {
-       uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-
        /* Create a CBW with a SCSI command to issue PREVENT ALLOW MEDIUM REMOVAL command */
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
                {
@@ -702,22 +629,7 @@ uint8_t MassStore_PreventAllowMediumRemoval(const uint8_t LUNIndex,
                                }
                };
 
-       MS_CommandStatusWrapper_t SCSICommandStatus;
-
        /* Send the command and any data to the attached device */
-       if ((ErrorCode = MassStore_SendCommand(&SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       /* Retrieve status information from the attached device */
-       if ((ErrorCode = MassStore_GetReturnedStatus(&SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
-       {
-               Pipe_Freeze();
-               return ErrorCode;
-       }
-
-       return ErrorCode;
+       return MassStore_SendCommand(&SCSICommandBlock, NULL);
 }