diff options
| author | Jack Humbert <jack.humb@gmail.com> | 2017-07-07 11:55:23 -0400 |
|---|---|---|
| committer | Jack Humbert <jack.humb@gmail.com> | 2017-07-07 11:55:23 -0400 |
| commit | 8655d4f4948b2deef7844503c8d690f23ac1a062 (patch) | |
| tree | b2c6effc9d6cd5b5b43933a1e53b8bf17e9e82cf /lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c | |
| parent | 1896c76a2928c96f9ab7947bec2ef8dd37623cff (diff) | |
| parent | 60b30c036397cb5627fa374bb930794b225daa29 (diff) | |
| download | qmk_firmware-8655d4f4948b2deef7844503c8d690f23ac1a062.tar.gz qmk_firmware-8655d4f4948b2deef7844503c8d690f23ac1a062.zip | |
Merge commit '60b30c036397cb5627fa374bb930794b225daa29' as 'lib/lufa'
Diffstat (limited to 'lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c')
| -rw-r--r-- | lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c b/lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c new file mode 100644 index 000000000..62f10c4e2 --- /dev/null +++ b/lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c | |||
| @@ -0,0 +1,389 @@ | |||
| 1 | /* | ||
| 2 | LUFA Library | ||
| 3 | Copyright (C) Dean Camera, 2017. | ||
| 4 | |||
| 5 | dean [at] fourwalledcubicle [dot] com | ||
| 6 | www.lufa-lib.org | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||
| 11 | |||
| 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. | ||
| 20 | |||
| 21 | The author disclaims 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 | ||
| 28 | this software. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #define __INCLUDE_FROM_USB_DRIVER | ||
| 32 | #define __INCLUDE_FROM_HID_DRIVER | ||
| 33 | #include "HIDParser.h" | ||
| 34 | |||
| 35 | uint8_t USB_ProcessHIDReport(const uint8_t* ReportData, | ||
| 36 | uint16_t ReportSize, | ||
| 37 | HID_ReportInfo_t* const ParserData) | ||
| 38 | { | ||
| 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}; | ||
| 46 | |||
| 47 | memset(ParserData, 0x00, sizeof(HID_ReportInfo_t)); | ||
| 48 | memset(CurrStateTable, 0x00, sizeof(HID_StateTable_t)); | ||
| 49 | memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t)); | ||
| 50 | |||
| 51 | ParserData->TotalDeviceReports = 1; | ||
| 52 | |||
| 53 | while (ReportSize) | ||
| 54 | { | ||
| 55 | uint8_t HIDReportItem = *ReportData; | ||
| 56 | uint32_t ReportItemData; | ||
| 57 | |||
| 58 | ReportData++; | ||
| 59 | ReportSize--; | ||
| 60 | |||
| 61 | switch (HIDReportItem & HID_RI_DATA_SIZE_MASK) | ||
| 62 | { | ||
| 63 | case HID_RI_DATA_BITS_32: | ||
| 64 | ReportItemData = (((uint32_t)ReportData[3] << 24) | ((uint32_t)ReportData[2] << 16) | | ||
| 65 | ((uint16_t)ReportData[1] << 8) | ReportData[0]); | ||
| 66 | ReportSize -= 4; | ||
| 67 | ReportData += 4; | ||
| 68 | break; | ||
| 69 | |||
| 70 | case HID_RI_DATA_BITS_16: | ||
| 71 | ReportItemData = (((uint16_t)ReportData[1] << 8) | (ReportData[0])); | ||
| 72 | ReportSize -= 2; | ||
| 73 | ReportData += 2; | ||
| 74 | break; | ||
| 75 | |||
| 76 | case HID_RI_DATA_BITS_8: | ||
| 77 | ReportItemData = ReportData[0]; | ||
| 78 | ReportSize -= 1; | ||
| 79 | ReportData += 1; | ||
| 80 | break; | ||
| 81 | |||
| 82 | default: | ||
| 83 | ReportItemData = 0; | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | |||
| 87 | switch (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK)) | ||
| 88 | { | ||
| 89 | case HID_RI_PUSH(0): | ||
| 90 | if (CurrStateTable == &StateTable[HID_STATETABLE_STACK_DEPTH - 1]) | ||
| 91 | return HID_PARSE_HIDStackOverflow; | ||
| 92 | |||
| 93 | memcpy((CurrStateTable + 1), | ||
| 94 | CurrStateTable, | ||
| 95 | sizeof(HID_ReportItem_t)); | ||
| 96 | |||
| 97 | CurrStateTable++; | ||
| 98 | break; | ||
| 99 | |||
| 100 | case HID_RI_POP(0): | ||
| 101 | if (CurrStateTable == &StateTable[0]) | ||
| 102 | return HID_PARSE_HIDStackUnderflow; | ||
| 103 | |||
| 104 | CurrStateTable--; | ||
| 105 | break; | ||
| 106 | |||
| 107 | case HID_RI_USAGE_PAGE(0): | ||
| 108 | if ((HIDReportItem & HID_RI_DATA_SIZE_MASK) == HID_RI_DATA_BITS_32) | ||
| 109 | CurrStateTable->Attributes.Usage.Page = (ReportItemData >> 16); | ||
| 110 | |||
| 111 | CurrStateTable->Attributes.Usage.Page = ReportItemData; | ||
| 112 | break; | ||
| 113 | |||
| 114 | case HID_RI_LOGICAL_MINIMUM(0): | ||
| 115 | CurrStateTable->Attributes.Logical.Minimum = ReportItemData; | ||
| 116 | break; | ||
| 117 | |||
| 118 | case HID_RI_LOGICAL_MAXIMUM(0): | ||
| 119 | CurrStateTable->Attributes.Logical.Maximum = ReportItemData; | ||
| 120 | break; | ||
| 121 | |||
| 122 | case HID_RI_PHYSICAL_MINIMUM(0): | ||
| 123 | CurrStateTable->Attributes.Physical.Minimum = ReportItemData; | ||
| 124 | break; | ||
| 125 | |||
| 126 | case HID_RI_PHYSICAL_MAXIMUM(0): | ||
| 127 | CurrStateTable->Attributes.Physical.Maximum = ReportItemData; | ||
| 128 | break; | ||
| 129 | |||
| 130 | case HID_RI_UNIT_EXPONENT(0): | ||
| 131 | CurrStateTable->Attributes.Unit.Exponent = ReportItemData; | ||
| 132 | break; | ||
| 133 | |||
| 134 | case HID_RI_UNIT(0): | ||
| 135 | CurrStateTable->Attributes.Unit.Type = ReportItemData; | ||
| 136 | break; | ||
| 137 | |||
| 138 | case HID_RI_REPORT_SIZE(0): | ||
| 139 | CurrStateTable->Attributes.BitSize = ReportItemData; | ||
| 140 | break; | ||
| 141 | |||
| 142 | case HID_RI_REPORT_COUNT(0): | ||
| 143 | CurrStateTable->ReportCount = ReportItemData; | ||
| 144 | break; | ||
| 145 | |||
| 146 | case HID_RI_REPORT_ID(0): | ||
| 147 | CurrStateTable->ReportID = ReportItemData; | ||
| 148 | |||
| 149 | if (ParserData->UsingReportIDs) | ||
| 150 | { | ||
| 151 | CurrReportIDInfo = NULL; | ||
| 152 | |||
| 153 | for (uint8_t i = 0; i < ParserData->TotalDeviceReports; i++) | ||
| 154 | { | ||
| 155 | if (ParserData->ReportIDSizes[i].ReportID == CurrStateTable->ReportID) | ||
| 156 | { | ||
| 157 | CurrReportIDInfo = &ParserData->ReportIDSizes[i]; | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | if (CurrReportIDInfo == NULL) | ||
| 163 | { | ||
| 164 | if (ParserData->TotalDeviceReports == HID_MAX_REPORT_IDS) | ||
| 165 | return HID_PARSE_InsufficientReportIDItems; | ||
| 166 | |||
| 167 | CurrReportIDInfo = &ParserData->ReportIDSizes[ParserData->TotalDeviceReports++]; | ||
| 168 | memset(CurrReportIDInfo, 0x00, sizeof(HID_ReportSizeInfo_t)); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | ParserData->UsingReportIDs = true; | ||
| 173 | |||
| 174 | CurrReportIDInfo->ReportID = CurrStateTable->ReportID; | ||
| 175 | break; | ||
| 176 | |||
| 177 | case HID_RI_USAGE(0): | ||
| 178 | if (UsageListSize == HID_USAGE_STACK_DEPTH) | ||
| 179 | return HID_PARSE_UsageListOverflow; | ||
| 180 | |||
| 181 | UsageList[UsageListSize++] = ReportItemData; | ||
| 182 | break; | ||
| 183 | |||
| 184 | case HID_RI_USAGE_MINIMUM(0): | ||
| 185 | UsageMinMax.Minimum = ReportItemData; | ||
| 186 | break; | ||
| 187 | |||
| 188 | case HID_RI_USAGE_MAXIMUM(0): | ||
| 189 | UsageMinMax.Maximum = ReportItemData; | ||
| 190 | break; | ||
| 191 | |||
| 192 | case HID_RI_COLLECTION(0): | ||
| 193 | if (CurrCollectionPath == NULL) | ||
| 194 | { | ||
| 195 | CurrCollectionPath = &ParserData->CollectionPaths[0]; | ||
| 196 | } | ||
| 197 | else | ||
| 198 | { | ||
| 199 | HID_CollectionPath_t* ParentCollectionPath = CurrCollectionPath; | ||
| 200 | |||
| 201 | CurrCollectionPath = &ParserData->CollectionPaths[1]; | ||
| 202 | |||
| 203 | while (CurrCollectionPath->Parent != NULL) | ||
| 204 | { | ||
| 205 | if (CurrCollectionPath == &ParserData->CollectionPaths[HID_MAX_COLLECTIONS - 1]) | ||
| 206 | return HID_PARSE_InsufficientCollectionPaths; | ||
| 207 | |||
| 208 | CurrCollectionPath++; | ||
| 209 | } | ||
| 210 | |||
| 211 | CurrCollectionPath->Parent = ParentCollectionPath; | ||
| 212 | } | ||
| 213 | |||
| 214 | CurrCollectionPath->Type = ReportItemData; | ||
| 215 | CurrCollectionPath->Usage.Page = CurrStateTable->Attributes.Usage.Page; | ||
| 216 | |||
| 217 | if (UsageListSize) | ||
| 218 | { | ||
| 219 | CurrCollectionPath->Usage.Usage = UsageList[0]; | ||
| 220 | |||
| 221 | for (uint8_t i = 1; i < UsageListSize; i++) | ||
| 222 | UsageList[i - 1] = UsageList[i]; | ||
| 223 | |||
| 224 | UsageListSize--; | ||
| 225 | } | ||
| 226 | else if (UsageMinMax.Minimum <= UsageMinMax.Maximum) | ||
| 227 | { | ||
| 228 | CurrCollectionPath->Usage.Usage = UsageMinMax.Minimum++; | ||
| 229 | } | ||
| 230 | |||
| 231 | break; | ||
| 232 | |||
| 233 | case HID_RI_END_COLLECTION(0): | ||
| 234 | if (CurrCollectionPath == NULL) | ||
| 235 | return HID_PARSE_UnexpectedEndCollection; | ||
| 236 | |||
| 237 | CurrCollectionPath = CurrCollectionPath->Parent; | ||
| 238 | break; | ||
| 239 | |||
| 240 | case HID_RI_INPUT(0): | ||
| 241 | case HID_RI_OUTPUT(0): | ||
| 242 | case HID_RI_FEATURE(0): | ||
| 243 | for (uint8_t ReportItemNum = 0; ReportItemNum < CurrStateTable->ReportCount; ReportItemNum++) | ||
| 244 | { | ||
| 245 | HID_ReportItem_t NewReportItem; | ||
| 246 | |||
| 247 | memcpy(&NewReportItem.Attributes, | ||
| 248 | &CurrStateTable->Attributes, | ||
| 249 | sizeof(HID_ReportItem_Attributes_t)); | ||
| 250 | |||
| 251 | NewReportItem.ItemFlags = ReportItemData; | ||
| 252 | NewReportItem.CollectionPath = CurrCollectionPath; | ||
| 253 | NewReportItem.ReportID = CurrStateTable->ReportID; | ||
| 254 | |||
| 255 | if (UsageListSize) | ||
| 256 | { | ||
| 257 | NewReportItem.Attributes.Usage.Usage = UsageList[0]; | ||
| 258 | |||
| 259 | for (uint8_t i = 1; i < UsageListSize; i++) | ||
| 260 | UsageList[i - 1] = UsageList[i]; | ||
| 261 | |||
| 262 | UsageListSize--; | ||
| 263 | } | ||
| 264 | else if (UsageMinMax.Minimum <= UsageMinMax.Maximum) | ||
| 265 | { | ||
| 266 | NewReportItem.Attributes.Usage.Usage = UsageMinMax.Minimum++; | ||
| 267 | } | ||
| 268 | |||
| 269 | uint8_t ItemTypeTag = (HIDReportItem & (HID_RI_TYPE_MASK | HID_RI_TAG_MASK)); | ||
| 270 | |||
| 271 | if (ItemTypeTag == HID_RI_INPUT(0)) | ||
| 272 | NewReportItem.ItemType = HID_REPORT_ITEM_In; | ||
| 273 | else if (ItemTypeTag == HID_RI_OUTPUT(0)) | ||
| 274 | NewReportItem.ItemType = HID_REPORT_ITEM_Out; | ||
| 275 | else | ||
| 276 | NewReportItem.ItemType = HID_REPORT_ITEM_Feature; | ||
| 277 | |||
| 278 | NewReportItem.BitOffset = CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]; | ||
| 279 | |||
| 280 | CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType] += CurrStateTable->Attributes.BitSize; | ||
| 281 | |||
| 282 | ParserData->LargestReportSizeBits = MAX(ParserData->LargestReportSizeBits, CurrReportIDInfo->ReportSizeBits[NewReportItem.ItemType]); | ||
| 283 | |||
| 284 | if (ParserData->TotalReportItems == HID_MAX_REPORTITEMS) | ||
| 285 | return HID_PARSE_InsufficientReportItems; | ||
| 286 | |||
| 287 | memcpy(&ParserData->ReportItems[ParserData->TotalReportItems], | ||
| 288 | &NewReportItem, sizeof(HID_ReportItem_t)); | ||
| 289 | |||
| 290 | if (!(ReportItemData & HID_IOF_CONSTANT) && CALLBACK_HIDParser_FilterHIDReportItem(&NewReportItem)) | ||
| 291 | ParserData->TotalReportItems++; | ||
| 292 | } | ||
| 293 | |||
| 294 | break; | ||
| 295 | |||
| 296 | default: | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | |||
| 300 | if ((HIDReportItem & HID_RI_TYPE_MASK) == HID_RI_TYPE_MAIN) | ||
| 301 | { | ||
| 302 | UsageMinMax.Minimum = 0; | ||
| 303 | UsageMinMax.Maximum = 0; | ||
| 304 | UsageListSize = 0; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | if (!(ParserData->TotalReportItems)) | ||
| 309 | return HID_PARSE_NoUnfilteredReportItems; | ||
| 310 | |||
| 311 | return HID_PARSE_Successful; | ||
| 312 | } | ||
| 313 | |||
| 314 | bool USB_GetHIDReportItemInfo(const uint8_t* ReportData, | ||
| 315 | HID_ReportItem_t* const ReportItem) | ||
| 316 | { | ||
| 317 | if (ReportItem == NULL) | ||
| 318 | return false; | ||
| 319 | |||
| 320 | uint16_t DataBitsRem = ReportItem->Attributes.BitSize; | ||
| 321 | uint16_t CurrentBit = ReportItem->BitOffset; | ||
| 322 | uint32_t BitMask = (1 << 0); | ||
| 323 | |||
| 324 | if (ReportItem->ReportID) | ||
| 325 | { | ||
| 326 | if (ReportItem->ReportID != ReportData[0]) | ||
| 327 | return false; | ||
| 328 | |||
| 329 | ReportData++; | ||
| 330 | } | ||
| 331 | |||
| 332 | ReportItem->PreviousValue = ReportItem->Value; | ||
| 333 | ReportItem->Value = 0; | ||
| 334 | |||
| 335 | while (DataBitsRem--) | ||
| 336 | { | ||
| 337 | if (ReportData[CurrentBit / 8] & (1 << (CurrentBit % 8))) | ||
| 338 | ReportItem->Value |= BitMask; | ||
| 339 | |||
| 340 | CurrentBit++; | ||
| 341 | BitMask <<= 1; | ||
| 342 | } | ||
| 343 | |||
| 344 | return true; | ||
| 345 | } | ||
| 346 | |||
| 347 | void USB_SetHIDReportItemInfo(uint8_t* ReportData, | ||
| 348 | HID_ReportItem_t* const ReportItem) | ||
| 349 | { | ||
| 350 | if (ReportItem == NULL) | ||
| 351 | return; | ||
| 352 | |||
| 353 | uint16_t DataBitsRem = ReportItem->Attributes.BitSize; | ||
| 354 | uint16_t CurrentBit = ReportItem->BitOffset; | ||
| 355 | uint32_t BitMask = (1 << 0); | ||
| 356 | |||
| 357 | if (ReportItem->ReportID) | ||
| 358 | { | ||
| 359 | ReportData[0] = ReportItem->ReportID; | ||
| 360 | ReportData++; | ||
| 361 | } | ||
| 362 | |||
| 363 | ReportItem->PreviousValue = ReportItem->Value; | ||
| 364 | |||
| 365 | while (DataBitsRem--) | ||
| 366 | { | ||
| 367 | if (ReportItem->Value & BitMask) | ||
| 368 | ReportData[CurrentBit / 8] |= (1 << (CurrentBit % 8)); | ||
| 369 | |||
| 370 | CurrentBit++; | ||
| 371 | BitMask <<= 1; | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | uint16_t USB_GetHIDReportSize(HID_ReportInfo_t* const ParserData, | ||
| 376 | const uint8_t ReportID, | ||
| 377 | const uint8_t ReportType) | ||
| 378 | { | ||
| 379 | for (uint8_t i = 0; i < HID_MAX_REPORT_IDS; i++) | ||
| 380 | { | ||
| 381 | uint16_t ReportSizeBits = ParserData->ReportIDSizes[i].ReportSizeBits[ReportType]; | ||
| 382 | |||
| 383 | if (ParserData->ReportIDSizes[i].ReportID == ReportID) | ||
| 384 | return (ReportSizeBits / 8) + ((ReportSizeBits % 8) ? 1 : 0); | ||
| 385 | } | ||
| 386 | |||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
