Add new ARCH option to the makefiles to (eventually) specify the target device archit...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / CDC.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_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), NULL);
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 NULL);
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_SendData(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
315 const uint8_t* const Buffer,
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(Buffer, Length, NULL);
327 Pipe_Freeze();
328
329 return ErrorCode;
330 }
331
332 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
333 const char* const String)
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
342 Pipe_Unfreeze();
343 ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);
344 Pipe_Freeze();
345
346 return ErrorCode;
347 }
348
349 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
350 const uint8_t Data)
351 {
352 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
353 return PIPE_READYWAIT_DeviceDisconnected;
354
355 uint8_t ErrorCode;
356
357 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
358 Pipe_Unfreeze();
359
360 if (!(Pipe_IsReadWriteAllowed()))
361 {
362 Pipe_ClearOUT();
363
364 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
365 return ErrorCode;
366 }
367
368 Pipe_Write_Byte(Data);
369 Pipe_Freeze();
370
371 return PIPE_READYWAIT_NoError;
372 }
373
374 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
375 {
376 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
377 return 0;
378
379 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
380 Pipe_Unfreeze();
381
382 if (Pipe_IsINReceived())
383 {
384 if (!(Pipe_BytesInPipe()))
385 {
386 Pipe_ClearIN();
387 Pipe_Freeze();
388 return 0;
389 }
390 else
391 {
392 Pipe_Freeze();
393 return Pipe_BytesInPipe();
394 }
395 }
396 else
397 {
398 Pipe_Freeze();
399
400 return 0;
401 }
402 }
403
404 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
405 {
406 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
407 return -1;
408
409 int16_t ReceivedByte = -1;
410
411 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
412 Pipe_Unfreeze();
413
414 if (Pipe_IsINReceived())
415 {
416 if (Pipe_BytesInPipe())
417 ReceivedByte = Pipe_Read_Byte();
418
419 if (!(Pipe_BytesInPipe()))
420 Pipe_ClearIN();
421 }
422
423 Pipe_Freeze();
424
425 return ReceivedByte;
426 }
427
428 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
429 {
430 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
431 return PIPE_READYWAIT_DeviceDisconnected;
432
433 uint8_t ErrorCode;
434
435 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
436 Pipe_Unfreeze();
437
438 if (!(Pipe_BytesInPipe()))
439 return PIPE_READYWAIT_NoError;
440
441 bool BankFull = !(Pipe_IsReadWriteAllowed());
442
443 Pipe_ClearOUT();
444
445 if (BankFull)
446 {
447 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
448 return ErrorCode;
449
450 Pipe_ClearOUT();
451 }
452
453 Pipe_Freeze();
454
455 return PIPE_READYWAIT_NoError;
456 }
457
458 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
459 FILE* const Stream)
460 {
461 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
462 fdev_set_udata(Stream, CDCInterfaceInfo);
463 }
464
465 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
466 FILE* const Stream)
467 {
468 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
469 fdev_set_udata(Stream, CDCInterfaceInfo);
470 }
471
472 static int CDC_Host_putchar(char c,
473 FILE* Stream)
474 {
475 return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
476 }
477
478 static int CDC_Host_getchar(FILE* Stream)
479 {
480 int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
481
482 if (ReceivedByte < 0)
483 return _FDEV_EOF;
484
485 return ReceivedByte;
486 }
487
488 static int CDC_Host_getchar_Blocking(FILE* Stream)
489 {
490 int16_t ReceivedByte;
491
492 while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
493 {
494 if (USB_HostState == HOST_STATE_Unattached)
495 return _FDEV_EOF;
496
497 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
498 USB_USBTask();
499 }
500
501 return ReceivedByte;
502 }
503
504 void CDC_Host_Event_Stub(void)
505 {
506
507 }
508
509 #endif
510