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 #include "HIDParser.h" 
  36 uint8_t USB_ProcessHIDReport(const uint8_t* ReportData
, uint16_t ReportSize
, HID_ReportInfo_t
* const ParserData
) 
  38         HID_StateTable_t      StateTable
[HID_STATETABLE_STACK_DEPTH
]; 
  39         HID_StateTable_t
*     CurrStateTable          
= &StateTable
[0]; 
  40         HID_CollectionPath_t
* CurrCollectionPath      
= NULL
; 
  41         HID_ReportSizeInfo_t
* CurrReportIDInfo        
= &ParserData
->ReportIDSizes
[0];                   
  42         uint16_t              UsageList
[HID_USAGE_STACK_DEPTH
]; 
  43         uint8_t               UsageListSize          
= 0; 
  45         memset(ParserData
,       0x00, sizeof(HID_ReportInfo_t
)); 
  46         memset(CurrStateTable
,   0x00, sizeof(HID_StateTable_t
)); 
  47         memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
  49         ParserData
->TotalDeviceReports 
= 1;      
  53                 uint8_t  HIDReportItem  
= *ReportData
; 
  54                 uint32_t ReportItemData 
= 0; 
  59                 switch (HIDReportItem 
& DATA_SIZE_MASK
) 
  62                                 ReportItemData  
= *((uint32_t*)ReportData
); 
  67                                 ReportItemData  
= *((uint16_t*)ReportData
); 
  72                                 ReportItemData  
= *((uint8_t*)ReportData
); 
  78                 switch (HIDReportItem 
& (TYPE_MASK 
| TAG_MASK
)) 
  80                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PUSH
): 
  81                                 if (CurrStateTable 
== &StateTable
[HID_STATETABLE_STACK_DEPTH 
- 1]) 
  82                                   return HID_PARSE_HIDStackOverflow
; 
  84                                 memcpy((CurrStateTable 
+ 1), 
  86                                        sizeof(HID_ReportItem_t
)); 
  90                         case (TYPE_GLOBAL 
| TAG_GLOBAL_POP
): 
  91                                 if (CurrStateTable 
== &StateTable
[0]) 
  92                                   return HID_PARSE_HIDStackUnderflow
; 
  96                         case (TYPE_GLOBAL 
| TAG_GLOBAL_USAGEPAGE
): 
  97                                 CurrStateTable
->Attributes
.Usage
.Page       
= ReportItemData
; 
  99                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMIN
): 
 100                                 CurrStateTable
->Attributes
.Logical
.Minimum  
= ReportItemData
; 
 102                         case (TYPE_GLOBAL 
| TAG_GLOBAL_LOGICALMAX
): 
 103                                 CurrStateTable
->Attributes
.Logical
.Maximum  
= ReportItemData
; 
 105                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMIN
): 
 106                                 CurrStateTable
->Attributes
.Physical
.Minimum 
= ReportItemData
; 
 108                         case (TYPE_GLOBAL 
| TAG_GLOBAL_PHYSMAX
): 
 109                                 CurrStateTable
->Attributes
.Physical
.Maximum 
= ReportItemData
; 
 111                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNITEXP
): 
 112                                 CurrStateTable
->Attributes
.Unit
.Exponent    
= ReportItemData
; 
 114                         case (TYPE_GLOBAL 
| TAG_GLOBAL_UNIT
): 
 115                                 CurrStateTable
->Attributes
.Unit
.Type        
= ReportItemData
; 
 117                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTSIZE
): 
 118                                 CurrStateTable
->Attributes
.BitSize          
= ReportItemData
; 
 120                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTCOUNT
): 
 121                                 CurrStateTable
->ReportCount                 
= ReportItemData
; 
 123                         case (TYPE_GLOBAL 
| TAG_GLOBAL_REPORTID
): 
 124                                 CurrStateTable
->ReportID                    
= ReportItemData
; 
 126                                 if (ParserData
->UsingReportIDs
) 
 128                                         CurrReportIDInfo 
