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_HID_DRIVER 
  37 #define  __INCLUDE_FROM_HID_HOST_C 
  40 uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, 
  41                                 uint16_t ConfigDescriptorSize
, 
  42                                 void* ConfigDescriptorData
) 
  44         USB_Descriptor_Endpoint_t
*  DataINEndpoint  
= NULL
; 
  45         USB_Descriptor_Endpoint_t
*  DataOUTEndpoint 
= NULL
; 
  46         USB_Descriptor_Interface_t
* HIDInterface    
= NULL
; 
  47         USB_HID_Descriptor_HID_t
*   HIDDescriptor   
= NULL
; 
  49         memset(&HIDInterfaceInfo
->State
, 0x00, sizeof(HIDInterfaceInfo
->State
)); 
  51         if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
) 
  52           return HID_ENUMERROR_InvalidConfigDescriptor
; 
  54         while (!(DataINEndpoint
) || !(DataOUTEndpoint
)) 
  56                 if (!(HIDInterface
) || 
  57                     USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  58                                               DCOMP_HID_Host_NextHIDInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  60                         if (DataINEndpoint 
|| DataOUTEndpoint
) 
  65                                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  66                                                               DCOMP_HID_Host_NextHIDInterface
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  68                                         return HID_ENUMERROR_NoCompatibleInterfaceFound
; 
  71                                 HIDInterface 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
); 
  72                         } while (HIDInterfaceInfo
->Config
.HIDInterfaceProtocol 
&& 
  73                                          (HIDInterface
->Protocol 
!= HIDInterfaceInfo
->Config
.HIDInterfaceProtocol
)); 
  75                         if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  76                                                       DCOMP_HID_Host_NextHIDDescriptor
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  78                                 return HID_ENUMERROR_NoCompatibleInterfaceFound
; 
  81                         HIDDescriptor 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_HID_Descriptor_HID_t
); 
  83                         DataINEndpoint  
= NULL
; 
  84                         DataOUTEndpoint 
= NULL
; 
  89                 USB_Descriptor_Endpoint_t
* EndpointData 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
); 
  91                 if (EndpointData
->EndpointAddress 
& ENDPOINT_DESCRIPTOR_DIR_IN
) 
  92                   DataINEndpoint  
= EndpointData
; 
  94                   DataOUTEndpoint 
= EndpointData
; 
  97         for (uint8_t PipeNum 
= 1; PipeNum 
< PIPE_TOTAL_PIPES
; PipeNum
++) 
 102                 uint8_t  EndpointAddress
; 
 103                 uint8_t  InterruptPeriod
; 
 106                 if (PipeNum 
== HIDInterfaceInfo
->Config
.DataINPipeNumber
) 
 108                         Size            
= le16_to_cpu(DataINEndpoint
->EndpointSize
); 
 109                         EndpointAddress 
= DataINEndpoint
->EndpointAddress
; 
 110                         Token           
= PIPE_TOKEN_IN
; 
 111                         Type            
= EP_TYPE_INTERRUPT
; 
 112                         DoubleBanked    
= HIDInterfaceInfo
->Config
.DataINPipeDoubleBank
; 
 113                         InterruptPeriod 
= DataINEndpoint
->PollingIntervalMS
; 
 115                         HIDInterfaceInfo
->State
.DataINPipeSize 
= DataINEndpoint
->EndpointSize
; 
 117                 else if (PipeNum 
== HIDInterfaceInfo
->Config
.DataOUTPipeNumber
) 
 119                         if (DataOUTEndpoint 
== NULL
) 
 122                         Size            
= le16_to_cpu(DataOUTEndpoint
->EndpointSize
); 
 123                         EndpointAddress 
= DataOUTEndpoint
->EndpointAddress
; 
 124                         Token           
= PIPE_TOKEN_OUT
; 
 125                         Type            
= EP_TYPE_INTERRUPT
; 
 126                         DoubleBanked    
= HIDInterfaceInfo
->Config
.DataOUTPipeDoubleBank
; 
 127                         InterruptPeriod 
= DataOUTEndpoint
->PollingIntervalMS
; 
 129                         HIDInterfaceInfo
->State
.DataOUTPipeSize   
= DataOUTEndpoint
->EndpointSize
; 
 130                         HIDInterfaceInfo
