3      Copyright (C) Dean Camera, 2012. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2012  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 "../../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))) 
 117         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo
->Config
.DataOUTPipe
, 1))) 
 120         if (!(Pipe_ConfigurePipeTable(&CDCInterfaceInfo
->Config
.NotificationPipe
, 1))) 
 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 uint8_t* 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_SendString(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 298                             const char* const String
) 
 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(String
, strlen(String
), NULL
); 
 314 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 317         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 318           return PIPE_READYWAIT_DeviceDisconnected
; 
 322         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 325         if (!(Pipe_IsReadWriteAllowed())) 
 329                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 336         return PIPE_READYWAIT_NoError
; 
 339 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 341         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 344         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipe
.Address
); 
 347         if (Pipe_IsINReceived()) 
 349                 if (!(Pipe_BytesInPipe())) 
 358                         return Pipe_BytesInPipe(); 
 369 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 371         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 374         int16_t ReceivedByte 
= -1; 
 376         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipe
.Address
); 
 379         if (Pipe_IsINReceived()) 
 381                 if (Pipe_BytesInPipe()) 
 382                   ReceivedByte 
= Pipe_Read_8(); 
 384                 if (!(Pipe_BytesInPipe())) 
 393 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 395         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 396           return PIPE_READYWAIT_DeviceDisconnected
; 
 400         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipe
.Address
); 
 403         if (!(Pipe_BytesInPipe())) 
 404           return PIPE_READYWAIT_NoError
; 
 406         bool BankFull 
= !(Pipe_IsReadWriteAllowed()); 
 412                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 420         return PIPE_READYWAIT_NoError
; 
 423 #if defined(FDEV_SETUP_STREAM) 
 424 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 427         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar
, _FDEV_SETUP_RW
); 
 428         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 431 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 434         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar_Blocking
, _FDEV_SETUP_RW
); 
 435         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 438 static int CDC_Host_putchar(char c
, 
 441         return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
), c
) ? _FDEV_ERR 
: 0; 
 444 static int CDC_Host_getchar(FILE* Stream
) 
 446         int16_t ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 448         if (ReceivedByte 
< 0) 
 454 static int CDC_Host_getchar_Blocking(FILE* Stream
) 
 456         int16_t ReceivedByte
; 
 458         while ((ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
))) < 0) 
 460                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 463                 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 471 // cppcheck-suppress unusedFunction 
 472 void CDC_Host_Event_Stub(void)