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_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 void SImage_Host_USBTask(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 150 static uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, SI_PIMA_Container_t
* const PIMAHeader
) 
 154         PIMAHeader
->TransactionID 
= SIInterfaceInfo
->State
.TransactionID
++; 
 156         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 159         if ((ErrorCode 
= Pipe_Write_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 162         uint8_t ParamBytes 
= (PIMAHeader
->DataLength 
- PIMA_COMMAND_SIZE(0)); 
 166                 if ((ErrorCode 
= Pipe_Write_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 173         return PIPE_RWSTREAM_NoError
; 
 176 static uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, SI_PIMA_Container_t
* const PIMAHeader
) 
 178         uint16_t TimeoutMSRem 
= COMMAND_DATA_TIMEOUT_MS
; 
 180         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 183         while (!(Pipe_IsReadWriteAllowed())) 
 185                 if (USB_INT_HasOccurred(USB_INT_HSOFI
)) 
 187                         USB_INT_Clear(USB_INT_HSOFI
); 
 192                                 return PIPE_RWSTREAM_Timeout
; 
 197                 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 200                 if (Pipe_IsStalled()) 
 202                         USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 203                         return PIPE_RWSTREAM_PipeStalled
; 
 207                 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 210                 if (Pipe_IsStalled()) 
 212                         USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 213                         return PIPE_RWSTREAM_PipeStalled
; 
 216                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 217                   return PIPE_RWSTREAM_DeviceDisconnected
; 
 220         Pipe_Read_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
); 
 222         if (PIMAHeader
->Type 
== CType_ResponseBlock
) 
 224                 uint8_t ParamBytes 
= (PIMAHeader
->DataLength 
- PIMA_COMMAND_SIZE(0)); 
 227                   Pipe_Read_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
); 
 231                 PIMAHeader
->Code 
&= 0x0000000F; 
 236         return PIPE_RWSTREAM_NoError
; 
 239 uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, void* Buffer
, const uint16_t Bytes
) 
 243         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 246         ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
); 
 254 uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, void* Buffer
, const uint16_t Bytes
) 
 258         Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
); 
 261         ErrorCode 
= Pipe_Read_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
); 
 268 bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t
* SIInterfaceInfo
) 
 270         bool IsEventReceived 
= false; 
 272         Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
); 
 275         if (Pipe_BytesInPipe()) 
 276           IsEventReceived 
= true; 
 280         return IsEventReceived
; 
 283 uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, SI_PIMA_Container_t
* const PIMAHeader
) 
 287         Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
); 
 290         ErrorCode 
= Pipe_Read_Stream_LE(PIMAHeader
, sizeof(SI_PIMA_Container_t
), NO_STREAM_CALLBACK
); 
 298 uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 300         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 301           return HOST_SENDCONTROL_DeviceDisconnect
; 
 305         SI_PIMA_Container_t PIMABlock 
= (SI_PIMA_Container_t
) 
 307                                                                 .DataLength    
= PIMA_COMMAND_SIZE(0), 
 308                                                                 .Type          
= CType_CommandBlock
, 
 313         if ((ErrorCode 
= SImage_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 316         if ((ErrorCode 
= SImage_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 319         if ((PIMABlock
.Type 
!= CType_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 320           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 322         SIInterfaceInfo
->State
.TransactionID 
= 0; 
 323         SIInterfaceInfo
->State
.IsSessionOpen 
= true; 
 325         return PIPE_RWSTREAM_NoError
; 
 328 uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 330         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 331           return HOST_SENDCONTROL_DeviceDisconnect
; 
 335         SI_PIMA_Container_t PIMABlock 
= (SI_PIMA_Container_t
) 
 337                                                                 .DataLength    
= PIMA_COMMAND_SIZE(0), 
 338                                                                 .Type          
= CType_CommandBlock
, 
 343         if ((ErrorCode 
= SImage_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 346         if ((ErrorCode 
= SImage_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 349         SIInterfaceInfo
->State
.IsSessionOpen 
= false; 
 351         if ((PIMABlock
.Type 
!= CType_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 352           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 354         return PIPE_RWSTREAM_NoError
; 
 357 uint8_t SImage_Host_SendCommand(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
, const uint16_t Operation
, 
 358                                 const uint8_t TotalParams
, uint32_t* Params
) 
 360         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
)) 
 361           return HOST_SENDCONTROL_DeviceDisconnect
; 
 365         SI_PIMA_Container_t PIMABlock 
= (SI_PIMA_Container_t
) 
 367                                                                 .DataLength    
= PIMA_COMMAND_SIZE(TotalParams
), 
 368                                                                 .Type          
= CType_CommandBlock
, 
 372         memcpy(&PIMABlock
.Params
, Params
, sizeof(uint32_t) * TotalParams
); 
 374         if ((ErrorCode 
= SImage_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 377         return PIPE_RWSTREAM_NoError
; 
 380 uint8_t SImage_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
) 
 383         SI_PIMA_Container_t PIMABlock
; 
 385         if ((ErrorCode 
= SImage_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
) 
 388         if ((PIMABlock
.Type 
!= CType_ResponseBlock
) || (PIMABlock
.Code 
!= 0x2001)) 
 389           return SI_ERROR_LOGICAL_CMD_FAILED
; 
 391         return PIPE_RWSTREAM_NoError
;