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
.IsActive
= 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
.IsActive
))
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
.IsActive
))
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
)
335 return 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
.IsActive
))
341 return HOST_SENDCONTROL_DeviceDisconnect
;
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
)
368 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
371 return PIPE_RWSTREAM_NoError
;
374 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
)
376 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
377 return HOST_SENDCONTROL_DeviceDisconnect
;
381 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
383 .Signature
= CBW_SIGNATURE
,
384 .DataTransferLength
= 0,
385 .Flags
= COMMAND_DIRECTION_DATA_IN
,
387 .SCSICommandLength
= 6,
390 SCSI_CMD_TEST_UNIT_READY
,
395 0x00 // Unused (control)
399 MS_CommandStatusWrapper_t SCSICommandStatus
;
401 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
404 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
407 return PIPE_RWSTREAM_NoError
;
410 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
411 SCSI_Capacity_t
* DeviceCapacity
)
413 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
414 return HOST_SENDCONTROL_DeviceDisconnect
;
418 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
420 .Signature
= CBW_SIGNATURE
,
421 .DataTransferLength
= sizeof(SCSI_Capacity_t
),
422 .Flags
= COMMAND_DIRECTION_DATA_IN
,
424 .SCSICommandLength
= 10,
427 SCSI_CMD_READ_CAPACITY_10
,
429 0x00, // MSB of Logical block address
432 0x00, // LSB of Logical block address
435 0x00, // Partial Medium Indicator
436 0x00 // Unused (control)
440 MS_CommandStatusWrapper_t SCSICommandStatus
;
442 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, DeviceCapacity
)) != PIPE_RWSTREAM_NoError
)
445 DeviceCapacity
->Blocks
= SwapEndian_32(DeviceCapacity
->Blocks
);
446 DeviceCapacity
->BlockSize
= SwapEndian_32(DeviceCapacity
->BlockSize
);
448 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
451 return PIPE_RWSTREAM_NoError
;
454 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
455 SCSI_Request_Sense_Response_t
* SenseData
)
457 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
458 return HOST_SENDCONTROL_DeviceDisconnect
;
462 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
464 .Signature
= CBW_SIGNATURE
,
465 .DataTransferLength
= sizeof(SCSI_Request_Sense_Response_t
),
466 .Flags
= COMMAND_DIRECTION_DATA_IN
,
468 .SCSICommandLength
= 6,
471 SCSI_CMD_REQUEST_SENSE
,
475 sizeof(SCSI_Request_Sense_Response_t
), // Allocation Length
476 0x00 // Unused (control)
480 MS_CommandStatusWrapper_t SCSICommandStatus
;
482 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, SenseData
)) != PIPE_RWSTREAM_NoError
)
485 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
488 return PIPE_RWSTREAM_NoError
;
491 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, bool PreventRemoval
)
493 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
494 return HOST_SENDCONTROL_DeviceDisconnect
;
498 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
500 .Signature
= CBW_SIGNATURE
,
501 .DataTransferLength
= 0,
502 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
504 .SCSICommandLength
= 6,
507 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
,
510 PreventRemoval
, // Prevent flag
512 0x00 // Unused (control)
516 MS_CommandStatusWrapper_t SCSICommandStatus
;
518 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
521 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
524 return PIPE_RWSTREAM_NoError
;
527 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
528 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
530 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
531 return HOST_SENDCONTROL_DeviceDisconnect
;
535 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
537 .Signature
= CBW_SIGNATURE
,
538 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
539 .Flags
= COMMAND_DIRECTION_DATA_IN
,
541 .SCSICommandLength
= 10,
545 0x00, // Unused (control bits, all off)
546 (BlockAddress
>> 24), // MSB of Block Address
547 (BlockAddress
>> 16),
549 (BlockAddress
& 0xFF), // LSB of Block Address
550 0x00, // Unused (reserved)
551 0x00, // MSB of Total Blocks to Read
552 Blocks
, // LSB of Total Blocks to Read
553 0x00 // Unused (control)
557 MS_CommandStatusWrapper_t SCSICommandStatus
;
559 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
562 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
565 return PIPE_RWSTREAM_NoError
;
568 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
569 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
571 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
572 return HOST_SENDCONTROL_DeviceDisconnect
;
576 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
578 .Signature
= CBW_SIGNATURE
,
579 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
580 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
582 .SCSICommandLength
= 10,
586 0x00, // Unused (control bits, all off)
587 (BlockAddress
>> 24), // MSB of Block Address
588 (BlockAddress
>> 16),
590 (BlockAddress
& 0xFF), // LSB of Block Address
591 0x00, // Unused (reserved)
592 0x00, // MSB of Total Blocks to Write
593 Blocks
, // LSB of Total Blocks to Write
594 0x00 // Unused (control)
598 MS_CommandStatusWrapper_t SCSICommandStatus
;
600 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
603 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
606 return PIPE_RWSTREAM_NoError
;