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 #include "../../HighLevel/USBMode.h" 
  32 #if defined(USB_CAN_BE_HOST) 
  34 #define INCLUDE_FROM_SI_CLASS_HOST_C 
  35 #include "StillImage.h" 
  37 uint8_t SImage_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, uint16_t ConfigDescriptorSize
, 
  38                                    void* DeviceConfigDescriptor
) 
  40         uint8_t  FoundEndpoints 
= 0; 
  42         memset(&SIInterfaceInfo
->State
, 0x00, sizeof(SIInterfaceInfo
->State
)); 
  44         if (DESCRIPTOR_TYPE(DeviceConfigDescriptor
) != DTYPE_Configuration
) 
  45           return SI_ENUMERROR_InvalidConfigDescriptor
; 
  47         if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &DeviceConfigDescriptor
, 
  48                                       DComp_SI_Host_NextSIInterface
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  50                 return SI_ENUMERROR_NoSIInterfaceFound
; 
  53         while (FoundEndpoints 
!= (SI_FOUND_EVENTS_IN 
| SI_FOUND_DATAPIPE_IN 
| SI_FOUND_DATAPIPE_OUT
)) 
  55                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &DeviceConfigDescriptor
, 
  56                                               DComp_SI_Host_NextSIInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  58                         return SI_ENUMERROR_EndpointsNotFound
; 
  61                 USB_Descriptor_Endpoint_t
* EndpointData 
= DESCRIPTOR_PCAST(DeviceConfigDescriptor
, USB_Descriptor_Endpoint_t
); 
  63                 if ((EndpointData
->Attributes 
& EP_TYPE_MASK
) == EP_TYPE_INTERRUPT
) 
  65                         if (EndpointData
->EndpointAddress 
& ENDPOINT_DESCRIPTOR_DIR_IN
) 
  67                                 Pipe_ConfigurePipe(SIInterfaceInfo
->Config
.EventsPipeNumber
, EP_TYPE_INTERRUPT
, PIPE_TOKEN_IN
, 
  68                                                                    EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
, 
  69                                                                    SIInterfaceInfo
->Config
.EventsPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
);                  
  70                                 SIInterfaceInfo
->State
.EventsPipeSize 
= EndpointData
->EndpointSize
; 
  72                                 Pipe_SetInterruptPeriod(EndpointData
->PollingIntervalMS
); 
  74                                 FoundEndpoints 
|= SI_FOUND_EVENTS_IN
; 
  79                         if (EndpointData
->EndpointAddress 
& ENDPOINT_DESCRIPTOR_DIR_IN
) 
  81                                 Pipe_ConfigurePipe(SIInterfaceInfo
->Config
.DataINPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_IN
, 
  82                                                                    EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
, 
  83                                                                    SIInterfaceInfo
->Config
.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
  84                                 SIInterfaceInfo
->State
.DataINPipeSize 
= EndpointData
->EndpointSize
; 
  86                                 FoundEndpoints 
|= SI_FOUND_DATAPIPE_IN
; 
  90                                 Pipe_ConfigurePipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
, EP_TYPE_BULK
, PIPE_TOKEN_OUT
, 
  91                                                                    EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
, 
  92                                                                    SIInterfaceInfo
->Config
.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
  93                                 SIInterfaceInfo
->State
.DataOUTPipeSize 
= EndpointData
->EndpointSize
; 
  95                                 FoundEndpoints 
|= SI_FOUND_DATAPIPE_OUT
; 
 100         SIInterfaceInfo
->State
.IsActive 
= true; 
 101         return SI_ENUMERROR_NoError
; 
 104 uint8_t DComp_SI_Host_NextSIInterface(void* const CurrentDescriptor
) 
 106         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 108                 USB_Descriptor_Interface_t
* CurrentInterface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 109                                                                                 USB_Descriptor_Interface_t
); 
 111                 if ((CurrentInterface
->Class    
== STILL_IMAGE_CLASS
)    && 
 112                     (CurrentInterface
->SubClass 
== STILL_IMAGE_SUBCLASS
) && 
 113                     (CurrentInterface
->Protocol 
== STILL_IMAGE_PROTOCOL
)) 
 115                         return DESCRIPTOR_SEARCH_Found
; 
 119         return DESCRIPTOR_SEARCH_NotFound
; 
 122 uint8_t DComp_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor
) 
 124         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
) 
 126                 USB_Descriptor_Endpoint_t
* CurrentEndpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 127                                                                               USB_Descriptor_Endpoint_t
); 
 129                 uint8_t EndpointType 
= (CurrentEndpoint
->Attributes 
& EP_TYPE_MASK
); 
 131                 if (((EndpointType 
== EP_TYPE_BULK
) || (EndpointType 
== EP_TYPE_INTERRUPT
)) && 
 132                     (!(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
)))) 
 134                         return DESCRIPTOR_SEARCH_Found
; 
 137         else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 139                 return DESCRIPTOR_SEARCH_Fail
; 
 142         return DESCRIPTOR_SEARCH_NotFound
; 
 145 uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, SI_PIMA_Container_t
* const PIMAHeader
) 
 149         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 150           return PIPE_RWSTREAM_DeviceDisconnected
; 
 152         PIMAHeader
