3      Copyright (C) Dean Camera, 2009. 
   5   dean [at] fourwalledcubicle [dot] com 
   6       www.fourwalledcubicle.com 
  10   Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com) 
  12   Permission to use, copy, modify, and distribute this software 
  13   and its documentation for any purpose and without fee is hereby 
  14   granted, provided that the above copyright notice appear in all 
  15   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 #include "../../HighLevel/USBMode.h" 
  32 #if defined(USB_CAN_BE_HOST) 
  34 #define INCLUDE_FROM_HID_CLASS_HOST_C 
  37 uint8_t HID_Host_ConfigurePipes(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, uint16_t ConfigDescriptorSize
, 
  38                                 void* ConfigDescriptorData
) 
  40         uint8_t FoundEndpoints 
= 0; 
  42         memset(&HIDInterfaceInfo
->State
, 0x00, sizeof(HIDInterfaceInfo
->State
)); 
  44         if (DESCRIPTOR_TYPE(ConfigDescriptorData
) != DTYPE_Configuration
) 
  45           return HID_ENUMERROR_InvalidConfigDescriptor
; 
  47         USB_Descriptor_Interface_t
* CurrentHIDInterface
; 
  51                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  52                                                                           DComp_HID_Host_NextHIDInterface
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  54                         return HID_ENUMERROR_NoHIDInterfaceFound
; 
  57                 CurrentHIDInterface 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Interface_t
); 
  58         } while (HIDInterfaceInfo
->Config
.HIDInterfaceProtocol 
&& 
  59                  (CurrentHIDInterface
->Protocol 
!= HIDInterfaceInfo
->Config
.HIDInterfaceProtocol
)); 
  61         HIDInterfaceInfo
->State
.InterfaceNumber      
= CurrentHIDInterface
->InterfaceNumber
; 
  62         HIDInterfaceInfo
->State
.SupportsBootProtocol 
= (CurrentHIDInterface
->SubClass 
!= HID_NON_BOOT_PROTOCOL
); 
  64         if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, DComp_NextHID
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  66                 return HID_ENUMERROR_NoHIDDescriptorFound
; 
  69         HIDInterfaceInfo
->State
.HIDReportSize 
= DESCRIPTOR_CAST(ConfigDescriptorData
, USB_HID_Descriptor_t
).HIDReportLength
; 
  71         while (FoundEndpoints 
!= (HID_FOUND_DATAPIPE_IN 
| HID_FOUND_DATAPIPE_OUT
)) 
  73                 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize
, &ConfigDescriptorData
, 
  74                                               DComp_HID_Host_NextHIDInterfaceEndpoint
) != DESCRIPTOR_SEARCH_COMP_Found
) 
  76                         if (FoundEndpoints 
& HID_FOUND_DATAPIPE_IN
) 
  79                         return HID_ENUMERROR_EndpointsNotFound
; 
  82                 USB_Descriptor_Endpoint_t
* EndpointData 
= DESCRIPTOR_PCAST(ConfigDescriptorData
, USB_Descriptor_Endpoint_t
); 
  84                 if (EndpointData
->EndpointAddress 
& ENDPOINT_DESCRIPTOR_DIR_IN
) 
  86                         Pipe_ConfigurePipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
, EP_TYPE_INTERRUPT
, PIPE_TOKEN_IN
, 
  87                                                            EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
, 
  88                                                            HIDInterfaceInfo
->Config
.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
  89                         HIDInterfaceInfo
->State
.DataINPipeSize 
= EndpointData
->EndpointSize
; 
  91                         FoundEndpoints 
|= HID_FOUND_DATAPIPE_IN
; 
  95                         Pipe_ConfigurePipe(HIDInterfaceInfo
->Config
.DataOUTPipeNumber
, EP_TYPE_INTERRUPT
, PIPE_TOKEN_OUT
, 
  96                                                            EndpointData
->EndpointAddress
, EndpointData
->EndpointSize
, 
  97                                                            HIDInterfaceInfo
->Config
.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE 
: PIPE_BANK_SINGLE
); 
  98                         HIDInterfaceInfo
->State
.DataOUTPipeSize 
= EndpointData
->EndpointSize
; 
 100                         HIDInterfaceInfo
->State
.DeviceUsesOUTPipe 
= true; 
 102                         FoundEndpoints 
