Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (14.9 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_CDC_DRIVER
37
#define  __INCLUDE_FROM_CDC_HOST_C
38
#include "CDC.h"
39

    
40
uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
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*  NotificationEndpoint = NULL;
47
        USB_Descriptor_Interface_t* CDCControlInterface  = NULL;
48

    
49
        memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
50

    
51
        if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
52
          return CDC_ENUMERROR_InvalidConfigDescriptor;
53

    
54
        while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
55
        {
56
                if (!(CDCControlInterface) ||
57
                    USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
58
                                              DCOMP_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
59
                {
60
                        if (NotificationEndpoint)
61
                        {
62
                                if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
63
                                                              DCOMP_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
64
                                {
65
                                        return CDC_ENUMERROR_NoCompatibleInterfaceFound;
66
                                }
67

    
68
                                DataINEndpoint  = NULL;
69
                                DataOUTEndpoint = NULL;
70
                        }
71
                        else
72
                        {
73
                                if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
74
                                                              DCOMP_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
75
                                {
76
                                        return CDC_ENUMERROR_NoCompatibleInterfaceFound;
77
                                }
78

    
79
                                CDCControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
80

    
81
                                NotificationEndpoint = NULL;
82
                        }
83

    
84
                        continue;
85
                }
86

    
87
                USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
88

    
89
                if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
90
                {
91
                        if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
92
                          NotificationEndpoint = EndpointData;
93
                        else
94
                          DataINEndpoint = EndpointData;
95
                }
96
                else
97
                {
98
                        DataOUTEndpoint = EndpointData;
99
                }
100
        }
101

    
102
        for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
103
        {
104
                uint16_t Size;
105
                uint8_t  Type;
106
                uint8_t  Token;
107
                uint8_t  EndpointAddress;
108
                uint8_t  InterruptPeriod;
109
                bool     DoubleBanked;
110

    
111
                if (PipeNum == CDCInterfaceInfo->Config.DataINPipeNumber)
112
                {
113
                        Size            = le16_to_cpu(DataINEndpoint->EndpointSize);
114
                        EndpointAddress = DataINEndpoint->EndpointAddress;
115
                        Token           = PIPE_TOKEN_IN;
116
                        Type            = EP_TYPE_BULK;
117
                        DoubleBanked    = CDCInterfaceInfo->Config.DataINPipeDoubleBank;
118
                        InterruptPeriod = 0;
119

    
120
                        CDCInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
121
                }
122
                else if (PipeNum == CDCInterfaceInfo->Config.DataOUTPipeNumber)
123
                {
124
                        Size            = le16_to_cpu(DataOUTEndpoint->EndpointSize);
125
                        EndpointAddress = DataOUTEndpoint->EndpointAddress;
126
                        Token           = PIPE_TOKEN_OUT;
127
                        Type            = EP_TYPE_BULK;
128
                        DoubleBanked    = CDCInterfaceInfo->Config.DataOUTPipeDoubleBank;
129
                        InterruptPeriod = 0;
130

    
131
                        CDCInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
132
                }
133
                else if (PipeNum == CDCInterfaceInfo->Config.NotificationPipeNumber)
134
                {
135
                        Size            = le16_to_cpu(NotificationEndpoint->EndpointSize);
136
                        EndpointAddress = NotificationEndpoint->EndpointAddress;
137
                        Token           = PIPE_TOKEN_IN;
138
                        Type            = EP_TYPE_INTERRUPT;
139
                        DoubleBanked    = CDCInterfaceInfo->Config.NotificationPipeDoubleBank;
140
                        InterruptPeriod = NotificationEndpoint->PollingIntervalMS;
141

    
142
                        CDCInterfaceInfo->State.NotificationPipeSize = NotificationEndpoint->EndpointSize;
143
                }
144
                else
145
                {
146
                        continue;
147
                }
148
                
149
                if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
150
                                         DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
151
                {
152
                        return CDC_ENUMERROR_PipeConfigurationFailed;
153
                }
154
                
155
                if (InterruptPeriod)
156
                  Pipe_SetInterruptPeriod(InterruptPeriod);
157
        }
158

    
159
        CDCInterfaceInfo->State.ControlInterfaceNumber = CDCControlInterface->InterfaceNumber;
160
        CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
161
        CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD  | CDC_CONTROL_LINE_IN_DSR);
162
        CDCInterfaceInfo->State.IsActive = true;
163

    
164
        return CDC_ENUMERROR_NoError;
165
}
166

    
167
static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
168
{
169
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
170

    
171
        if (Header->Type == DTYPE_Interface)
172
        {
173
                USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
174

    
175
                if ((Interface->Class    == CDC_CSCP_CDCClass)    &&
176
                    (Interface->SubClass == CDC_CSCP_ACMSubclass) &&
177
                    (Interface->Protocol == CDC_CSCP_ATCommandProtocol))
178
                {
179
                        return DESCRIPTOR_SEARCH_Found;
180
                }
181
        }
182

    
183
        return DESCRIPTOR_SEARCH_NotFound;
184
}
185

    
186
static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
187
{
188
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
189

    
190
        if (Header->Type == DTYPE_Interface)
191
        {
192
                USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
193

    
194
                if ((Interface->Class    == CDC_CSCP_CDCDataClass)   &&
195
                    (Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
196
                    (Interface->Protocol == CDC_CSCP_NoDataProtocol))
197
                {
198
                        return DESCRIPTOR_SEARCH_Found;
199
                }
200
        }
201

    
202
        return DESCRIPTOR_SEARCH_NotFound;
203
}
204

    
205
static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
206
{
207
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
208

    
209
        if (Header->Type == DTYPE_Endpoint)
210
        {
211
                USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
212

    
213
                uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
214

    
215
                if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
216
                    !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
217
                {
218
                        return DESCRIPTOR_SEARCH_Found;
219
                }
220
        }
221
        else if (Header->Type == DTYPE_Interface)
222
        {
223
                return DESCRIPTOR_SEARCH_Fail;
224
        }
225

    
226
        return DESCRIPTOR_SEARCH_NotFound;
227
}
228

    
229
void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
230
{
231
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
232
          return;
233

    
234
        Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
235
        Pipe_Unfreeze();
236

    
237
        if (Pipe_IsINReceived())
238
        {
239
                USB_Request_Header_t Notification;
240
                Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL);
241

    
242
                if ((Notification.bRequest      == CDC_NOTIF_SerialState) &&
243
                    (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
244
                {
245
                        Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
246
                                            sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
247
                                            NULL);
248

    
249
                        Pipe_ClearIN();
250

    
251
                        EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
252
                }
253
                else
254
                {
255
                        Pipe_ClearIN();
256
                }
257
        }
258

    
259
        Pipe_Freeze();
260

    
261
        #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
262
        CDC_Host_Flush(CDCInterfaceInfo);
263
        #endif
264
}
265

    
266
uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
267
{
268
        USB_ControlRequest = (USB_Request_Header_t)
269
        {
270
                .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
271
                .bRequest      = CDC_REQ_SetLineEncoding,
272
                .wValue        = 0,
273
                .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
274
                .wLength       = sizeof(CDCInterfaceInfo->State.LineEncoding),
275
        };
276

    
277
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
278

    
279
        return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
280
}
281

    
282
uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
283
{
284
        USB_ControlRequest = (USB_Request_Header_t)
285
        {
286
                .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
287
                .bRequest      = CDC_REQ_SetControlLineState,
288
                .wValue        = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
289
                .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
290
                .wLength       = 0,
291
        };
292

    
293
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
294

    
295
        return USB_Host_SendControlRequest(NULL);
296
}
297

    
298
uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
299
                           const uint8_t Duration)
