Documentation improvements - put driver example code into its own section, fix incorr...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / CDC.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2010.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2010 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_CDC_DRIVER
36 #define __INCLUDE_FROM_CDC_HOST_C
37 #include "CDC.h"
38
39 uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
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* NotificationEndpoint = NULL;
46 USB_Descriptor_Interface_t* CDCControlInterface = NULL;
47
48 memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
49
50 if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
51 return CDC_ENUMERROR_InvalidConfigDescriptor;
52
53 while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
54 {
55 if (!(CDCControlInterface) ||
56 USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
57 DCOMP_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
58 {
59 if (NotificationEndpoint)
60 {
61 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
62 DCOMP_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
63 {
64 return CDC_ENUMERROR_NoCompatibleInterfaceFound;
65 }
66
67 DataINEndpoint = NULL;
68 DataOUTEndpoint = NULL;
69 }
70 else
71 {
72 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
73 DCOMP_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
74 {
75 return CDC_ENUMERROR_NoCompatibleInterfaceFound;
76 }
77
78 CDCControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
79
80 NotificationEndpoint = NULL;
81 }
82
83 continue;
84 }
85
86 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
87
88 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
89 {
90 if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
91 NotificationEndpoint = EndpointData;
92 else
93 DataINEndpoint = EndpointData;
94 }
95 else
96 {
97 DataOUTEndpoint = EndpointData;
98 }
99 }
100
101 for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
102 {
103 uint16_t Size;
104 uint8_t Type;
105 uint8_t Token;
106 uint8_t EndpointAddress;
107 uint8_t InterruptPeriod;
108 bool DoubleBanked;
109
110 if (PipeNum == CDCInterfaceInfo->Config.DataINPipeNumber)
111 {
112 Size = DataINEndpoint->EndpointSize;
113 EndpointAddress = DataINEndpoint->EndpointAddress;
114 Token = PIPE_TOKEN_IN;
115 Type = EP_TYPE_BULK;
116 DoubleBanked = CDCInterfaceInfo->Config.DataINPipeDoubleBank;
117 InterruptPeriod = 0;
118
119 CDCInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
120 }
121 else if (PipeNum == CDCInterfaceInfo->Config.DataOUTPipeNumber)
122 {
123 Size = DataOUTEndpoint->EndpointSize;
124 EndpointAddress = DataOUTEndpoint->EndpointAddress;
125 Token = PIPE_TOKEN_OUT;
126 Type = EP_TYPE_BULK;
127 DoubleBanked = CDCInterfaceInfo->Config.DataOUTPipeDoubleBank;
128 InterruptPeriod = 0;
129
130 CDCInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
131 }
132 else if (PipeNum == CDCInterfaceInfo->Config.NotificationPipeNumber)
133 {
134 Size = NotificationEndpoint->EndpointSize;
135 EndpointAddress = NotificationEndpoint->EndpointAddress;
136 Token = PIPE_TOKEN_IN;
137 Type = EP_TYPE_INTERRUPT;
138 DoubleBanked = CDCInterfaceInfo->Config.NotificationPipeDoubleBank;
139 InterruptPeriod = NotificationEndpoint->PollingIntervalMS;
140
141 CDCInterfaceInfo->State.NotificationPipeSize = NotificationEndpoint->EndpointSize;
142 }
143 else
144 {
145 continue;
146 }
147
148 if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
149 DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
150 {
151 return CDC_ENUMERROR_PipeConfigurationFailed;
152 }
153
154 if (InterruptPeriod)
155 Pipe_SetInterruptPeriod(InterruptPeriod);
156 }
157
158 CDCInterfaceInfo->State.ControlInterfaceNumber = CDCControlInterface->InterfaceNumber;
159 CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
160 CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD | CDC_CONTROL_LINE_IN_DSR);
161 CDCInterfaceInfo->State.IsActive = true;
162
163 return CDC_ENUMERROR_NoError;
164 }
165
166 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
167 {
168 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
169
170 if (Header->Type == DTYPE_Interface)
171 {
172 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
173
174 if ((Interface->Class == CDC_CSCP_CDCClass) &&
175 (Interface->SubClass == CDC_CSCP_ACMSubclass) &&
176 (Interface->Protocol == CDC_CSCP_ATCommandProtocol))
177 {
178 return DESCRIPTOR_SEARCH_Found;
179 }
180 }
181
182 return DESCRIPTOR_SEARCH_NotFound;
183 }
184
185 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
186 {
187 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
188
189 if (Header->Type == DTYPE_Interface)
190 {
191 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
192
193 if ((Interface->Class == CDC_CSCP_CDCDataClass) &&
194 (Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
195 (Interface->Protocol == CDC_CSCP_NoDataProtocol))
196 {
197 return DESCRIPTOR_SEARCH_Found;
198 }
199 }
200
201 return DESCRIPTOR_SEARCH_NotFound;
202 }
203
204 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
205 {
206 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
207
208 if (Header->Type == DTYPE_Endpoint)
209 {
210 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
211
212 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
213
214 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
215 !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
216 {
217 return DESCRIPTOR_SEARCH_Found;
218 }
219 }
220 else if (Header->Type == DTYPE_Interface)
221 {
222 return DESCRIPTOR_SEARCH_Fail;
223 }
224
225 return DESCRIPTOR_SEARCH_NotFound;
226 }
227
228 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
229 {
230 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
231 return;
232
233 Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
234 Pipe_Unfreeze();
235
236 if (Pipe_IsINReceived())
237 {
238 USB_Request_Header_t Notification;
239 Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK);
240
241 if ((Notification.bRequest == CDC_NOTIF_SerialState) &&
242 (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
243 {
244 Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
245 sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
246 NO_STREAM_CALLBACK);
247
248 Pipe_ClearIN();
249
250 EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
251 }
252 else
253 {
254 Pipe_ClearIN();
255 }
256 }
257
258 Pipe_Freeze();
259
260 #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
261 CDC_Host_Flush(CDCInterfaceInfo);
262 #endif
263 }
264
265 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
266 {
267 USB_ControlRequest = (USB_Request_Header_t)
268 {
269 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
270 .bRequest = CDC_REQ_SetLineEncoding,
271 .wValue = 0,
272 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
273 .wLength = sizeof(CDCInterfaceInfo->State.LineEncoding),
274 };
275
276 Pipe_SelectPipe(PIPE_CONTROLPIPE);
277
278 return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
279 }
280
281 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
282 {
283 USB_ControlRequest = (USB_Request_Header_t)
284 {
285 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
286 .bRequest = CDC_REQ_SetControlLineState,
287 .wValue = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
288 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
289 .wLength = 0,
290 };
291
292 Pipe_SelectPipe(PIPE_CONTROLPIPE);
293
294 return USB_Host_SendControlRequest(NULL);
295 }
296
297 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
298 const uint8_t Duration)
299 {
300 USB_ControlRequest = (USB_Request_Header_t)
301 {
302 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
303 .bRequest = CDC_REQ_SendBreak,
304 .wValue = Duration,
305 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
306 .wLength = 0,
307 };
308
309 Pipe_SelectPipe(PIPE_CONTROLPIPE);
310
311 return USB_Host_SendControlRequest(NULL);
312 }
313
314 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
315 const char* const Data,
316 const uint16_t Length)
317 {
318 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
319 return PIPE_READYWAIT_DeviceDisconnected;
320
321 uint8_t ErrorCode;
322
323 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
324
325 Pipe_Unfreeze();
326 ErrorCode = Pipe_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
327 Pipe_Freeze();
328
329 return ErrorCode;
330 }
331
332 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
333 const uint8_t Data)
334 {
335 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
336 return PIPE_READYWAIT_DeviceDisconnected;
337
338 uint8_t ErrorCode;
339
340 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
341 Pipe_Unfreeze();
342
343 if (!(Pipe_IsReadWriteAllowed()))
344 {
345 Pipe_ClearOUT();
346
347 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
348 return ErrorCode;
349 }
350
351 Pipe_Write_Byte(Data);
352 Pipe_Freeze();
353
354 return PIPE_READYWAIT_NoError;
355 }
356
357 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
358 {
359 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
360 return 0;
361
362 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
363 Pipe_Unfreeze();
364
365 if (Pipe_IsINReceived())
366 {
367 if (!(Pipe_BytesInPipe()))
368 {
369 Pipe_ClearIN();
370 Pipe_Freeze();
371 return 0;
372 }
373 else
374 {
375 Pipe_Freeze();
376 return Pipe_BytesInPipe();
377 }
378 }
379 else
380 {
381 Pipe_Freeze();
382
383 return 0;
384 }
385 }
386
387 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
388 {
389 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
390 return -1;
391
392 int16_t ReceivedByte = -1;
393
394 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
395 Pipe_Unfreeze();
396
397 if (Pipe_IsINReceived())
398 {
399 if (Pipe_BytesInPipe())
400 ReceivedByte = Pipe_Read_Byte();
401
402 if (!(Pipe_BytesInPipe()))
403 Pipe_ClearIN();
404 }
405
406 Pipe_Freeze();
407
408 return ReceivedByte;
409 }
410
411 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
412 {
413 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
414 return PIPE_READYWAIT_DeviceDisconnected;
415
416 uint8_t ErrorCode;
417
418 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
419 Pipe_Unfreeze();
420
421 if (!(Pipe_BytesInPipe()))
422 return PIPE_READYWAIT_NoError;
423
424 bool BankFull = !(Pipe_IsReadWriteAllowed());
425
426 Pipe_ClearOUT();
427
428 if (BankFull)
429 {
430 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
431 return ErrorCode;
432
433 Pipe_ClearOUT();
434 }
435
436 Pipe_Freeze();
437
438 return PIPE_READYWAIT_NoError;
439 }
440
441 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
442 FILE* const Stream)
443 {
444 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
445 fdev_set_udata(Stream, CDCInterfaceInfo);
446 }
447
448 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
449 FILE* const Stream)
450 {
451 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
452 fdev_set_udata(Stream, CDCInterfaceInfo);
453 }
454
455 static int CDC_Host_putchar(char c,
456 FILE* Stream)
457 {
458 return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
459 }
460
461 static int CDC_Host_getchar(FILE* Stream)
462 {
463 int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
464
465 if (ReceivedByte < 0)
466 return _FDEV_EOF;
467
468 return ReceivedByte;
469 }
470
471 static int CDC_Host_getchar_Blocking(FILE* Stream)
472 {
473 int16_t ReceivedByte;
474
475 while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
476 {
477 if (USB_HostState == HOST_STATE_Unattached)
478 return _FDEV_EOF;
479
480 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
481 USB_USBTask();
482 }
483
484 return ReceivedByte;
485 }
486
487 void CDC_Host_Event_Stub(void)
488 {
489
490 }
491
492 #endif
493