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
);