diff options
author | Dean Camera <dean@fourwalledcubicle.com> | 2009-08-27 06:28:18 +0000 |
---|---|---|
committer | Dean Camera <dean@fourwalledcubicle.com> | 2009-08-27 06:28:18 +0000 |
commit | f89059280651a8dae6e4d46d4504dd566164af4e (patch) | |
tree | cd36aa95d85050525b2f57976571ef84350ce06f | |
parent | 559ca2ba046e47faa54f0845339f0385a5cfbb26 (diff) | |
download | lufa-f89059280651a8dae6e4d46d4504dd566164af4e.tar.gz lufa-f89059280651a8dae6e4d46d4504dd566164af4e.tar.bz2 lufa-f89059280651a8dae6e4d46d4504dd566164af4e.zip |
Completed initial Host mode Mass Storage class driver.
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/MassStorage.c | 224 | ||||
-rw-r--r-- | LUFA/Drivers/USB/Class/Host/MassStorage.h | 57 |
2 files changed, 271 insertions, 10 deletions
diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.c b/LUFA/Drivers/USB/Class/Host/MassStorage.c index 4c23e8153..6c01ed4d8 100644 --- a/LUFA/Drivers/USB/Class/Host/MassStorage.c +++ b/LUFA/Drivers/USB/Class/Host/MassStorage.c @@ -34,8 +34,6 @@ #define INCLUDE_FROM_MS_CLASS_HOST_C
#include "MassStorage.h"
-#warning The Mass Storage Host mode Class driver is currently incomplete and is for preview purposes only.
-
uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint16_t ConfigDescriptorLength,
uint8_t* DeviceConfigDescriptor)
{
@@ -478,14 +476,224 @@ uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uin }
uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
- SCSI_Request_Sense_Response_t* SenseData);
+ SCSI_Request_Sense_Response_t* SenseData)
+{
+ if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
+ return HOST_SENDCONTROL_DeviceDisconnect;
-uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, bool PreventRemoval);
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
-uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddr,
- uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer);
+ MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
+ {
+ .Signature = CBW_SIGNATURE,
+ .Tag = MSInterfaceInfo->State.TransactionTag,
+ .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
+ .Flags = COMMAND_DIRECTION_DATA_IN,
+ .LUN = LUNIndex,
+ .SCSICommandLength = 6,
+ .SCSICommandData =
+ {
+ SCSI_CMD_REQUEST_SENSE,
+ 0x00, // Reserved
+ 0x00, // Reserved
+ 0x00, // Reserved
+ sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
+ 0x00 // Unused (control)
+ }
+ };
+
+ if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ MS_CommandStatusWrapper_t SCSICommandStatus;
+ if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if (SCSICommandStatus.Status != SCSI_Command_Pass)
+ ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
-uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddr,
- uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer);
+ return ErrorCode;
+}
+
+uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, bool PreventRemoval)
+{
+ if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
+ return HOST_SENDCONTROL_DeviceDisconnect;
+
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
+
+ MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
+ {
+ .Signature = CBW_SIGNATURE,
+ .Tag = MSInterfaceInfo->State.TransactionTag,
+ .DataTransferLength = 0,
+ .Flags = COMMAND_DIRECTION_DATA_OUT,
+ .LUN = LUNIndex,
+ .SCSICommandLength = 6,
+ .SCSICommandData =
+ {
+ SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
+ 0x00, // Reserved
+ 0x00, // Reserved
+ PreventRemoval, // Prevent flag
+ 0x00, // Reserved
+ 0x00 // Unused (control)
+ }
+ };
+
+ if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ MS_CommandStatusWrapper_t SCSICommandStatus;
+ if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if (SCSICommandStatus.Status != SCSI_Command_Pass)
+ ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
+
+ return ErrorCode;
+}
+
+uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
+ uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
+{
+ if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
+ return HOST_SENDCONTROL_DeviceDisconnect;
+
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
+
+ MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
+ {
+ .Signature = CBW_SIGNATURE,
+ .Tag = MSInterfaceInfo->State.TransactionTag,
+ .DataTransferLength = ((uint32_t)Blocks * BlockSize),
+ .Flags = COMMAND_DIRECTION_DATA_IN,
+ .LUN = LUNIndex,
+ .SCSICommandLength = 10,
+ .SCSICommandData =
+ {
+ SCSI_CMD_READ_10,
+ 0x00, // Unused (control bits, all off)
+ (BlockAddress >> 24), // MSB of Block Address
+ (BlockAddress >> 16),
+ (BlockAddress >> 8),
+ (BlockAddress & 0xFF), // LSB of Block Address
+ 0x00, // Unused (reserved)
+ 0x00, // MSB of Total Blocks to Read
+ Blocks, // LSB of Total Blocks to Read
+ 0x00 // Unused (control)
+ }
+ };
+
+ if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ MS_CommandStatusWrapper_t SCSICommandStatus;
+ if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if (SCSICommandStatus.Status != SCSI_Command_Pass)
+ ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
+
+ return ErrorCode;
+}
+
+uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
+ uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
+{
+ if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
+ return HOST_SENDCONTROL_DeviceDisconnect;
+
+ uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
+
+ MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
+ {
+ .Signature = CBW_SIGNATURE,
+ .Tag = MSInterfaceInfo->State.TransactionTag,
+ .DataTransferLength = ((uint32_t)Blocks * BlockSize),
+ .Flags = COMMAND_DIRECTION_DATA_OUT,
+ .LUN = LUNIndex,
+ .SCSICommandLength = 10,
+ .SCSICommandData =
+ {
+ SCSI_CMD_WRITE_10,
+ 0x00, // Unused (control bits, all off)
+ (BlockAddress >> 24), // MSB of Block Address
+ (BlockAddress >> 16),
+ (BlockAddress >> 8),
+ (BlockAddress & 0xFF), // LSB of Block Address
+ 0x00, // Unused (reserved)
+ 0x00, // MSB of Total Blocks to Write
+ Blocks, // LSB of Total Blocks to Write
+ 0x00 // Unused (control)
+ }
+ };
+
+ if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ MS_CommandStatusWrapper_t SCSICommandStatus;
+ if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
+ {
+ Pipe_Freeze();
+ return ErrorCode;
+ }
+
+ if (SCSICommandStatus.Status != SCSI_Command_Pass)
+ ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
+
+ return ErrorCode;
+}
#endif
diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.h b/LUFA/Drivers/USB/Class/Host/MassStorage.h index 1678aefee..e64e143a7 100644 --- a/LUFA/Drivers/USB/Class/Host/MassStorage.h +++ b/LUFA/Drivers/USB/Class/Host/MassStorage.h @@ -226,21 +226,74 @@ uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
SCSI_Inquiry_Response_t* InquiryData) ATTR_NON_NULL_PTR_ARG(1, 3);
+ /** Sends a TEST UNIT READY command to the device, to determine if it is ready to accept other SCSI commands.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
+ * \param[in] LUNIndex LUN index within the device the command is being issued to
+ *
+ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
+ */
uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex) ATTR_NON_NULL_PTR_ARG(1);
+ /** Retrieves the total capacity of the attached USB Mass Storage device, in blocks, and block size.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
+ * \param[in] LUNIndex LUN index within the device the command is being issued to
+ * \param[out] DeviceCapacity Pointer to the location where the capacity information should be stored
+ *
+ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
+ */
uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
SCSI_Capacity_t* DeviceCapacity) ATTR_NON_NULL_PTR_ARG(1, 3);
+ /** Retrieves the device sense data, indicating the current device state and error codes for the previously
+ * issued command.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
+ * \param[in] LUNIndex LUN index within the device the command is being issued to
+ * \param[out] SenseData Pointer to the location where the sense information should be stored
+ *
+ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
+ */
uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
SCSI_Request_Sense_Response_t* SenseData) ATTR_NON_NULL_PTR_ARG(1, 3);
+ /** Issues a PREVENT MEDIUM REMOVAL command, to logically (or, depending on the type of device, physically) lock
+ * the device from removal so that blocks of data on the medium can be read or altered.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
+ * \param[in] LUNIndex LUN index within the device the command is being issued to
+ * \param[in] PreventRemoval Boolean true if the device should be locked from removal, false otherwise
+ *
+ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
+ */
uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
bool PreventRemoval) ATTR_NON_NULL_PTR_ARG(1);
- uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddr,
+ /** Reads blocks of data from the attached Mass Storage device's medium.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
+ * \param[in] LUNIndex LUN index within the device the command is being issued to
+ * \param[in] BlockAddress Starting block address within the device to read from
+ * \param[in] Blocks Total number of blocks to read
+ * \param[out] BlockBuffer Pointer to where the read data from the device should be stored
+ *
+ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
+ */
+ uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1, 6);
- uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddr,
+ /** Writes blocks of data to the attached Mass Storage device's medium.
+ *
+ * \param[in,out] MSInterfaceInfo Pointer to a structure containing a MS Class host configuration and state
+ * \param[in] LUNIndex LUN index within the device the command is being issued to
+ * \param[in] BlockAddress Starting block address within the device to write to
+ * \param[in] Blocks Total number of blocks to read
+ * \param[in] BlockBuffer Pointer to where the data to write should be sourced from
+ *
+ * \return A value from the \ref Pipe_Stream_RW_ErrorCodes_t enum or MS_ERROR_LOGICAL_CMD_FAILED if not ready
+ */
+ uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer) ATTR_NON_NULL_PTR_ARG(1, 6);
/* Private Interface - For use in library only: */
|