3      Copyright (C) Dean Camera, 2015. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2015  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 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 
  31 #define  __INCLUDE_FROM_USB_DRIVER 
  32 #include "../../Core/USBMode.h" 
  34 #if defined(USB_CAN_BE_HOST) 
  36 #define  __INCLUDE_FROM_CDC_DRIVER 
  37 #define  __INCLUDE_FROM_CDC_HOST_C 
  38 #include "CDCClassHost.h" 
  40 uint8_t CDC_Host_ConfigurePipes(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
  41                                 uint16_t ConfigDescriptorSize
, 
  42                                 void* ConfigDescriptorData
) 
  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
; 
  49         memset(&CDCInterfaceInfo
->State
, 0x00, sizeof(CDCInterfaceInfo
->State
)); 
  51         if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
) 
  52           return CDC_ENUMERROR_InvalidConfigDescriptor
; 
  54         while (!(DataINEndpoint
) || !(DataOUTEndpoint
) || !(NotificationEndpoint
)) 
  56                 if (!(CDCControlInterface
) || 
  57                     USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  58                                               DCOMP_CDC_Host_NextCDCInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  60                         if (NotificationEndpoint
) 
  62                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  63                                                               DCOMP_CDC_Host_NextCDCDataInterface
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  65                                         return CDC_ENUMERROR_NoCompatibleInterfaceFound
; 
  68                                 DataINEndpoint  
= NULL
; 
  69                                 DataOUTEndpoint 
= NULL
; 
  73                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  74                                                               DCOMP_CDC_Host_NextCDCControlInterface
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  76                                         return CDC_ENUMERROR_NoCompatibleInterfaceFound
; 
  79                                 CDCControlInterface 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
); 
  81                                 NotificationEndpoint 
= NULL
; 
  87                 USB_Descriptor_Endpoint_t
* EndpointData 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
); 
  89                 if ((EndpointData
->EndpointAddress 
& ENDPOINT_DIR_MASK
) == ENDPOINT_DIR_IN
) 
  91                         if ((EndpointData
->Attributes 
& EP_TYPE_MASK
) == EP_TYPE_INTERRUPT
) 
  92                           NotificationEndpoint 
= EndpointData
; 
  94                           DataINEndpoint 
= EndpointData
; 
  98                         DataOUTEndpoint 
= EndpointData
; 
 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
; 
 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
; 
 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
; 
 114         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo
->Config
.DataINPipe
, 1))) 
 115           return CDC_ENUMERROR_PipeConfigurationFailed
; 
 117         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo
->Config
.DataOUTPipe
, 1))) 
 118           return CDC_ENUMERROR_PipeConfigurationFailed
; 
 120         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo
->Config
.NotificationPipe
, 1))) 
 121           return CDC_ENUMERROR_PipeConfigurationFailed
; 
 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; 
 128         return CDC_ENUMERROR_NoError
; 
 131 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor
) 
 133         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 135         if (Header
->Type 
== DTYPE_Interface
) 
 137                 USB_Descriptor_Interface_t
* Interface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
); 
 139                 if ((Interface
->Class    
== CDC_CSCP_CDCClass
)    && 
 140                     (Interface
->SubClass 
== CDC_CSCP_ACMSubclass
) && 
 141                     (Interface
->Protocol 
== CDC_CSCP_ATCommandProtocol
)) 
 143                         return DESCRIPTOR_SEARCH_Found
; 
 147         return DESCRIPTOR_SEARCH_NotFound
; 
 150 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor
) 
 152         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 154         if (Header
->Type 
== DTYPE_Interface
) 
 156                 USB_Descriptor_Interface_t
* Interface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
); 
 158                 if ((Interface
->Class    
== CDC_CSCP_CDCDataClass
)   && 
 159                     (Interface
->SubClass 
== CDC_CSCP_NoDataSubclass
) && 
 160                     (Interface
->Protocol 
== CDC_CSCP_NoDataProtocol
)) 
 162                         return DESCRIPTOR_SEARCH_Found
; 
 166         return DESCRIPTOR_SEARCH_NotFound
; 
 169 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor
) 
 171         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 173         if (Header
->Type 
== DTYPE_Endpoint
) 
 175                 USB_Descriptor_Endpoint_t
* Endpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
); 
 177                 uint8_t EndpointType 
= (Endpoint
->Attributes 
& EP_TYPE_MASK
); 
 179                 if (((EndpointType 
== EP_TYPE_BULK
) || (EndpointType 
== EP_TYPE_INTERRUPT
)) && 
 180                     !(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
))) 
 182                         return DESCRIPTOR_SEARCH_Found
; 
 185         else if (Header
->Type 
== DTYPE_Interface
) 
 187                 return DESCRIPTOR_SEARCH_Fail
; 
 190         return DESCRIPTOR_SEARCH_NotFound
