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