3 Copyright (C) Dean Camera, 2010.
5 dean [at] fourwalledcubicle [dot] com
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
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.
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
31 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
35 #define __INCLUDE_FROM_CDC_DRIVER
36 #define __INCLUDE_FROM_CDC_HOST_C
39 uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
,
40 uint16_t ConfigDescriptorSize
,
41 void* ConfigDescriptorData
)
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
;
48 memset(&CDCInterfaceInfo
->State
, 0x00, sizeof(CDCInterfaceInfo
->State
));
50 if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
)
51 return CDC_ENUMERROR_InvalidConfigDescriptor
;
53 while (!(DataINEndpoint
) || !(DataOUTEndpoint
) || !(NotificationEndpoint
))
55 if (!(CDCControlInterface
) ||
56 USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
57 DCOMP_CDC_Host_NextCDCInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
)
59 if (NotificationEndpoint
)
61 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
62 DCOMP_CDC_Host_NextCDCDataInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
64 return CDC_ENUMERROR_NoCompatibleInterfaceFound
;
67 DataINEndpoint
= NULL
;
68 DataOUTEndpoint
= NULL
;
72 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
,
73 DCOMP_CDC_Host_NextCDCControlInterface
) != DESCRIPTOR_SEARCH_COMP_Found
)
75 return CDC_ENUMERROR_NoCompatibleInterfaceFound
;
78 CDCControlInterface
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
);
80 NotificationEndpoint
= NULL
;
86 USB_Descriptor_Endpoint_t
* EndpointData
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
);
88 if (EndpointData
->EndpointAddress
& ENDPOINT_DESCRIPTOR_DIR_IN
)
90 if ((EndpointData
->Attributes
& EP_TYPE_MASK
) == EP_TYPE_INTERRUPT
)
91 NotificationEndpoint
= EndpointData
;
93 DataINEndpoint
= EndpointData
;
97 DataOUTEndpoint
= EndpointData
;
101 for (uint8_t PipeNum
= 1; PipeNum
< PIPE_TOTAL_PIPES
; PipeNum
++)
106 uint8_t EndpointAddress
;
107 uint8_t InterruptPeriod
;
110 if (PipeNum
== CDCInterfaceInfo
->Config
.DataINPipeNumber
)
112 Size
= DataINEndpoint
->EndpointSize
;
113 EndpointAddress
= DataINEndpoint
->EndpointAddress
;
114 Token
= PIPE_TOKEN_IN
;
116 DoubleBanked
= CDCInterfaceInfo
->Config
.DataINPipeDoubleBank
;
119 CDCInterfaceInfo
->State
.DataINPipeSize
= DataINEndpoint
->EndpointSize
;
121 else if (PipeNum
== CDCInterfaceInfo
->Config
.DataOUTPipeNumber
)
123 Size
= DataOUTEndpoint
->EndpointSize
;
124 EndpointAddress
= DataOUTEndpoint
->EndpointAddress
;
125 Token
= PIPE_TOKEN_OUT
;
127 DoubleBanked
= CDCInterfaceInfo
->Config
.DataOUTPipeDoubleBank
;
130 CDCInterfaceInfo
->State
.DataOUTPipeSize
= DataOUTEndpoint
->EndpointSize
;
132 else if (PipeNum
== CDCInterfaceInfo
->Config
.NotificationPipeNumber
)
134 Size
= NotificationEndpoint
->EndpointSize
;
135 EndpointAddress
= NotificationEndpoint
->EndpointAddress
;
136 Token
= PIPE_TOKEN_IN
;
137 Type
= EP_TYPE_INTERRUPT
;
138 DoubleBanked
= CDCInterfaceInfo
->Config
.NotificationPipeDoubleBank
;
139 InterruptPeriod
= NotificationEndpoint
->PollingIntervalMS
;
141 CDCInterfaceInfo
->State
.NotificationPipeSize
= NotificationEndpoint
->EndpointSize
;
148 if (!(Pipe_ConfigurePipe(PipeNum
, Type
, Token
, EndpointAddress
, Size
,
149 DoubleBanked ? PIPE_BANK_DOUBLE
: PIPE_BANK_SINGLE
)))
151 return CDC_ENUMERROR_PipeConfigurationFailed
;
155 Pipe_SetInterruptPeriod(InterruptPeriod
);
158 CDCInterfaceInfo
->State
.ControlInterfaceNumber
= CDCControlInterface
->InterfaceNumber
;
159 CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice
= (CDC_CONTROL_LINE_OUT_RTS
| CDC_CONTROL_LINE_OUT_DTR
);
160 CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
= (CDC_CONTROL_LINE_IN_DCD
| CDC_CONTROL_LINE_IN_DSR
);
161 CDCInterfaceInfo
->State
.IsActive
= true;
163 return CDC_ENUMERROR_NoError
;
166 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor
)
168 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
170 if (Header
->Type
== DTYPE_Interface
)
172 USB_Descriptor_Interface_t
* Interface
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
);
174 if ((Interface
->Class
== CDC_CSCP_CDCClass
) &&
175 (Interface
->SubClass
== CDC_CSCP_ACMSubclass
) &&
176 (Interface
->Protocol
== CDC_CSCP_ATCommandProtocol
))
178 return DESCRIPTOR_SEARCH_Found
;
182 return DESCRIPTOR_SEARCH_NotFound
;
185 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor
)
187 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
189 if (Header
->Type
== DTYPE_Interface
)
191 USB_Descriptor_Interface_t
* Interface
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
);
193 if ((Interface
->Class
== CDC_CSCP_CDCDataClass
) &&
194 (Interface
->SubClass
== CDC_CSCP_NoDataSubclass
) &&
195 (Interface
->Protocol
== CDC_CSCP_NoDataProtocol
))
197 return DESCRIPTOR_SEARCH_Found
;
201 return DESCRIPTOR_SEARCH_NotFound
;
204 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor
)
206 USB_Descriptor_Header_t
* Header
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
);
208 if (Header
->Type
== DTYPE_Endpoint
)
210 USB_Descriptor_Endpoint_t
* Endpoint
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
);
212 uint8_t EndpointType
= (Endpoint
->Attributes
& EP_TYPE_MASK
);
214 if (((EndpointType
== EP_TYPE_BULK
) || (EndpointType
== EP_TYPE_INTERRUPT
)) &&
215 !(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
)))
217 return DESCRIPTOR_SEARCH_Found
;
220 else if (Header
->Type
== DTYPE_Interface
)
222 return DESCRIPTOR_SEARCH_Fail
;
225 return DESCRIPTOR_SEARCH_NotFound
;
228 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)
230 if ((USB_HostState
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
))
233 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.NotificationPipeNumber
);
236 if (Pipe_IsINReceived())
238 USB_Request_Header_t Notification
;
239 Pipe_Read_Stream_LE(&Notification
, sizeof(USB_Request_Header_t
), NO_STREAM_CALLBACK
);
241 if ((Notification
.bRequest
== CDC_NOTIF_SerialState
) &&
242 (Notification
.bmRequestType
== (REQDIR_DEVICETOHOST
| REQTYPE_CLASS
| REQREC_INTERFACE
)))
244 Pipe_Read_Stream_LE(&CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
,
245 sizeof(CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
),
250 EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo
);
260 #if !defined(NO_CLASS_DRIVER_AUTOFLUSH)
261 CDC_Host_Flush(CDCInterfaceInfo
);
265 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)
267 USB_ControlRequest
= (USB_Request_Header_t
)
269 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
270 .bRequest
= CDC_REQ_SetLineEncoding
,
272 .wIndex
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
,
273 .wLength
= sizeof(CDCInterfaceInfo
->State
.LineEncoding
),
276 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
278 return USB_Host_SendControlRequest(&CDCInterfaceInfo
->State
.LineEncoding
);
281 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)
283 USB_ControlRequest
= (USB_Request_Header_t
)
285 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
286 .bRequest
= CDC_REQ_SetControlLineState
,
287 .wValue
= CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice
,
288 .wIndex
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
,
292 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
294 return USB_Host_SendControlRequest(NULL
);
297 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
,
298 const uint8_t Duration
)
300 USB_ControlRequest
= (USB_Request_Header_t
)
302 .bmRequestType
= (REQDIR_HOSTTODEVICE
| REQTYPE_CLASS
| REQREC_INTERFACE
),
303 .bRequest
= CDC_REQ_SendBreak
,
305 .wIndex
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
,
309 Pipe_SelectPipe(PIPE_CONTROLPIPE
);
311 return USB_Host_SendControlRequest(NULL
);
314 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
,
315 const char* const Data
,
316 const uint16_t Length
)
318 if ((USB_HostState
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
))
319 return PIPE_READYWAIT_DeviceDisconnected
;
323 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
);
326 ErrorCode
= Pipe_Write_Stream_LE(Data
, Length
, NO_STREAM_CALLBACK
);
332 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
,
335 if ((USB_HostState
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
))
336 return PIPE_READYWAIT_DeviceDisconnected
;
340 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
);
343 if (!(Pipe_IsReadWriteAllowed()))
347 if ((ErrorCode
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
)
351 Pipe_Write_Byte(Data
);
354 return PIPE_READYWAIT_NoError
;
357 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)
359 if ((USB_HostState
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
))
362 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipeNumber
);
365 if (Pipe_IsINReceived())
367 if (!(Pipe_BytesInPipe()))
376 return Pipe_BytesInPipe();
387 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)
389 if ((USB_HostState
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
))
392 int16_t ReceivedByte
= -1;
394 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipeNumber
);
397 if (Pipe_IsINReceived())
399 if (Pipe_BytesInPipe())
400 ReceivedByte
= Pipe_Read_Byte();
402 if (!(Pipe_BytesInPipe()))
411 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)
413 if ((USB_HostState
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
))
414 return PIPE_READYWAIT_DeviceDisconnected
;
418 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
);
421 if (!(Pipe_BytesInPipe()))
422 return PIPE_READYWAIT_NoError
;
424 bool BankFull
= !(Pipe_IsReadWriteAllowed());
430 if ((ErrorCode
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
)
438 return PIPE_READYWAIT_NoError
;
441 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
,
444 *Stream
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar
, _FDEV_SETUP_RW
);
445 fdev_set_udata(Stream
, CDCInterfaceInfo
);
448 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
,
451 *Stream
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar_Blocking
, _FDEV_SETUP_RW
);
452 fdev_set_udata(Stream
, CDCInterfaceInfo
);
455 static int CDC_Host_putchar(char c
,
458 return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
), c
) ? _FDEV_ERR
: 0;
461 static int CDC_Host_getchar(FILE* Stream
)
463 int16_t ReceivedByte
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
));
465 if (ReceivedByte
< 0)
471 static int CDC_Host_getchar_Blocking(FILE* Stream
)
473 int16_t ReceivedByte
;
475 while ((ReceivedByte
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
))) < 0)
477 if (USB_HostState
== HOST_STATE_Unattached
)
480 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
));
487 void CDC_Host_Event_Stub(void)