Add descriptor class, subclass and protocol constants to the class drivers, modify...
[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_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 CDC_Host_Flush(CDCInterfaceInfo);
230 }
231
232 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
233 {
234 USB_ControlRequest = (USB_Request_Header_t)
235 {
236 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
237 .bRequest = CDC_REQ_SetLineEncoding,
238 .wValue = 0,
239 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
240 .wLength = sizeof(CDCInterfaceInfo->State.LineEncoding),
241 };
242
243 Pipe_SelectPipe(PIPE_CONTROLPIPE);
244
245 return USB_Host_SendControlRequest(&CDCInterfaceInfo->State.LineEncoding);
246 }
247
248 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
249 {
250 USB_ControlRequest = (USB_Request_Header_t)
251 {
252 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
253 .bRequest = CDC_REQ_SetControlLineState,
254 .wValue = CDCInterfaceInfo->State.ControlLineStates.HostToDevice,
255 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
256 .wLength = 0,
257 };
258
259 Pipe_SelectPipe(PIPE_CONTROLPIPE);
260
261 return USB_Host_SendControlRequest(NULL);
262 }
263
264 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
265 const uint8_t Duration)
266 {
267 USB_ControlRequest = (USB_Request_Header_t)
268 {
269 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
270 .bRequest = CDC_REQ_SendBreak,
271 .wValue = Duration,
272 .wIndex = CDCInterfaceInfo->State.ControlInterfaceNumber,
273 .wLength = 0,
274 };
275
276 Pipe_SelectPipe(PIPE_CONTROLPIPE);
277
278 return USB_Host_SendControlRequest(NULL);
279 }
280
281 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
282 const char* const Data,
283 const uint16_t Length)
284 {
285 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
286 return PIPE_READYWAIT_DeviceDisconnected;
287
288 uint8_t ErrorCode;
289
290 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
291
292 Pipe_Unfreeze();
293 ErrorCode = Pipe_Write_Stream_LE(Data, Length, NO_STREAM_CALLBACK);
294 Pipe_Freeze();
295
296 return ErrorCode;
297 }
298
299 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
300 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 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
308 Pipe_Unfreeze();
309
310 if (!(Pipe_IsReadWriteAllowed()))
311 {
312 Pipe_ClearOUT();
313
314 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
315 return ErrorCode;
316 }
317
318 Pipe_Write_Byte(Data);
319 Pipe_Freeze();
320
321 return PIPE_READYWAIT_NoError;
322 }
323
324 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
325 {
326 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
327 return 0;
328
329 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
330 Pipe_Unfreeze();
331
332 if (Pipe_IsINReceived())
333 {
334 if (!(Pipe_BytesInPipe()))
335 {
336 Pipe_ClearIN();
337 Pipe_Freeze();
338 return 0;
339 }
340 else
341 {
342 Pipe_Freeze();
343 return Pipe_BytesInPipe();
344 }
345 }
346 else
347 {
348 Pipe_Freeze();
349
350 return 0;
351 }
352 }
353
354 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
355 {
356 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
357 return -1;
358
359 int16_t ReceivedByte = -1;
360
361 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataINPipeNumber);
362 Pipe_Unfreeze();
363
364 if (Pipe_IsINReceived())
365 {
366 if (Pipe_BytesInPipe())
367 ReceivedByte = Pipe_Read_Byte();
368
369 if (!(Pipe_BytesInPipe()))
370 Pipe_ClearIN();
371 }
372
373 Pipe_Freeze();
374
375 return ReceivedByte;
376 }
377
378 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo)
379 {
380 if ((USB_HostState != HOST_STATE_Configured) || !(CDCInterfaceInfo->State.IsActive))
381 return PIPE_READYWAIT_DeviceDisconnected;
382
383 uint8_t ErrorCode;
384
385 Pipe_SelectPipe(CDCInterfaceInfo->Config.DataOUTPipeNumber);
386 Pipe_Unfreeze();
387
388 if (!(Pipe_BytesInPipe()))
389 return PIPE_READYWAIT_NoError;
390
391 bool BankFull = !(Pipe_IsReadWriteAllowed());
392
393 Pipe_ClearOUT();
394
395 if (BankFull)
396 {
397 if ((ErrorCode = Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError)
398 return ErrorCode;
399
400 Pipe_ClearOUT();
401 }
402
403 Pipe_Freeze();
404
405 return PIPE_READYWAIT_NoError;
406 }
407
408 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
409 FILE* const Stream)
410 {
411 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar, _FDEV_SETUP_RW);
412 fdev_set_udata(Stream, CDCInterfaceInfo);
413 }
414
415 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t* const CDCInterfaceInfo,
416 FILE* const Stream)
417 {
418 *Stream = (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar, CDC_Host_getchar_Blocking, _FDEV_SETUP_RW);
419 fdev_set_udata(Stream, CDCInterfaceInfo);
420 }
421
422 static int CDC_Host_putchar(char c,
423 FILE* Stream)
424 {
425 return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream), c) ? _FDEV_ERR : 0;
426 }
427
428 static int CDC_Host_getchar(FILE* Stream)
429 {
430 int16_t ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
431
432 if (ReceivedByte < 0)
433 return _FDEV_EOF;
434
435 return ReceivedByte;
436 }
437
438 static int CDC_Host_getchar_Blocking(FILE* Stream)
439 {
440 int16_t ReceivedByte;
441
442 while ((ReceivedByte = CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream))) < 0)
443 {
444 if (USB_HostState == HOST_STATE_Unattached)
445 return _FDEV_EOF;
446
447 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t*)fdev_get_udata(Stream));
448 USB_USBTask();
449 }
450
451 return ReceivedByte;
452 }
453
454 void CDC_Host_Event_Stub(void)
455 {
456
457 }
458
459 #endif
460