; 
 193 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 195         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 198         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.NotificationPipe
.Address
); 
 201         if (Pipe_IsINReceived()) 
 203                 USB_Request_Header_t Notification
; 
 204                 Pipe_Read_Stream_LE(&Notification
, sizeof(USB_Request_Header_t
), NULL
); 
 206                 if ((Notification
.bRequest      
== CDC_NOTIF_SerialState
) && 
 207                     (Notification
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
))) 
 209                         Pipe_Read_Stream_LE(&CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
, 
 210                                             sizeof(CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
), 
 215                         EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo
); 
 225         #if !defined(NO_CLASS_DRIVER_AUTOFLUSH) 
 226         CDC_Host_Flush(CDCInterfaceInfo
); 
 230 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 232         USB_ControlRequest 
= (USB_Request_Header_t
) 
 234                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 235                 .bRequest      
= CDC_REQ_SetLineEncoding
, 
 237                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 238                 .wLength       
= sizeof(CDCInterfaceInfo
->State
.LineEncoding
), 
 241         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 243         return USB_Host_SendControlRequest(&CDCInterfaceInfo
->State
.LineEncoding
); 
 246 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 248         USB_ControlRequest 
= (USB_Request_Header_t
) 
 250                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 251                 .bRequest      
= CDC_REQ_SetControlLineState
, 
 252                 .wValue        
= CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice
, 
 253                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 257         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 259         return USB_Host_SendControlRequest(NULL
); 
 262 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 263                            const uint8_t Duration
) 
 265         USB_ControlRequest 
= (USB_Request_Header_t
) 
 267                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 268                 .bRequest      
= CDC_REQ_SendBreak
, 
 270                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 274         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 276         return USB_Host_SendControlRequest(NULL
); 
 279 uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 280                           const void* const Buffer
, 
 281                           const uint16_t Length
) 
 283         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 284           return PIPE_READYWAIT_DeviceDisconnected
; 
 288         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 291         ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, Length
, NULL
); 
 297 uint8_t CDC_Host_SendData_P(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 298                           const void* const Buffer
, 
 299                           const uint16_t Length
) 
 301         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 302           return PIPE_READYWAIT_DeviceDisconnected
; 
 306         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 309         ErrorCode 
= Pipe_Write_PStream_LE(Buffer
, Length
, NULL
); 
 315 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 316                             const char* const String
) 
 318         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 319           return PIPE_READYWAIT_DeviceDisconnected
; 
 323         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 326         ErrorCode 
= Pipe_Write_Stream_LE(String
, strlen(String
), NULL
); 
 332 uint8_t CDC_Host_SendString_P(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 333                             const char* const String
) 
 335         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 336           return PIPE_READYWAIT_DeviceDisconnected
; 
 340         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 343         ErrorCode 
= Pipe_Write_PStream_LE(String
, strlen_P(String
), NULL
); 
 349 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 352         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 353           return PIPE_READYWAIT_DeviceDisconnected
; 
 357         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 360         if (!(Pipe_IsReadWriteAllowed())) 
 364                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 371         return PIPE_READYWAIT_NoError
; 
 374 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 376         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 379         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipe
.Address
); 
 382         if (Pipe_IsINReceived()) 
 384                 if (!(Pipe_BytesInPipe())) 
 393                         return Pipe_BytesInPipe(); 
 404 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 406         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 409         int16_t ReceivedByte 
= -1; 
 411         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipe
.Address
); 
 414         if (Pipe_IsINReceived()) 
 416                 if (Pipe_BytesInPipe()) 
 417                   ReceivedByte 
= Pipe_Read_8(); 
 419                 if (!(Pipe_BytesInPipe())) 
 428 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 430         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 431           return PIPE_READYWAIT_DeviceDisconnected
; 
 435         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 438         if (!(Pipe_BytesInPipe())) 
 439           return PIPE_READYWAIT_NoError
; 
 441         bool BankFull 
= !(Pipe_IsReadWriteAllowed()); 
 447                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 455         return PIPE_READYWAIT_NoError
; 
 458 #if defined(FDEV_SETUP_STREAM) 
 459 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 462         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar
, _FDEV_SETUP_RW
); 
 463         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 466 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 469         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar_Blocking
, _FDEV_SETUP_RW
); 
 470         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 473 static int CDC_Host_putchar(char c
, 
 476         return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
), c
) ? _FDEV_ERR 
: 0; 
 479 static int CDC_Host_getchar(FILE* Stream
) 
 481         int16_t ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 483         if (ReceivedByte 
< 0) 
 489 static int CDC_Host_getchar_Blocking(FILE* Stream
) 
 491         int16_t ReceivedByte
; 
 493         while ((ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
))) < 0) 
 495                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 498                 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 506 void CDC_Host_Event_Stub(void)