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 #warning The Mass Storage Host mode Class driver is currently incomplete and is for preview purposes only.
39 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint16_t ConfigDescriptorLength
,
40 uint8_t* DeviceConfigDescriptor
)
42 uint8_t FoundEndpoints
= 0;
44 memset(&MSInterfaceInfo
->State
, 0x00, sizeof(MSInterfaceInfo
->State
));
46 if (DESCRIPTOR_TYPE(DeviceConfigDescriptor
) != DTYPE_Configuration
)
47 return MS_ENUMERROR_InvalidConfigDescriptor
;
49 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength
, &DeviceConfigDescriptor
,
50 DComp_NextMassStorageInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
52 return MS_ENUMERROR_NoMSInterfaceFound
;
55 MSInterfaceInfo
->State
.InterfaceNumber
=
56 #if defined(USE_NONSTANDARD_DESCRIPTOR_NAMES)
57 DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Interface_t
)->InterfaceNumber
;
59 DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Interface_t
)->bInterfaceNumber
;
62 while (FoundEndpoints
!= (MS_FOUND_DATAPIPE_IN
| MS_FOUND_DATAPIPE_OUT
))
64 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength
, &DeviceConfigDescriptor
,
65 DComp_NextInterfaceBulkDataEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
67 return MS_ENUMERROR_EndpointsNotFound
;
70 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Endpoint_t
);
72 if (EndpointData
->EndpointAddress
& ENDPOINT_DESCRIPTOR_DIR_IN
)
74 Pipe_ConfigurePipe(MSInterfaceInfo
->Config
.DataINPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_IN
,
75 EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
,
77 MSInterfaceInfo
->State
.DataINPipeSize
= EndpointData
->EndpointSize
;
79 FoundEndpoints
|= MS_FOUND_DATAPIPE_IN
;
83 Pipe_ConfigurePipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_OUT
,
84 EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
,
86 MSInterfaceInfo
->State
.DataOUTPipeSize
= EndpointData
->EndpointSize
;
88 FoundEndpoints
|= MS_FOUND_DATAPIPE_OUT
;
92 MSInterfaceInfo
->State
.Active
= true;
93 return MS_ENUMERROR_NoError
;
96 static uint8_t DComp_NextMassStorageInterface(void* CurrentDescriptor
)
98 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
100 if ((DESCRIPTOR_CAST(CurrentDescriptor
, USB_Descriptor_Interface_t
).Class
== MASS_STORE_CLASS
) &&
101 (DESCRIPTOR_CAST(CurrentDescriptor
, USB_Descriptor_Interface_t
).SubClass
== MASS_STORE_SUBCLASS
) &&
102 (DESCRIPTOR_CAST(CurrentDescriptor
, USB_Descriptor_Interface_t
).Protocol
== MASS_STORE_PROTOCOL
))
104 return DESCRIPTOR_SEARCH_Found
;
108 return DESCRIPTOR_SEARCH_NotFound
;
111 static uint8_t DComp_NextInterfaceBulkDataEndpoint(void* CurrentDescriptor
)
113 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
)
115 uint8_t EndpointType
= (DESCRIPTOR_CAST(CurrentDescriptor
,
116 USB_Descriptor_Endpoint_t
).Attributes
& EP_TYPE_MASK
);
118 if (EndpointType
== EP_TYPE_BULK
)
119 return DESCRIPTOR_SEARCH_Found
;
121 else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
123 return DESCRIPTOR_SEARCH_Fail
;
126 return DESCRIPTOR_SEARCH_NotFound
;
129 void MS_Host_USBTask(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
134 static uint8_t MassStore_SendCommand(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, MS_CommandBlockWrapper_t
* SCSICommandBlock
)
136 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
138 if (++MSInterfaceInfo
->State
.TransactionTag
== 0xFFFFFFFF)
139 MSInterfaceInfo
->State
.TransactionTag
= 1;
141 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
144 if ((ErrorCode
= Pipe_Write_Stream_LE(SCSICommandBlock
, sizeof(MS_CommandBlockWrapper_t
))) != PIPE_RWSTREAM_NoError
)
148 while(!(Pipe_IsOUTReady()));
152 return PIPE_RWSTREAM_NoError
;
155 static uint8_t MassStore_WaitForDataReceived(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
157 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
159 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
162 while (!(Pipe_IsINReceived()))
164 if (USB_INT_HasOccurred(USB_INT_HSOFI
))
166 USB_INT_Clear(USB_INT_HSOFI
);
170 return PIPE_RWSTREAM_Timeout
;
174 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
177 if (Pipe_IsStalled())
179 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
181 return PIPE_RWSTREAM_PipeStalled
;
185 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
188 if (Pipe_IsStalled())
190 USB_Host_ClearPipeStall(MSInterfaceInfo
->Config
.DataINPipeNumber
);
192 return PIPE_RWSTREAM_PipeStalled
;
195 if (USB_HostState
== HOST_STATE_Unattached
)
196 return PIPE_RWSTREAM_DeviceDisconnected
;
199 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
202 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
205 return PIPE_RWSTREAM_NoError
;
208 static uint8_t MassStore_SendReceiveData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
209 MS_CommandBlockWrapper_t
* SCSICommandBlock
, void* BufferPtr
)
211 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
212 uint16_t BytesRem
= SCSICommandBlock
->DataTransferLength
;
214 if (SCSICommandBlock
->Flags
& COMMAND_DIRECTION_DATA_IN
)
216 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
219 if ((ErrorCode
= Pipe_Read_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
226 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataOUTPipeNumber
);
229 if ((ErrorCode
= Pipe_Write_Stream_LE(BufferPtr
, BytesRem
)) != PIPE_RWSTREAM_NoError
)
234 while (!(Pipe_IsOUTReady()))
236 if (USB_HostState
== HOST_STATE_Unattached
)
237 return PIPE_RWSTREAM_DeviceDisconnected
;
243 return PIPE_RWSTREAM_NoError
;
246 static uint8_t MassStore_GetReturnedStatus(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
,
247 MS_CommandStatusWrapper_t
* SCSICommandStatus
)
249 uint8_t ErrorCode
= PIPE_RWSTREAM_NoError
;
251 if ((ErrorCode
= MassStore_WaitForDataReceived(MSInterfaceInfo
)) != PIPE_RWSTREAM_NoError
)
254 Pipe_SelectPipe(MSInterfaceInfo
->Config
.DataINPipeNumber
);
257 if ((ErrorCode
= Pipe_Read_Stream_LE(&SCSICommandStatus
, sizeof(MS_CommandStatusWrapper_t
))) != PIPE_RWSTREAM_NoError
)
263 return PIPE_RWSTREAM_NoError
;
266 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
)
268 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
269 return HOST_SENDCONTROL_DeviceDisconnect
;
271 USB_ControlRequest
= (USB_Request_Header_t
)
273 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
274 .bRequest
= REQ_MassStorageReset
,
276 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
280 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
282 return USB_Host_SendControlRequest(NULL
);
285 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t* MaxLUNIndex
)
287 if ((USB_HostState
!= HOST_STATE_Configured
) || !(MSInterfaceInfo
->State
.Active
))
288 return HOST_SENDCONTROL_DeviceDisconnect
;
292 USB_ControlRequest
= (USB_Request_Header_t
)
294 .bmRequestType
= (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
),
295 .bRequest
= REQ_GetMaxLUN
,
297 .wIndex
= MSInterfaceInfo
->State
.InterfaceNumber
,
301 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
303 if ((ErrorCode
= USB_Host_SendControlRequest(MaxLUNIndex
)) == HOST_SENDCONTROL_SetupStalled
)
313 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, SCSI_Inquiry_Response_t
* InquiryData
)
318 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
, bool* DeviceReady
);
319 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t
* MSInterfaceInfo
, uint8_t LUNIndex
,
320 SCSI_Capacity_t
* DeviceCapacity
);