3      Copyright (C) Dean Camera, 2011. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2011  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_SI_DRIVER 
  36 #define  __INCLUDE_FROM_STILLIMAGE_HOST_C 
  37 #include "StillImage.h" 
  39 uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
  40                                uint16_t ConfigDescriptorSize
, 
  41                                void* ConfigDescriptorData
) 
  43         USB_Descriptor_Endpoint_t
*  DataINEndpoint      
= NULL
; 
  44         USB_Descriptor_Endpoint_t
*  DataOUTEndpoint     
= NULL
; 
  45         USB_Descriptor_Endpoint_t
*  EventsEndpoint      
= NULL
; 
  46         USB_Descriptor_Interface_t
* StillImageInterface 
= NULL
; 
  48         memset(&SIInterfaceInfo
->State
, 0x00, sizeof(SIInterfaceInfo
->State
)); 
  50         if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
) 
  51           return SI_ENUMERROR_InvalidConfigDescriptor
; 
  53         while (!(DataINEndpoint
) || !(DataOUTEndpoint
)) 
  55                 if (!(StillImageInterface
) || 
  56                     USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  57                                               DCOMP_SI_Host_NextSIInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  59                         if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  60                                                       DCOMP_SI_Host_NextSIInterface
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  62                                 return SI_ENUMERROR_NoCompatibleInterfaceFound
; 
  65                         StillImageInterface 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
); 
  67                         DataINEndpoint  
= NULL
; 
  68                         DataOUTEndpoint 
= NULL
; 
  69                         EventsEndpoint  
= NULL
; 
  74                 USB_Descriptor_Endpoint_t
* EndpointData 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
); 
  76                 if (EndpointData
->EndpointAddress 
& ENDPOINT_DESCRIPTOR_DIR_IN
) 
  78                         if ((EndpointData
->Attributes 
& EP_TYPE_MASK
) == EP_TYPE_INTERRUPT
) 
  79                           EventsEndpoint 
= EndpointData
; 
  81                           DataINEndpoint 
= EndpointData
; 
  85                         DataOUTEndpoint 
= EndpointData
; 
  89         for (uint8_t PipeNum 
= 1; PipeNum 
< PIPE_TOTAL_PIPES
; PipeNum
++) 
  94                 uint8_t  EndpointAddress
; 
  95                 uint8_t  InterruptPeriod
; 
  98                 if (PipeNum 
== SIInterfaceInfo
->Config
.DataINPipeNumber
) 
 100                         Size            
= DataINEndpoint
->EndpointSize
; 
 101                         EndpointAddress 
= DataINEndpoint
->EndpointAddress
; 
 102                         Token           
= PIPE_TOKEN_IN
; 
 104                         DoubleBanked    
= SIInterfaceInfo
->Config
.DataINPipeDoubleBank
; 
 107                         SIInterfaceInfo
->State
.DataINPipeSize 
= DataINEndpoint
->EndpointSize
; 
 109                 else if (PipeNum 
== SIInterfaceInfo
->Config
.DataOUTPipeNumber
) 
 111                         Size            
= DataOUTEndpoint
->EndpointSize
; 
 112                         EndpointAddress 
= DataOUTEndpoint
->EndpointAddress
; 
 113                         Token           
= PIPE_TOKEN_OUT
; 
 115                         DoubleBanked    
= SIInterfaceInfo
->Config
.DataOUTPipeDoubleBank
; 
 118                         SIInterfaceInfo
->State
.DataOUTPipeSize 
= DataOUTEndpoint
->EndpointSize
; 
 120                 else if (PipeNum 
== SIInterfaceInfo
->Config
.EventsPipeNumber
) 
 122                         Size            
= EventsEndpoint
->EndpointSize
; 
 123                         EndpointAddress 
= EventsEndpoint
->EndpointAddress
; 
 124                         Token           
= PIPE_TOKEN_IN
; 
 125                         Type            
= EP_TYPE_INTERRUPT
; 
 126                         DoubleBanked    
= SIInterfaceInfo
->Config
.EventsPipeDoubleBank
; 
 127                         InterruptPeriod 
