3      Copyright (C) Dean Camera, 2010. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2010  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
++) 
 103                 if (PipeNum 
== CDCInterfaceInfo
->Config
.DataINPipeNumber
) 
 105                         Pipe_ConfigurePipe(PipeNum
, EP_TYPE_BULK
, PIPE_TOKEN_IN
, 
 106                                            DataINEndpoint
->EndpointAddress
, DataINEndpoint
->EndpointSize
, 
 107                                            CDCInterfaceInfo
->Config
.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
 109                         CDCInterfaceInfo
->State
.DataINPipeSize 
= DataINEndpoint
->EndpointSize
; 
 111                 else if (PipeNum 
== CDCInterfaceInfo
->Config
.DataOUTPipeNumber
) 
 113                         Pipe_ConfigurePipe(PipeNum
, EP_TYPE_BULK
, PIPE_TOKEN_OUT
, 
 114                                            DataOUTEndpoint
->EndpointAddress
, DataOUTEndpoint
->EndpointSize
, 
 115                                            CDCInterfaceInfo
->Config
.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
 117                         CDCInterfaceInfo
->State
.DataOUTPipeSize 
= DataOUTEndpoint
->EndpointSize
; 
 119                 else if (PipeNum 
== CDCInterfaceInfo
->Config
.NotificationPipeNumber
) 
 121                         Pipe_ConfigurePipe(PipeNum
, EP_TYPE_INTERRUPT
, PIPE_TOKEN_IN
, 
 122                                            NotificationEndpoint
->EndpointAddress
, NotificationEndpoint
->EndpointSize
, 
 123                                            CDCInterfaceInfo
->Config
.NotificationPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
 124                         Pipe_SetInterruptPeriod(NotificationEndpoint
->PollingIntervalMS
); 
 126                         CDCInterfaceInfo
->State
.NotificationPipeSize 
= NotificationEndpoint
->EndpointSize
; 
 130         CDCInterfaceInfo
->State
.ControlInterfaceNumber 
= CDCControlInterface
->InterfaceNumber
; 
 131         CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice 
= (CDC_CONTROL_LINE_OUT_RTS 
| CDC_CONTROL_LINE_OUT_DTR
); 
 132         CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost 
= (CDC_CONTROL_LINE_IN_DCD  
| CDC_CONTROL_LINE_IN_DSR
); 
 133         CDCInterfaceInfo
->State
.IsActive 
= true; 
 135         return CDC_ENUMERROR_NoError
; 
 138 static uint8_t DCOMP_CDC_Host_NextCDCControlInterface(void* const CurrentDescriptor
) 
 140         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 142                 USB_Descriptor_Interface_t
* CurrentInterface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 143                                                                                 USB_Descriptor_Interface_t
); 
 145                 if ((CurrentInterface
->Class    
== CDC_CSCP_CDCClass
)    && 
 146                     (CurrentInterface
->SubClass 
== CDC_CSCP_ACMSubclass
) && 
 147                     (CurrentInterface
->Protocol 
== CDC_CSCP_ATCommandProtocol
)) 
 149                         return DESCRIPTOR_SEARCH_Found
; 
 153         return DESCRIPTOR_SEARCH_NotFound
; 
 156 static uint8_t DCOMP_CDC_Host_NextCDCDataInterface(void* const CurrentDescriptor
) 
 158         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 160                 USB_Descriptor_Interface_t
* CurrentInterface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 161                                                                                 USB_Descriptor_Interface_t
); 
 163                 if ((CurrentInterface
->Class    
== CDC_CSCP_CDCDataClass
)   && 
 164                     (CurrentInterface
->SubClass 
== CDC_CSCP_NoDataSubclass
) && 
 165                     (CurrentInterface
->Protocol 
== CDC_CSCP_NoDataProtocol
)) 
 167                         return DESCRIPTOR_SEARCH_Found
; 
 171         return DESCRIPTOR_SEARCH_NotFound
; 
 174 static uint8_t DCOMP_CDC_Host_NextCDCInterfaceEndpoint(void* const CurrentDescriptor
) 
 176         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
) 
 178                 USB_Descriptor_Endpoint_t
* CurrentEndpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 179                                                                               USB_Descriptor_Endpoint_t
); 
 181                 uint8_t EndpointType 
= (CurrentEndpoint
->Attributes 
& EP_TYPE_MASK
); 
 183                 if (((EndpointType 
== EP_TYPE_BULK
) || (EndpointType 
== EP_TYPE_INTERRUPT
)) && 
 184                     !(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
))) 
 186                         return DESCRIPTOR_SEARCH_Found
; 
 189         else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 191                 return DESCRIPTOR_SEARCH_Fail
; 
 194         return DESCRIPTOR_SEARCH_NotFound
; 
 197 void CDC_Host_USBTask(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 199         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 202         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.NotificationPipeNumber
); 
 205         if (Pipe_IsINReceived()) 
 207                 USB_Request_Header_t Notification
