Statistics
| Branch: | Tag: | Revision:

root / LUFA / Drivers / USB / Class / Host / StillImage.c @ 978b99e5

History | View | Annotate | Download (14.4 KB)

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_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
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_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
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