= EventsEndpoint
->PollingIntervalMS
; 
 129                         SIInterfaceInfo
->State
.EventsPipeSize 
= EventsEndpoint
->EndpointSize
; 
 136                 if (!(Pipe_ConfigurePipe(PipeNum
, Type
, Token
, EndpointAddress
, Size
, 
 137                                          DoubleBanked ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
))) 
 139                         return SI_ENUMERROR_PipeConfigurationFailed
; 
 143                   Pipe_SetInterruptPeriod(InterruptPeriod
); 
 146         SIInterfaceInfo
->State
.InterfaceNumber 
= StillImageInterface
->InterfaceNumber
; 
 147         SIInterfaceInfo
->State
.IsActive 
= true; 
 149         return SI_ENUMERROR_NoError
; 
 152 uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor
) 
 154         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 156         if (Header
->Type 
== DTYPE_Interface
) 
 158                 USB_Descriptor_Interface_t
* Interface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
); 
 160                 if ((Interface
->Class    
== SI_CSCP_StillImageClass
)    && 
 161                     (Interface
->SubClass 
== SI_CSCP_StillImageSubclass
) && 
 162                     (Interface
->Protocol 
== SI_CSCP_BulkOnlyProtocol
)) 
 164                         return DESCRIPTOR_SEARCH_Found
; 
 168         return DESCRIPTOR_SEARCH_NotFound
; 
 171 uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor
) 
 173         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 175         if (Header
->Type 
== DTYPE_Endpoint
) 
 177                 USB_Descriptor_Endpoint_t
* Endpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
); 
 179                 uint8_t EndpointType 
= (Endpoint
->Attributes 
& EP_TYPE_MASK
); 
 181                 if (((EndpointType 
== EP_TYPE_BULK
) || (EndpointType 
== EP_TYPE_INTERRUPT
)) && 
 182                     (!(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
)))) 
 184                         return DESCRIPTOR_SEARCH_Found
; 
 187         else if (Header
->Type 
== DTYPE_Interface
) 
 189                 return DESCRIPTOR_SEARCH_Fail
; 
 192         return DESCRIPTOR_SEARCH_NotFound
; 
 195 uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
 196                                 PIMA_Container_t
* const PIMAHeader
) 
 200         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 201           return PIPE_RWSTREAM_DeviceDisconnected
; 
 203         if (SIInterfaceInfo
->State
.IsSessionOpen
) 
 204           PIMAHeader
->TransactionID 
= SIInterfaceInfo
->State
.TransactionID
++; 
 206         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 209         if ((ErrorCode 
= Pipe_Write_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 212         uint8_t ParamBytes 
= (PIMAHeader
->DataLength 
- PIMA_COMMAND_SIZE(0)); 
 216                 if ((ErrorCode 
= Pipe_Write_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 223         return PIPE_RWSTREAM_NoError
; 
 226 uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
 227                                    PIMA_Container_t
* const PIMAHeader
) 
 229         uint16_t TimeoutMSRem        
= SI_COMMAND_DATA_TIMEOUT_MS
; 
 230         uint16_t PreviousFrameNumber 
= USB_Host_GetFrameNumber(); 
 232         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 233           return PIPE_RWSTREAM_DeviceDisconnected
; 
 235         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 238         while (!(Pipe_IsINReceived())) 
 240                 uint16_t CurrentFrameNumber 
= USB_Host_GetFrameNumber(); 
 242                 if (CurrentFrameNumber 
!= PreviousFrameNumber
) 
 244                         PreviousFrameNumber 
= CurrentFrameNumber
; 
 246                         if (!(TimeoutMSRem
--)) 
 247                           return PIPE_RWSTREAM_Timeout
; 
 251                 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 254                 if (Pipe_IsStalled()) 
 256                         USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 257                         return PIPE_RWSTREAM_PipeStalled
; 
 261                 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 264                 if (Pipe_IsStalled()) 
 266                         USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 267                         return PIPE_RWSTREAM_PipeStalled
; 
 270                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 271                   return PIPE_RWSTREAM_DeviceDisconnected
; 
 274         Pipe_Read_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
); 
 276         if (PIMAHeader
->Type 
== PIMA_CONTAINER_ResponseBlock
) 
 278                 uint8_t ParamBytes 
= (PIMAHeader
->DataLength 
- PIMA_COMMAND_SIZE(0)); 
 281                   Pipe_Read_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
); 
 288         return PIPE_RWSTREAM_NoError
; 
 291 uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
 293                          const uint16_t Bytes
) 
 297         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 298           return PIPE_RWSTREAM_DeviceDisconnected
