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 #include "HIDParser.h" 
  37 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData
, uint16_t ReportSize
, HID_ReportInfo_t
* const ParserData
) 
  39         HID_StateTable_t      StateTable
[HID_STATETABLE_STACK_DEPTH
]; 
  40         HID_StateTable_t
*     CurrStateTable          
= &StateTable
[0]; 
  41         HID_CollectionPath_t
* CurrCollectionPath      
= NULL
; 
  42         HID_ReportSizeInfo_t
* CurrReportIDInfo        
= &ParserData
->ReportIDSizes
[0];                   
  43         uint16_t              UsageList
[HID_USAGE_STACK_DEPTH
]; 
  44         uint8_t               UsageListSize           
= 0; 
  45         HID_MinMax_t          UsageMinMax             
= {0, 0}; 
  47         memset(ParserData
,       0x00, sizeof(HID_ReportInfo_t
)); 
  48         memset(CurrStateTable
,   0x00, sizeof(HID_StateTable_t
)); 
  49         memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
  51         ParserData
->TotalDeviceReports 
= 1;      
  55                 uint8_t  HIDReportItem  
= *ReportData
; 
  56                 uint32_t ReportItemData 
= 0; 
  61                 switch (HIDReportItem 
& DATA_SIZE_MASK
) 
  64                                 ReportItemData  
= *((uint32_t*)ReportData
); 
  69                                 ReportItemData  
= *((uint16_t*)ReportData
); 
  74                                 ReportItemData  
= *((uint8_t*)ReportData
); 
  80                 switch (HIDReportItem 
& (TYPE_MASK 
| TAG_MASK
)) 
  82                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PUSH
): 
  83                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH 
- 1]) 
  84                                   return HID_PARSE_HIDStackOverflow
; 
  86                                 memcpy((CurrStateTable 
+ 1), 
  88                                        sizeof(HID_ReportItem_t
)); 
  92                         case (TYPE_GLOBAL 
| TAG_GLOBAL_POP
): 
  93                                 if (CurrStateTable 
== &StateTable
[0]) 
  94                                   return HID_PARSE_HIDStackUnderflow
; 
  98                         case (TYPE_GLOBAL 
| TAG_GLOBAL_USAGEPAGE
): 
  99                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
 101                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMIN
): 
 102                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
 104                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMAX
): 
 105                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
 107                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMIN
): 
 108                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
 110                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMAX
): 
 111                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
 113                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNITEXP
): 
 114                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 116                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNIT
): 
 117                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 119                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTSIZE
): 
 120                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 122                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTCOUNT
): 
 123                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 125                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTID
): 
 126                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 128                                 if (ParserData
->UsingReportIDs
) 
 130                                         CurrReportIDInfo 
= NULL
; 
 132                                         for (uint8_t i 
= 0; i 
< ParserData
->TotalDeviceReports
; i
++) 
 134                                                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== CurrStateTable
->ReportID
) 
 136                                                         CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[i
]; 
 141                                         if (CurrReportIDInfo 
== NULL
) 
 143                                                 if (ParserData
->TotalDeviceReports 
== HID_MAX_REPORT_IDS
) 
 144                                                   return HID_PARSE_InsufficientReportIDItems
; 
 146                                                 CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[ParserData
->TotalDeviceReports
++]; 
 147                                                 memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
 151                                 ParserData
->UsingReportIDs 
= true;                               
 153                                 CurrReportIDInfo
->ReportID 
= CurrStateTable
->ReportID
; 
 155                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGE
): 
 156                                 if (UsageListSize 
== HID_USAGE_STACK_DEPTH
) 
 157                                   return HID_PARSE_UsageListOverflow
; 
 159                                 UsageList
[UsageListSize
++] = ReportItemData
; 
 161                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMIN
): 
 162                                 UsageMinMax
.Minimum 
= ReportItemData
; 
 164                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMAX
): 
 165                                 UsageMinMax
.Maximum 
= ReportItemData
; 
 167                         case (TYPE_MAIN 
| TAG_MAIN_COLLECTION
): 
 168                                 if (CurrCollectionPath 
== NULL
) 
 170                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 174                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 176                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 178                                         while (CurrCollectionPath
->Parent 
!= NULL
) 
 180                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS 
- 1]) 
 181                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 183                                                 CurrCollectionPath
++; 
 186                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 189                                 CurrCollectionPath
->Type 
= ReportItemData
; 
 190                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 194                                         CurrCollectionPath
->Usage
.Usage 
= UsageList
[0]; 
 196                                         for (uint8_t i 
= 0; i 
< UsageListSize
; i
++) 
 197                                           UsageList
[i
] = UsageList
[i 
+ 1]; 
 201                                 else if (UsageMinMax
.Minimum 
<= UsageMinMax
.Maximum
) 
 203                                         CurrCollectionPath
