3 Copyright (C) Dean Camera, 2010.
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all 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 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
35 #define __INCLUDE_FROM_MS_CLASS_HOST_C
36 #define __INCLUDE_FROM_MS_DRIVER
37 #include "MassStorage.h"
39 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
40 uint16_t ConfigDescriptorSize
,
41 void* DeviceConfigDescriptor
)
43 uint8_t FoundEndpoints
= 0;
45 memset(&MSInterfaceInfo
->State
, 0x00, sizeof(MSInterfaceInfo
->State
));
47 if (DESCRIPTOR_TYPE(DeviceConfigDescriptor
) != DTYPE_Configuration
)
48 return MS_ENUMERROR_InvalidConfigDescriptor
;
50 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &DeviceConfigDescriptor
,
51 DCOMP_MS_NextMSInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
53 return MS_ENUMERROR_NoMSInterfaceFound
;
56 MSInterfaceInfo
->State
.InterfaceNumber
= DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Interface_t
)->InterfaceNumber
;
58 while (FoundEndpoints
!= (MS_FOUND_DATAPIPE_IN
| MS_FOUND_DATAPIPE_OUT
))
60 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &DeviceConfigDescriptor
,
61 DCOMP_MS_NextMSInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
63 return MS_ENUMERROR_EndpointsNotFound
;
66 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Endpoint_t
);
68 if (EndpointData
->EndpointAddress
& ENDPOINT_DESCRIPTOR_DIR_IN
)
70 Pipe_ConfigurePipe(MSInterfaceInfo
->Config
.DataINPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_IN
,
71 EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
,
72 MSInterfaceInfo
->Config
.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
);
73 MSInterfaceInfo
->State
.DataINPipeSize
= EndpointData
->EndpointSize
;
75 FoundEndpoints
|= MS_FOUND_DATAPIPE_IN
;
79 Pipe_ConfigurePipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_OUT
,
80 EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
,
81 MSInterfaceInfo
->Config
.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
);
82 MSInterfaceInfo
->State
.DataOUTPipeSize
= EndpointData
->EndpointSize
;
84 FoundEndpoints
|= MS_FOUND_DATAPIPE_OUT
;
88 MSInterfaceInfo
->State
.IsActive
= true;
89 return MS_ENUMERROR_NoError
;
92 static uint8_t DCOMP_MS_NextMSInterface(void* const CurrentDescriptor
)
94 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
96 USB_Descriptor_Interface_t
* CurrentInterface
= DESCRIPTOR_PCAST(CurrentDescriptor
,
97 USB_Descriptor_Interface_t
);
99 if ((CurrentInterface
->Class
== MASS_STORE_CLASS
) &&
100 (CurrentInterface
->SubClass
== MASS_STORE_SUBCLASS
) &&
101 (CurrentInterface
->Protocol
== MASS_STORE_PROTOCOL
))
103 return DESCRIPTOR_SEARCH_Found
;
107 return DESCRIPTOR_SEARCH_NotFound
;
110 static uint8_t DCOMP_MS_NextMSInterfaceEndpoint(void* const CurrentDescriptor
)
112 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
)
114 USB_Descriptor_Endpoint_t
* CurrentEndpoint
= DESCRIPTOR_PCAST(CurrentDescriptor
,
115 USB_Descriptor_Endpoint_t
);
117 uint8_t EndpointType
= (CurrentEndpoint
->Attributes
& EP_TYPE_MASK
);
119 if ((EndpointType
== EP_TYPE_BULK
) &&
120 (!(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
))))
122 return DESCRIPTOR_SEARCH_Found
;
125 else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
127 return DESCRIPTOR_SEARCH_Fail
;
130 return DESCRIPTOR_SEARCH_NotFound
;
133 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
134 MS_CommandBlockWrapper_t
* const SCSICommandBlock
,
135 const void* const BufferPtr
)
137 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
139 SCSICommandBlock
->Signature
= CBW_SIGNATURE
;
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
),
149 NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
153 Pipe_WaitUntilReady();
157 if ((BufferPtr
!= NULL
) &&
158 ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, SCSICommandBlock
, (void*)BufferPtr
)) != PIPE_RWSTREAM_NoError
))
167 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
)
169 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
170 uint16_t PreviousFrameNumber
= USB_Host_GetFrameNumber();
172 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
175 while (!(Pipe_IsINReceived()))
177 uint16_t CurrentFrameNumber
= USB_Host_GetFrameNumber();
179 if (CurrentFrameNumber
!= PreviousFrameNumber
)
181 PreviousFrameNumber
= CurrentFrameNumber
;
183 if (!(TimeoutMSRem
--))
184 return PIPE_RWSTREAM_Timeout
;
188 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
191 if (Pipe_IsStalled())
193 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
195 return PIPE_RWSTREAM_PipeStalled
;
199 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
202 if (Pipe_IsStalled())
204 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataINPipeNumber
);
206 return PIPE_RWSTREAM_PipeStalled
;
209 if (USB_HostState
== HOST_STATE_Unattached
)
210 return PIPE_RWSTREAM_DeviceDisconnected
;
213 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
216 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
219 return PIPE_RWSTREAM_NoError
;
222 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
223 MS_CommandBlockWrapper_t
* const SCSICommandBlock
,
226 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
227 uint16_t BytesRem
= SCSICommandBlock
->DataTransferLength
;
229 if (SCSICommandBlock
->Flags
& COMMAND_DIRECTION_DATA_IN
)
231 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
237 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
240 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPtr
, BytesRem
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
247 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
250 if ((ErrorCode
= Pipe_Write_Stream_LE(BufferPtr
, BytesRem
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
255 while (!(Pipe_IsOUTReady()))
257 if (USB_HostState
== HOST_STATE_Unattached
)
258 return PIPE_RWSTREAM_DeviceDisconnected
;
267 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
268 MS_CommandStatusWrapper_t
* const SCSICommandStatus
)
270 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
272 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
275 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
278 if ((ErrorCode
= Pipe_Read_Stream_LE(SCSICommandStatus
, sizeof(MS_CommandStatusWrapper_t
),
279 NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
287 if (SCSICommandStatus
->Status
!= SCSI_Command_Pass
)
288 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
293 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
)
295 USB_ControlRequest
= (USB_Request_Header_t
)
297 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
298 .bRequest
= REQ_MassStorageReset
,
300 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
304 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
306 return USB_Host_SendControlRequest(NULL
);
309 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
310 uint8_t* const MaxLUNIndex
)
312 uint8_t ErrorCode
= HOST_SENDCONTROL_Successful
;
314 USB_ControlRequest
= (USB_Request_Header_t
)
316 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
317 .bRequest
= REQ_GetMaxLUN
,
319 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
323 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
325 if ((ErrorCode
= USB_Host_SendControlRequest(MaxLUNIndex
)) != HOST_SENDCONTROL_Successful
)
328 ErrorCode
= HOST_SENDCONTROL_Successful
;
334 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
335 const uint8_t LUNIndex
,
336 SCSI_Inquiry_Response_t
* const InquiryData
)
338 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
339 return HOST_SENDCONTROL_DeviceDisconnected
;
343 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
345 .DataTransferLength
= sizeof(SCSI_Inquiry_Response_t
),
346 .Flags
= COMMAND_DIRECTION_DATA_IN
,
348 .SCSICommandLength
= 6,
355 sizeof(SCSI_Inquiry_Response_t
), // Allocation Length
356 0x00 // Unused (control)
360 MS_CommandStatusWrapper_t SCSICommandStatus
;
362 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, InquiryData
)) != PIPE_RWSTREAM_NoError
)
365 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
368 return PIPE_RWSTREAM_NoError
;
371 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
372 const uint8_t LUNIndex
)
374 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
375 return HOST_SENDCONTROL_DeviceDisconnected
;
379 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
381 .DataTransferLength
= 0,
382 .Flags
= COMMAND_DIRECTION_DATA_IN
,
384 .SCSICommandLength
= 6,
387 SCSI_CMD_TEST_UNIT_READY
,
392 0x00 // Unused (control)
396 MS_CommandStatusWrapper_t SCSICommandStatus
;
398 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
401 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
404 return PIPE_RWSTREAM_NoError
;
407 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
408 const uint8_t LUNIndex
,
409 SCSI_Capacity_t
* const DeviceCapacity
)
411 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
412 return HOST_SENDCONTROL_DeviceDisconnected
;
416 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
418 .DataTransferLength
= sizeof(SCSI_Capacity_t
),
419 .Flags
= COMMAND_DIRECTION_DATA_IN
,
421 .SCSICommandLength
= 10,
424 SCSI_CMD_READ_CAPACITY_10
,
426 0x00, // MSB of Logical block address
429 0x00, // LSB of Logical block address
432 0x00, // Partial Medium Indicator
433 0x00 // Unused (control)
437 MS_CommandStatusWrapper_t SCSICommandStatus
;
439 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, DeviceCapacity
)) != PIPE_RWSTREAM_NoError
)
442 SwapEndian_n(&DeviceCapacity
->Blocks
, sizeof(DeviceCapacity
->Blocks
));
443 SwapEndian_n(&DeviceCapacity
->BlockSize
, sizeof(DeviceCapacity
->BlockSize
));
445 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
448 return PIPE_RWSTREAM_NoError
;
451 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
452 const uint8_t LUNIndex
,
453 SCSI_Request_Sense_Response_t
* const SenseData
)
455 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
456 return HOST_SENDCONTROL_DeviceDisconnected
;
460 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
462 .DataTransferLength
= sizeof(SCSI_Request_Sense_Response_t
),
463 .Flags
= COMMAND_DIRECTION_DATA_IN
,
465 .SCSICommandLength
= 6,
468 SCSI_CMD_REQUEST_SENSE
,
472 sizeof(SCSI_Request_Sense_Response_t
), // Allocation Length
473 0x00 // Unused (control)
477 MS_CommandStatusWrapper_t SCSICommandStatus
;
479 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, SenseData
)) != PIPE_RWSTREAM_NoError
)
482 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
485 return PIPE_RWSTREAM_NoError
;
488 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
489 const uint8_t LUNIndex
,
490 const bool PreventRemoval
)
492 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
493 return HOST_SENDCONTROL_DeviceDisconnected
;
497 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
499 .DataTransferLength
= 0,
500 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
502 .SCSICommandLength
= 6,
505 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
,
508 PreventRemoval
, // Prevent flag
510 0x00 // Unused (control)
514 MS_CommandStatusWrapper_t SCSICommandStatus
;
516 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
519 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
522 return PIPE_RWSTREAM_NoError
;
525 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
526 const uint8_t LUNIndex
,
527 const uint32_t BlockAddress
,
528 const uint8_t Blocks
,
529 const uint16_t BlockSize
,
532 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
533 return HOST_SENDCONTROL_DeviceDisconnected
;
537 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
539 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
540 .Flags
= COMMAND_DIRECTION_DATA_IN
,
542 .SCSICommandLength
= 10,
546 0x00, // Unused (control bits, all off)
547 (BlockAddress
>> 24), // MSB of Block Address
548 (BlockAddress
>> 16),
550 (BlockAddress
& 0xFF), // LSB of Block Address
552 0x00, // MSB of Total Blocks to Read
553 Blocks
, // LSB of Total Blocks to Read
554 0x00 // Unused (control)
558 MS_CommandStatusWrapper_t SCSICommandStatus
;
560 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
563 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
566 return PIPE_RWSTREAM_NoError
;
569 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t
* const MSInterfaceInfo
,
570 const uint8_t LUNIndex
,
571 const uint32_t BlockAddress
,
572 const uint8_t Blocks
,
573 const uint16_t BlockSize
,
574 const void* BlockBuffer
)
576 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.IsActive
))
577 return HOST_SENDCONTROL_DeviceDisconnected
;
581 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
583 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
584 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
586 .SCSICommandLength
= 10,
590 0x00, // Unused (control bits, all off)
591 (BlockAddress
>> 24), // MSB of Block Address
592 (BlockAddress
>> 16),
594 (BlockAddress
& 0xFF), // LSB of Block Address
596 0x00, // MSB of Total Blocks to Write
597 Blocks
, // LSB of Total Blocks to Write
598 0x00 // Unused (control)
602 MS_CommandStatusWrapper_t SCSICommandStatus
;
604 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
607 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
610 return PIPE_RWSTREAM_NoError
;