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 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
35 #define __INCLUDE_FROM_SI_CLASS_HOST_C
36 #define __INCLUDE_FROM_SI_DRIVER
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
;
47 memset(&SIInterfaceInfo
->State
, 0x00, sizeof(SIInterfaceInfo
->State
));
49 if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
)
50 return SI_ENUMERROR_InvalidConfigDescriptor
;
52 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
53 DCOMP_SI_Host_NextSIInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
55 return SI_ENUMERROR_NoCompatibleInterfaceFound
;
58 SIInterfaceInfo
->State
.InterfaceNumber
= DESCRIPTOR_PCAST(ConfigDescriptorData
,
59 USB_Descriptor_Interface_t
)->InterfaceNumber
;
61 while (!(DataINEndpoint
) || !(DataOUTEndpoint
))
63 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
64 DCOMP_SI_Host_NextSIInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
66 DataINEndpoint
= NULL
;
67 DataOUTEndpoint
= NULL
;
68 EventsEndpoint
= NULL
;
70 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
71 DCOMP_SI_Host_NextSIInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
73 return SI_ENUMERROR_NoCompatibleInterfaceFound
;
76 SIInterfaceInfo
->State
.InterfaceNumber
= DESCRIPTOR_PCAST(ConfigDescriptorData
,
77 USB_Descriptor_Interface_t
)->InterfaceNumber
;
82 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
);
84 if (EndpointData
->EndpointAddress
& ENDPOINT_DESCRIPTOR_DIR_IN
)
86 if ((EndpointData
->Attributes
& EP_TYPE_MASK
) == EP_TYPE_INTERRUPT
)
87 EventsEndpoint
= EndpointData
;
89 DataINEndpoint
= EndpointData
;
93 DataOUTEndpoint
= EndpointData
;
97 for (uint8_t PipeNum
= 1; PipeNum
< PIPE_TOTAL_PIPES
; PipeNum
++)
99 if (PipeNum
== SIInterfaceInfo
->Config
.DataINPipeNumber
)
101 Pipe_ConfigurePipe(PipeNum
, EP_TYPE_BULK
, PIPE_TOKEN_IN
,
102 DataINEndpoint
->EndpointAddress
, DataINEndpoint
->EndpointSize
,
103 SIInterfaceInfo
->Config
.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
);
105 SIInterfaceInfo
->State
.DataINPipeSize
= DataINEndpoint
->EndpointSize
;
107 else if (PipeNum
== SIInterfaceInfo
->Config
.DataOUTPipeNumber
)
109 Pipe_ConfigurePipe(PipeNum
, EP_TYPE_BULK
, PIPE_TOKEN_OUT
,
110 DataOUTEndpoint
->EndpointAddress
, DataOUTEndpoint
->EndpointSize
,
111 SIInterfaceInfo
->Config
.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
);
113 SIInterfaceInfo
->State
.DataOUTPipeSize
= DataOUTEndpoint
->EndpointSize
;
115 else if (PipeNum
== SIInterfaceInfo
->Config
.EventsPipeNumber
)
117 Pipe_ConfigurePipe(PipeNum
, EP_TYPE_INTERRUPT
, PIPE_TOKEN_IN
,
118 EventsEndpoint
->EndpointAddress
, EventsEndpoint
->EndpointSize
,
119 SIInterfaceInfo
->Config
.EventsPipeDoubleBank ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
);
120 Pipe_SetInterruptPeriod(EventsEndpoint
->PollingIntervalMS
);
122 SIInterfaceInfo
->State
.EventsPipeSize
= EventsEndpoint
->EndpointSize
;
126 SIInterfaceInfo
->State
.IsActive
= true;
127 return SI_ENUMERROR_NoError
;
130 uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor
)
132 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
134 USB_Descriptor_Interface_t
* CurrentInterface
= DESCRIPTOR_PCAST(CurrentDescriptor
,
135 USB_Descriptor_Interface_t
);
137 if ((CurrentInterface
->Class
== STILL_IMAGE_CLASS
) &&
138 (CurrentInterface
->SubClass
== STILL_IMAGE_SUBCLASS
) &&
139 (CurrentInterface
->Protocol
== STILL_IMAGE_PROTOCOL
))
141 return DESCRIPTOR_SEARCH_Found
;
145 return DESCRIPTOR_SEARCH_NotFound
;
148 uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor
)
150 if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
)
152 USB_Descriptor_Endpoint_t
* CurrentEndpoint
= DESCRIPTOR_PCAST(CurrentDescriptor
,
153 USB_Descriptor_Endpoint_t
);
155 uint8_t EndpointType
= (CurrentEndpoint
->Attributes
& EP_TYPE_MASK
);
157 if (((EndpointType
== EP_TYPE_BULK
) || (EndpointType
== EP_TYPE_INTERRUPT
)) &&
158 (!(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
))))
160 return DESCRIPTOR_SEARCH_Found
;
163 else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
)
165 return DESCRIPTOR_SEARCH_Fail
;
168 return DESCRIPTOR_SEARCH_NotFound
;
171 uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
,
172 SI_PIMA_Container_t
* const PIMAHeader
)
176 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
177 return PIPE_RWSTREAM_DeviceDisconnected
;
179 if (SIInterfaceInfo
->State
.IsSessionOpen
)
180 PIMAHeader
->TransactionID
= SIInterfaceInfo
->State
.TransactionID
++;
182 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
);
185 if ((ErrorCode
= Pipe_Write_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
188 uint8_t ParamBytes
= (PIMAHeader
->DataLength
- PIMA_COMMAND_SIZE(0));
192 if ((ErrorCode
= Pipe_Write_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
)
199 return PIPE_RWSTREAM_NoError
;
202 uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
,
203 SI_PIMA_Container_t
* const PIMAHeader
)
205 uint16_t TimeoutMSRem
= COMMAND_DATA_TIMEOUT_MS
;
206 uint16_t PreviousFrameNumber
= USB_Host_GetFrameNumber();
208 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
209 return PIPE_RWSTREAM_DeviceDisconnected
;
211 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
);
214 while (!(Pipe_IsINReceived()))
216 uint16_t CurrentFrameNumber
= USB_Host_GetFrameNumber();
218 if (CurrentFrameNumber
!= PreviousFrameNumber
)
220 PreviousFrameNumber
= CurrentFrameNumber
;
222 if (!(TimeoutMSRem
--))
223 return PIPE_RWSTREAM_Timeout
;
227 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
);
230 if (Pipe_IsStalled())
232 USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataOUTPipeNumber
);
233 return PIPE_RWSTREAM_PipeStalled
;
237 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
);
240 if (Pipe_IsStalled())
242 USB_Host_ClearPipeStall(SIInterfaceInfo
->Config
.DataINPipeNumber
);
243 return PIPE_RWSTREAM_PipeStalled
;
246 if (USB_HostState
== HOST_STATE_Unattached
)
247 return PIPE_RWSTREAM_DeviceDisconnected
;
250 Pipe_Read_Stream_LE(PIMAHeader
, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK
);
252 if (PIMAHeader
->Type
== SI_PIMA_CONTAINER_ResponseBlock
)
254 uint8_t ParamBytes
= (PIMAHeader
->DataLength
- PIMA_COMMAND_SIZE(0));
257 Pipe_Read_Stream_LE(&PIMAHeader
->Params
, ParamBytes
, NO_STREAM_CALLBACK
);
264 return PIPE_RWSTREAM_NoError
;
267 uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
,
269 const uint16_t Bytes
)
273 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
274 return PIPE_RWSTREAM_DeviceDisconnected
;
276 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataOUTPipeNumber
);
279 ErrorCode
= Pipe_Write_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
);
287 uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
,
289 const uint16_t Bytes
)
293 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
294 return PIPE_RWSTREAM_DeviceDisconnected
;
296 Pipe_SelectPipe(SIInterfaceInfo
->Config
.DataINPipeNumber
);
299 ErrorCode
= Pipe_Read_Stream_LE(Buffer
, Bytes
, NO_STREAM_CALLBACK
);
306 bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
)
308 bool IsEventReceived
= false;
310 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
313 Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
);
316 if (Pipe_BytesInPipe())
317 IsEventReceived
= true;
321 return IsEventReceived
;
324 uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
,
325 SI_PIMA_Container_t
* const PIMAHeader
)
329 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
330 return PIPE_RWSTREAM_DeviceDisconnected
;
332 Pipe_SelectPipe(SIInterfaceInfo
->Config
.EventsPipeNumber
);
335 ErrorCode
= Pipe_Read_Stream_LE(PIMAHeader
, sizeof(SI_PIMA_Container_t
), NO_STREAM_CALLBACK
);
343 uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
)
345 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
346 return HOST_SENDCONTROL_DeviceDisconnected
;
350 SIInterfaceInfo
->State
.TransactionID
= 0;
351 SIInterfaceInfo
->State
.IsSessionOpen
= false;
353 SI_PIMA_Container_t PIMABlock
= (SI_PIMA_Container_t
)
355 .DataLength
= PIMA_COMMAND_SIZE(1),
356 .Type
= SI_PIMA_CONTAINER_CommandBlock
,
361 if ((ErrorCode
= SI_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
)
364 if ((ErrorCode
= SI_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
)
367 if ((PIMABlock
.Type
!= SI_PIMA_CONTAINER_ResponseBlock
) || (PIMABlock
.Code
!= 0x2001))
368 return SI_ERROR_LOGICAL_CMD_FAILED
;
370 SIInterfaceInfo
->State
.IsSessionOpen
= true;
372 return PIPE_RWSTREAM_NoError
;
375 uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
)
377 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
378 return HOST_SENDCONTROL_DeviceDisconnected
;
382 SI_PIMA_Container_t PIMABlock
= (SI_PIMA_Container_t
)
384 .DataLength
= PIMA_COMMAND_SIZE(1),
385 .Type
= SI_PIMA_CONTAINER_CommandBlock
,
390 if ((ErrorCode
= SI_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
)
393 if ((ErrorCode
= SI_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
)
396 SIInterfaceInfo
->State
.IsSessionOpen
= false;
398 if ((PIMABlock
.Type
!= SI_PIMA_CONTAINER_ResponseBlock
) || (PIMABlock
.Code
!= 0x2001))
399 return SI_ERROR_LOGICAL_CMD_FAILED
;
401 return PIPE_RWSTREAM_NoError
;
404 uint8_t SI_Host_SendCommand(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
,
405 const uint16_t Operation
,
406 const uint8_t TotalParams
,
407 uint32_t* const Params
)
409 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
410 return HOST_SENDCONTROL_DeviceDisconnected
;
414 SI_PIMA_Container_t PIMABlock
= (SI_PIMA_Container_t
)
416 .DataLength
= PIMA_COMMAND_SIZE(TotalParams
),
417 .Type
= SI_PIMA_CONTAINER_CommandBlock
,
421 memcpy(&PIMABlock
.Params
, Params
, sizeof(uint32_t) * TotalParams
);
423 if ((ErrorCode
= SI_Host_SendBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
)
426 return PIPE_RWSTREAM_NoError
;
429 uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t
* const SIInterfaceInfo
)
432 SI_PIMA_Container_t PIMABlock
;
434 if ((USB_HostState
!= HOST_STATE_Configured
) || !(SIInterfaceInfo
->State
.IsActive
))
435 return HOST_SENDCONTROL_DeviceDisconnected
;
437 if ((ErrorCode
= SI_Host_ReceiveBlockHeader(SIInterfaceInfo
, &PIMABlock
)) != PIPE_RWSTREAM_NoError
)
440 if ((PIMABlock
.Type
!= SI_PIMA_CONTAINER_ResponseBlock
) || (PIMABlock
.Code
!= 0x2001))
441 return SI_ERROR_LOGICAL_CMD_FAILED
;
443 return PIPE_RWSTREAM_NoError
;