300
{
301
        USB_ControlRequest = (USB_Request_Header_t)
302
        {
303
                .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
304
                .bRequest      = CDC_REQ_SendBreak,
305
                .wValue        = Duration,
306
                .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
307
                .wLength       = 0,
308
        };
309

    
310
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
311

    
312
        return USB_Host_SendControlRequest(NULL);
313
}
314

    
315
uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
316
                          const uint8_t* const Buffer,
317
                          const uint16_t Length)
318
{
319
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
320
          return PIPE_READYWAIT_DeviceDisconnected;
321

    
322
        uint8_t ErrorCode;
323

    
324
        Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
325

    
326
        Pipe_Unfreeze();
327
        ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL);
328
        Pipe_Freeze();
329

    
330
        return ErrorCode;
331
}
332

    
333
uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
334
                            const char* const String)
335
{
336
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
337
          return PIPE_READYWAIT_DeviceDisconnected;
338

    
339
        uint8_t ErrorCode;
340

    
341
        Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
342

    
343
        Pipe_Unfreeze();
344
        ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);
345
        Pipe_Freeze();
346

    
347
        return ErrorCode;
348
}
349

    
350
uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
351
                          const uint8_t Data)
352
{
353
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
354
          return PIPE_READYWAIT_DeviceDisconnected;
355

    
356
        uint8_t ErrorCode;
357

    
358
        Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
359
        Pipe_Unfreeze();
360

    
361
        if (!(Pipe_IsReadWriteAllowed()))
362
        {
363
                Pipe_ClearOUT();
364

    
365
                if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
366
                  return ErrorCode;
367
        }
368

    
369
        Pipe_Write_8(Data);
370
        Pipe_Freeze();
371

    
372
        return PIPE_READYWAIT_NoError;
373
}
374

    
375
uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
376
{
377
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
378
          return 0;
379

    
380
        Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
381
        Pipe_Unfreeze();
382

    
383
        if (Pipe_IsINReceived())
384
        {
385
                if (!(Pipe_BytesInPipe()))
386
                {
387
                        Pipe_ClearIN();
388
                        Pipe_Freeze();
389
                        return 0;
390
                }
391
                else
392
                {
393
                        Pipe_Freeze();
394
                        return Pipe_BytesInPipe();
395
                }
396
        }
397
        else
398
        {
399
                Pipe_Freeze();
400

    
401
                return 0;
402
        }
403
}
404

    
405
int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
406
{
407
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
408
          return -1;
409

    
410
        int16_t ReceivedByte = -1;
411

    
412
        Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
413
        Pipe_Unfreeze();
414

    
415
        if (Pipe_IsINReceived())
416
        {
417
                if (Pipe_BytesInPipe())
418
                  ReceivedByte = Pipe_Read_8();
419

    
420
                if (!(Pipe_BytesInPipe()))
421
                  Pipe_ClearIN();
422
        }
423

    
424
        Pipe_Freeze();
425

    
426
        return ReceivedByte;
427
}
428

    
429
uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
430
{
431
        if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
432
          return PIPE_READYWAIT_DeviceDisconnected;
433

    
434
        uint8_t ErrorCode;
435

    
436
        Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
437
        Pipe_Unfreeze();
438

    
439
        if (!(Pipe_BytesInPipe()))
440
          return PIPE_READYWAIT_NoError;
441

    
442
        bool BankFull = !(Pipe_IsReadWriteAllowed());
443

    
444
        Pipe_ClearOUT();
445

    
446
        if (BankFull)
447
        {
448
                if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
449
                  return ErrorCode;
450

    
451
                Pipe_ClearOUT();
452
        }
453

    
454
        Pipe_Freeze();
455

    
456
        return PIPE_READYWAIT_NoError;
457
}
458

    
459
#if defined(FDEV_SETUP_STREAM)
460
void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
461
                           FILE* const Stream)
462
{
463
        *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
464
        fdev_set_udata(Stream, CDCInterfaceInfo);
465
}
466

    
467
void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
468
                                   FILE* const Stream)
469
{
470
        *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
471
        fdev_set_udata(Stream, CDCInterfaceInfo);
472
}
473

    
474
static int CDC_Host_putchar(char c,
475
                            FILE* Stream)
476
{
477
        return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
478
}
479

    
480
static int CDC_Host_getchar(FILE* Stream)
481
{
482
        int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
483

    
484
        if (ReceivedByte < 0)
485
          return _FDEV_EOF;
486

    
487
        return ReceivedByte;
488
}
489

    
490
static int CDC_Host_getchar_Blocking(FILE* Stream)
491
{
492
        int16_t ReceivedByte;
493

    
494
        while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
495
        {
496
                if (USB_HostState == HOST_STATE_Unattached)
497
                  return _FDEV_EOF;
498

    
499
                CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
500
                USB_USBTask();
501
        }
502

    
503
        return ReceivedByte;
504
}
505
#endif
506

    
507
void CDC_Host_Event_Stub(void)
508
{
509

    
510
}
511

    
512
#endif
513