3      Copyright (C) Dean Camera, 2011. 
   5   dean [at] fourwalledcubicle [dot] com 
  10   Copyright 2011  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 
  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_DESCRIPTOR_DIR_IN
) 
  91                         if ((EndpointData
->Attributes 
& EP_TYPE_MASK
) == EP_TYPE_INTERRUPT
) 
  92                           NotificationEndpoint 
= EndpointData
; 
  94                           DataINEndpoint 
= EndpointData
; 
  98                         DataOUTEndpoint 
= EndpointData
; 
 102         for (uint8_t PipeNum 
= 1; PipeNum 
< PIPE_TOTAL_PIPES
; PipeNum
++) 
 107                 uint8_t  EndpointAddress
; 
 108                 uint8_t  InterruptPeriod
; 
 111                 if (PipeNum 
== CDCInterfaceInfo
->Config
.DataINPipeNumber
) 
 113                         Size            
= DataINEndpoint
->EndpointSize
; 
 114                         EndpointAddress 
= DataINEndpoint
->EndpointAddress
; 
 115                         Token           
= PIPE_TOKEN_IN
; 
 117                         DoubleBanked    
= CDCInterfaceInfo
->Config
.DataINPipeDoubleBank
; 
 120                         CDCInterfaceInfo
->State
.DataINPipeSize 
= DataINEndpoint
->EndpointSize
; 
 122                 else if (PipeNum 
== CDCInterfaceInfo
->Config
.DataOUTPipeNumber
) 
 124                         Size            
= DataOUTEndpoint
->EndpointSize
; 
 125                         EndpointAddress 
= DataOUTEndpoint
->EndpointAddress
; 
 126                         Token           
= PIPE_TOKEN_OUT
; 
 128                         DoubleBanked    
= CDCInterfaceInfo
->Config
.DataOUTPipeDoubleBank
; 
 131                         CDCInterfaceInfo
->State
.DataOUTPipeSize 
= DataOUTEndpoint
->EndpointSize
; 
 133                 else if (PipeNum 
== CDCInterfaceInfo
->Config
.NotificationPipeNumber
) 
 135                         Size            
= NotificationEndpoint
->EndpointSize
; 
 136                         EndpointAddress 
= NotificationEndpoint
->EndpointAddress
; 
 137                         Token           
= PIPE_TOKEN_IN
; 
 138                         Type            
= EP_TYPE_INTERRUPT
; 
 139                         DoubleBanked    
= CDCInterfaceInfo
->Config
.NotificationPipeDoubleBank
; 
 140                         InterruptPeriod 
= NotificationEndpoint
->PollingIntervalMS
; 
 142                         CDCInterfaceInfo
->State
.NotificationPipeSize 
= NotificationEndpoint
->EndpointSize
; 
 149                 if (!(Pipe_ConfigurePipe(PipeNum
, Type
, Token
, EndpointAddress
, Size
, 
 150                                          DoubleBanked ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
))) 
 152                         return CDC_ENUMERROR_PipeConfigurationFailed
; 
 156                   Pipe_SetInterruptPeriod(InterruptPeriod
); 
 159         CDCInterfaceInfo
->State
.ControlInterfaceNumber 
= CDCControlInterface
->InterfaceNumber
; 
 160         CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice 
= (CDC_CONTROL_LINE_OUT_RTS 
| CDC_CONTROL_LINE_OUT_DTR
); 
 161         CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost 
= (CDC_CONTROL_LINE_IN_DCD  
| CDC_CONTROL_LINE_IN_DSR
); 
 162         CDCInterfaceInfo
->State
.IsActive 
= true; 
 164         return CDC_ENUMERROR_NoError
; 
 167 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor
) 
 169         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 171         if (Header
->Type 
== DTYPE_Interface
) 
 173                 USB_Descriptor_Interface_t
* Interface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
); 
 175                 if ((Interface
->Class    
== CDC_CSCP_CDCClass
)    && 
 176                     (Interface
->SubClass 
== CDC_CSCP_ACMSubclass
) && 
 177                     (Interface
->Protocol 
== CDC_CSCP_ATCommandProtocol
)) 
 179                         return DESCRIPTOR_SEARCH_Found
; 
 183         return DESCRIPTOR_SEARCH_NotFound
; 
 186 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor
) 
 188         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 190         if (Header
->Type 
== DTYPE_Interface
) 
 192                 USB_Descriptor_Interface_t
* Interface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
); 
 194                 if ((Interface
->Class    
== CDC_CSCP_CDCDataClass
)   && 
 195                     (Interface
->SubClass 
== CDC_CSCP_NoDataSubclass
) && 
 196                     (Interface
->Protocol 
== CDC_CSCP_NoDataProtocol
)) 
 198                         return DESCRIPTOR_SEARCH_Found
; 
 202         return DESCRIPTOR_SEARCH_NotFound
