3 Copyright (C) Dean Camera, 2009.
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
31 #include "../../HighLevel/USBMode.h"
32 #if defined(USB_CAN_BE_HOST)
34 #define INCLUDE_FROM_MS_CLASS_HOST_C
35 #include "MassStorage.h"
37 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint16_t ConfigDescriptorLength
,
38 uint8_t* DeviceConfigDescriptor
)
40 uint8_t FoundEndpoints
= 0;
42 memset(&MSInterfaceInfo
->State
, 0x00, sizeof(MSInterfaceInfo
->State
));
44 if (DESCRIPTOR_TYPE(DeviceConfigDescriptor
) != DTYPE_Configuration
)
45 return MS_ENUMERROR_InvalidConfigDescriptor
;
47 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength
, &DeviceConfigDescriptor
,
48 DComp_NextMassStorageInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
50 return MS_ENUMERROR_NoMSInterfaceFound
;
53 MSInterfaceInfo
->State
.InterfaceNumber
=
54 #if defined(USE_NONSTANDARD_DESCRIPTOR_NAMES)
55 DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Interface_t
)->InterfaceNumber
;
57 DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Interface_t
)->bInterfaceNumber
;
60 while (FoundEndpoints
!= (MS_FOUND_DATAPIPE_IN
| MS_FOUND_DATAPIPE_OUT
))
62 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength
, &DeviceConfigDescriptor
,
63 DComp_NextInterfaceBulkDataEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
65 return MS_ENUMERROR_EndpointsNotFound
;
68 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Endpoint_t
);
70 if (EndpointData
->EndpointAddress
& ENDPOINT_DESCRIPTOR_DIR_IN
)
72 Pipe_ConfigurePipe(MSInterfaceInfo
->Config
.DataINPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_IN
,
73 EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
,
75 MSInterfaceInfo
->State
.DataINPipeSize
= EndpointData
->EndpointSize
;
77 FoundEndpoints
|= MS_FOUND_DATAPIPE_IN
;
81 Pipe_ConfigurePipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_OUT
,
82 EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
,
84 MSInterfaceInfo
->State
.DataOUTPipeSize
= EndpointData
->EndpointSize
;
86 FoundEndpoints
|= MS_FOUND_DATAPIPE_OUT
;
90 MSInterfaceInfo
->State
.Active
= true;
91 return MS_ENUMERROR_NoError
;
94 static uint8_t DComp_NextMassStorageInterface(void* CurrentDescriptor
)
96 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
98 if ((DESCRIPTOR_CAST(CurrentDescriptor
, USB_Descriptor_Interface_t
).Class
== MASS_STORE_CLASS
) &&
99 (DESCRIPTOR_CAST(CurrentDescriptor
, USB_Descriptor_Interface_t
).SubClass
== MASS_STORE_SUBCLASS
) &&
100 (DESCRIPTOR_CAST(CurrentDescriptor
, USB_Descriptor_Interface_t
).Protocol
== MASS_STORE_PROTOCOL
))
102 return DESCRIPTOR_SEARCH_Found
;
106 return DESCRIPTOR_SEARCH_NotFound
;
109 static uint8_t DComp_NextInterfaceBulkDataEndpoint(void* CurrentDescriptor
)
111 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
)
113 uint8_t EndpointType
= (DESCRIPTOR_CAST(CurrentDescriptor
,
114 USB_Descriptor_Endpoint_t
).Attributes
& EP_TYPE_MASK
);
116 if (EndpointType
== EP_TYPE_BULK
)
117 return DESCRIPTOR_SEARCH_Found
;
119 else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
121 return DESCRIPTOR_SEARCH_Fail
;
124 return DESCRIPTOR_SEARCH_NotFound
;
127 void MS_Host_USBTask(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
132 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, MS_CommandBlockWrapper_t
* SCSICommandBlock
)
134 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
136 if (++MSInterfaceInfo
->State
.TransactionTag
== 0xFFFFFFFF)
137 MSInterfaceInfo
->State
.TransactionTag
= 1;
139 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
142 if ((ErrorCode
= Pipe_Write_Stream_LE(SCSICommandBlock
, sizeof(MS_CommandBlockWrapper_t
))) != PIPE_RWSTREAM_NoError
)
146 while(!(Pipe_IsOUTReady()));
150 return PIPE_RWSTREAM_NoError
;
153 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
155 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
157 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
160 while (!(Pipe_IsINReceived()))
162 if (USB_INT_HasOccurred(USB_INT_HSOFI
))
164 USB_INT_Clear(USB_INT_HSOFI
);
168 return PIPE_RWSTREAM_Timeout
;
172 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
175 if (Pipe_IsStalled())
177 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
179 return PIPE_RWSTREAM_PipeStalled
;
183 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
186 if (Pipe_IsStalled())
188 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataINPipeNumber
);
190 return PIPE_RWSTREAM_PipeStalled
;
193 if (USB_HostState
== HOST_STATE_Unattached
)
194 return PIPE_RWSTREAM_DeviceDisconnected
;
197 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
200 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
203 return PIPE_RWSTREAM_NoError
;
206 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
207 MS_CommandBlockWrapper_t
* SCSICommandBlock
, void* BufferPtr
)
209 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
210 uint16_t BytesRem
= SCSICommandBlock
->DataTransferLength
;
212 if (SCSICommandBlock
->Flags
& COMMAND_DIRECTION_DATA_IN
)
214 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
217 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
224 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
227 if ((ErrorCode
= Pipe_Write_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
232 while (!(Pipe_IsOUTReady()))
234 if (USB_HostState
== HOST_STATE_Unattached
)
235 return PIPE_RWSTREAM_DeviceDisconnected
;
241 return PIPE_RWSTREAM_NoError
;
244 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
245 MS_CommandStatusWrapper_t
* SCSICommandStatus
)
247 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
249 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
252 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
255 if ((ErrorCode
= Pipe_Read_Stream_LE(SCSICommandStatus
, sizeof(MS_CommandStatusWrapper_t
))) != PIPE_RWSTREAM_NoError
)
261 return PIPE_RWSTREAM_NoError
;
264 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
266 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
267 return HOST_SENDCONTROL_DeviceDisconnect
;
269 USB_ControlRequest
= (USB_Request_Header_t
)
271 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
272 .bRequest
= REQ_MassStorageReset
,
274 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
278 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
280 return USB_Host_SendControlRequest(NULL
);
283 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t* MaxLUNIndex
)
285 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
286 return HOST_SENDCONTROL_DeviceDisconnect
;
290 USB_ControlRequest
= (USB_Request_Header_t
)
292 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
293 .bRequest
= REQ_GetMaxLUN
,
295 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
299 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
301 if ((ErrorCode
= USB_Host_SendControlRequest(MaxLUNIndex
)) == HOST_SENDCONTROL_SetupStalled
)
311 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, SCSI_Inquiry_Response_t
* InquiryData
)
313 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
314 return HOST_SENDCONTROL_DeviceDisconnect
;
316 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
318 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
320 .Signature
= CBW_SIGNATURE
,
321 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
322 .DataTransferLength
= sizeof(SCSI_Inquiry_Response_t
),
323 .Flags
= COMMAND_DIRECTION_DATA_IN
,
325 .SCSICommandLength
= 6,
332 sizeof(SCSI_Inquiry_Response_t
), // Allocation Length
333 0x00 // Unused (control)
337 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
343 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
349 if ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, &SCSICommandBlock
, InquiryData
)) != PIPE_RWSTREAM_NoError
)
355 MS_CommandStatusWrapper_t SCSICommandStatus
;
356 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
362 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
363 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
368 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
)
370 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
371 return HOST_SENDCONTROL_DeviceDisconnect
;
373 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
375 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
377 .Signature
= CBW_SIGNATURE
,
378 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
379 .DataTransferLength
= 0,
380 .Flags
= COMMAND_DIRECTION_DATA_IN
,
382 .SCSICommandLength
= 6,
385 SCSI_CMD_TEST_UNIT_READY
,
390 0x00 // Unused (control)
394 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
400 MS_CommandStatusWrapper_t SCSICommandStatus
;
401 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
407 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
408 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
413 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
414 SCSI_Capacity_t
* DeviceCapacity
)
416 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
417 return HOST_SENDCONTROL_DeviceDisconnect
;
419 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
421 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
423 .Signature
= CBW_SIGNATURE
,
424 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
425 .DataTransferLength
= sizeof(SCSI_Capacity_t
),
426 .Flags
= COMMAND_DIRECTION_DATA_IN
,
428 .SCSICommandLength
= 10,
431 SCSI_CMD_READ_CAPACITY_10
,
433 0x00, // MSB of Logical block address
436 0x00, // LSB of Logical block address
439 0x00, // Partial Medium Indicator
440 0x00 // Unused (control)
444 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
450 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
456 if ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, &SCSICommandBlock
, DeviceCapacity
)) != PIPE_RWSTREAM_NoError
)
462 DeviceCapacity
->Blocks
= SwapEndian_32(DeviceCapacity
->Blocks
);
463 DeviceCapacity
->BlockSize
= SwapEndian_32(DeviceCapacity
->BlockSize
);
465 MS_CommandStatusWrapper_t SCSICommandStatus
;
466 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
472 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
473 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
478 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
479 SCSI_Request_Sense_Response_t
* SenseData
)
481 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
482 return HOST_SENDCONTROL_DeviceDisconnect
;
484 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
486 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
488 .Signature
= CBW_SIGNATURE
,
489 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
490 .DataTransferLength
= sizeof(SCSI_Request_Sense_Response_t
),
491 .Flags
= COMMAND_DIRECTION_DATA_IN
,
493 .SCSICommandLength
= 6,
496 SCSI_CMD_REQUEST_SENSE
,
500 sizeof(SCSI_Request_Sense_Response_t
), // Allocation Length
501 0x00 // Unused (control)
505 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
511 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
517 if ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, &SCSICommandBlock
, SenseData
)) != PIPE_RWSTREAM_NoError
)
523 MS_CommandStatusWrapper_t SCSICommandStatus
;
524 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
530 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
531 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
536 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, bool PreventRemoval
)
538 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
539 return HOST_SENDCONTROL_DeviceDisconnect
;
541 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
543 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
545 .Signature
= CBW_SIGNATURE
,
546 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
547 .DataTransferLength
= 0,
548 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
550 .SCSICommandLength
= 6,
553 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
,
556 PreventRemoval
, // Prevent flag
558 0x00 // Unused (control)
562 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
568 MS_CommandStatusWrapper_t SCSICommandStatus
;
569 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
575 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
576 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
581 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
582 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
584 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
585 return HOST_SENDCONTROL_DeviceDisconnect
;
587 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
589 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
591 .Signature
= CBW_SIGNATURE
,
592 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
593 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
594 .Flags
= COMMAND_DIRECTION_DATA_IN
,
596 .SCSICommandLength
= 10,
600 0x00, // Unused (control bits, all off)
601 (BlockAddress
>> 24), // MSB of Block Address
602 (BlockAddress
>> 16),
604 (BlockAddress
& 0xFF), // LSB of Block Address
605 0x00, // Unused (reserved)
606 0x00, // MSB of Total Blocks to Read
607 Blocks
, // LSB of Total Blocks to Read
608 0x00 // Unused (control)
612 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
618 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
624 if ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
630 MS_CommandStatusWrapper_t SCSICommandStatus
;
631 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
637 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
638 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
643 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
644 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
646 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
647 return HOST_SENDCONTROL_DeviceDisconnect
;
649 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
651 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
653 .Signature
= CBW_SIGNATURE
,
654 .Tag
= MSInterfaceInfo
->State
.TransactionTag
,
655 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
656 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
658 .SCSICommandLength
= 10,
662 0x00, // Unused (control bits, all off)
663 (BlockAddress
>> 24), // MSB of Block Address
664 (BlockAddress
>> 16),
666 (BlockAddress
& 0xFF), // LSB of Block Address
667 0x00, // Unused (reserved)
668 0x00, // MSB of Total Blocks to Write
669 Blocks
, // LSB of Total Blocks to Write
670 0x00 // Unused (control)
674 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
)) != PIPE_RWSTREAM_NoError
)
680 if ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
686 MS_CommandStatusWrapper_t SCSICommandStatus
;
687 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
693 if (SCSICommandStatus
.Status
!= SCSI_Command_Pass
)
694 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;