->State
.DeviceUsesOUTPipe 
= true; 
 137                 if (!(Pipe_ConfigurePipe(PipeNum
, Type
, Token
, EndpointAddress
, Size
, 
 138                                          DoubleBanked ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
))) 
 140                         return HID_ENUMERROR_PipeConfigurationFailed
; 
 144                   Pipe_SetInterruptPeriod(InterruptPeriod
); 
 147         HIDInterfaceInfo
->State
.InterfaceNumber      
= HIDInterface
->InterfaceNumber
; 
 148         HIDInterfaceInfo
->State
.HIDReportSize        
= LE16_TO_CPU(HIDDescriptor
->HIDReportLength
); 
 149         HIDInterfaceInfo
->State
.SupportsBootProtocol 
= (HIDInterface
->SubClass 
!= HID_CSCP_NonBootProtocol
); 
 150         HIDInterfaceInfo
->State
.LargestReportSize    
= 8; 
 151         HIDInterfaceInfo
->State
.IsActive             
= true; 
 153         return HID_ENUMERROR_NoError
; 
 156 static uint8_t DCOMP_HID_Host_NextHIDInterface(void* const CurrentDescriptor
) 
 158         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 160         if (Header
->Type 
== DTYPE_Interface
) 
 162                 USB_Descriptor_Interface_t
* Interface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Interface_t
); 
 164                 if (Interface
->Class 
== HID_CSCP_HIDClass
) 
 165                   return DESCRIPTOR_SEARCH_Found
; 
 168         return DESCRIPTOR_SEARCH_NotFound
; 
 171 static uint8_t DCOMP_HID_Host_NextHIDDescriptor(void* const CurrentDescriptor
) 
 173         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 175         if (Header
->Type 
== HID_DTYPE_HID
) 
 176           return DESCRIPTOR_SEARCH_Found
; 
 177         else if (Header
->Type 
== DTYPE_Interface
) 
 178           return DESCRIPTOR_SEARCH_Fail
; 
 180           return DESCRIPTOR_SEARCH_NotFound
; 
 183 static uint8_t DCOMP_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor
) 
 185         USB_Descriptor_Header_t
* Header 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Header_t
); 
 187         if (Header
->Type 
== DTYPE_Endpoint
) 
 189                 USB_Descriptor_Endpoint_t
* Endpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, USB_Descriptor_Endpoint_t
); 
 191                 if (!(Pipe_IsEndpointBound(Endpoint
->EndpointAddress
))) 
 192                   return DESCRIPTOR_SEARCH_Found
; 
 194         else if (Header
->Type 
== DTYPE_Interface
) 
 196                 return DESCRIPTOR_SEARCH_Fail
; 
 199         return DESCRIPTOR_SEARCH_NotFound
; 
 202 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 203 uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, 
 204                                    const uint8_t ReportID
, 
 207         USB_ControlRequest 
= (USB_Request_Header_t
) 
 209                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 210                 .bRequest      
= HID_REQ_SetReport
, 
 211                 .wValue        
= ((HID_REPORT_ITEM_In 
+ 1) << 8) | ReportID
, 
 212                 .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 213                 .wLength       
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, HID_REPORT_ITEM_In
), 
 216         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 218         return USB_Host_SendControlRequest(Buffer
); 
 222 uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, 
 225         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
)) 
 226           return PIPE_READYWAIT_DeviceDisconnected
; 
 230         Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
); 
 234         uint8_t* BufferPos 
= Buffer
; 
 236 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 237         if (!(HIDInterfaceInfo
->State
.UsingBootProtocol
)) 
 239                 uint8_t ReportID 
= 0; 
 241                 if (HIDInterfaceInfo
->Config
.HIDParserData
->UsingReportIDs
) 
 243                         ReportID 
= Pipe_Read_8(); 
 244                         *(BufferPos
++) = ReportID
; 
 247                 ReportSize 
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, HID_REPORT_ITEM_In
); 
 252                 ReportSize 
= Pipe_BytesInPipe(); 
 255         if ((ErrorCode 
= Pipe_Read_Stream_LE(BufferPos
, ReportSize
, NULL
)) != PIPE_RWSTREAM_NoError
) 
 261         return PIPE_RWSTREAM_NoError
; 
 264 uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, 
 265 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 266                                 const uint8_t ReportID