; 
 208                 Pipe_Read_Stream_LE(&Notification
, sizeof(USB_Request_Header_t
), NO_STREAM_CALLBACK
); 
 210                 if ((Notification
.bRequest      
== CDC_NOTIF_SerialState
) && 
 211                     (Notification
.bmRequestType 
== (REQDIR_DEVICETOHOST 
| REQTYPE_CLASS 
| REQREC_INTERFACE
))) 
 213                         Pipe_Read_Stream_LE(&CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
, 
 214                                             sizeof(CDCInterfaceInfo
->State
.ControlLineStates
.DeviceToHost
), 
 219                         EVENT_CDC_Host_ControLineStateChanged(CDCInterfaceInfo
); 
 229         CDC_Host_Flush(CDCInterfaceInfo
); 
 232 uint8_t CDC_Host_SetLineEncoding(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 234         USB_ControlRequest 
= (USB_Request_Header_t
) 
 236                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 237                 .bRequest      
= CDC_REQ_SetLineEncoding
, 
 239                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 240                 .wLength       
= sizeof(CDCInterfaceInfo
->State
.LineEncoding
), 
 243         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 245         return USB_Host_SendControlRequest(&CDCInterfaceInfo
->State
.LineEncoding
); 
 248 uint8_t CDC_Host_SendControlLineStateChange(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 250         USB_ControlRequest 
= (USB_Request_Header_t
) 
 252                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 253                 .bRequest      
= CDC_REQ_SetControlLineState
, 
 254                 .wValue        
= CDCInterfaceInfo
->State
.ControlLineStates
.HostToDevice
, 
 255                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 259         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 261         return USB_Host_SendControlRequest(NULL
); 
 264 uint8_t CDC_Host_SendBreak(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 265                            const uint8_t Duration
) 
 267         USB_ControlRequest 
= (USB_Request_Header_t
) 
 269                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 270                 .bRequest      
= CDC_REQ_SendBreak
, 
 272                 .wIndex        
= CDCInterfaceInfo
->State
.ControlInterfaceNumber
, 
 276         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 278         return USB_Host_SendControlRequest(NULL
); 
 281 uint8_t CDC_Host_SendString(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 282                             const char* const Data
, 
 283                             const uint16_t Length
) 
 285         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 286           return PIPE_READYWAIT_DeviceDisconnected
; 
 290         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 293         ErrorCode 
= Pipe_Write_Stream_LE(Data
, Length
, NO_STREAM_CALLBACK
); 
 299 uint8_t CDC_Host_SendByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 302         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 303           return PIPE_READYWAIT_DeviceDisconnected
; 
 307         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 310         if (!(Pipe_IsReadWriteAllowed())) 
 314                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 318         Pipe_Write_Byte(Data
); 
 321         return PIPE_READYWAIT_NoError
; 
 324 uint16_t CDC_Host_BytesReceived(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 326         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 329         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipeNumber
); 
 332         if (Pipe_IsINReceived()) 
 334                 if (!(Pipe_BytesInPipe())) 
 343                         return Pipe_BytesInPipe(); 
 354 int16_t CDC_Host_ReceiveByte(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 356         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 359         int16_t ReceivedByte 
= -1; 
 361         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataINPipeNumber
); 
 364         if (Pipe_IsINReceived()) 
 366                 if (Pipe_BytesInPipe()) 
 367                   ReceivedByte 
= Pipe_Read_Byte(); 
 369                 if (!(Pipe_BytesInPipe())) 
 378 uint8_t CDC_Host_Flush(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
) 
 380         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(CDCInterfaceInfo
->State
.IsActive
)) 
 381           return PIPE_READYWAIT_DeviceDisconnected
; 
 385         Pipe_SelectPipe(CDCInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 388         if (!(Pipe_BytesInPipe())) 
 389           return PIPE_READYWAIT_NoError
; 
 391         bool BankFull 
= !(Pipe_IsReadWriteAllowed()); 
 397                 if ((ErrorCode 
= Pipe_WaitUntilReady()) != PIPE_READYWAIT_NoError
) 
 405         return PIPE_READYWAIT_NoError
; 
 408 void CDC_Host_CreateStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 411         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar
, _FDEV_SETUP_RW
); 
 412         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 415 void CDC_Host_CreateBlockingStream(USB_ClassInfo_CDC_Host_t
* const CDCInterfaceInfo
, 
 418         *Stream 
= (FILE)FDEV_SETUP_STREAM(CDC_Host_putchar
, CDC_Host_getchar_Blocking
, _FDEV_SETUP_RW
); 
 419         fdev_set_udata(Stream
, CDCInterfaceInfo
); 
 422 static int CDC_Host_putchar(char c
, 
 425         return CDC_Host_SendByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
), c
) ? _FDEV_ERR 
: 0; 
 428 static int CDC_Host_getchar(FILE* Stream
) 
 430         int16_t ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 432         if (ReceivedByte 
< 0) 
 438 static int CDC_Host_getchar_Blocking(FILE* Stream
) 
 440         int16_t ReceivedByte
; 
 442         while ((ReceivedByte 
= CDC_Host_ReceiveByte((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
))) < 0) 
 444                 if (USB_HostState 
== HOST_STATE_Unattached
) 
 447                 CDC_Host_USBTask((USB_ClassInfo_CDC_Host_t
*)fdev_get_udata(Stream
)); 
 454 void CDC_Host_Event_Stub(void)