|= HID_FOUND_DATAPIPE_OUT
;                
 106         HIDInterfaceInfo
->State
.LargestReportSize 
= 8; 
 107         HIDInterfaceInfo
->State
.IsActive 
= true; 
 108         return HID_ENUMERROR_NoError
; 
 111 static uint8_t DComp_HID_Host_NextHIDInterface(void* const CurrentDescriptor
) 
 113         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 115                 USB_Descriptor_Interface_t
* CurrentInterface 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 116                                                                                 USB_Descriptor_Interface_t
); 
 118                 if (CurrentInterface
->Class 
== HID_INTERFACE_CLASS
) 
 119                   return DESCRIPTOR_SEARCH_Found
; 
 122         return DESCRIPTOR_SEARCH_NotFound
; 
 125 static uint8_t DComp_NextHID(void* const CurrentDescriptor
) 
 127         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_HID
) 
 128           return DESCRIPTOR_SEARCH_Found
; 
 129         else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 130           return DESCRIPTOR_SEARCH_Fail
; 
 132           return DESCRIPTOR_SEARCH_NotFound
;       
 135 static uint8_t DComp_HID_Host_NextHIDInterfaceEndpoint(void* const CurrentDescriptor
) 
 137         if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Endpoint
) 
 139                 USB_Descriptor_Endpoint_t
* CurrentEndpoint 
= DESCRIPTOR_PCAST(CurrentDescriptor
, 
 140                                                                               USB_Descriptor_Endpoint_t
);        
 142                 if (!(Pipe_IsEndpointBound(CurrentEndpoint
->EndpointAddress
))) 
 143                   return DESCRIPTOR_SEARCH_Found
; 
 145         else if (DESCRIPTOR_TYPE(CurrentDescriptor
) == DTYPE_Interface
) 
 147                 return DESCRIPTOR_SEARCH_Fail
; 
 150         return DESCRIPTOR_SEARCH_NotFound
; 
 153 void HID_Host_USBTask(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 158 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 159 uint8_t HID_Host_ReceiveReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, const uint8_t ReportID
, void* Buffer
) 
 161         USB_ControlRequest 
= (USB_Request_Header_t
) 
 163                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 164                 .bRequest      
= REQ_SetReport
, 
 165                 .wValue        
= (REPORT_ITEM_TYPE_In 
<< 8) | ReportID
, 
 166                 .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 167                 .wLength       
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, REPORT_ITEM_TYPE_In
), 
 170         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 172         return USB_Host_SendControlRequest(Buffer
); 
 176 uint8_t HID_Host_ReceiveReport(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, void* Buffer
) 
 178         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
)) 
 183         Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
); 
 188 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 189         if (!(HIDInterfaceInfo
->State
.UsingBootProtocol
)) 
 191                 uint8_t ReportID 
= 0; 
 193                 if (HIDInterfaceInfo
->Config
.HIDParserData
->UsingReportIDs
) 
 195                         ReportID 
= Pipe_Read_Byte(); 
 196                         *((uint8_t*)Buffer
++) = ReportID
; 
 199                 ReportSize 
= USB_GetHIDReportSize(HIDInterfaceInfo
->Config
.HIDParserData
, ReportID
, REPORT_ITEM_TYPE_In
); 
 204                 ReportSize 
= Pipe_BytesInPipe(); 
 207         if ((ErrorCode 
= Pipe_Read_Stream_LE(Buffer
, ReportSize
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 213         return PIPE_RWSTREAM_NoError
; 
 216 uint8_t HID_Host_SendReportByID(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
, 
 217 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 218                                 const uint8_t ReportID
, 
 220                                 void* Buffer
, const uint16_t ReportSize
) 
 222         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
)) 
 225 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 226         if (HIDInterfaceInfo
->State
.DeviceUsesOUTPipe
) 
 230                 Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataOUTPipeNumber
); 
 234                   Pipe_Write_Stream_LE(&ReportID
, sizeof(ReportID
), NO_STREAM_CALLBACK
); 
 236                 if ((ErrorCode 
= Pipe_Write_Stream_LE(Buffer
, ReportSize
, NO_STREAM_CALLBACK
)) != PIPE_RWSTREAM_NoError
) 
 242                 return PIPE_RWSTREAM_NoError