; 
 300         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 303         ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
); 
 311 uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
 313                          const uint16_t Bytes
) 
 317         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 318           return PIPE_RWSTREAM_DeviceDisconnected
; 
 320         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 323         ErrorCode 
= Pipe_Read_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
); 
 330 bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 332         bool IsEventReceived 
= false; 
 334         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 337         Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
); 
 340         if (Pipe_BytesInPipe()) 
 341           IsEventReceived 
= true; 
 345         return IsEventReceived
; 
 348 uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
 349                                    PIMA_Container_t
* const PIMAHeader
) 
 353         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 354           return PIPE_RWSTREAM_DeviceDisconnected
; 
 356         Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
); 
 359         ErrorCode 
= Pipe_Read_Stream_LE(PIMAHeader
, sizeof(PIMA_Container_t
), NO_STREAM_CALLBACK
); 
 367 uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 369         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 370           return HOST_SENDCONTROL_DeviceDisconnected
; 
 374         SIInterfaceInfo
->State
.TransactionID 
= 0; 
 375         SIInterfaceInfo
->State
.IsSessionOpen 
= false; 
 377         PIMA_Container_t PIMABlock 
= (PIMA_Container_t
) 
 379                         .DataLength    
= PIMA_COMMAND_SIZE(1), 
 380                         .Type          
= PIMA_CONTAINER_CommandBlock
, 
 385         if ((ErrorCode 
= SI_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 388         if ((ErrorCode 
= SI_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 391         if ((PIMABlock
.Type 
!= PIMA_CONTAINER_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 392           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 394         SIInterfaceInfo
->State
.IsSessionOpen 
= true; 
 396         return PIPE_RWSTREAM_NoError
; 
 399 uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 401         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 402           return HOST_SENDCONTROL_DeviceDisconnected
; 
 406         PIMA_Container_t PIMABlock 
= (PIMA_Container_t
) 
 408                         .DataLength    
= PIMA_COMMAND_SIZE(1), 
 409                         .Type          
= PIMA_CONTAINER_CommandBlock
, 
 414         if ((ErrorCode 
= SI_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 417         if ((ErrorCode 
= SI_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 420         SIInterfaceInfo
->State
.IsSessionOpen 
= false; 
 422         if ((PIMABlock
.Type 
!= PIMA_CONTAINER_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 423           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 425         return PIPE_RWSTREAM_NoError
; 
 428 uint8_t SI_Host_SendCommand(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, 
 429                             const uint16_t Operation
, 
 430                             const uint8_t TotalParams
, 
 431                             uint32_t* const Params
) 
 433         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 434           return HOST_SENDCONTROL_DeviceDisconnected
; 
 438         PIMA_Container_t PIMABlock 
= (PIMA_Container_t
) 
 440                         .DataLength    
= PIMA_COMMAND_SIZE(TotalParams
), 
 441                         .Type          
= PIMA_CONTAINER_CommandBlock
, 
 445         memcpy(&PIMABlock
.Params
, Params
, sizeof(uint32_t) * TotalParams
); 
 447         if ((ErrorCode 
= SI_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 450         return PIPE_RWSTREAM_NoError
; 
 453 uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 456         PIMA_Container_t PIMABlock
; 
 458         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 459           return HOST_SENDCONTROL_DeviceDisconnected
; 
 461         if ((ErrorCode 
= SI_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 464         if ((PIMABlock
.Type 
!= PIMA_CONTAINER_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 465           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 467         return PIPE_RWSTREAM_NoError
;