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 (!(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
))))
119 return DESCRIPTOR_SEARCH_Found
;
122 else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
124 return DESCRIPTOR_SEARCH_Fail
;
127 return DESCRIPTOR_SEARCH_NotFound
;
130 void MS_Host_USBTask(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
135 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, MS_CommandBlockWrapper_t
* SCSICommandBlock
,
138 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
140 SCSICommandBlock
->Tag
= MSInterfaceInfo
->State
.TransactionTag
++;
142 if (MSInterfaceInfo
->State
.TransactionTag
== 0xFFFFFFFF)
143 MSInterfaceInfo
->State
.TransactionTag
= 1;
145 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
148 if ((ErrorCode
= Pipe_Write_Stream_LE(SCSICommandBlock
, sizeof(MS_CommandBlockWrapper_t
))) != PIPE_RWSTREAM_NoError
)
152 Pipe_WaitUntilReady();
156 if ((BufferPtr
!= NULL
) &&
157 ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, SCSICommandBlock
, BufferPtr
)) != PIPE_RWSTREAM_NoError
))
166 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
168 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
170 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
173 while (!(Pipe_IsINReceived()))
175 if (USB_INT_HasOccurred(USB_INT_HSOFI
))
177 USB_INT_Clear(USB_INT_HSOFI
);
181 return PIPE_RWSTREAM_Timeout
;
185 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
188 if (Pipe_IsStalled())
190 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
192 return PIPE_RWSTREAM_PipeStalled
;
196 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
199 if (Pipe_IsStalled())
201 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataINPipeNumber
);
203 return PIPE_RWSTREAM_PipeStalled
;
206 if (USB_HostState
== HOST_STATE_Unattached
)
207 return PIPE_RWSTREAM_DeviceDisconnected
;
210 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
213 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
216 return PIPE_RWSTREAM_NoError
;
219 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
220 MS_CommandBlockWrapper_t
* SCSICommandBlock
, void* BufferPtr
)
222 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
223 uint16_t BytesRem
= SCSICommandBlock
->DataTransferLength
;
225 if (SCSICommandBlock
->Flags
& COMMAND_DIRECTION_DATA_IN
)
227 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
233 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
236 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
243 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
246 if ((ErrorCode
= Pipe_Write_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
251 while (!(Pipe_IsOUTReady()))
253 if (USB_HostState
== HOST_STATE_Unattached
)
254 return PIPE_RWSTREAM_DeviceDisconnected
;
263 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
264 MS_CommandStatusWrapper_t
* SCSICommandStatus
)
266 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
268 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
271 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
274 if ((ErrorCode
= Pipe_Read_Stream_LE(SCSICommandStatus
, sizeof(MS_CommandStatusWrapper_t
))) != PIPE_RWSTREAM_NoError
)
280 if (SCSICommandStatus
->Status
!= SCSI_Command_Pass
)
281 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
286 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
288 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
289 return HOST_SENDCONTROL_DeviceDisconnect
;
291 USB_ControlRequest
= (USB_Request_Header_t
)
293 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
294 .bRequest
= REQ_MassStorageReset
,
296 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
300 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
302 return USB_Host_SendControlRequest(NULL
);
305 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t* MaxLUNIndex
)
307 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
308 return HOST_SENDCONTROL_DeviceDisconnect
;
312 USB_ControlRequest
= (USB_Request_Header_t
)
314 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
315 .bRequest
= REQ_GetMaxLUN
,
317 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
321 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
323 if ((ErrorCode
= USB_Host_SendControlRequest(MaxLUNIndex
)) == HOST_SENDCONTROL_SetupStalled
)
333 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, SCSI_Inquiry_Response_t
* InquiryData
)
335 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
336 return HOST_SENDCONTROL_DeviceDisconnect
;
338 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
340 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
342 .Signature
= CBW_SIGNATURE
,
343 .DataTransferLength
= sizeof(SCSI_Inquiry_Response_t
),
344 .Flags
= COMMAND_DIRECTION_DATA_IN
,
346 .SCSICommandLength
= 6,
353 sizeof(SCSI_Inquiry_Response_t
), // Allocation Length
354 0x00 // Unused (control)
358 MS_CommandStatusWrapper_t SCSICommandStatus
;
360 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, InquiryData
)) != PIPE_RWSTREAM_NoError
)
366 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
375 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
)
377 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
378 return HOST_SENDCONTROL_DeviceDisconnect
;
380 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
382 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
384 .Signature
= CBW_SIGNATURE
,
385 .DataTransferLength
= 0,
386 .Flags
= COMMAND_DIRECTION_DATA_IN
,
388 .SCSICommandLength
= 6,
391 SCSI_CMD_TEST_UNIT_READY
,
396 0x00 // Unused (control)
400 MS_CommandStatusWrapper_t SCSICommandStatus
;
402 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
408 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
417 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
418 SCSI_Capacity_t
* DeviceCapacity
)
420 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
421 return HOST_SENDCONTROL_DeviceDisconnect
;
423 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
425 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
427 .Signature
= CBW_SIGNATURE
,
428 .DataTransferLength
= sizeof(SCSI_Capacity_t
),
429 .Flags
= COMMAND_DIRECTION_DATA_IN
,
431 .SCSICommandLength
= 10,
434 SCSI_CMD_READ_CAPACITY_10
,
436 0x00, // MSB of Logical block address
439 0x00, // LSB of Logical block address
442 0x00, // Partial Medium Indicator
443 0x00 // Unused (control)
447 MS_CommandStatusWrapper_t SCSICommandStatus
;
449 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, DeviceCapacity
)) != PIPE_RWSTREAM_NoError
)
455 DeviceCapacity
->Blocks
= SwapEndian_32(DeviceCapacity
->Blocks
);
456 DeviceCapacity
->BlockSize
= SwapEndian_32(DeviceCapacity
->BlockSize
);
458 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
467 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
468 SCSI_Request_Sense_Response_t
* SenseData
)
470 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
471 return HOST_SENDCONTROL_DeviceDisconnect
;
473 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
475 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
477 .Signature
= CBW_SIGNATURE
,
478 .DataTransferLength
= sizeof(SCSI_Request_Sense_Response_t
),
479 .Flags
= COMMAND_DIRECTION_DATA_IN
,
481 .SCSICommandLength
= 6,
484 SCSI_CMD_REQUEST_SENSE
,
488 sizeof(SCSI_Request_Sense_Response_t
), // Allocation Length
489 0x00 // Unused (control)
493 MS_CommandStatusWrapper_t SCSICommandStatus
;
495 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, SenseData
)) != PIPE_RWSTREAM_NoError
)
501 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
510 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, bool PreventRemoval
)
512 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
513 return HOST_SENDCONTROL_DeviceDisconnect
;
515 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
517 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
519 .Signature
= CBW_SIGNATURE
,
520 .DataTransferLength
= 0,
521 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
523 .SCSICommandLength
= 6,
526 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
,
529 PreventRemoval
, // Prevent flag
531 0x00 // Unused (control)
535 MS_CommandStatusWrapper_t SCSICommandStatus
;
537 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
543 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
552 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
553 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
555 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
556 return HOST_SENDCONTROL_DeviceDisconnect
;
558 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
560 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
562 .Signature
= CBW_SIGNATURE
,
563 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
564 .Flags
= COMMAND_DIRECTION_DATA_IN
,
566 .SCSICommandLength
= 10,
570 0x00, // Unused (control bits, all off)
571 (BlockAddress
>> 24), // MSB of Block Address
572 (BlockAddress
>> 16),
574 (BlockAddress
& 0xFF), // LSB of Block Address
575 0x00, // Unused (reserved)
576 0x00, // MSB of Total Blocks to Read
577 Blocks
, // LSB of Total Blocks to Read
578 0x00 // Unused (control)
582 MS_CommandStatusWrapper_t SCSICommandStatus
;
584 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
590 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
599 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
600 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
602 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
603 return HOST_SENDCONTROL_DeviceDisconnect
;
605 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
607 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
609 .Signature
= CBW_SIGNATURE
,
610 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
611 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
613 .SCSICommandLength
= 10,
617 0x00, // Unused (control bits, all off)
618 (BlockAddress
>> 24), // MSB of Block Address
619 (BlockAddress
>> 16),
621 (BlockAddress
& 0xFF), // LSB of Block Address
622 0x00, // Unused (reserved)
623 0x00, // MSB of Total Blocks to Write
624 Blocks
, // LSB of Total Blocks to Write
625 0x00 // Unused (control)
629 MS_CommandStatusWrapper_t SCSICommandStatus
;
631 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
637 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)