->TransactionID 
= SIInterfaceInfo
->State
.TransactionID
++; 
 154         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 157         if ((ErrorCode 
= Pipe_Write_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 160         uint8_t ParamBytes 
= (PIMAHeader
->DataLength 
- PIMA_COMMAND_SIZE(0)); 
 164                 if ((ErrorCode 
= Pipe_Write_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 171         return PIPE_RWSTREAM_NoError
; 
 174 uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, SI_PIMA_Container_t
* const PIMAHeader
) 
 176         uint16_t TimeoutMSRem 
= COMMAND_DATA_TIMEOUT_MS
; 
 178         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 179           return PIPE_RWSTREAM_DeviceDisconnected
; 
 181         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 184         while (!(Pipe_IsReadWriteAllowed())) 
 186                 if (USB_INT_HasOccurred(USB_INT_HSOFI
)) 
 188                         USB_INT_Clear(USB_INT_HSOFI
); 
 193                                 return PIPE_RWSTREAM_Timeout
; 
 198                 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 201                 if (Pipe_IsStalled()) 
 203                         USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 204                         return PIPE_RWSTREAM_PipeStalled
; 
 208                 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 211                 if (Pipe_IsStalled()) 
 213                         USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 214                         return PIPE_RWSTREAM_PipeStalled
; 
 217                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 218                   return PIPE_RWSTREAM_DeviceDisconnected
; 
 221         Pipe_Read_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
); 
 223         if (PIMAHeader
->Type 
== CType_ResponseBlock
) 
 225                 uint8_t ParamBytes 
= (PIMAHeader
->DataLength 
- PIMA_COMMAND_SIZE(0)); 
 228                   Pipe_Read_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
); 
 235         return PIPE_RWSTREAM_NoError
; 
 238 uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, void* Buffer
, const uint16_t Bytes
) 
 242         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 243           return PIPE_RWSTREAM_DeviceDisconnected
; 
 245         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 248         ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
); 
 256 uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, void* Buffer
, const uint16_t Bytes
) 
 260         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 261           return PIPE_RWSTREAM_DeviceDisconnected
; 
 263         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 266         ErrorCode 
= Pipe_Read_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
); 
 273 bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t
* SIInterfaceInfo
) 
 275         bool IsEventReceived 
= false; 
 277         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 280         Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
); 
 283         if (Pipe_BytesInPipe()) 
 284           IsEventReceived 
= true; 
 288         return IsEventReceived
; 
 291 uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, SI_PIMA_Container_t
* const PIMAHeader
) 
 295         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 296           return PIPE_RWSTREAM_DeviceDisconnected
; 
 298         Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
); 
 301         ErrorCode 
= Pipe_Read_Stream_LE(PIMAHeader
, sizeof(SI_PIMA_Container_t
), NO_STREAM_CALLBACK
); 
 309 uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 311         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 312           return HOST_SENDCONTROL_DeviceDisconnected
; 
 316         SI_PIMA_Container_t PIMABlock 
= (SI_PIMA_Container_t
) 
 318                                                                 .DataLength    
= PIMA_COMMAND_SIZE(0), 
 319                                                                 .Type          
= CType_CommandBlock
, 
 324         if ((ErrorCode 
= SImage_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 327         if ((ErrorCode 
= SImage_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 330         if ((PIMABlock
.Type 
!= CType_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 331           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 333         SIInterfaceInfo
->State
.TransactionID 
= 0; 
 334         SIInterfaceInfo
->State
.IsSessionOpen 
= true; 
 336         return PIPE_RWSTREAM_NoError
; 
 339 uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 341         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 342           return HOST_SENDCONTROL_DeviceDisconnected
; 
 346         SI_PIMA_Container_t PIMABlock 
= (SI_PIMA_Container_t
) 
 348                                                                 .DataLength    
= PIMA_COMMAND_SIZE(0), 
 349                                                                 .Type          
= CType_CommandBlock
, 
 354         if ((ErrorCode 
= SImage_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 357         if ((ErrorCode 
= SImage_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 360         SIInterfaceInfo
->State
.IsSessionOpen 
= false; 
 362         if ((PIMABlock
.Type 
!= CType_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 363           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 365         return PIPE_RWSTREAM_NoError
; 
 368 uint8_t SImage_Host_SendCommand(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, const uint16_t Operation
, 
 369                                 const uint8_t TotalParams
, uint32_t* Params
) 
 371         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 372           return HOST_SENDCONTROL_DeviceDisconnected
; 
 376         SI_PIMA_Container_t PIMABlock 
= (SI_PIMA_Container_t
) 
 378                                                                 .DataLength    
= PIMA_COMMAND_SIZE(TotalParams
), 
 379                                                                 .Type          
= CType_CommandBlock
, 
 383         memcpy(&PIMABlock
.Params
, Params
, sizeof(uint32_t) * TotalParams
); 
 385         if ((ErrorCode 
= SImage_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 388         return PIPE_RWSTREAM_NoError
; 
 391 uint8_t SImage_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 394         SI_PIMA_Container_t PIMABlock
; 
 396         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 397           return HOST_SENDCONTROL_DeviceDisconnected
; 
 399         if ((ErrorCode 
= SImage_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 402         if ((PIMABlock
.Type 
!= CType_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 403           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 405         return PIPE_RWSTREAM_NoError
;