]> git.donarmstrong.com Git - qmk_firmware.git/blob - lib/lufa/LUFA/Drivers/USB/Class/Host/CDCClassHost.c
cc93f96010c1fc20f5f41f029679b1f276cce654
[qmk_firmware.git] / lib / lufa / LUFA / Drivers / USB / Class / Host / CDCClassHost.c
1 /*
2              LUFA Library
3      Copyright (C) Dean Camera, 2017.
4
5   dean [at] fourwalledcubicle [dot] com
6            www.lufa-lib.org
7 */
8
9 /*
10   Copyright 2017  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 disclaims 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 "../../Core/USBMode.h"
33
34 #if defined(USB_CAN_BE_HOST)
35
36 #define  __INCLUDE_FROM_CDC_DRIVER
37 #define  __INCLUDE_FROM_CDC_HOST_C
38 #include "CDCClassHost.h"
39
40 uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
41                                 uint16_t ConfigDescriptorSize,
42                                 void* ConfigDescriptorData)
43 {
44         USB_Descriptor_Endpoint_t*  DataINEndpoint       = NULL;
45         USB_Descriptor_Endpoint_t*  DataOUTEndpoint      = NULL;
46         USB_Descriptor_Endpoint_t*  NotificationEndpoint = NULL;
47         USB_Descriptor_Interface_t* CDCControlInterface  = NULL;
48
49         memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));
50
51         if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
52           return CDC_ENUMERROR_InvalidConfigDescriptor;
53
54         while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))
55         {
56                 if (!(CDCControlInterface) ||
57                     USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
58                                               DCOMP_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
59                 {
60                         if (NotificationEndpoint)
61                         {
62                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
63                                                               DCOMP_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)
64                                 {
65                                         return CDC_ENUMERROR_NoCompatibleInterfaceFound;
66                                 }
67
68                                 DataINEndpoint  = NULL;
69                                 DataOUTEndpoint = NULL;
70                         }
71                         else
72                         {
73                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
74                                                               DCOMP_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)
75                                 {
76                                         return CDC_ENUMERROR_NoCompatibleInterfaceFound;
77                                 }
78
79                                 CDCControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
80
81                                 NotificationEndpoint = NULL;
82                         }
83
84                         continue;
85                 }
86
87                 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
88
89                 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
90                 {
91                         if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)
92                           NotificationEndpoint = EndpointData;
93                         else
94                           DataINEndpoint = EndpointData;
95                 }
96                 else
97                 {
98                         DataOUTEndpoint = EndpointData;
99                 }
100         }
101
102         CDCInterfaceInfo->Config.DataINPipe.Size  = le16_to_cpu(DataINEndpoint->EndpointSize);
103         CDCInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
104         CDCInterfaceInfo->Config.DataINPipe.Type  = EP_TYPE_BULK;
105
106         CDCInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
107         CDCInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
108         CDCInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
109
110         CDCInterfaceInfo->Config.NotificationPipe.Size = le16_to_cpu(NotificationEndpoint->EndpointSize);
111         CDCInterfaceInfo->Config.NotificationPipe.EndpointAddress = NotificationEndpoint->EndpointAddress;
112         CDCInterfaceInfo->Config.NotificationPipe.Type = EP_TYPE_INTERRUPT;
113
114         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.DataINPipe, 1)))
115           return CDC_ENUMERROR_PipeConfigurationFailed;
116
117         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.DataOUTPipe, 1)))
118           return CDC_ENUMERROR_PipeConfigurationFailed;
119
120         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.NotificationPipe, 1)))
121           return CDC_ENUMERROR_PipeConfigurationFailed;
122
123         CDCInterfaceInfo->State.ControlInterfaceNumber = CDCControlInterface->InterfaceNumber;
124         CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);
125         CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD  | CDC_CONTROL_LINE_IN_DSR);
126         CDCInterfaceInfo->State.IsActive = true;
127
128         return CDC_ENUMERROR_NoError;
129 }
130
131 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)
132 {
133         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
134
135         if (Header->Type == DTYPE_Interface)
136         {
137                 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
138
139                 if ((Interface->Class    == CDC_CSCP_CDCClass)    &&
140                     (Interface->SubClass == CDC_CSCP_ACMSubclass) &&
141                     (Interface->Protocol == CDC_CSCP_ATCommandProtocol))
142                 {
143                         return DESCRIPTOR_SEARCH_Found;
144                 }
145         }
146
147         return DESCRIPTOR_SEARCH_NotFound;
148 }
149
150 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)
151 {
152         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
153
154         if (Header->Type == DTYPE_Interface)
155         {
156                 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
157
158                 if ((Interface->Class    == CDC_CSCP_CDCDataClass)   &&
159                     (Interface->SubClass == CDC_CSCP_NoDataSubclass) &&
160                     (Interface->Protocol == CDC_CSCP_NoDataProtocol))
161                 {
162                         return DESCRIPTOR_SEARCH_Found;
163                 }
164         }
165
166         return DESCRIPTOR_SEARCH_NotFound;
167 }
168
169 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)
170 {
171         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
172
173         if (Header->Type == DTYPE_Endpoint)
174         {
175                 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
176
177                 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
178
179                 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&
180                     !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))
181                 {
182                         return DESCRIPTOR_SEARCH_Found;
183                 }
184         }
185         else if (Header->Type == DTYPE_Interface)
186         {
187                 return DESCRIPTOR_SEARCH_Fail;
188         }
189
190         return DESCRIPTOR_SEARCH_NotFound;
191 }
192
193 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
194 {
195         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
196           return;
197
198         Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipe.Address);
199         Pipe_Unfreeze();
200
201         if (Pipe_IsINReceived())
202         {
203                 USB_Request_Header_t Notification;
204                 Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL);
205
206                 if ((Notification.bRequest      == CDC_NOTIF_SerialState) &&
207                     (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))
208                 {
209                         Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,
210                                             sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),
211                                             NULL);
212
213                         Pipe_ClearIN();
214
215                         EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);
216                 }
217                 else
218                 {
219                         Pipe_ClearIN();
220                 }
221         }
222
223         Pipe_Freeze();
224
225         #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
226         CDC_Host_Flush(CDCInterfaceInfo);
227         #endif
228 }
229
230 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
231 {
232         USB_ControlRequest = (USB_Request_Header_t)
233         {
234                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
235                 .bRequest      = CDC_REQ_SetLineEncoding,
236                 .wValue        = 0,
237                 .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
238                 .wLength       = sizeof(CDCInterfaceInfo->State.LineEncoding),
239         };
240
241         Pipe_SelectPipe(PIPE_CONTROLPIPE);
242
243         return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
244 }
245
246 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
247 {
248         USB_ControlRequest = (USB_Request_Header_t)
249         {
250                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
251                 .bRequest      = CDC_REQ_SetControlLineState,
252                 .wValue        = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
253                 .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
254                 .wLength       = 0,
255         };
256
257         Pipe_SelectPipe(PIPE_CONTROLPIPE);
258
259         return USB_Host_SendControlRequest(NULL);
260 }
261
262 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
263                            const uint8_t Duration)
264 {
265         USB_ControlRequest = (USB_Request_Header_t)
266         {
267                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
268                 .bRequest      = CDC_REQ_SendBreak,
269                 .wValue        = Duration,
270                 .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,
271                 .wLength       = 0,
272         };
273
274         Pipe_SelectPipe(PIPE_CONTROLPIPE);
275
276         return USB_Host_SendControlRequest(NULL);
277 }
278
279 uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
280                           const void* const Buffer,
281                           const uint16_t Length)
282 {
283         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
284           return PIPE_READYWAIT_DeviceDisconnected;
285
286         uint8_t ErrorCode;
287
288         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);
289
290         Pipe_Unfreeze();
291         ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL);
292         Pipe_Freeze();
293
294         return ErrorCode;
295 }
296
297 uint8_t CDC_Host_SendData_P(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
298                           const void* const Buffer,
299                           const uint16_t Length)
300 {
301         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
302           return PIPE_READYWAIT_DeviceDisconnected;
303
304         uint8_t ErrorCode;
305
306         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);
307
308         Pipe_Unfreeze();
309         ErrorCode = Pipe_Write_PStream_LE(Buffer, Length, NULL);
310         Pipe_Freeze();
311
312         return ErrorCode;
313 }
314
315 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
316                             const char* const String)
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.DataOUTPipe.Address);
324
325         Pipe_Unfreeze();
326         ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);
327         Pipe_Freeze();
328
329         return ErrorCode;
330 }
331
332 uint8_t CDC_Host_SendString_P(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.DataOUTPipe.Address);
341
342         Pipe_Unfreeze();
343         ErrorCode = Pipe_Write_PStream_LE(String, strlen_P(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.DataOUTPipe.Address);
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_8(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.DataINPipe.Address);
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.DataINPipe.Address);
412         Pipe_Unfreeze();
413
414         if (Pipe_IsINReceived())
415         {
416                 if (Pipe_BytesInPipe())
417                   ReceivedByte = Pipe_Read_8();
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.DataOUTPipe.Address);
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 #if defined(FDEV_SETUP_STREAM)
459 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
460                            FILE* const Stream)
461 {
462         *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
463         fdev_set_udata(Stream, CDCInterfaceInfo);
464 }
465
466 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
467                                    FILE* const Stream)
468 {
469         *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
470         fdev_set_udata(Stream, CDCInterfaceInfo);
471 }
472
473 static int CDC_Host_putchar(char c,
474                             FILE* Stream)
475 {
476         return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
477 }
478
479 static int CDC_Host_getchar(FILE* Stream)
480 {
481         int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
482
483         if (ReceivedByte < 0)
484           return _FDEV_EOF;
485
486         return ReceivedByte;
487 }
488
489 static int CDC_Host_getchar_Blocking(FILE* Stream)
490 {
491         int16_t ReceivedByte;
492
493         while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
494         {
495                 if (USB_HostState == HOST_STATE_Unattached)
496                   return _FDEV_EOF;
497
498                 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
499                 USB_USBTask();
500         }
501
502         return ReceivedByte;
503 }
504 #endif
505
506 void CDC_Host_Event_Stub(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
507 {
508
509 }
510
511 #endif
512