->Usage
.Usage 
= UsageMinMax
.Minimum
++; 
 207                         case (TYPE_MAIN 
| TAG_MAIN_ENDCOLLECTION
): 
 208                                 if (CurrCollectionPath 
== NULL
) 
 209                                   return HID_PARSE_UnexpectedEndCollection
; 
 211                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 213                         case (TYPE_MAIN 
| TAG_MAIN_INPUT
): 
 214                         case (TYPE_MAIN 
| TAG_MAIN_OUTPUT
): 
 215                         case (TYPE_MAIN 
| TAG_MAIN_FEATURE
): 
 216                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 218                                         HID_ReportItem_t NewReportItem
; 
 220                                         memcpy(&NewReportItem
.Attributes
, 
 221                                                &CurrStateTable
->Attributes
, 
 222                                                sizeof(HID_ReportItem_Attributes_t
)); 
 224                                         NewReportItem
.ItemFlags      
= ReportItemData
; 
 225                                         NewReportItem
.CollectionPath 
= CurrCollectionPath
; 
 226                                         NewReportItem
.ReportID       
= CurrStateTable
->ReportID
; 
 230                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageList
[0]; 
 232                                                 for (uint8_t i 
= 0; i 
< UsageListSize
; i
++) 
 233                                                   UsageList
[i
] = UsageList
[i 
+ 1]; 
 237                                         else if (UsageMinMax
.Minimum 
<= UsageMinMax
.Maximum
) 
 239                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageMinMax
.Minimum
++; 
 242                                         uint8_t ItemTag 
= (HIDReportItem 
& TAG_MASK
); 
 244                                         if (ItemTag 
== TAG_MAIN_INPUT
) 
 245                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_In
; 
 246                                         else if (ItemTag 
== TAG_MAIN_OUTPUT
) 
 247                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_Out
; 
 249                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_Feature
; 
 251                                         NewReportItem
.BitOffset 
= CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
]; 
 253                                         CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
] += CurrStateTable
->Attributes
.BitSize
; 
 255                                         if (ParserData
->LargestReportSizeBits 
< NewReportItem
.BitOffset
) 
 256                                           ParserData
->LargestReportSizeBits 
= NewReportItem
.BitOffset
; 
 258                                         if (!(ReportItemData 
& IOF_CONSTANT
) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem
)) 
 260                                                 if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 261                                                   return HID_PARSE_InsufficientReportItems
; 
 263                                                 memcpy(&ParserData
->ReportItems
[ParserData
->TotalReportItems
], 
 264                                                        &NewReportItem
, sizeof(HID_ReportItem_t
)); 
 266                                                 ParserData
->TotalReportItems
++; 
 273                 if ((HIDReportItem 
& TYPE_MASK
) == TYPE_MAIN
) 
 275                         UsageMinMax
.Minimum 
= 0; 
 276                         UsageMinMax
.Maximum 
= 0; 
 281         if (!(ParserData
->TotalReportItems
)) 
 282           return HID_PARSE_NoUnfilteredReportItems
; 
 284         return HID_PARSE_Successful
; 
 287 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 289         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 290         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 291         uint32_t BitMask      
= (1 << 0); 
 293         ReportItem
->PreviousValue 
= ReportItem
->Value
; 
 294         ReportItem
->Value 
= 0; 
 296         if (ReportItem
->ReportID
) 
 298                 if (ReportItem
->ReportID 
!= ReportData
[0]) 
 304         while (DataBitsRem
--) 
 306                 if (ReportData
[CurrentBit 
/ 8] & (1 << (CurrentBit 
% 8))) 
 307                   ReportItem
->Value 
|= BitMask
; 
 316 void USB_SetHIDReportItemInfo(uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 318         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 319         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 320         uint32_t BitMask      
= (1 << 0); 
 322         if (ReportItem
->ReportID
) 
 324                 ReportData
[0] = ReportItem
->ReportID
; 
 328         ReportItem
->PreviousValue 
= ReportItem
->Value
; 
 330         while (DataBitsRem
--) 
 332                 if (ReportItem
->Value 
& (1 << (CurrentBit 
% 8))) 
 333                   ReportData
[CurrentBit 
/ 8] |= BitMask
; 
 340 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t
* const ParserData
, const uint8_t ReportID
, const uint8_t ReportType
) 
 342         for (uint8_t i 
= 0; i 
< HID_MAX_REPORT_IDS
; i
++) 
 344                 uint16_t ReportSizeBits 
= ParserData
->ReportIDSizes
[i
].ReportSizeBits
[ReportType
]; 
 346                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== ReportID
) 
 347                   return ((ReportSizeBits 
>> 3) + ((ReportSizeBits 
& 0x07) ? 
1 : 0));