, 
 268                                 const uint8_t ReportType
, 
 270                                 const uint16_t ReportSize
) 
 272 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 273         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
)) 
 276         if (HIDInterfaceInfo
->State
.DeviceUsesOUTPipe 
&& (ReportType 
== HID_REPORT_ITEM_Out
)) 
 280                 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 284                   Pipe_Write_Stream_LE(&ReportID
, sizeof(ReportID
), NULL
); 
 286                 if ((ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, ReportSize
, NULL
)) != PIPE_RWSTREAM_NoError
) 
 292                 return PIPE_RWSTREAM_NoError
; 
 297                 USB_ControlRequest 
= (USB_Request_Header_t
) 
 299                         .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 300                         .bRequest      
= HID_REQ_SetReport
, 
 301 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 302                         .wValue        
= ((ReportType 
+ 1) << 8) | ReportID
, 
 304                         .wValue        
= ((ReportType 
+ 1) << 8), 
 306                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 307                         .wLength       
= ReportSize
, 
 310                 Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 312                 return USB_Host_SendControlRequest(Buffer
); 
 316 bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 318         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
)) 
 323         Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
); 
 326         ReportReceived 
= Pipe_IsINReceived(); 
 330         return ReportReceived
; 
 333 uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 337         if (!(HIDInterfaceInfo
->State
.SupportsBootProtocol
)) 
 338           return HID_ERROR_LOGICAL
; 
 340         USB_ControlRequest 
= (USB_Request_Header_t
) 
 342                         .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 343                         .bRequest      
= HID_REQ_SetProtocol
, 
 345                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 349         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 351         if ((ErrorCode 
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
) 
 354         HIDInterfaceInfo
->State
.LargestReportSize 
= 8; 
 355         HIDInterfaceInfo
->State
.UsingBootProtocol 
= true; 
 357         return HOST_SENDCONTROL_Successful
; 
 360 uint8_t HID_Host_SetIdlePeriod(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, 
 363         USB_ControlRequest 
= (USB_Request_Header_t
) 
 365                         .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 366                         .bRequest      
= HID_REQ_SetIdle
, 
 367                         .wValue        
= ((MS 
<< 6) & 0xFF00), 
 368                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 372         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 374         return USB_Host_SendControlRequest(NULL
); 
 377 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 378 uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 382         uint8_t HIDReportData
[HIDInterfaceInfo
->State
.HIDReportSize
]; 
 384         USB_ControlRequest 
= (USB_Request_Header_t
) 
 386                         .bmRequestType 
= (REQDIR_DEVICETOHOST 
| REQTYPE_STANDARD 
| REQREC_INTERFACE
), 
 387                         .bRequest      
= REQ_GetDescriptor
, 
 388                         .wValue        
= (HID_DTYPE_Report 
<< 8), 
 389                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 390                         .wLength       
= HIDInterfaceInfo
->State
.HIDReportSize
, 
 393         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 395         if ((ErrorCode 
= USB_Host_SendControlRequest(HIDReportData
)) != HOST_SENDCONTROL_Successful
) 
 398         if (HIDInterfaceInfo
->State
.UsingBootProtocol
) 
 400                 USB_ControlRequest 
= (USB_Request_Header_t
) 
 402                                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 403                                 .bRequest      
= HID_REQ_SetProtocol
, 
 405                                 .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 409                 if ((ErrorCode 
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
) 
 412                 HIDInterfaceInfo
->State
.UsingBootProtocol 
= false; 
 415         if (HIDInterfaceInfo
->Config
.HIDParserData 
== NULL
) 
 416           return HID_ERROR_LOGICAL
; 
 418         if ((ErrorCode 
= USB_ProcessHIDReport(HIDReportData
, HIDInterfaceInfo
->State
.HIDReportSize
, 
 419                                               HIDInterfaceInfo
->Config
.HIDParserData
)) != HID_PARSE_Successful
) 
 421                 return HID_ERROR_LOGICAL 
| ErrorCode
; 
 424         uint8_t LargestReportSizeBits 
= HIDInterfaceInfo
->Config
.HIDParserData
->LargestReportSizeBits
; 
 425         HIDInterfaceInfo
->State
.LargestReportSize 
= (LargestReportSizeBits 
>> 3) + ((LargestReportSizeBits 
& 0x07) != 0);