int HIDParse(HIDParser* pParser, HIDData* pData) { int Found=0; while(!Found && pParser->Pos<pParser->ReportDescSize) { /* Get new pParser->Item if current pParser->Count is empty */ if(pParser->Count==0) { pParser->Item=pParser->ReportDesc[pParser->Pos++]; pParser->Value=0; #ifdef WORDS_BIGENDIAN { int i; unsigned long valTmp=0; for (i=0;i<ItemSize[pParser->Item & SIZE_MASK];i++) { memcpy(&valTmp, &pParser->ReportDesc[(pParser->Pos)+i], 1); pParser->Value+=valTmp>>((3-i)*8); valTmp=0; } } #else memcpy(&pParser->Value, &pParser->ReportDesc[pParser->Pos], ItemSize[pParser->Item & SIZE_MASK]); #endif /* Pos on next item */ pParser->Pos+=ItemSize[pParser->Item & SIZE_MASK]; } switch(pParser->Item & ITEM_MASK) { case ITEM_UPAGE : { /* Copy UPage in Usage stack */ pParser->UPage=(ushort)pParser->Value; break; } case ITEM_USAGE : { /* Copy global or local UPage if any, in Usage stack */ if((pParser->Item & SIZE_MASK)>2) pParser->UsageTab[pParser->UsageSize].UPage=(ushort)(pParser->Value>>16); else pParser->UsageTab[pParser->UsageSize].UPage=pParser->UPage; /* Copy Usage in Usage stack */ pParser->UsageTab[pParser->UsageSize].Usage=(ushort)(pParser->Value & 0xFFFF); /* Increment Usage stack size */ pParser->UsageSize++; break; } case ITEM_COLLECTION : { /* Get UPage/Usage from UsageTab and store them in pParser->Data.Path */ pParser->Data.Path.Node[pParser->Data.Path.Size].UPage=pParser->UsageTab[0].UPage; pParser->Data.Path.Node[pParser->Data.Path.Size].Usage=pParser->UsageTab[0].Usage; pParser->Data.Path.Size++; /* Unstack UPage/Usage from UsageTab (never remove the last) */ if(pParser->UsageSize>0) { uchar ii=0; while(ii<pParser->UsageSize) { pParser->UsageTab[ii].Usage=pParser->UsageTab[ii+1].Usage; pParser->UsageTab[ii].UPage=pParser->UsageTab[ii+1].UPage; ii++; } /* Remove Usage */ pParser->UsageSize--; } /* Get Index if any */ if(pParser->Value>=0x80) { pParser->Data.Path.Node[pParser->Data.Path.Size].UPage=0xFF; pParser->Data.Path.Node[pParser->Data.Path.Size].Usage=pParser->Value & 0x7F; pParser->Data.Path.Size++; } ResetLocalState(pParser); break; } case ITEM_END_COLLECTION : { pParser->Data.Path.Size--; /* Remove Index if any */ if(pParser->Data.Path.Node[pParser->Data.Path.Size].UPage==0xFF) pParser->Data.Path.Size--; ResetLocalState(pParser); break; } case ITEM_FEATURE : case ITEM_INPUT : case ITEM_OUTPUT : { /* An object was found */ Found=1; /* Increment object count */ pParser->nObject++; /* Get new pParser->Count from global value */ if(pParser->Count==0) { pParser->Count=pParser->ReportCount; } /* Get UPage/Usage from UsageTab and store them in pParser->Data.Path */ pParser->Data.Path.Node[pParser->Data.Path.Size].UPage=pParser->UsageTab[0].UPage; pParser->Data.Path.Node[pParser->Data.Path.Size].Usage=pParser->UsageTab[0].Usage; pParser->Data.Path.Size++; /* Unstack UPage/Usage from UsageTab (never remove the last) */ if(pParser->UsageSize>0) { uchar ii=0; while(ii<pParser->UsageSize) { pParser->UsageTab[ii].UPage=pParser->UsageTab[ii+1].UPage; pParser->UsageTab[ii].Usage=pParser->UsageTab[ii+1].Usage; ii++; } /* Remove Usage */ pParser->UsageSize--; } /* Copy data type */ pParser->Data.Type=(uchar)(pParser->Item & ITEM_MASK); /* Copy data attribute */ pParser->Data.Attribute=(uchar)pParser->Value; /* Store offset */ pParser->Data.Offset=*GetReportOffset(pParser, pParser->Data.ReportID, (uchar)(pParser->Item & ITEM_MASK)); /* Get Object in pData */ /* -------------------------------------------------------------------------- */ memcpy(pData, &pParser->Data, sizeof(HIDData)); /* -------------------------------------------------------------------------- */ /* Increment Report Offset */ *GetReportOffset(pParser, pParser->Data.ReportID, (uchar)(pParser->Item & ITEM_MASK)) += pParser->Data.Size; /* Remove path last node */ pParser->Data.Path.Size--; /* Decrement count */ pParser->Count--; if (pParser->Count == 0) { ResetLocalState(pParser); } break; } case ITEM_REP_ID : { pParser->Data.ReportID=(uchar)pParser->Value; break; } case ITEM_REP_SIZE : { pParser->Data.Size=(uchar)pParser->Value; break; } case ITEM_REP_COUNT : { pParser->ReportCount=(uchar)pParser->Value; break; } case ITEM_UNIT_EXP : { pParser->Data.UnitExp=(char)pParser->Value; // Convert 4 bits signed value to 8 bits signed value if (pParser->Data.UnitExp > 7) pParser->Data.UnitExp|=0xF0; break; } case ITEM_UNIT : { pParser->Data.Unit=pParser->Value; break; } case ITEM_LOG_MIN : { pParser->Data.LogMin=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; } case ITEM_LOG_MAX : { pParser->Data.LogMax=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; } case ITEM_PHY_MIN : { pParser->Data.PhyMin=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; } case ITEM_PHY_MAX : { pParser->Data.PhyMax=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; } case ITEM_LONG : { /* can't handle long items, but should at least skip them */ pParser->Pos+=(u_char)(pParser->Value & 0xff); } }
/* * HIDParse(HIDParser_t* pParser, HIDData_t *pData) * * Analyse Report descriptor stored in HIDParser struct and store local and * global context. * Return in pData the last object found. * Return -1 when there is no other Item to parse, 1 if a new object was found * or 0 if a continuation of a previous object was found. * -------------------------------------------------------------------------- */ static int HIDParse(HIDParser_t *pParser, HIDData_t *pData) { int Found = -1; while ((Found < 0) && (pParser->Pos < pParser->ReportDescSize)) { /* Get new pParser->Item if current pParser->Count is empty */ if (pParser->Count == 0) { pParser->Item = pParser->ReportDesc[pParser->Pos++]; pParser->Value = 0; #if WORDS_BIGENDIAN { int i; unsigned long valTmp = 0; for (i = 0; i < ItemSize[pParser->Item & SIZE_MASK]; i++) { memcpy(&valTmp, &pParser->ReportDesc[(pParser->Pos)+i], 1); pParser->Value += valTmp >> ((3-i)*8); valTmp = 0; } } #else memcpy(&pParser->Value, &pParser->ReportDesc[pParser->Pos], ItemSize[pParser->Item & SIZE_MASK]); #endif /* Pos on next item */ pParser->Pos += ItemSize[pParser->Item & SIZE_MASK]; } switch (pParser->Item & ITEM_MASK) { case ITEM_UPAGE: /* Copy UPage in Usage stack */ pParser->UPage=(uint16_t)pParser->Value; break; case ITEM_USAGE: /* Copy global or local UPage if any, in Usage stack */ if ((pParser->Item & SIZE_MASK) > 2) { pParser->UsageTab[pParser->UsageSize] = pParser->Value; } else { pParser->UsageTab[pParser->UsageSize] = (pParser->UPage << 16) | (pParser->Value & 0xFFFF); } /* Increment Usage stack size */ pParser->UsageSize++; break; case ITEM_COLLECTION: /* Get UPage/Usage from UsageTab and store them in pParser->Data.Path */ pParser->Data.Path.Node[pParser->Data.Path.Size] = pParser->UsageTab[0]; pParser->Data.Path.Size++; /* Unstack UPage/Usage from UsageTab (never remove the last) */ if (pParser->UsageSize > 0) { int i; for (i = 0; i < pParser->UsageSize; i++) { pParser->UsageTab[i] = pParser->UsageTab[i+1]; } /* Remove Usage */ pParser->UsageSize--; } /* Get Index if any */ if (pParser->Value >= 0x80) { pParser->Data.Path.Node[pParser->Data.Path.Size] = 0x00ff0000 | (pParser->Value & 0x7F); pParser->Data.Path.Size++; } ResetLocalState(pParser); break; case ITEM_END_COLLECTION : pParser->Data.Path.Size--; /* Remove Index if any */ if((pParser->Data.Path.Node[pParser->Data.Path.Size] & 0xffff0000) == 0x00ff0000) { pParser->Data.Path.Size--; } ResetLocalState(pParser); break; case ITEM_FEATURE: case ITEM_INPUT: case ITEM_OUTPUT: if (pParser->UsageTab[0] != 0x00000000) { /* An object was found if the path does not end with 0x00000000 */ Found = 1; } else { /* It is a continuation of a previous object */ Found = 0; } /* Get new pParser->Count from global value */ if(pParser->Count == 0) { pParser->Count = pParser->ReportCount; } /* Get UPage/Usage from UsageTab and store them in pParser->Data.Path */ pParser->Data.Path.Node[pParser->Data.Path.Size] = pParser->UsageTab[0]; pParser->Data.Path.Size++; /* Unstack UPage/Usage from UsageTab (never remove the last) */ if(pParser->UsageSize > 0) { int i; for (i = 0; i < pParser->UsageSize; i++) { pParser->UsageTab[i] = pParser->UsageTab[i+1]; } /* Remove Usage */ pParser->UsageSize--; } /* Copy data type */ pParser->Data.Type = (uint8_t)(pParser->Item & ITEM_MASK); /* Copy data attribute */ pParser->Data.Attribute = (uint8_t)pParser->Value; /* Store offset */ pParser->Data.Offset = *GetReportOffset(pParser, pParser->Data.ReportID, (uint8_t)(pParser->Item & ITEM_MASK)); /* Get Object in pData */ /* -------------------------------------------------------------------------- */ memcpy(pData, &pParser->Data, sizeof(HIDData_t)); /* -------------------------------------------------------------------------- */ /* Increment Report Offset */ *GetReportOffset(pParser, pParser->Data.ReportID, (uint8_t)(pParser->Item & ITEM_MASK)) += pParser->Data.Size; /* Remove path last node */ pParser->Data.Path.Size--; /* Decrement count */ pParser->Count--; if (pParser->Count == 0) { ResetLocalState(pParser); } break; case ITEM_REP_ID : pParser->Data.ReportID = (uint8_t)pParser->Value; break; case ITEM_REP_SIZE : pParser->Data.Size = (uint8_t)pParser->Value; break; case ITEM_REP_COUNT : pParser->ReportCount = (uint8_t)pParser->Value; break; case ITEM_UNIT_EXP : pParser->Data.UnitExp = (int8_t)pParser->Value; if (pParser->Data.UnitExp > 7) { pParser->Data.UnitExp |= 0xF0; } break; case ITEM_UNIT : pParser->Data.Unit = pParser->Value; break; case ITEM_LOG_MIN : pParser->Data.LogMin = FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; case ITEM_LOG_MAX : pParser->Data.LogMax = FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); break; case ITEM_PHY_MIN : pParser->Data.PhyMin=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); pParser->Data.have_PhyMin = 1; break; case ITEM_PHY_MAX : pParser->Data.PhyMax=FormatValue(pParser->Value, ItemSize[pParser->Item & SIZE_MASK]); pParser->Data.have_PhyMax = 1; break; case ITEM_LONG : /* can't handle long items, but should at least skip them */ pParser->Pos += (uint8_t)(pParser->Value & 0xff); break; } } /* while ((Found < 0) && (pParser->Pos < pParser->ReportDescSize)) */