; 
 247                 USB_ControlRequest 
= (USB_Request_Header_t
) 
 249                         .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 250                         .bRequest      
= REQ_SetReport
, 
 251 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 252                         .wValue        
= (REPORT_ITEM_TYPE_Out 
<< 8) | ReportID
, 
 256                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 257                         .wLength       
= ReportSize
, 
 260                 Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 262                 return USB_Host_SendControlRequest(Buffer
); 
 266 bool HID_Host_IsReportReceived(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 268         if ((USB_HostState 
!= HOST_STATE_Configured
) || !(HIDInterfaceInfo
->State
.IsActive
)) 
 273         Pipe_SelectPipe(HIDInterfaceInfo
->Config
.DataINPipeNumber
); 
 276         ReportReceived 
= Pipe_IsINReceived(); 
 280         return ReportReceived
; 
 283 uint8_t HID_Host_SetBootProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 285         if (HIDInterfaceInfo
->State
.UsingBootProtocol
) 
 286           return HOST_SENDCONTROL_Successful
; 
 290         USB_ControlRequest 
= (USB_Request_Header_t
) 
 292                         .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 293                         .bRequest      
= REQ_SetProtocol
, 
 295                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 299         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 301         if (!(HIDInterfaceInfo
->State
.SupportsBootProtocol
)) 
 302           return HID_ERROR_LOGICAL
; 
 304         if ((ErrorCode 
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
) 
 307         HIDInterfaceInfo
->State
.LargestReportSize 
= 8; 
 308         HIDInterfaceInfo
->State
.UsingBootProtocol 
= true; 
 310         return HOST_SENDCONTROL_Successful
; 
 313 #if !defined(HID_HOST_BOOT_PROTOCOL_ONLY) 
 314 uint8_t HID_Host_SetReportProtocol(USB_ClassInfo_HID_Host_t
* const HIDInterfaceInfo
) 
 318         uint8_t HIDReportData
[HIDInterfaceInfo
->State
.HIDReportSize
]; 
 320         USB_ControlRequest 
= (USB_Request_Header_t
) 
 322                         .bmRequestType 
= (REQDIR_DEVICETOHOST 
| REQTYPE_STANDARD 
| REQREC_INTERFACE
), 
 323                         .bRequest      
= REQ_GetDescriptor
, 
 324                         .wValue        
= (DTYPE_Report 
<< 8), 
 325                         .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 326                         .wLength       
= HIDInterfaceInfo
->State
.HIDReportSize
, 
 329         Pipe_SelectPipe(PIPE_CONTROLPIPE
); 
 331         if ((ErrorCode 
= USB_Host_SendControlRequest(HIDReportData
)) != HOST_SENDCONTROL_Successful
) 
 334         if (HIDInterfaceInfo
->State
.UsingBootProtocol
) 
 336                 USB_ControlRequest 
= (USB_Request_Header_t
) 
 338                                 .bmRequestType 
= (REQDIR_HOSTTODEVICE 
| REQTYPE_CLASS 
| REQREC_INTERFACE
), 
 339                                 .bRequest      
= REQ_SetProtocol
, 
 341                                 .wIndex        
= HIDInterfaceInfo
->State
.InterfaceNumber
, 
 345                 if ((ErrorCode 
= USB_Host_SendControlRequest(NULL
)) != HOST_SENDCONTROL_Successful
) 
 348                 HIDInterfaceInfo
->State
.UsingBootProtocol 
= false; 
 351         if (HIDInterfaceInfo
->Config
.HIDParserData 
== NULL
) 
 352           return HID_ERROR_LOGICAL
; 
 354         if ((ErrorCode 
= USB_ProcessHIDReport(HIDReportData
, HIDInterfaceInfo
->State
.HIDReportSize
, 
 355                                               HIDInterfaceInfo
->Config
.HIDParserData
)) != HID_PARSE_Successful
) 
 357                 return HID_ERROR_LOGICAL 
| ErrorCode
; 
 360         uint8_t LargestReportSizeBits 
= HIDInterfaceInfo
->Config
.HIDParserData
->LargestReportSizeBits
; 
 361         HIDInterfaceInfo
->State
.LargestReportSize 
= (LargestReportSizeBits 
>> 3) + ((LargestReportSizeBits 
& 0x07) != 0);