= NULL
; 
 130                                         for (uint8_t i 
= 0; i 
< ParserData
->TotalDeviceReports
; i
++) 
 132                                                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== CurrStateTable
->ReportID
) 
 134                                                         CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[i
]; 
 139                                         if (CurrReportIDInfo 
== NULL
) 
 141                                                 if (ParserData
->TotalDeviceReports 
== HID_MAX_REPORT_IDS
) 
 142                                                   return HID_PARSE_InsufficientReportIDItems
; 
 144                                                 CurrReportIDInfo 
= &ParserData
->ReportIDSizes
[ParserData
->TotalDeviceReports
++]; 
 145                                                 memset(CurrReportIDInfo
, 0x00, sizeof(HID_ReportSizeInfo_t
)); 
 149                                 ParserData
->UsingReportIDs 
= true;                               
 151                                 CurrReportIDInfo
->ReportID 
= CurrStateTable
->ReportID
; 
 153                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGE
): 
 154                                 if (UsageListSize 
== HID_USAGE_STACK_DEPTH
) 
 155                                   return HID_PARSE_UsageListOverflow
; 
 157                                 UsageList
[UsageListSize
++] = ReportItemData
; 
 159                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMIN
): 
 160                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= ReportItemData
; 
 162                         case (TYPE_LOCAL 
| TAG_LOCAL_USAGEMAX
): 
 163                                 CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= ReportItemData
; 
 165                         case (TYPE_MAIN 
| TAG_MAIN_COLLECTION
): 
 166                                 if (CurrCollectionPath 
== NULL
) 
 168                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[0]; 
 172                                         HID_CollectionPath_t
* ParentCollectionPath 
= CurrCollectionPath
; 
 174                                         CurrCollectionPath 
= &ParserData
->CollectionPaths
[1]; 
 176                                         while (CurrCollectionPath
->Parent 
!= NULL
) 
 178                                                 if (CurrCollectionPath 
== &ParserData
->CollectionPaths
[HID_MAX_COLLECTIONS 
- 1]) 
 179                                                   return HID_PARSE_InsufficientCollectionPaths
; 
 181                                                 CurrCollectionPath
++; 
 184                                         CurrCollectionPath
->Parent 
= ParentCollectionPath
; 
 187                                 CurrCollectionPath
->Type 
= ReportItemData
; 
 188                                 CurrCollectionPath
->Usage
.Page 
= CurrStateTable
->Attributes
.Usage
.Page
; 
 192                                         CurrCollectionPath
->Usage
.Usage 
= UsageList
[0]; 
 194                                         for (uint8_t i 
= 0; i 
< UsageListSize
; i
++) 
 195                                           UsageList
[i
] = UsageList
[i 
+ 1]; 
 201                         case (TYPE_MAIN 
| TAG_MAIN_ENDCOLLECTION
): 
 202                                 if (CurrCollectionPath 
== NULL
) 
 203                                   return HID_PARSE_UnexpectedEndCollection
; 
 205                                 CurrCollectionPath 
= CurrCollectionPath
->Parent
; 
 207                         case (TYPE_MAIN 
| TAG_MAIN_INPUT
): 
 208                         case (TYPE_MAIN 
| TAG_MAIN_OUTPUT
): 
 209                         case (TYPE_MAIN 
| TAG_MAIN_FEATURE
): 
 210                                 for (uint8_t ReportItemNum 
= 0; ReportItemNum 
< CurrStateTable
->ReportCount
; ReportItemNum
++) 
 212                                         HID_ReportItem_t NewReportItem
; 
 214                                         memcpy(&NewReportItem
.Attributes
, 
 215                                                &CurrStateTable
->Attributes
, 
 216                                                sizeof(HID_ReportItem_Attributes_t
)); 
 218                                         NewReportItem
.ItemFlags      
= ReportItemData
; 
 219                                         NewReportItem
.CollectionPath 
= CurrCollectionPath
; 
 220                                         NewReportItem
.ReportID       
= CurrStateTable
->ReportID
; 
 224                                                 NewReportItem
