Add StillImage Host Class Driver functions for opening and closing sessions. Ensure...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / StillImage.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
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.
20
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
28 this software.
29 */
30
31 #include "../../HighLevel/USBMode.h"
32 #if defined(USB_CAN_BE_HOST)
33
34 #define INCLUDE_FROM_SI_CLASS_HOST_C
35 #include "StillImage.h"
36
37 #warning The Still Image Host mode Class driver is currently incomplete and is for preview purposes only.
38
39 uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* SIInterfaceInfo, uint16_t ConfigDescriptorLength,
40 uint8_t* DeviceConfigDescriptor)
41 {
42 uint8_t FoundEndpoints = 0;
43
44 memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State));
45
46 if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration)
47 return SI_ENUMERROR_InvalidConfigDescriptor;
48
49 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength, &DeviceConfigDescriptor,
50 DComp_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found)
51 {
52 return SI_ENUMERROR_NoSIInterfaceFound;
53 }
54
55 while (FoundEndpoints != (SI_FOUND_EVENTS_IN | SI_FOUND_DATAPIPE_IN | SI_FOUND_DATAPIPE_OUT))
56 {
57 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength, &DeviceConfigDescriptor,
58 DComp_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
59 {
60 return SI_ENUMERROR_EndpointsNotFound;
61 }
62
63 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
64
65 if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
66 {
67 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
68 {
69 Pipe_ConfigurePipe(SIInterfaceInfo->Config.EventsPipeNumber, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
70 EndpointData->EndpointAddress, EndpointData->EndpointSize,
71 PIPE_BANK_DOUBLE);
72 SIInterfaceInfo->State.EventsPipeSize = EndpointData->EndpointSize;
73
74 Pipe_SetInterruptPeriod(EndpointData->PollingIntervalMS);
75
76 FoundEndpoints |= SI_FOUND_EVENTS_IN;
77 }
78 }
79 else
80 {
81 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
82 {
83 Pipe_ConfigurePipe(SIInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
84 EndpointData->EndpointAddress, EndpointData->EndpointSize,
85 PIPE_BANK_DOUBLE);
86 SIInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
87
88 FoundEndpoints |= SI_FOUND_DATAPIPE_IN;
89 }
90 else
91 {
92 Pipe_ConfigurePipe(SIInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
93 EndpointData->EndpointAddress, EndpointData->EndpointSize,
94 PIPE_BANK_DOUBLE);
95 SIInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
96
97 FoundEndpoints |= SI_FOUND_DATAPIPE_OUT;
98 }
99 }
100 }
101
102 SIInterfaceInfo->State.IsActive = true;
103 return SI_ENUMERROR_NoError;
104 }
105
106 uint8_t DComp_SI_Host_NextSIInterface(void* CurrentDescriptor)
107 {
108 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
109 {
110 USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
111 USB_Descriptor_Interface_t);
112
113 if ((CurrentInterface->Class == STILL_IMAGE_CLASS) &&
114 (CurrentInterface->SubClass == STILL_IMAGE_SUBCLASS) &&
115 (CurrentInterface->Protocol == STILL_IMAGE_PROTOCOL))
116 {
117 return DESCRIPTOR_SEARCH_Found;
118 }
119 }
120
121 return DESCRIPTOR_SEARCH_NotFound;
122 }
123
124 uint8_t DComp_SI_Host_NextSIInterfaceEndpoint(void* CurrentDescriptor)
125 {
126 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
127 {
128 USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
129 USB_Descriptor_Endpoint_t);
130
131 uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
132
133 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
134 (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))))
135 {
136 return DESCRIPTOR_SEARCH_Found;
137 }
138 }
139 else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
140 {
141 return DESCRIPTOR_SEARCH_Fail;
142 }
143
144 return DESCRIPTOR_SEARCH_NotFound;
145 }
146
147 void SI_Host_USBTask(USB_ClassInfo_SI_Host_t* SIInterfaceInfo)
148 {
149
150 }
151
152 static uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* SIInterfaceInfo, SI_PIMA_Container_t* PIMAHeader)
153 {
154 uint8_t ErrorCode;
155
156 if (SIInterfaceInfo->State.IsSessionOpen)
157 PIMAHeader->TransactionID = SIInterfaceInfo->State.TransactionID++;
158 else
159 PIMAHeader->TransactionID = 0;
160
161 Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
162 Pipe_Unfreeze();
163
164 if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
165 return ErrorCode;
166
167 if (PIMAHeader->Type == CType_CommandBlock)
168 {
169 uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
170
171 if (ParamBytes)
172 {
173 if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
174 return ErrorCode;
175 }
176 }
177
178 Pipe_ClearOUT();
179 Pipe_Freeze();
180
181 return PIPE_RWSTREAM_NoError;
182 }
183
184 static uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* SIInterfaceInfo, SI_PIMA_Container_t* PIMAHeader)
185 {
186 uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;
187
188 Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
189 Pipe_Unfreeze();
190
191 while (!(Pipe_IsReadWriteAllowed()))
192 {
193 if (USB_INT_HasOccurred(USB_INT_HSOFI))
194 {
195 USB_INT_Clear(USB_INT_HSOFI);
196 TimeoutMSRem--;
197
198 if (!(TimeoutMSRem))
199 {
200 return PIPE_RWSTREAM_Timeout;
201 }
202 }
203
204 Pipe_Freeze();
205 Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
206 Pipe_Unfreeze();
207
208 if (Pipe_IsStalled())
209 {
210 USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber);
211 return PIPE_RWSTREAM_PipeStalled;
212 }
213
214 Pipe_Freeze();
215 Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
216 Pipe_Unfreeze();
217
218 if (Pipe_IsStalled())
219 {
220 USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber);
221 return PIPE_RWSTREAM_PipeStalled;
222 }
223
224 if (USB_HostState == HOST_STATE_Unattached)
225 return PIPE_RWSTREAM_DeviceDisconnected;
226 }
227
228 Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NO_STREAM_CALLBACK);
229
230 if (PIMAHeader->Type == CType_ResponseBlock)
231 {
232 uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
233
234 if (ParamBytes)
235 Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NO_STREAM_CALLBACK);
236
237 Pipe_ClearIN();
238
239 PIMAHeader->Code &= 0x0000000F;
240 }
241
242 Pipe_Freeze();
243
244 return PIPE_RWSTREAM_NoError;
245 }
246
247 static uint8_t SImage_Host_SendData(USB_ClassInfo_SI_Host_t* SIInterfaceInfo, void* Buffer, uint16_t Bytes)
248 {
249 uint8_t ErrorCode;
250
251 Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
252 Pipe_Unfreeze();
253
254 ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NO_STREAM_CALLBACK);
255
256 Pipe_ClearOUT();
257 Pipe_Freeze();
258
259 return ErrorCode;
260 }
261
262 static uint8_t SImage_Host_ReadData(USB_ClassInfo_SI_Host_t* SIInterfaceInfo, void* Buffer, uint16_t Bytes)
263 {
264 uint8_t ErrorCode;
265
266 Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
267 Pipe_Unfreeze();
268
269 ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NO_STREAM_CALLBACK);
270
271 Pipe_Freeze();
272
273 return ErrorCode;
274 }
275
276 static bool SImage_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* SIInterfaceInfo)
277 {
278 bool IsEventReceived = false;
279
280 Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
281 Pipe_Unfreeze();
282
283 if (Pipe_BytesInPipe())
284 IsEventReceived = true;
285
286 Pipe_Freeze();
287
288 return IsEventReceived;
289 }
290
291 static uint8_t SImage_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* SIInterfaceInfo, SI_PIMA_Container_t* PIMAHeader)
292 {
293 uint8_t ErrorCode;
294
295 Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
296 Pipe_Unfreeze();
297
298 ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(SI_PIMA_Container_t), NO_STREAM_CALLBACK);
299
300 Pipe_ClearIN();
301 Pipe_Freeze();
302
303 return ErrorCode;
304 }
305
306 uint8_t SImage_Host_OpenSession(USB_ClassInfo_SI_Host_t* SIInterfaceInfo)
307 {
308 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
309 return HOST_SENDCONTROL_DeviceDisconnect;
310
311 uint8_t ErrorCode;
312
313 SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t)
314 {
315 .DataLength = PIMA_COMMAND_SIZE(0),
316 .Type = CType_CommandBlock,
317 .Code = 0x1002,
318 .Params = {},
319 };
320
321 SIInterfaceInfo->State.TransactionID = 1;
322
323 if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
324 return ErrorCode;
325
326 if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
327 return ErrorCode;
328
329 SIInterfaceInfo->State.IsSessionOpen = true;
330
331 return PIPE_RWSTREAM_NoError;
332 }
333
334 uint8_t SImage_Host_CloseSession(USB_ClassInfo_SI_Host_t* SIInterfaceInfo)
335 {
336 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
337 return HOST_SENDCONTROL_DeviceDisconnect;
338
339 uint8_t ErrorCode;
340
341 SI_PIMA_Container_t PIMABlock = (SI_PIMA_Container_t)
342 {
343 .DataLength = PIMA_COMMAND_SIZE(0),
344 .Type = CType_CommandBlock,
345 .Code = 0x1003,
346 .Params = {},
347 };
348
349 if ((ErrorCode = SImage_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
350 return ErrorCode;
351
352 if ((ErrorCode = SImage_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
353 return ErrorCode;
354
355 SIInterfaceInfo->State.IsSessionOpen = false;
356
357 return PIPE_RWSTREAM_NoError;
358 }
359
360 #endif