]> git.donarmstrong.com Git - qmk_firmware.git/blob - protocol/lufa/LUFA-120730/LUFA/Drivers/USB/Class/Host/CDCClassHost.c
Change TOP_DIR to TMK_DIR in makefiles
[qmk_firmware.git] / protocol / lufa / LUFA-120730 / LUFA / Drivers / USB / Class / Host / CDCClassHost.c
1 /*\r
2              LUFA Library\r
3      Copyright (C) Dean Camera, 2012.\r
4 \r
5   dean [at] fourwalledcubicle [dot] com\r
6            www.lufa-lib.org\r
7 */\r
8 \r
9 /*\r
10   Copyright 2012  Dean Camera (dean [at] fourwalledcubicle [dot] com)\r
11 \r
12   Permission to use, copy, modify, distribute, and sell this\r
13   software and its documentation for any purpose is hereby granted\r
14   without fee, provided that the above copyright notice appear in\r
15   all copies and that both that the copyright notice and this\r
16   permission notice and warranty disclaimer appear in supporting\r
17   documentation, and that the name of the author not be used in\r
18   advertising or publicity pertaining to distribution of the\r
19   software without specific, written prior permission.\r
20 \r
21   The author disclaim all warranties with regard to this\r
22   software, including all implied warranties of merchantability\r
23   and fitness.  In no event shall the author be liable for any\r
24   special, indirect or consequential damages or any damages\r
25   whatsoever resulting from loss of use, data or profits, whether\r
26   in an action of contract, negligence or other tortious action,\r
27   arising out of or in connection with the use or performance of\r
28   this software.\r
29 */\r
30 \r
31 #define  __INCLUDE_FROM_USB_DRIVER\r
32 #include "../../Core/USBMode.h"\r
33 \r
34 #if defined(USB_CAN_BE_HOST)\r
35 \r
36 #define  __INCLUDE_FROM_CDC_DRIVER\r
37 #define  __INCLUDE_FROM_CDC_HOST_C\r
38 #include "CDCClassHost.h"\r
39 \r
40 uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
41                                 uint16_t ConfigDescriptorSize,\r
42                                 void* ConfigDescriptorData)\r
43 {\r
44         USB_Descriptor_Endpoint_t*  DataINEndpoint       = NULL;\r
45         USB_Descriptor_Endpoint_t*  DataOUTEndpoint      = NULL;\r
46         USB_Descriptor_Endpoint_t*  NotificationEndpoint = NULL;\r
47         USB_Descriptor_Interface_t* CDCControlInterface  = NULL;\r
48 \r
49         memset(&CDCInterfaceInfo->State, 0x00, sizeof(CDCInterfaceInfo->State));\r
50 \r
51         if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)\r
52           return CDC_ENUMERROR_InvalidConfigDescriptor;\r
53 \r
54         while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))\r
55         {\r
56                 if (!(CDCControlInterface) ||\r
57                     USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
58                                               DCOMP_CDC_Host_NextCDCInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)\r
59                 {\r
60                         if (NotificationEndpoint)\r
61                         {\r
62                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
63                                                               DCOMP_CDC_Host_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)\r
64                                 {\r
65                                         return CDC_ENUMERROR_NoCompatibleInterfaceFound;\r
66                                 }\r
67 \r
68                                 DataINEndpoint  = NULL;\r
69                                 DataOUTEndpoint = NULL;\r
70                         }\r
71                         else\r
72                         {\r
73                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,\r
74                                                               DCOMP_CDC_Host_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)\r
75                                 {\r
76                                         return CDC_ENUMERROR_NoCompatibleInterfaceFound;\r
77                                 }\r
78 \r
79                                 CDCControlInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);\r
80 \r
81                                 NotificationEndpoint = NULL;\r
82                         }\r
83 \r
84                         continue;\r
85                 }\r
86 \r
87                 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);\r
88 \r
89                 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)\r
90                 {\r
91                         if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT)\r
92                           NotificationEndpoint = EndpointData;\r
93                         else\r
94                           DataINEndpoint = EndpointData;\r
95                 }\r
96                 else\r
97                 {\r
98                         DataOUTEndpoint = EndpointData;\r
99                 }\r
100         }\r
101 \r
102         CDCInterfaceInfo->Config.DataINPipe.Size  = le16_to_cpu(DataINEndpoint->EndpointSize);\r
103         CDCInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;\r
104         CDCInterfaceInfo->Config.DataINPipe.Type  = EP_TYPE_BULK;\r
105         \r
106         CDCInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);\r
107         CDCInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;\r
108         CDCInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;\r
109         \r
110         CDCInterfaceInfo->Config.NotificationPipe.Size = le16_to_cpu(NotificationEndpoint->EndpointSize);\r
111         CDCInterfaceInfo->Config.NotificationPipe.EndpointAddress = NotificationEndpoint->EndpointAddress;\r
112         CDCInterfaceInfo->Config.NotificationPipe.Type = EP_TYPE_INTERRUPT;\r
113 \r
114         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.DataINPipe, 1)))\r
115           return false;\r
116         \r
117         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.DataOUTPipe, 1)))\r
118           return false;\r
119 \r
120         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo->Config.NotificationPipe, 1)))\r
121           return false;\r
122 \r
123         CDCInterfaceInfo->State.ControlInterfaceNumber = CDCControlInterface->InterfaceNumber;\r
124         CDCInterfaceInfo->State.ControlLineStates.HostToDevice = (CDC_CONTROL_LINE_OUT_RTS | CDC_CONTROL_LINE_OUT_DTR);\r
125         CDCInterfaceInfo->State.ControlLineStates.DeviceToHost = (CDC_CONTROL_LINE_IN_DCD  | CDC_CONTROL_LINE_IN_DSR);\r
126         CDCInterfaceInfo->State.IsActive = true;\r
127 \r
128         return CDC_ENUMERROR_NoError;\r
129 }\r
130 \r
131 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor)\r
132 {\r
133         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
134 \r
135         if (Header->Type == DTYPE_Interface)\r
136         {\r
137                 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);\r
138 \r
139                 if ((Interface->Class    == CDC_CSCP_CDCClass)    &&\r
140                     (Interface->SubClass == CDC_CSCP_ACMSubclass) &&\r
141                     (Interface->Protocol == CDC_CSCP_ATCommandProtocol))\r
142                 {\r
143                         return DESCRIPTOR_SEARCH_Found;\r
144                 }\r
145         }\r
146 \r
147         return DESCRIPTOR_SEARCH_NotFound;\r
148 }\r
149 \r
150 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor)\r
151 {\r
152         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
153 \r
154         if (Header->Type == DTYPE_Interface)\r
155         {\r
156                 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);\r
157 \r
158                 if ((Interface->Class    == CDC_CSCP_CDCDataClass)   &&\r
159                     (Interface->SubClass == CDC_CSCP_NoDataSubclass) &&\r
160                     (Interface->Protocol == CDC_CSCP_NoDataProtocol))\r
161                 {\r
162                         return DESCRIPTOR_SEARCH_Found;\r
163                 }\r
164         }\r
165 \r
166         return DESCRIPTOR_SEARCH_NotFound;\r
167 }\r
168 \r
169 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor)\r
170 {\r
171         USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);\r
172 \r
173         if (Header->Type == DTYPE_Endpoint)\r
174         {\r
175                 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);\r
176 \r
177                 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);\r
178 \r
179                 if (((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) &&\r
180                     !(Pipe_IsEndpointBound(Endpoint->EndpointAddress)))\r
181                 {\r
182                         return DESCRIPTOR_SEARCH_Found;\r
183                 }\r
184         }\r
185         else if (Header->Type == DTYPE_Interface)\r
186         {\r
187                 return DESCRIPTOR_SEARCH_Fail;\r
188         }\r
189 \r
190         return DESCRIPTOR_SEARCH_NotFound;\r
191 }\r
192 \r
193 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)\r
194 {\r
195         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
196           return;\r
197 \r
198         Pipe_SelectPipe(CDCInterfaceInfo->Config.NotificationPipe.Address);\r
199         Pipe_Unfreeze();\r
200 \r
201         if (Pipe_IsINReceived())\r
202         {\r
203                 USB_Request_Header_t Notification;\r
204                 Pipe_Read_Stream_LE(&Notification, sizeof(USB_Request_Header_t), NULL);\r
205 \r
206                 if ((Notification.bRequest      == CDC_NOTIF_SerialState) &&\r
207                     (Notification.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)))\r
208                 {\r
209                         Pipe_Read_Stream_LE(&CDCInterfaceInfo->State.ControlLineStates.DeviceToHost,\r
210                                             sizeof(CDCInterfaceInfo->State.ControlLineStates.DeviceToHost),\r
211                                             NULL);\r
212 \r
213                         Pipe_ClearIN();\r
214 \r
215                         EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo);\r
216                 }\r
217                 else\r
218                 {\r
219                         Pipe_ClearIN();\r
220                 }\r
221         }\r
222 \r
223         Pipe_Freeze();\r
224 \r
225         #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)\r
226         CDC_Host_Flush(CDCInterfaceInfo);\r
227         #endif\r
228 }\r
229 \r
230 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)\r
231 {\r
232         USB_ControlRequest = (USB_Request_Header_t)\r
233         {\r
234                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
235                 .bRequest      = CDC_REQ_SetLineEncoding,\r
236                 .wValue        = 0,\r
237                 .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,\r
238                 .wLength       = sizeof(CDCInterfaceInfo->State.LineEncoding),\r
239         };\r
240 \r
241         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
242 \r
243         return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);\r
244 }\r
245 \r
246 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)\r
247 {\r
248         USB_ControlRequest = (USB_Request_Header_t)\r
249         {\r
250                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
251                 .bRequest      = CDC_REQ_SetControlLineState,\r
252                 .wValue        = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,\r
253                 .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,\r
254                 .wLength       = 0,\r
255         };\r
256 \r
257         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
258 \r
259         return USB_Host_SendControlRequest(NULL);\r
260 }\r
261 \r
262 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
263                            const uint8_t Duration)\r
264 {\r
265         USB_ControlRequest = (USB_Request_Header_t)\r
266         {\r
267                 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),\r
268                 .bRequest      = CDC_REQ_SendBreak,\r
269                 .wValue        = Duration,\r
270                 .wIndex        = CDCInterfaceInfo->State.ControlInterfaceNumber,\r
271                 .wLength       = 0,\r
272         };\r
273 \r
274         Pipe_SelectPipe(PIPE_CONTROLPIPE);\r
275 \r
276         return USB_Host_SendControlRequest(NULL);\r
277 }\r
278 \r
279 uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
280                           const uint8_t* const Buffer,\r
281                           const uint16_t Length)\r
282 {\r
283         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
284           return PIPE_READYWAIT_DeviceDisconnected;\r
285 \r
286         uint8_t ErrorCode;\r
287 \r
288         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);\r
289 \r
290         Pipe_Unfreeze();\r
291         ErrorCode = Pipe_Write_Stream_LE(Buffer, Length, NULL);\r
292         Pipe_Freeze();\r
293 \r
294         return ErrorCode;\r
295 }\r
296 \r
297 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
298                             const char* const String)\r
299 {\r
300         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
301           return PIPE_READYWAIT_DeviceDisconnected;\r
302 \r
303         uint8_t ErrorCode;\r
304 \r
305         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);\r
306 \r
307         Pipe_Unfreeze();\r
308         ErrorCode = Pipe_Write_Stream_LE(String, strlen(String), NULL);\r
309         Pipe_Freeze();\r
310 \r
311         return ErrorCode;\r
312 }\r
313 \r
314 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
315                           const uint8_t Data)\r
316 {\r
317         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
318           return PIPE_READYWAIT_DeviceDisconnected;\r
319 \r
320         uint8_t ErrorCode;\r
321 \r
322         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);\r
323         Pipe_Unfreeze();\r
324 \r
325         if (!(Pipe_IsReadWriteAllowed()))\r
326         {\r
327                 Pipe_ClearOUT();\r
328 \r
329                 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)\r
330                   return ErrorCode;\r
331         }\r
332 \r
333         Pipe_Write_8(Data);\r
334         Pipe_Freeze();\r
335 \r
336         return PIPE_READYWAIT_NoError;\r
337 }\r
338 \r
339 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)\r
340 {\r
341         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
342           return 0;\r
343 \r
344         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipe.Address);\r
345         Pipe_Unfreeze();\r
346 \r
347         if (Pipe_IsINReceived())\r
348         {\r
349                 if (!(Pipe_BytesInPipe()))\r
350                 {\r
351                         Pipe_ClearIN();\r
352                         Pipe_Freeze();\r
353                         return 0;\r
354                 }\r
355                 else\r
356                 {\r
357                         Pipe_Freeze();\r
358                         return Pipe_BytesInPipe();\r
359                 }\r
360         }\r
361         else\r
362         {\r
363                 Pipe_Freeze();\r
364 \r
365                 return 0;\r
366         }\r
367 }\r
368 \r
369 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)\r
370 {\r
371         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
372           return -1;\r
373 \r
374         int16_t ReceivedByte = -1;\r
375 \r
376         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipe.Address);\r
377         Pipe_Unfreeze();\r
378 \r
379         if (Pipe_IsINReceived())\r
380         {\r
381                 if (Pipe_BytesInPipe())\r
382                   ReceivedByte = Pipe_Read_8();\r
383 \r
384                 if (!(Pipe_BytesInPipe()))\r
385                   Pipe_ClearIN();\r
386         }\r
387 \r
388         Pipe_Freeze();\r
389 \r
390         return ReceivedByte;\r
391 }\r
392 \r
393 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)\r
394 {\r
395         if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))\r
396           return PIPE_READYWAIT_DeviceDisconnected;\r
397 \r
398         uint8_t ErrorCode;\r
399 \r
400         Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipe.Address);\r
401         Pipe_Unfreeze();\r
402 \r
403         if (!(Pipe_BytesInPipe()))\r
404           return PIPE_READYWAIT_NoError;\r
405 \r
406         bool BankFull = !(Pipe_IsReadWriteAllowed());\r
407 \r
408         Pipe_ClearOUT();\r
409 \r
410         if (BankFull)\r
411         {\r
412                 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)\r
413                   return ErrorCode;\r
414 \r
415                 Pipe_ClearOUT();\r
416         }\r
417 \r
418         Pipe_Freeze();\r
419 \r
420         return PIPE_READYWAIT_NoError;\r
421 }\r
422 \r
423 #if defined(FDEV_SETUP_STREAM)\r
424 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
425                            FILE* const Stream)\r
426 {\r
427         *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);\r
428         fdev_set_udata(Stream, CDCInterfaceInfo);\r
429 }\r
430 \r
431 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,\r
432                                    FILE* const Stream)\r
433 {\r
434         *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);\r
435         fdev_set_udata(Stream, CDCInterfaceInfo);\r
436 }\r
437 \r
438 static int CDC_Host_putchar(char c,\r
439                             FILE* Stream)\r
440 {\r
441         return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;\r
442 }\r
443 \r
444 static int CDC_Host_getchar(FILE* Stream)\r
445 {\r
446         int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));\r
447 \r
448         if (ReceivedByte < 0)\r
449           return _FDEV_EOF;\r
450 \r
451         return ReceivedByte;\r
452 }\r
453 \r
454 static int CDC_Host_getchar_Blocking(FILE* Stream)\r
455 {\r
456         int16_t ReceivedByte;\r
457 \r
458         while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)\r
459         {\r
460                 if (USB_HostState == HOST_STATE_Unattached)\r
461                   return _FDEV_EOF;\r
462 \r
463                 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));\r
464                 USB_USBTask();\r
465         }\r
466 \r
467         return ReceivedByte;\r
468 }\r
469 #endif\r
470 \r
471 // cppcheck-suppress unusedFunction\r
472 void CDC_Host_Event_Stub(void)\r
473 {\r
474 \r
475 }\r
476 \r
477 #endif\r
478 \r