; 
 205 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor
) 
 207         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 209         if (Header
->Type 
== DTYPE_Endpoint
) 
 211                 USB_Descriptor_Endpoint_t
* Endpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
); 
 213                 uint8_t EndpointType 
= (Endpoint
->Attributes 
& EP_TYPE_MASK
); 
 215                 if (((EndpointType 
== EP_TYPE_BULK
) || (EndpointType 
== EP_TYPE_INTERRUPT
)) && 
 216                     !(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
))) 
 218                         return DESCRIPTOR_SEARCH_Found
; 
 221         else if (Header
->Type 
== DTYPE_Interface
) 
 223                 return DESCRIPTOR_SEARCH_Fail
; 
 226         return DESCRIPTOR_SEARCH_NotFound
; 
 229 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 231         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 234         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.NotificationPipeNumber
); 
 237         if (Pipe_IsINReceived()) 
 239                 USB_Request_Header_t Notification
; 
 240                 Pipe_Read_Stream_LE(&Notification
, sizeof(USB_Request_Header_t
), NULL
); 
 242                 if ((Notification
.bRequest      
== CDC_NOTIF_SerialState
) && 
 243                     (Notification
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
))) 
 245                         Pipe_Read_Stream_LE(&CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
, 
 246                                             sizeof(CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
), 
 251                         EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo
); 
 261         #if !defined(NO_CLASS_DRIVER_AUTOFLUSH) 
 262         CDC_Host_Flush(CDCInterfaceInfo
); 
 266 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 268         USB_ControlRequest 
= (USB_Request_Header_t
) 
 270                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 271                 .bRequest      
= CDC_REQ_SetLineEncoding
, 
 273                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 274                 .wLength       
= sizeof(CDCInterfaceInfo
->State
.LineEncoding
), 
 277         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 279         return USB_Host_SendControlRequest(&CDCInterfaceInfo
->State
.LineEncoding
); 
 282 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 284         USB_ControlRequest 
= (USB_Request_Header_t
) 
 286                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 287                 .bRequest      
= CDC_REQ_SetControlLineState
, 
 288                 .wValue        
= CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice
, 
 289                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 293         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 295         return USB_Host_SendControlRequest(NULL
); 
 298 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 299                            const uint8_t Duration
) 
 301         USB_ControlRequest 
= (USB_Request_Header_t
) 
 303                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 304                 .bRequest      
= CDC_REQ_SendBreak
, 
 306                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 310         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 312         return USB_Host_SendControlRequest(NULL
); 
 315 uint8_t CDC_Host_SendData(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 316                           const uint8_t* const Buffer
, 
 317                           const uint16_t Length
) 
 319         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 320           return PIPE_READYWAIT_DeviceDisconnected
; 
 324         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 327         ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, Length
, NULL
); 
 333 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 334                             const char* const String
) 
 336         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 337           return PIPE_READYWAIT_DeviceDisconnected
; 
 341         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 344         ErrorCode 
= Pipe_Write_Stream_LE(String
, strlen(String
), NULL
); 
 350 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 353         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 354           return PIPE_READYWAIT_DeviceDisconnected
; 
 358         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 361         if (!(Pipe_IsReadWriteAllowed())) 
 365                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 369         Pipe_Write_Byte(Data
); 
 372         return PIPE_READYWAIT_NoError
; 
 375 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 377         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 380         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipeNumber
); 
 383         if (Pipe_IsINReceived()) 
 385                 if (!(Pipe_BytesInPipe())) 
 394                         return Pipe_BytesInPipe(); 
 405 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 407         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 410         int16_t ReceivedByte 
= -1; 
 412         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipeNumber
); 
 415         if (Pipe_IsINReceived()) 
 417                 if (Pipe_BytesInPipe()) 
 418                   ReceivedByte 
= Pipe_Read_Byte(); 
 420                 if (!(Pipe_BytesInPipe())) 
 429 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 431         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 432           return PIPE_READYWAIT_DeviceDisconnected
; 
 436         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 439         if (!(Pipe_BytesInPipe())) 
 440           return PIPE_READYWAIT_NoError
; 
 442         bool BankFull 
= !(Pipe_IsReadWriteAllowed()); 
 448                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 456         return PIPE_READYWAIT_NoError
; 
 459 #if defined(FDEV_SETUP_STREAM) 
 460 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 463         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar
, _FDEV_SETUP_RW
); 
 464         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 467 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 470         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar_Blocking
, _FDEV_SETUP_RW
); 
 471         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 474 static int CDC_Host_putchar(char c
, 
 477         return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
), c
) ? _FDEV_ERR 
: 0; 
 480 static int CDC_Host_getchar(FILE* Stream
) 
 482         int16_t ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 484         if (ReceivedByte 
< 0) 
 490 static int CDC_Host_getchar_Blocking(FILE* Stream
) 
 492         int16_t ReceivedByte
; 
 494         while ((ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
))) < 0) 
 496                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 499                 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 507 void CDC_Host_Event_Stub(void)