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_NextMSInterface
) != 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_NextMSInterfaceEndpoint
) != 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_NextMSInterface(void* CurrentDescriptor
)
96 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
98 USB_Descriptor_Interface_t
* CurrentInterface
= DESCRIPTOR_PCAST(CurrentDescriptor
,
99 USB_Descriptor_Interface_t
);
101 if ((CurrentInterface
->Class
== MASS_STORE_CLASS
) &&
102 (CurrentInterface
->SubClass
== MASS_STORE_SUBCLASS
) &&
103 (CurrentInterface
->Protocol
== MASS_STORE_PROTOCOL
))
105 return DESCRIPTOR_SEARCH_Found
;
109 return DESCRIPTOR_SEARCH_NotFound
;
112 static uint8_t DComp_NextMSInterfaceEndpoint(void* CurrentDescriptor
)
114 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
)
116 USB_Descriptor_Endpoint_t
* CurrentEndpoint
= DESCRIPTOR_PCAST(CurrentDescriptor
,
117 USB_Descriptor_Endpoint_t
);
119 uint8_t EndpointType
= (CurrentEndpoint
->Attributes
& EP_TYPE_MASK
);
121 if ((EndpointType
== EP_TYPE_BULK
) &&
122 (!(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
))))
124 return DESCRIPTOR_SEARCH_Found
;
127 else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
129 return DESCRIPTOR_SEARCH_Fail
;
132 return DESCRIPTOR_SEARCH_NotFound
;
135 void MS_Host_USBTask(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
140 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, MS_CommandBlockWrapper_t
* SCSICommandBlock
,
143 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
145 SCSICommandBlock
->Tag
= ++MSInterfaceInfo
->State
.TransactionTag
;
147 if (MSInterfaceInfo
->State
.TransactionTag
== 0xFFFFFFFF)
148 MSInterfaceInfo
->State
.TransactionTag
= 1;
150 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
153 if ((ErrorCode
= Pipe_Write_Stream_LE(SCSICommandBlock
, sizeof(MS_CommandBlockWrapper_t
))) != PIPE_RWSTREAM_NoError
)
157 Pipe_WaitUntilReady();
161 if ((BufferPtr
!= NULL
) &&
162 ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, SCSICommandBlock
, BufferPtr
)) != PIPE_RWSTREAM_NoError
))
171 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
173 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
175 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
178 while (!(Pipe_IsINReceived()))
180 if (USB_INT_HasOccurred(USB_INT_HSOFI
))
182 USB_INT_Clear(USB_INT_HSOFI
);
186 return PIPE_RWSTREAM_Timeout
;
190 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
193 if (Pipe_IsStalled())
195 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
197 return PIPE_RWSTREAM_PipeStalled
;
201 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
204 if (Pipe_IsStalled())
206 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataINPipeNumber
);
208 return PIPE_RWSTREAM_PipeStalled
;
211 if (USB_HostState
== HOST_STATE_Unattached
)
212 return PIPE_RWSTREAM_DeviceDisconnected
;
215 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
218 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
221 return PIPE_RWSTREAM_NoError
;
224 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
225 MS_CommandBlockWrapper_t
* SCSICommandBlock
, void* BufferPtr
)
227 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
228 uint16_t BytesRem
= SCSICommandBlock
->DataTransferLength
;
230 if (SCSICommandBlock
->Flags
& COMMAND_DIRECTION_DATA_IN
)
232 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
238 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
241 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
248 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
251 if ((ErrorCode
= Pipe_Write_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
256 while (!(Pipe_IsOUTReady()))
258 if (USB_HostState
== HOST_STATE_Unattached
)
259 return PIPE_RWSTREAM_DeviceDisconnected
;
268 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
269 MS_CommandStatusWrapper_t
* SCSICommandStatus
)
271 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
273 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
276 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
279 if ((ErrorCode
= Pipe_Read_Stream_LE(SCSICommandStatus
, sizeof(MS_CommandStatusWrapper_t
))) != PIPE_RWSTREAM_NoError
)
285 if (SCSICommandStatus
->Status
!= SCSI_Command_Pass
)
286 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
291 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
293 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
294 return HOST_SENDCONTROL_DeviceDisconnect
;
296 USB_ControlRequest
= (USB_Request_Header_t
)
298 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
299 .bRequest
= REQ_MassStorageReset
,
301 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
305 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
307 return USB_Host_SendControlRequest(NULL
);
310 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t* MaxLUNIndex
)
312 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
313 return HOST_SENDCONTROL_DeviceDisconnect
;
317 USB_ControlRequest
= (USB_Request_Header_t
)
319 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
320 .bRequest
= REQ_GetMaxLUN
,
322 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
326 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
328 if ((ErrorCode
= USB_Host_SendControlRequest(MaxLUNIndex
)) == HOST_SENDCONTROL_SetupStalled
)
338 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, SCSI_Inquiry_Response_t
* InquiryData
)
340 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
341 return HOST_SENDCONTROL_DeviceDisconnect
;
343 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
345 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
347 .Signature
= CBW_SIGNATURE
,
348 .DataTransferLength
= sizeof(SCSI_Inquiry_Response_t
),
349 .Flags
= COMMAND_DIRECTION_DATA_IN
,
351 .SCSICommandLength
= 6,
358 sizeof(SCSI_Inquiry_Response_t
), // Allocation Length
359 0x00 // Unused (control)
363 MS_CommandStatusWrapper_t SCSICommandStatus
;
365 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, InquiryData
)) != PIPE_RWSTREAM_NoError
)
371 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
380 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
)
382 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
383 return HOST_SENDCONTROL_DeviceDisconnect
;
385 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
387 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
389 .Signature
= CBW_SIGNATURE
,
390 .DataTransferLength
= 0,
391 .Flags
= COMMAND_DIRECTION_DATA_IN
,
393 .SCSICommandLength
= 6,
396 SCSI_CMD_TEST_UNIT_READY
,
401 0x00 // Unused (control)
405 MS_CommandStatusWrapper_t SCSICommandStatus
;
407 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
413 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
422 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
423 SCSI_Capacity_t
* DeviceCapacity
)
425 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
426 return HOST_SENDCONTROL_DeviceDisconnect
;
428 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
430 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
432 .Signature
= CBW_SIGNATURE
,
433 .DataTransferLength
= sizeof(SCSI_Capacity_t
),
434 .Flags
= COMMAND_DIRECTION_DATA_IN
,
436 .SCSICommandLength
= 10,
439 SCSI_CMD_READ_CAPACITY_10
,
441 0x00, // MSB of Logical block address
444 0x00, // LSB of Logical block address
447 0x00, // Partial Medium Indicator
448 0x00 // Unused (control)
452 MS_CommandStatusWrapper_t SCSICommandStatus
;
454 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, DeviceCapacity
)) != PIPE_RWSTREAM_NoError
)
460 DeviceCapacity
->Blocks
= SwapEndian_32(DeviceCapacity
->Blocks
);
461 DeviceCapacity
->BlockSize
= SwapEndian_32(DeviceCapacity
->BlockSize
);
463 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
472 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
473 SCSI_Request_Sense_Response_t
* SenseData
)
475 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
476 return HOST_SENDCONTROL_DeviceDisconnect
;
478 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
480 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
482 .Signature
= CBW_SIGNATURE
,
483 .DataTransferLength
= sizeof(SCSI_Request_Sense_Response_t
),
484 .Flags
= COMMAND_DIRECTION_DATA_IN
,
486 .SCSICommandLength
= 6,
489 SCSI_CMD_REQUEST_SENSE
,
493 sizeof(SCSI_Request_Sense_Response_t
), // Allocation Length
494 0x00 // Unused (control)
498 MS_CommandStatusWrapper_t SCSICommandStatus
;
500 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, SenseData
)) != PIPE_RWSTREAM_NoError
)
506 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
515 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, bool PreventRemoval
)
517 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
518 return HOST_SENDCONTROL_DeviceDisconnect
;
520 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
522 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
524 .Signature
= CBW_SIGNATURE
,
525 .DataTransferLength
= 0,
526 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
528 .SCSICommandLength
= 6,
531 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
,
534 PreventRemoval
, // Prevent flag
536 0x00 // Unused (control)
540 MS_CommandStatusWrapper_t SCSICommandStatus
;
542 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
548 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
557 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
558 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
560 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
561 return HOST_SENDCONTROL_DeviceDisconnect
;
563 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
565 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
567 .Signature
= CBW_SIGNATURE
,
568 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
569 .Flags
= COMMAND_DIRECTION_DATA_IN
,
571 .SCSICommandLength
= 10,
575 0x00, // Unused (control bits, all off)
576 (BlockAddress
>> 24), // MSB of Block Address
577 (BlockAddress
>> 16),
579 (BlockAddress
& 0xFF), // LSB of Block Address
580 0x00, // Unused (reserved)
581 0x00, // MSB of Total Blocks to Read
582 Blocks
, // LSB of Total Blocks to Read
583 0x00 // Unused (control)
587 MS_CommandStatusWrapper_t SCSICommandStatus
;
589 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
595 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
604 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
605 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
607 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
608 return HOST_SENDCONTROL_DeviceDisconnect
;
610 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
612 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
614 .Signature
= CBW_SIGNATURE
,
615 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
616 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
618 .SCSICommandLength
= 10,
622 0x00, // Unused (control bits, all off)
623 (BlockAddress
>> 24), // MSB of Block Address
624 (BlockAddress
>> 16),
626 (BlockAddress
& 0xFF), // LSB of Block Address
627 0x00, // Unused (reserved)
628 0x00, // MSB of Total Blocks to Write
629 Blocks
, // LSB of Total Blocks to Write
630 0x00 // Unused (control)
634 MS_CommandStatusWrapper_t SCSICommandStatus
;
636 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
642 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)