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
,
135 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
137 SCSICommandBlock
->Tag
= MSInterfaceInfo
->State
.TransactionTag
++;
139 if (MSInterfaceInfo
->State
.TransactionTag
== 0xFFFFFFFF)
140 MSInterfaceInfo
->State
.TransactionTag
= 1;
142 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
145 if ((ErrorCode
= Pipe_Write_Stream_LE(SCSICommandBlock
, sizeof(MS_CommandBlockWrapper_t
))) != PIPE_RWSTREAM_NoError
)
149 Pipe_WaitUntilReady();
153 if ((BufferPtr
!= NULL
) &&
154 ((ErrorCode
= MS_Host_SendReceiveData(MSInterfaceInfo
, SCSICommandBlock
, BufferPtr
)) != PIPE_RWSTREAM_NoError
))
163 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
165 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
167 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
170 while (!(Pipe_IsINReceived()))
172 if (USB_INT_HasOccurred(USB_INT_HSOFI
))
174 USB_INT_Clear(USB_INT_HSOFI
);
178 return PIPE_RWSTREAM_Timeout
;
182 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
185 if (Pipe_IsStalled())
187 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
189 return PIPE_RWSTREAM_PipeStalled
;
193 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
196 if (Pipe_IsStalled())
198 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataINPipeNumber
);
200 return PIPE_RWSTREAM_PipeStalled
;
203 if (USB_HostState
== HOST_STATE_Unattached
)
204 return PIPE_RWSTREAM_DeviceDisconnected
;
207 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
210 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
213 return PIPE_RWSTREAM_NoError
;
216 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
217 MS_CommandBlockWrapper_t
* SCSICommandBlock
, void* BufferPtr
)
219 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
220 uint16_t BytesRem
= SCSICommandBlock
->DataTransferLength
;
222 if (SCSICommandBlock
->Flags
& COMMAND_DIRECTION_DATA_IN
)
224 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
230 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
233 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
240 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
243 if ((ErrorCode
= Pipe_Write_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
248 while (!(Pipe_IsOUTReady()))
250 if (USB_HostState
== HOST_STATE_Unattached
)
251 return PIPE_RWSTREAM_DeviceDisconnected
;
260 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
261 MS_CommandStatusWrapper_t
* SCSICommandStatus
)
263 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
265 if ((ErrorCode
= MS_Host_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
268 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
271 if ((ErrorCode
= Pipe_Read_Stream_LE(SCSICommandStatus
, sizeof(MS_CommandStatusWrapper_t
))) != PIPE_RWSTREAM_NoError
)
277 if (SCSICommandStatus
->Status
!= SCSI_Command_Pass
)
278 ErrorCode
= MS_ERROR_LOGICAL_CMD_FAILED
;
283 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
285 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
286 return HOST_SENDCONTROL_DeviceDisconnect
;
288 USB_ControlRequest
= (USB_Request_Header_t
)
290 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
291 .bRequest
= REQ_MassStorageReset
,
293 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
297 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
299 return USB_Host_SendControlRequest(NULL
);
302 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t* MaxLUNIndex
)
304 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
305 return HOST_SENDCONTROL_DeviceDisconnect
;
309 USB_ControlRequest
= (USB_Request_Header_t
)
311 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
312 .bRequest
= REQ_GetMaxLUN
,
314 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
318 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
320 if ((ErrorCode
= USB_Host_SendControlRequest(MaxLUNIndex
)) == HOST_SENDCONTROL_SetupStalled
)
330 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, SCSI_Inquiry_Response_t
* InquiryData
)
332 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
333 return HOST_SENDCONTROL_DeviceDisconnect
;
335 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
337 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
339 .Signature
= CBW_SIGNATURE
,
340 .DataTransferLength
= sizeof(SCSI_Inquiry_Response_t
),
341 .Flags
= COMMAND_DIRECTION_DATA_IN
,
343 .SCSICommandLength
= 6,
350 sizeof(SCSI_Inquiry_Response_t
), // Allocation Length
351 0x00 // Unused (control)
355 MS_CommandStatusWrapper_t SCSICommandStatus
;
357 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, InquiryData
)) != PIPE_RWSTREAM_NoError
)
363 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
372 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
)
374 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
375 return HOST_SENDCONTROL_DeviceDisconnect
;
377 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
379 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
381 .Signature
= CBW_SIGNATURE
,
382 .DataTransferLength
= 0,
383 .Flags
= COMMAND_DIRECTION_DATA_IN
,
385 .SCSICommandLength
= 6,
388 SCSI_CMD_TEST_UNIT_READY
,
393 0x00 // Unused (control)
397 MS_CommandStatusWrapper_t SCSICommandStatus
;
399 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
405 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
414 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
415 SCSI_Capacity_t
* DeviceCapacity
)
417 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
418 return HOST_SENDCONTROL_DeviceDisconnect
;
420 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
422 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
424 .Signature
= CBW_SIGNATURE
,
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 MS_CommandStatusWrapper_t SCSICommandStatus
;
446 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, DeviceCapacity
)) != PIPE_RWSTREAM_NoError
)
452 DeviceCapacity
->Blocks
= SwapEndian_32(DeviceCapacity
->Blocks
);
453 DeviceCapacity
->BlockSize
= SwapEndian_32(DeviceCapacity
->BlockSize
);
455 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
464 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
465 SCSI_Request_Sense_Response_t
* SenseData
)
467 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
468 return HOST_SENDCONTROL_DeviceDisconnect
;
470 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
472 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
474 .Signature
= CBW_SIGNATURE
,
475 .DataTransferLength
= sizeof(SCSI_Request_Sense_Response_t
),
476 .Flags
= COMMAND_DIRECTION_DATA_IN
,
478 .SCSICommandLength
= 6,
481 SCSI_CMD_REQUEST_SENSE
,
485 sizeof(SCSI_Request_Sense_Response_t
), // Allocation Length
486 0x00 // Unused (control)
490 MS_CommandStatusWrapper_t SCSICommandStatus
;
492 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, SenseData
)) != PIPE_RWSTREAM_NoError
)
498 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
507 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, bool PreventRemoval
)
509 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
510 return HOST_SENDCONTROL_DeviceDisconnect
;
512 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
514 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
516 .Signature
= CBW_SIGNATURE
,
517 .DataTransferLength
= 0,
518 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
520 .SCSICommandLength
= 6,
523 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL
,
526 PreventRemoval
, // Prevent flag
528 0x00 // Unused (control)
532 MS_CommandStatusWrapper_t SCSICommandStatus
;
534 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, NULL
)) != PIPE_RWSTREAM_NoError
)
540 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
549 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
550 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
552 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
553 return HOST_SENDCONTROL_DeviceDisconnect
;
555 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
557 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
559 .Signature
= CBW_SIGNATURE
,
560 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
561 .Flags
= COMMAND_DIRECTION_DATA_IN
,
563 .SCSICommandLength
= 10,
567 0x00, // Unused (control bits, all off)
568 (BlockAddress
>> 24), // MSB of Block Address
569 (BlockAddress
>> 16),
571 (BlockAddress
& 0xFF), // LSB of Block Address
572 0x00, // Unused (reserved)
573 0x00, // MSB of Total Blocks to Read
574 Blocks
, // LSB of Total Blocks to Read
575 0x00 // Unused (control)
579 MS_CommandStatusWrapper_t SCSICommandStatus
;
581 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
587 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)
596 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, uint32_t BlockAddress
,
597 uint8_t Blocks
, uint16_t BlockSize
, void* BlockBuffer
)
599 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
600 return HOST_SENDCONTROL_DeviceDisconnect
;
602 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
604 MS_CommandBlockWrapper_t SCSICommandBlock
= (MS_CommandBlockWrapper_t
)
606 .Signature
= CBW_SIGNATURE
,
607 .DataTransferLength
= ((uint32_t)Blocks
* BlockSize
),
608 .Flags
= COMMAND_DIRECTION_DATA_OUT
,
610 .SCSICommandLength
= 10,
614 0x00, // Unused (control bits, all off)
615 (BlockAddress
>> 24), // MSB of Block Address
616 (BlockAddress
>> 16),
618 (BlockAddress
& 0xFF), // LSB of Block Address
619 0x00, // Unused (reserved)
620 0x00, // MSB of Total Blocks to Write
621 Blocks
, // LSB of Total Blocks to Write
622 0x00 // Unused (control)
626 MS_CommandStatusWrapper_t SCSICommandStatus
;
628 if ((ErrorCode
= MS_Host_SendCommand(MSInterfaceInfo
, &SCSICommandBlock
, BlockBuffer
)) != PIPE_RWSTREAM_NoError
)
634 if ((ErrorCode
= MS_Host_GetReturnedStatus(MSInterfaceInfo
, &SCSICommandStatus
)) != PIPE_RWSTREAM_NoError
)