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 "../../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)