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