3      Copyright (C) Dean Camera, 2020. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2020  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_SendString(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 280                             const char* const String
) 
 282         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 283           return PIPE_READYWAIT_DeviceDisconnected
; 
 287         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 290         ErrorCode 
= Pipe_Write_Stream_LE(String
, strlen(String
), NULL
); 
 296 uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 297                           const void* const Buffer
, 
 298                           const uint16_t Length
) 
 300         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 301           return PIPE_READYWAIT_DeviceDisconnected
; 
 305         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 308         ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, Length
, NULL
); 
 314 #if defined(ARCH_HAS_FLASH_ADDRESS_SPACE) 
 315         uint8_t CDC_Host_SendString_P(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_PStream_LE(String
, strlen_P(String
), NULL
); 
 332         uint8_t CDC_Host_SendData_P(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 333                                     const void* const Buffer
, 
 334                                     const uint16_t Length
) 
 336                 if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 337                   return PIPE_READYWAIT_DeviceDisconnected
; 
 341                 Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 344                 ErrorCode 
= Pipe_Write_PStream_LE(Buffer
, Length
, NULL
); 
 351 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 354         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 355           return PIPE_READYWAIT_DeviceDisconnected
; 
 359         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 362         if (!(Pipe_IsReadWriteAllowed())) 
 366                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 373         return PIPE_READYWAIT_NoError
; 
 376 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 378         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 381         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipe
.Address
); 
 384         if (Pipe_IsINReceived()) 
 386                 if (!(Pipe_BytesInPipe())) 
 395                         return Pipe_BytesInPipe(); 
 406 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 408         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 411         int16_t ReceivedByte 
= -1; 
 413         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipe
.Address
); 
 416         if (Pipe_IsINReceived()) 
 418                 if (Pipe_BytesInPipe()) 
 419                   ReceivedByte 
= Pipe_Read_8(); 
 421                 if (!(Pipe_BytesInPipe())) 
 430 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 432         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 433           return PIPE_READYWAIT_DeviceDisconnected
; 
 437         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 440         if (!(Pipe_BytesInPipe())) 
 441           return PIPE_READYWAIT_NoError
; 
 443         bool BankFull 
= !(Pipe_IsReadWriteAllowed()); 
 449                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 457         return PIPE_READYWAIT_NoError
; 
 460 #if defined(FDEV_SETUP_STREAM) 
 461         void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 464                 *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar
, _FDEV_SETUP_RW
); 
 465                 fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 468         void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 471                 *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar_Blocking
, _FDEV_SETUP_RW
); 
 472                 fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 475         static int CDC_Host_putchar(char c
, 
 478                 return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
), c
) ? _FDEV_ERR 
: 0; 
 481         static int CDC_Host_getchar(FILE* Stream
) 
 483                 int16_t ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 485                 if (ReceivedByte 
< 0) 
 491         static int CDC_Host_getchar_Blocking(FILE* Stream
) 
 493                 int16_t ReceivedByte
; 
 495                 while ((ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
))) < 0) 
 497                         if (USB_HostState 
== HOST_STATE_Unattached
) 
 500                         CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 508 void CDC_Host_Event_Stub(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
)