Updated MS_Host_ResetMSInterface() to now perform a full Mass Storage reset sequence to prevent data corruption in the event of a device lock up or timeout (thanks to David Lyons).
Add parenthesis around the library Endianness macros that do nothing on a particular architecture to prevent operator precedence issues depending on usage.
Minor documentation corrections.
if (Pipe_IsStalled())
{
/* Clear the stall condition on the OUT pipe */
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;
}
return PIPE_RWSTREAM_PipeStalled;
}
if (Pipe_IsStalled())
{
/* Clear the stall condition on the IN pipe */
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;
}
return PIPE_RWSTREAM_PipeStalled;
}
}
/** Issues a Mass Storage class specific request to reset the attached device's Mass Storage interface,
}
/** 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 sucessfuly.
*
* \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)
{
*
* \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)
{
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
/* Select the control pipe for the request transfer */
Pipe_SelectPipe(PIPE_CONTROLPIPE);
/* Select the control pipe for the request transfer */
Pipe_SelectPipe(PIPE_CONTROLPIPE);
+
+ 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);
- return USB_Host_SendControlRequest(NULL);
+ 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
}
/** Issues a Mass Storage class specific request to determine the index of the highest numbered Logical
if (Pipe_IsStalled())
{
/* Clear the stall condition on the OUT pipe */
if (Pipe_IsStalled())
{
/* Clear the stall condition on the OUT pipe */
- USB_Host_ClearPipeStall(SIMAGE_DATA_OUT_PIPE);
+ USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
/* Return error code and break out of the loop */
return PIPE_RWSTREAM_PipeStalled;
/* Return error code and break out of the loop */
return PIPE_RWSTREAM_PipeStalled;
if (Pipe_IsStalled())
{
/* Clear the stall condition on the IN pipe */
if (Pipe_IsStalled())
{
/* Clear the stall condition on the IN pipe */
- USB_Host_ClearPipeStall(SIMAGE_DATA_IN_PIPE);
+ USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
/* Return error code */
return PIPE_RWSTREAM_PipeStalled;
/* Return error code */
return PIPE_RWSTREAM_PipeStalled;
#if defined(ARCH_BIG_ENDIAN) && !defined(le16_to_cpu)
#define le16_to_cpu(x) SwapEndian_16(x)
#define le32_to_cpu(x) SwapEndian_32(x)
#if defined(ARCH_BIG_ENDIAN) && !defined(le16_to_cpu)
#define le16_to_cpu(x) SwapEndian_16(x)
#define le32_to_cpu(x) SwapEndian_32(x)
- #define be16_to_cpu(x) x
- #define be32_to_cpu(x) x
+ #define be16_to_cpu(x) (x)
+ #define be32_to_cpu(x) (x)
#define cpu_to_le16(x) SwapEndian_16(x)
#define cpu_to_le32(x) SwapEndian_32(x)
#define cpu_to_le16(x) SwapEndian_16(x)
#define cpu_to_le32(x) SwapEndian_32(x)
- #define cpu_to_be16(x) x
- #define cpu_to_be32(x) x
+ #define cpu_to_be16(x) (x)
+ #define cpu_to_be32(x) (x)
#define LE16_TO_CPU(x) SWAPENDIAN_16(x)
#define LE32_TO_CPU(x) SWAPENDIAN_32(x)
#define LE16_TO_CPU(x) SWAPENDIAN_16(x)
#define LE32_TO_CPU(x) SWAPENDIAN_32(x)
- #define BE16_TO_CPU(x) x
- #define BE32_TO_CPU(x) x
+ #define BE16_TO_CPU(x) (x)
+ #define BE32_TO_CPU(x) (x)
#define CPU_TO_LE16(x) SWAPENDIAN_16(x)
#define CPU_TO_LE32(x) SWAPENDIAN_32(x)
#define CPU_TO_LE16(x) SWAPENDIAN_16(x)
#define CPU_TO_LE32(x) SWAPENDIAN_32(x)
- #define CPU_TO_BE16(x) x
- #define CPU_TO_BE32(x) x
+ #define CPU_TO_BE16(x) (x)
+ #define CPU_TO_BE32(x) (x)
#elif !defined(le16_to_cpu)
/** \name Run-time endianness conversion */
//@{
#elif !defined(le16_to_cpu)
/** \name Run-time endianness conversion */
//@{
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define le16_to_cpu(x) x
+ #define le16_to_cpu(x) (x)
/** Performs a conversion between a Little Endian encoded 32-bit piece of data and the
* Endianness of the currently selected CPU architecture.
/** Performs a conversion between a Little Endian encoded 32-bit piece of data and the
* Endianness of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define le32_to_cpu(x) x
+ #define le32_to_cpu(x) (x)
/** Performs a conversion between a Big Endian encoded 16-bit piece of data and the
* Endianness of the currently selected CPU architecture.
/** Performs a conversion between a Big Endian encoded 16-bit piece of data and the
* Endianness of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define cpu_to_le16(x) x
+ #define cpu_to_le16(x) (x)
/** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
* is in Little Endian format regardless of the currently selected CPU architecture.
/** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
* is in Little Endian format regardless of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define cpu_to_le32(x) x
+ #define cpu_to_le32(x) (x)
/** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
* is in Big Endian format regardless of the currently selected CPU architecture.
/** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
* is in Big Endian format regardless of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define LE16_TO_CPU(x) x
+ #define LE16_TO_CPU(x) (x)
/** Performs a conversion between a Little Endian encoded 32-bit piece of data and the
* Endianness of the currently selected CPU architecture.
/** Performs a conversion between a Little Endian encoded 32-bit piece of data and the
* Endianness of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define LE32_TO_CPU(x) x
+ #define LE32_TO_CPU(x) (x)
/** Performs a conversion between a Big Endian encoded 16-bit piece of data and the
* Endianness of the currently selected CPU architecture.
/** Performs a conversion between a Big Endian encoded 16-bit piece of data and the
* Endianness of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define CPU_TO_LE16(x) x
+ #define CPU_TO_LE16(x) (x)
/** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
* is in Little Endian format regardless of the currently selected CPU architecture.
/** Performs a conversion on a natively encoded 32-bit piece of data to ensure that it
* is in Little Endian format regardless of the currently selected CPU architecture.
*
* \return Endian corrected version of the input value.
*/
*
* \return Endian corrected version of the input value.
*/
- #define CPU_TO_LE32(x) x
+ #define CPU_TO_LE32(x) (x)
/** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
* is in Big Endian format regardless of the currently selected CPU architecture.
/** Performs a conversion on a natively encoded 16-bit piece of data to ensure that it
* is in Big Endian format regardless of the currently selected CPU architecture.
- USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
-
+ USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
return PIPE_RWSTREAM_PipeStalled;
}
return PIPE_RWSTREAM_PipeStalled;
}
- USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
-
+ USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
return PIPE_RWSTREAM_PipeStalled;
}
return PIPE_RWSTREAM_PipeStalled;
}
uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
{
uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
{
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
USB_ControlRequest = (USB_Request_Header_t)
{
.bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
Pipe_SelectPipe(PIPE_CONTROLPIPE);
Pipe_SelectPipe(PIPE_CONTROLPIPE);
- return USB_Host_SendControlRequest(NULL);
+ if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
+ return ErrorCode;
+
+ Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
+
+ if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
+ return ErrorCode;
+
+ Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
+
+ if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
+ return ErrorCode;
+
+ return HOST_SENDCONTROL_Successful;
}
uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
}
uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
- USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber);
+ USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
return PIPE_RWSTREAM_PipeStalled;
}
return PIPE_RWSTREAM_PipeStalled;
}
- USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber);
+ USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
return PIPE_RWSTREAM_PipeStalled;
}
return PIPE_RWSTREAM_PipeStalled;
}
const uint16_t Size,
const uint8_t Banks);
const uint16_t Size,
const uint8_t Banks);
- /** Spin-loops until the currently selected non-control pipe is ready for the next packed of data to be read
+ /** Spin-loops until the currently selected non-control pipe is ready for the next packet of data to be read
* or written to it, aborting in the case of an error condition (such as a timeout or device disconnect).
*
* \ingroup Group_PipeRW_AVR8
* or written to it, aborting in the case of an error condition (such as a timeout or device disconnect).
*
* \ingroup Group_PipeRW_AVR8
return USB_Host_SendControlRequest(FeatureStatus);
}
return USB_Host_SendControlRequest(FeatureStatus);
}
-uint8_t USB_Host_ClearPipeStall(const uint8_t EndpointAddress)
+uint8_t USB_Host_ClearEndpointStall(const uint8_t EndpointAddress)
{
USB_ControlRequest = (USB_Request_Header_t)
{
{
USB_ControlRequest = (USB_Request_Header_t)
{
*
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum to indicate the result.
*/
*
* \return A value from the \ref USB_Host_SendControlErrorCodes_t enum to indicate the result.
*/
- uint8_t USB_Host_ClearPipeStall(const uint8_t EndpointAddress);
+ uint8_t USB_Host_ClearEndpointStall(const uint8_t EndpointAddress);
/** Selects a given alternative setting for the specified interface, via a SET INTERFACE standard request to
* the attached device.
/** Selects a given alternative setting for the specified interface, via a SET INTERFACE standard request to
* the attached device.
* Under GCC, strings prefixed with the "L" character (before
* the opening string quotation mark) are considered to be
* Unicode strings, and may be used instead of an explicit
* Under GCC, strings prefixed with the "L" character (before
* the opening string quotation mark) are considered to be
* Unicode strings, and may be used instead of an explicit
- * array of ASCII characters.
+ * array of ASCII characters on little endian devices with
+ * UTF-16-LE \c wchar_t encoding.
*/
#endif
} ATTR_PACKED USB_Descriptor_String_t;
*/
#endif
} ATTR_PACKED USB_Descriptor_String_t;
const uint16_t Size,
const uint8_t Banks);
const uint16_t Size,
const uint8_t Banks);
- /** Spin-loops until the currently selected non-control pipe is ready for the next packed of data to be read
+ /** Spin-loops until the currently selected non-control pipe is ready for the next packet of data to be read
* or written to it, aborting in the case of an error condition (such as a timeout or device disconnect).
*
* \ingroup Group_PipeRW_UC3
* or written to it, aborting in the case of an error condition (such as a timeout or device disconnect).
*
* \ingroup Group_PipeRW_UC3
* - Removed the ENDPOINT_DESCRIPTOR_DIR_* macros, replaced by ENDPOINT_DIR_* instead
* - Renamed the JTAG_DEBUG_ASSERT() macro to JTAG_ASSERT()
* - Added variable number of axis to HID_DESCRIPTOR_JOYSTICK() for multi-axis joysticks above just X and Y
* - Removed the ENDPOINT_DESCRIPTOR_DIR_* macros, replaced by ENDPOINT_DIR_* instead
* - Renamed the JTAG_DEBUG_ASSERT() macro to JTAG_ASSERT()
* - Added variable number of axis to HID_DESCRIPTOR_JOYSTICK() for multi-axis joysticks above just X and Y
+ * - Renamed USB_Host_ClearPipeStall() to USB_Host_ClearEndpointStall() as the function works on an endpoint address within the attached device,
+ * and not a Pipe within the host
+ * - The MS_Host_ResetMSInterface() now performs a full Mass Storage reset sequence to prevent data corruption in the event of a device
+ * lock up or timeout (thanks to David Lyons)
* - Library Applications:
* - Modified the Low Level and Class Driver AudioInput and AudioOutput demos to support multiple audio sample rates
* - Updated all host mode demos and projects to use the EVENT_USB_Host_DeviceEnumerationComplete() event callback for device configuration
* - Library Applications:
* - Modified the Low Level and Class Driver AudioInput and AudioOutput demos to support multiple audio sample rates
* - Updated all host mode demos and projects to use the EVENT_USB_Host_DeviceEnumerationComplete() event callback for device configuration