Changed over www.fourwalledcubicle.com links to the new www.lufa-lib.org redirect...
[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 if (PipeNum == CDCInterfaceInfo->Config.DataINPipeNumber)
104 {
105 Pipe_ConfigurePipe(PipeNum, EP_TYPE_BULK, PIPE_TOKEN_IN,
106 DataINEndpoint->EndpointAddress, DataINEndpoint->EndpointSize,
107 CDCInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
108
109 CDCInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
110 }
111 else if (PipeNum == CDCInterfaceInfo->Config.DataOUTPipeNumber)
112 {
113 Pipe_ConfigurePipe(PipeNum, EP_TYPE_BULK, PIPE_TOKEN_OUT,
114 DataOUTEndpoint->EndpointAddress, DataOUTEndpoint->EndpointSize,
115 CDCInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
116
117 CDCInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
118 }
119 else if (PipeNum == CDCInterfaceInfo->Config.NotificationPipeNumber)
120 {
121 Pipe_ConfigurePipe(PipeNum, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN,
122 NotificationEndpoint->EndpointAddress, NotificationEndpoint->EndpointSize,
123 CDCInterfaceInfo->Config.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
124 Pipe_SetInterruptPeriod(NotificationEndpoint->PollingIntervalMS);
125
126 CDCInterfaceInfo->State.NotificationPipeSize = NotificationEndpoint->EndpointSize;
127 }
128 }
129
130 CDCInterfaceInfo->State.ControlInterfaceNumber = CDCControlInterface->InterfaceNumber;
131 CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
132 CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD | CDC_CONTROL_LINE_IN_DSR);
133 CDCInterfaceInfo->State.IsActive = true;
134
135 return CDC_ENUMERROR_NoError;
136 }
137
138 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
139 {
140 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
141 {
142 USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
143 USB_Descriptor_Interface_t);
144
145 if ((CurrentInterface->Class == CDC_CSCP_CDCClass) &&
146 (CurrentInterface->SubClass == CDC_CSCP_ACMSubclass) &&
147 (CurrentInterface->Protocol == CDC_CSCP_ATCommandProtocol))
148 {
149 return DESCRIPTOR_SEARCH_Found;
150 }
151 }
152
153 return DESCRIPTOR_SEARCH_NotFound;
154 }
155
156 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
157 {
158 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
159 {
160 USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
161 USB_Descriptor_Interface_t);
162
163 if ((CurrentInterface->Class == CDC_CSCP_CDCDataClass) &&
164 (CurrentInterface->SubClass == CDC_CSCP_NoDataSubclass) &&
165 (CurrentInterface->Protocol == CDC_CSCP_NoDataProtocol))
166 {
167 return DESCRIPTOR_SEARCH_Found;
168 }
169 }
170
171 return DESCRIPTOR_SEARCH_NotFound;
172 }
173
174 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
175 {
176 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
177 {
178 USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
179 USB_Descriptor_Endpoint_t);
180
181 uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
182
183 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
184 !(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress)))
185 {
186 return DESCRIPTOR_SEARCH_Found;
187 }
188 }
189 else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
190 {
191 return DESCRIPTOR_SEARCH_Fail;
192 }
193
194 return DESCRIPTOR_SEARCH_NotFound;
195 }
196
197 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
198 {
199 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
200 return;
201
202 Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipeNumber);
203 Pipe_Unfreeze();
204
205 if (Pipe_IsINReceived())
206 {
207 USB_Request_Header_t Notification;
208 Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NO_STREAM_CALLBACK);
209
210 if ((Notification.bRequest == CDC_NOTIF_SerialState) &&
211 (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
212 {
213 Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
214 sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
215 NO_STREAM_CALLBACK);
216
217 Pipe_ClearIN();
218
219 EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
220 }
221 else
222 {
223 Pipe_ClearIN();
224 }
225 }
226
227 Pipe_Freeze();
228
229 #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
230 CDC_Host_Flush(CDCInterfaceInfo);
231 #endif
232 }
233
234 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
235 {
236 USB_ControlRequest = (USB_Request_Header_t)
237 {
238 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
239 .bRequest = CDC_REQ_SetLineEncoding,
240 .wValue = 0,
241 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
242 .wLength = sizeof(CDCInterfaceInfo->State.LineEncoding),
243 };
244
245 Pipe_SelectPipe(PIPE_CONTROLPIPE);
246
247 return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
248 }
249
250 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
251 {
252 USB_ControlRequest = (USB_Request_Header_t)
253 {
254 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
255 .bRequest = CDC_REQ_SetControlLineState,
256 .wValue = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
257 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
258 .wLength = 0,
259 };
260
261 Pipe_SelectPipe(PIPE_CONTROLPIPE);
262
263 return USB_Host_SendControlRequest(NULL);
264 }
265
266 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
267 const uint8_t Duration)
268 {
269 USB_ControlRequest = (USB_Request_Header_t)
270 {
271 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
272 .bRequest = CDC_REQ_SendBreak,
273 .wValue = Duration,
274 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
275 .wLength = 0,
276 };
277
278 Pipe_SelectPipe(PIPE_CONTROLPIPE);
279
280 return USB_Host_SendControlRequest(NULL);
281 }
282
283 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
284 const char* const Data,
285 const uint16_t Length)
286 {
287 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
288 return PIPE_READYWAIT_DeviceDisconnected;
289
290 uint8_t ErrorCode;
291
292 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
293
294 Pipe_Unfreeze();
295 ErrorCode = Pipe_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
296 Pipe_Freeze();
297
298 return ErrorCode;
299 }
300
301 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
302 const uint8_t Data)
303 {
304 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
305 return PIPE_READYWAIT_DeviceDisconnected;
306
307 uint8_t ErrorCode;
308
309 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
310 Pipe_Unfreeze();
311
312 if (!(Pipe_IsReadWriteAllowed()))
313 {
314 Pipe_ClearOUT();
315
316 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
317 return ErrorCode;
318 }
319
320 Pipe_Write_Byte(Data);
321 Pipe_Freeze();
322
323 return PIPE_READYWAIT_NoError;
324 }
325
326 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
327 {
328 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
329 return 0;
330
331 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
332 Pipe_Unfreeze();
333
334 if (Pipe_IsINReceived())
335 {
336 if (!(Pipe_BytesInPipe()))
337 {
338 Pipe_ClearIN();
339 Pipe_Freeze();
340 return 0;
341 }
342 else
343 {
344 Pipe_Freeze();
345 return Pipe_BytesInPipe();
346 }
347 }
348 else
349 {
350 Pipe_Freeze();
351
352 return 0;
353 }
354 }
355
356 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
357 {
358 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
359 return -1;
360
361 int16_t ReceivedByte = -1;
362
363 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
364 Pipe_Unfreeze();
365
366 if (Pipe_IsINReceived())
367 {
368 if (Pipe_BytesInPipe())
369 ReceivedByte = Pipe_Read_Byte();
370
371 if (!(Pipe_BytesInPipe()))
372 Pipe_ClearIN();
373 }
374
375 Pipe_Freeze();
376
377 return ReceivedByte;
378 }
379
380 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
381 {
382 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
383 return PIPE_READYWAIT_DeviceDisconnected;
384
385 uint8_t ErrorCode;
386
387 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
388 Pipe_Unfreeze();
389
390 if (!(Pipe_BytesInPipe()))
391 return PIPE_READYWAIT_NoError;
392
393 bool BankFull = !(Pipe_IsReadWriteAllowed());
394
395 Pipe_ClearOUT();
396
397 if (BankFull)
398 {
399 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
400 return ErrorCode;
401
402 Pipe_ClearOUT();
403 }
404
405 Pipe_Freeze();
406
407 return PIPE_READYWAIT_NoError;
408 }
409
410 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
411 FILE* const Stream)
412 {
413 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
414 fdev_set_udata(Stream, CDCInterfaceInfo);
415 }
416
417 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
418 FILE* const Stream)
419 {
420 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
421 fdev_set_udata(Stream, CDCInterfaceInfo);
422 }
423
424 static int CDC_Host_putchar(char c,
425 FILE* Stream)
426 {
427 return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
428 }
429
430 static int CDC_Host_getchar(FILE* Stream)
431 {
432 int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
433
434 if (ReceivedByte < 0)
435 return _FDEV_EOF;
436
437 return ReceivedByte;
438 }
439
440 static int CDC_Host_getchar_Blocking(FILE* Stream)
441 {
442 int16_t ReceivedByte;
443
444 while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
445 {
446 if (USB_HostState == HOST_STATE_Unattached)
447 return _FDEV_EOF;
448
449 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
450 USB_USBTask();
451 }
452
453 return ReceivedByte;
454 }
455
456 void CDC_Host_Event_Stub(void)
457 {
458
459 }
460
461 #endif
462