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