.Attributes
.Usage
.Usage 
= UsageList
[0]; 
 226                                                 for (uint8_t i 
= 0; i 
< UsageListSize
; i
++) 
 227                                                   UsageList
[i
] = UsageList
[i 
+ 1]; 
 232                                         uint8_t ItemTag 
= (HIDReportItem 
& TAG_MASK
); 
 234                                         if (ItemTag 
== TAG_MAIN_INPUT
) 
 235                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_In
; 
 236                                         else if (ItemTag 
== TAG_MAIN_OUTPUT
) 
 237                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_Out
; 
 239                                           NewReportItem
.ItemType 
= REPORT_ITEM_TYPE_Feature
; 
 241                                         NewReportItem
.BitOffset 
= CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
]; 
 243                                         CurrReportIDInfo
->ReportSizeBits
[NewReportItem
.ItemType
] += CurrStateTable
->Attributes
.BitSize
; 
 245                                         if (ParserData
->LargestReportSizeBits 
< NewReportItem
.BitOffset
) 
 246                                           ParserData
->LargestReportSizeBits 
= NewReportItem
.BitOffset
; 
 248                                         if (!(ReportItemData 
& IOF_CONSTANT
) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem
)) 
 250                                                 if (ParserData
->TotalReportItems 
== HID_MAX_REPORTITEMS
) 
 251                                                   return HID_PARSE_InsufficientReportItems
; 
 253                                                 memcpy(&ParserData
->ReportItems
[ParserData
->TotalReportItems
], 
 254                                                        &NewReportItem
, sizeof(HID_ReportItem_t
)); 
 256                                                 ParserData
->TotalReportItems
++; 
 263                 if ((HIDReportItem 
& TYPE_MASK
) == TYPE_MAIN
) 
 265                         CurrStateTable
->Attributes
.Usage
.MinMax
.Minimum 
= 0; 
 266                         CurrStateTable
->Attributes
.Usage
.MinMax
.Maximum 
= 0; 
 271         if (!(ParserData
->TotalReportItems
)) 
 272           return HID_PARSE_NoUnfilteredReportItems
; 
 274         return HID_PARSE_Successful
; 
 277 bool USB_GetHIDReportItemInfo(const uint8_t* ReportData
, HID_ReportItem_t
* const ReportItem
) 
 279         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 280         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 281         uint32_t BitMask      
= (1 << 0); 
 283         ReportItem
->Value 
= 0; 
 285         if (ReportItem
->ReportID
) 
 287                 if (ReportItem
->ReportID 
!= ReportData
[0]) 
 293         while (DataBitsRem
--) 
 295                 if (ReportData
[CurrentBit 
/ 8] & (1 << (CurrentBit 
% 8))) 
 296                   ReportItem
->Value 
|= BitMask
; 
 305 void USB_SetHIDReportItemInfo(uint8_t* ReportData
, const HID_ReportItem_t
* ReportItem
) 
 307         uint16_t DataBitsRem  
= ReportItem
->Attributes
.BitSize
; 
 308         uint16_t CurrentBit   
= ReportItem
->BitOffset
; 
 309         uint32_t BitMask      
= (1 << 0); 
 311         if (ReportItem
->ReportID
) 
 313                 ReportData
[0] = ReportItem
->ReportID
; 
 317         while (DataBitsRem
--) 
 319                 if (ReportItem
->Value 
& (1 << (CurrentBit 
% 8))) 
 320                   ReportData
[CurrentBit 
/ 8] |= BitMask
; 
 327 uint16_t USB_GetHIDReportSize(HID_ReportInfo_t
* const ParserData
, const uint8_t ReportID
, const uint8_t ReportType
) 
 329         for (uint8_t i 
= 0; i 
< HID_MAX_REPORT_IDS
; i
++) 
 331                 if (ParserData
->ReportIDSizes
[i
].ReportID 
== ReportID
) 
 332                   return ParserData
->ReportIDSizes
[i
].ReportSizeBits
[ReportType
];