3bfd36ca7056c3b755ab98fb0636b40ecc8adc5c
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / StillImage.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2011.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
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.
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 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
34
35 #define __INCLUDE_FROM_SI_DRIVER
36 #define __INCLUDE_FROM_STILLIMAGE_HOST_C
37 #include "StillImage.h"
38
39 uint8_t SI_Host_ConfigurePipes(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
40 uint16_t ConfigDescriptorSize,
41 void* ConfigDescriptorData)
42 {
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;
47
48 memset(&SIInterfaceInfo->State, 0x00, sizeof(SIInterfaceInfo->State));
49
50 if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
51 return SI_ENUMERROR_InvalidConfigDescriptor;
52
53 while (!(DataINEndpoint) || !(DataOUTEndpoint))
54 {
55 if (!(StillImageInterface) ||
56 USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
57 DCOMP_SI_Host_NextSIInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
58 {
59 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
60 DCOMP_SI_Host_NextSIInterface) != DESCRIPTOR_SEARCH_COMP_Found)
61 {
62 return SI_ENUMERROR_NoCompatibleInterfaceFound;
63 }
64
65 StillImageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
66
67 DataINEndpoint = NULL;
68 DataOUTEndpoint = NULL;
69 EventsEndpoint = NULL;
70
71 continue;
72 }
73
74 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
75
76 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
77 {
78 if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
79 EventsEndpoint = EndpointData;
80 else
81 DataINEndpoint = EndpointData;
82 }
83 else
84 {
85 DataOUTEndpoint = EndpointData;
86 }
87 }
88
89 for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
90 {
91 uint16_t Size;
92 uint8_t Type;
93 uint8_t Token;
94 uint8_t EndpointAddress;
95 uint8_t InterruptPeriod;
96 bool DoubleBanked;
97
98 if (PipeNum == SIInterfaceInfo->Config.DataINPipeNumber)
99 {
100 Size = DataINEndpoint->EndpointSize;
101 EndpointAddress = DataINEndpoint->EndpointAddress;
102 Token = PIPE_TOKEN_IN;
103 Type = EP_TYPE_BULK;
104 DoubleBanked = SIInterfaceInfo->Config.DataINPipeDoubleBank;
105 InterruptPeriod = 0;
106
107 SIInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
108 }
109 else if (PipeNum == SIInterfaceInfo->Config.DataOUTPipeNumber)
110 {
111 Size = DataOUTEndpoint->EndpointSize;
112 EndpointAddress = DataOUTEndpoint->EndpointAddress;
113 Token = PIPE_TOKEN_OUT;
114 Type = EP_TYPE_BULK;
115 DoubleBanked = SIInterfaceInfo->Config.DataOUTPipeDoubleBank;
116 InterruptPeriod = 0;
117
118 SIInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
119 }
120 else if (PipeNum == SIInterfaceInfo->Config.EventsPipeNumber)
121 {
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;
128
129 SIInterfaceInfo->State.EventsPipeSize = EventsEndpoint->EndpointSize;
130 }
131 else
132 {
133 continue;
134 }
135
136 if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
137 DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
138 {
139 return SI_ENUMERROR_PipeConfigurationFailed;
140 }
141
142 if (InterruptPeriod)
143 Pipe_SetInterruptPeriod(InterruptPeriod);
144 }
145
146 SIInterfaceInfo->State.InterfaceNumber = StillImageInterface->InterfaceNumber;
147 SIInterfaceInfo->State.IsActive = true;
148
149 return SI_ENUMERROR_NoError;
150 }
151
152 uint8_t DCOMP_SI_Host_NextSIInterface(void* const CurrentDescriptor)
153 {
154 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
155
156 if (Header->Type == DTYPE_Interface)
157 {
158 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
159
160 if ((Interface->Class == SI_CSCP_StillImageClass) &&
161 (Interface->SubClass == SI_CSCP_StillImageSubclass) &&
162 (Interface->Protocol == SI_CSCP_BulkOnlyProtocol))
163 {
164 return DESCRIPTOR_SEARCH_Found;
165 }
166 }
167
168 return DESCRIPTOR_SEARCH_NotFound;
169 }
170
171 uint8_t DCOMP_SI_Host_NextSIInterfaceEndpoint(void* const CurrentDescriptor)
172 {
173 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
174
175 if (Header->Type == DTYPE_Endpoint)
176 {
177 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
178
179 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
180
181 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
182 (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
183 {
184 return DESCRIPTOR_SEARCH_Found;
185 }
186 }
187 else if (Header->Type == DTYPE_Interface)
188 {
189 return DESCRIPTOR_SEARCH_Fail;
190 }
191
192 return DESCRIPTOR_SEARCH_NotFound;
193 }
194
195 uint8_t SI_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
196 PIMA_Container_t* const PIMAHeader)
197 {
198 uint8_t ErrorCode;
199
200 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
201 return PIPE_RWSTREAM_DeviceDisconnected;
202
203 if (SIInterfaceInfo->State.IsSessionOpen)
204 PIMAHeader->TransactionID = SIInterfaceInfo->State.TransactionID++;
205
206 Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
207 Pipe_Unfreeze();
208
209 if ((ErrorCode = Pipe_Write_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL)) != PIPE_RWSTREAM_NoError)
210 return ErrorCode;
211
212 uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
213
214 if (ParamBytes)
215 {
216 if ((ErrorCode = Pipe_Write_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL)) != PIPE_RWSTREAM_NoError)
217 return ErrorCode;
218 }
219
220 Pipe_ClearOUT();
221 Pipe_Freeze();
222
223 return PIPE_RWSTREAM_NoError;
224 }
225
226 uint8_t SI_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
227 PIMA_Container_t* const PIMAHeader)
228 {
229 uint16_t TimeoutMSRem = SI_COMMAND_DATA_TIMEOUT_MS;
230 uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
231
232 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
233 return PIPE_RWSTREAM_DeviceDisconnected;
234
235 Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
236 Pipe_Unfreeze();
237
238 while (!(Pipe_IsINReceived()))
239 {
240 uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
241
242 if (CurrentFrameNumber != PreviousFrameNumber)
243 {
244 PreviousFrameNumber = CurrentFrameNumber;
245
246 if (!(TimeoutMSRem--))
247 return PIPE_RWSTREAM_Timeout;
248 }
249
250 Pipe_Freeze();
251 Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
252 Pipe_Unfreeze();
253
254 if (Pipe_IsStalled())
255 {
256 USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataOUTPipeNumber);
257 return PIPE_RWSTREAM_PipeStalled;
258 }
259
260 Pipe_Freeze();
261 Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
262 Pipe_Unfreeze();
263
264 if (Pipe_IsStalled())
265 {
266 USB_Host_ClearPipeStall(SIInterfaceInfo->Config.DataINPipeNumber);
267 return PIPE_RWSTREAM_PipeStalled;
268 }
269
270 if (USB_HostState == HOST_STATE_Unattached)
271 return PIPE_RWSTREAM_DeviceDisconnected;
272 }
273
274 Pipe_Read_Stream_LE(PIMAHeader, PIMA_COMMAND_SIZE(0), NULL);
275
276 if (PIMAHeader->Type == PIMA_CONTAINER_ResponseBlock)
277 {
278 uint8_t ParamBytes = (PIMAHeader->DataLength - PIMA_COMMAND_SIZE(0));
279
280 if (ParamBytes)
281 Pipe_Read_Stream_LE(&PIMAHeader->Params, ParamBytes, NULL);
282
283 Pipe_ClearIN();
284 }
285
286 Pipe_Freeze();
287
288 return PIPE_RWSTREAM_NoError;
289 }
290
291 uint8_t SI_Host_SendData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
292 void* Buffer,
293 const uint16_t Bytes)
294 {
295 uint8_t ErrorCode;
296
297 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
298 return PIPE_RWSTREAM_DeviceDisconnected;
299
300 Pipe_SelectPipe(SIInterfaceInfo->Config.DataOUTPipeNumber);
301 Pipe_Unfreeze();
302
303 ErrorCode = Pipe_Write_Stream_LE(Buffer, Bytes, NULL);
304
305 Pipe_ClearOUT();
306 Pipe_Freeze();
307
308 return ErrorCode;
309 }
310
311 uint8_t SI_Host_ReadData(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
312 void* Buffer,
313 const uint16_t Bytes)
314 {
315 uint8_t ErrorCode;
316
317 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
318 return PIPE_RWSTREAM_DeviceDisconnected;
319
320 Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber);
321 Pipe_Unfreeze();
322
323 ErrorCode = Pipe_Read_Stream_LE(Buffer, Bytes, NULL);
324
325 Pipe_Freeze();
326
327 return ErrorCode;
328 }
329
330 bool SI_Host_IsEventReceived(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
331 {
332 bool IsEventReceived = false;
333
334 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
335 return false;
336
337 Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
338 Pipe_Unfreeze();
339
340 if (Pipe_BytesInPipe())
341 IsEventReceived = true;
342
343 Pipe_Freeze();
344
345 return IsEventReceived;
346 }
347
348 uint8_t SI_Host_ReceiveEventHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo,
349 PIMA_Container_t* const PIMAHeader)
350 {
351 uint8_t ErrorCode;
352
353 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
354 return PIPE_RWSTREAM_DeviceDisconnected;
355
356 Pipe_SelectPipe(SIInterfaceInfo->Config.EventsPipeNumber);
357 Pipe_Unfreeze();
358
359 ErrorCode = Pipe_Read_Stream_LE(PIMAHeader, sizeof(PIMA_Container_t), NULL);
360
361 Pipe_ClearIN();
362 Pipe_Freeze();
363
364 return ErrorCode;
365 }
366
367 uint8_t SI_Host_OpenSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
368 {
369 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
370 return PIPE_RWSTREAM_DeviceDisconnected;
371
372 uint8_t ErrorCode;
373
374 SIInterfaceInfo->State.TransactionID = 0;
375 SIInterfaceInfo->State.IsSessionOpen = false;
376
377 PIMA_Container_t PIMABlock = (PIMA_Container_t)
378 {
379 .DataLength = PIMA_COMMAND_SIZE(1),
380 .Type = PIMA_CONTAINER_CommandBlock,
381 .Code = 0x1002,
382 .Params = {1},
383 };
384
385 if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
386 return ErrorCode;
387
388 if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
389 return ErrorCode;
390
391 if ((PIMABlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMABlock.Code != 0x2001))
392 return SI_ERROR_LOGICAL_CMD_FAILED;
393
394 SIInterfaceInfo->State.IsSessionOpen = true;
395
396 return PIPE_RWSTREAM_NoError;
397 }
398
399 uint8_t SI_Host_CloseSession(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
400 {
401 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
402 return PIPE_RWSTREAM_DeviceDisconnected;
403
404 uint8_t ErrorCode;
405
406 PIMA_Container_t PIMABlock = (PIMA_Container_t)
407 {
408 .DataLength = PIMA_COMMAND_SIZE(1),
409 .Type = PIMA_CONTAINER_CommandBlock,
410 .Code = 0x1003,
411 .Params = {1},
412 };
413
414 if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
415 return ErrorCode;
416
417 if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
418 return ErrorCode;
419
420 SIInterfaceInfo->State.IsSessionOpen = false;
421
422 if ((PIMABlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMABlock.Code != 0x2001))
423 return SI_ERROR_LOGICAL_CMD_FAILED;
424
425 return PIPE_RWSTREAM_NoError;
426 }
427
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)
432 {
433 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
434 return PIPE_RWSTREAM_DeviceDisconnected;
435
436 uint8_t ErrorCode;
437
438 PIMA_Container_t PIMABlock = (PIMA_Container_t)
439 {
440 .DataLength = PIMA_COMMAND_SIZE(TotalParams),
441 .Type = PIMA_CONTAINER_CommandBlock,
442 .Code = Operation,
443 };
444
445 memcpy(&PIMABlock.Params, Params, sizeof(uint32_t) * TotalParams);
446
447 if ((ErrorCode = SI_Host_SendBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
448 return ErrorCode;
449
450 return PIPE_RWSTREAM_NoError;
451 }
452
453 uint8_t SI_Host_ReceiveResponse(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo)
454 {
455 uint8_t ErrorCode;
456 PIMA_Container_t PIMABlock;
457
458 if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive))
459 return PIPE_RWSTREAM_DeviceDisconnected;
460
461 if ((ErrorCode = SI_Host_ReceiveBlockHeader(SIInterfaceInfo, &PIMABlock)) != PIPE_RWSTREAM_NoError)
462 return ErrorCode;
463
464 if ((PIMABlock.Type != PIMA_CONTAINER_ResponseBlock) || (PIMABlock.Code != 0x2001))
465 return SI_ERROR_LOGICAL_CMD_FAILED;
466
467 return PIPE_RWSTREAM_NoError;
468 }
469
470 #endif
471