1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267 |
- MODULE UsbHidParser; (** AUTHOR "ottigerm"; PURPOSE "HID Items parser with error codes" *)
- (**
- * Bluebottle USB HID Items Module
- *
- * This is the module providing item parsing as described in Device Class Definition for HID Version 1.11
- *
- * Overview:
- *
- * Main Items As described on page 28
- * Global Items As described on page 35
- * Local Items As described on page 39
- *
- * History:
- *
- * 02.06.2006 History started (ottigerm)
- * 27.09.2006 Version 1.0
- *)
- IMPORT SYSTEM, KernelLog, UsbHid, Usbdi, UsbHidErrors, HidParserExt := UsbHidParserExt, UsbHidReport;
- CONST
- Trace* = FALSE;
- Debug* = FALSE;
- ShortItemBTypeMain = 0H;
- ShortItemBTypeGlobal = 1H;
- ShortItemBTypeLocal = 2H;
- ShortItemBTypeReserved = 3H;
- UndefinedState* = UsbHidReport.UndefinedState;
- StatusCodeOk* = 1;
- StatusCodeFailed* = 0;
- (*Enum for global state*)
- IDUsagePage = HidParserExt.ParseIDUsagePage;
- IDLogicalMinimum = HidParserExt.ParseIDLogicalMinimum;
- IDLogicalMaximum = HidParserExt.ParseIDLogicalMaximum;
- IDPhysicalMinimum = HidParserExt.ParseIDPhysicalMinimum;
- IDPhysicalMaximum = HidParserExt.ParseIDPhysicalMaximum;
- IDUnitExponent = HidParserExt.ParseIDUnitExponent;
- IDUnit = HidParserExt.ParseIDUnit;
- IDReportSize = HidParserExt.ParseIDReportSize;
- IDReportID = HidParserExt.ParseIDReportID;
- IDReportCount = HidParserExt.ParseIDReportCount;
- LengthGlobalState = 10;
- (*Enum for local state*)
- IDLocalUsage = HidParserExt.ParseIDUsage;
- IDLocalUsageMinimum = HidParserExt.ParseIDUsageMinimum;
- IDLocalUsageMaximum = HidParserExt.ParseIDUsageMaximum;
- IDLocalDesignatorIndex = HidParserExt.ParseIDDesignatorIndex;
- IDLocalDesignatorMinimum = HidParserExt.ParseIDDesignatorMinimum;
- IDLocalDesignatorMaximum = HidParserExt.ParseIDDesignatorMaximum;
- IDLocalStringIndex = HidParserExt.ParseIDStringIndex-1;
- IDLocalStringMinimum = HidParserExt.ParseIDStringMinimum-1;
- IDLocalStringMaximum = HidParserExt.ParseIDStringMaximum-1;
- IDLocalDelimiter = HidParserExt.ParseIDDelimiter-1;
- LengthLocalState = 10;
- IDLocalExtUsage = HidParserExt.ParseIDUsage;
- IDLocalExtUsageMinimum = HidParserExt.ParseIDUsageMinimum;
- IDLocalExtUsageMaximum = HidParserExt.ParseIDUsageMaximum;
- LengthExtLocalState = 3;
- IDLocalAddStringIndex = 4;
- (*Main state*)
- IDMainIsConstant* = HidParserExt.ParseIDDataConstant;
- IDMainIsVariable* = HidParserExt.ParseIDArrayVariable;
- IDMainIsRelative* = HidParserExt.ParseIDAbsoluteRelative;
- IDMainIsWrap* = HidParserExt.ParseIDNoWrapWrap;
- IDMainIsNonLinear* = HidParserExt.ParseIDLinearNonLinear;
- IDMainIsNoPreferred* = HidParserExt.ParseIDPreferdStateNoPreferd;
- IDMainIsNullState* = HidParserExt.ParseIDNoNullPositionNullState;
- IDMainIsVolatile* = HidParserExt.ParseIDNonVolatileVolatile;
- IDMainIsBufferedBytes* = HidParserExt.ParseIDBitFieldBufferedByte;
- (*Main item tag*)
- IDMainItemInput = 08H;
- IDMainItemOutput = 09H;
- IDMainItemFeature = 0BH;
- IDMainItemCollection = 0AH;
- IDMainItemEndCollection = 0CH;
- TYPE
- (*as defined in device class definition for HID Version 1.11, p. 26, 6.2.2 ShortItems*)
- Item = RECORD
- bSize : LONGINT; (*bit 0,1: size of data*)
- bType : LONGINT; (*bit 2,3: Main, Global, Local or Reserved(Longitem) Type*)
- bTag : LONGINT; (*bit 4-7: index in the main, global or local tag table*)
- data : LONGINT; (*data to read after byte 0 depending on bSize*)
- END;
- (*holding the main state*)
- MainState = LONGINT;
- (*holding the state of all possible global states*)
- GlobalState = POINTER TO RECORD
- (*UsagePage, Logical Min, Logical Max, Physical Min, Physical Max, Unit Exp, Unit, ReportSize, ReportID, ReportCount*)
- state : ARRAY LengthGlobalState OF LONGINT;
- (*for detecting erros in the hid descriptor*)
- isReadByMain : ARRAY LengthGlobalState OF BOOLEAN;
- (*used when Push or Pop item is found. Push puts the actual global state at the beginning of the list; pop gets the first list item*)
- next : GlobalState;
- END;
- LocalState = POINTER TO RECORD
- (*Usage, Usage Min, Usage Max, Designator Index, Designator Maximum, String Index, String Minimum, String Maximum, Delimiter*)
- state : ARRAY LengthLocalState OF LONGINT;
- (*for detecting errors in the hid descriptor; usage Min and usage Max can have extensions*)
- ext : ARRAY LengthExtLocalState OF LONGINT;
- END;
- UsageQueueItem = POINTER TO RECORD
- usage : LONGINT;
- usagePage : LONGINT;
- arrLen : LONGINT;
- next : UsageQueueItem;
- END;
- PtrToUsageTupleArr = UsbHidReport.PtrToUsageTupleArr;
- (*Linked list for managing holding usages: there can be multiple usages between main items, so we need a dynamic datatype*)
- UsageQueue=OBJECT
- VAR
- first, last : UsageQueueItem;
- totalLen : LONGINT;
- (*adds the usage[0..arrLen-1] to the end of HIDUsageQueue
- * param: usage the usage to add
- * arrLen if more usages, the total number of usages
- * usageExt the usagePage
- *)
- PROCEDURE Add*(usage, arrLen, usageExt: LONGINT);
- BEGIN
- (*empty list*)
- IF (last = NIL) THEN
- NEW(last);
- first := last;
- ELSE
- NEW(last.next);
- last := last.next;
- END;
- last.usage := usage;
- last.usagePage := usageExt;
- last.arrLen:= arrLen;
- totalLen:= totalLen + arrLen;
- END Add;
- (*returns an UsbHidReport.UsageDictionary
- * param:
- * return: UsbHidReport.UsageDictionary
- *)
- PROCEDURE CreateUsageDictionary():UsbHidReport.UsageDictionary;
- VAR
- cursor: UsageQueueItem;
- usageQueueCounter, i: LONGINT;
- dict: UsbHidReport.UsageDictionary;
- BEGIN
- (*first count the length of usageQueue*)
- cursor := first;
- WHILE (cursor # NIL) DO
- cursor := cursor.next;
- usageQueueCounter := usageQueueCounter + 1;
- END;
- IF (usageQueueCounter>0) THEN
- NEW(dict);
- NEW(dict.elements,usageQueueCounter);
- cursor := first;
- FOR i:= 0 TO usageQueueCounter-1 DO
- dict.elements[i].firstUsageID := cursor.usage;
- dict.elements[i].otherUsagePage := cursor.usagePage;
- dict.elements[i].nofFollowing := cursor.arrLen-1;
- cursor := cursor.next;
- END;
- (*KernelLog.String("added usageDictionary with "); KernelLog.Int(usageQueueCounter,0); KernelLog.String(" elements."); KernelLog.Ln;*)
- END;
- RETURN dict;
- END CreateUsageDictionary;
- (*returns an array of usageTuples
- * param: the number of elements wanted in the array
- * return: pointer to the usage tuple array
- *)
- PROCEDURE CreateUsageTupleArray(reportCount: LONGINT; isArrayFlagSet:BOOLEAN): PtrToUsageTupleArr ;
- VAR
- i,index: LONGINT;
- cursor: UsageQueueItem;
- usageArr : PtrToUsageTupleArr ;
- BEGIN
- IF(totalLen>0) THEN
- NEW(usageArr, reportCount);
- cursor := first;
- index := 0;
- WHILE(cursor#NIL) DO
- FOR i:=0 TO cursor.arrLen-1 DO
- NEW(usageArr[index]);
- IF UsbHidReport.UseUsageDictionaryExt THEN
- (*depending on the array flag, we cannot predict the usageId, because the usageId will be and not the usageValue*)
- IF isArrayFlagSet THEN
- usageArr[index].usageID := UndefinedState;
- ELSE
- usageArr[index].usageID := cursor.usage+i;
- END;
- ELSE
- usageArr[index].usageID := cursor.usage+i;
- END;
- IF UsbHidReport.Debug THEN
- KernelLog.String("Created usage entry for usage "); KernelLog.Int(usageArr[index].usageID,0); KernelLog.Ln;
- END;
- IF (index>=reportCount-1) THEN
- RETURN usageArr;
- END;
- index := index + 1;
- END;
- (*if report count greater than the total of usages, we have to fill up the
- reportCount - usagesFilledUp usages with the last usage id+1, +2 +3, ...*)
- IF((cursor.next=NIL)&(reportCount>index)) THEN
- i:=0;
- WHILE(index<reportCount) DO
- NEW(usageArr[index]);
- usageArr[index].usageID := cursor.usage + cursor.arrLen+i;
- i := i + 1;
- index := index+1;
- IF Debug THEN
- KernelLog.String('UsbHidParser:CreateUsageTupleArray: reportCount>usages, fill up with usage '); KernelLog.Int(cursor.usage+cursor.arrLen+i-1,0);
- KernelLog.Ln;
- END;
- END;
- END;
- cursor := cursor.next;
- END;
- ELSE
- RETURN NIL;
- END;
- RETURN usageArr;
- END CreateUsageTupleArray;
- (*reset the usage queue *)
- PROCEDURE EmptyUsageQueue;
- BEGIN
- first:=NIL;
- last:=NIL;
- totalLen:= 0;
- END EmptyUsageQueue;
- PROCEDURE &Init*;
- BEGIN
- totalLen := 0;
- END Init;
- END UsageQueue;
- TYPE
- (*managing the global state*)
- GlobalStateObject* = OBJECT
- VAR
- firstGlobalState, globalState, gsCursor : GlobalState;
- (*returns the actual state of globalState
- * param: i the i th globalState, f.e. 0 means UsagePage
- * return: globalState [i]
- *)
- PROCEDURE State(i:SHORTINT):LONGINT;
- BEGIN
- IF ((i>=0) & (i < LengthGlobalState)) THEN
- RETURN globalState.state[i];
- ELSE
- RETURN UndefinedState;
- END;
- END State;
- (*push globalState on the stack, the new globalState is empty *)
- PROCEDURE Push;
- VAR i : LONGINT;
- BEGIN
- NEW(globalState.next);
- (*assign all values from globalState to globalState.next*)
- FOR i:= 0 TO LengthGlobalState-1 DO
- globalState.next.state[i] := globalState.state[i];
- globalState.next.isReadByMain[i] := globalState.isReadByMain[i];
- END;
- globalState:=globalState.next;
- END Push;
- (*pop globalState from stack and overwrites the current one *)
- PROCEDURE Pop():BOOLEAN;
- BEGIN
- IF(globalState=firstGlobalState) THEN
- RETURN FALSE;
- ELSE
- gsCursor := firstGlobalState;
- WHILE (gsCursor.next # globalState) DO
- gsCursor := gsCursor.next;
- END;
- globalState := gsCursor;
- globalState.next := NIL;
- RETURN TRUE;
- END;
- END Pop;
- (*deletes the global state
- * param: data the global state
- *)
- PROCEDURE CleanGlobalState(data: GlobalState);
- BEGIN
- data.state[IDUsagePage]:= UndefinedState;
- data.state[IDLogicalMinimum]:= UndefinedState;
- data.state[IDLogicalMaximum]:= UndefinedState;
- data.state[IDPhysicalMinimum]:= UndefinedState;
- data.state[IDPhysicalMaximum]:= UndefinedState;
- data.state[IDUnitExponent]:= UndefinedState;
- data.state[IDUnit]:= UndefinedState;
- data.state[IDReportSize]:= UndefinedState;
- data.state[IDReportID]:= UndefinedState;
- data.state[IDReportCount]:= UndefinedState;
- data.isReadByMain[IDUsagePage]:= FALSE;
- data.isReadByMain[IDLogicalMinimum]:= FALSE;
- data.isReadByMain[IDLogicalMaximum]:= FALSE;
- data.isReadByMain[IDPhysicalMinimum]:= FALSE;
- data.isReadByMain[IDPhysicalMaximum]:= FALSE;
- data.isReadByMain[IDUnitExponent]:= FALSE;
- data.isReadByMain[IDUnit]:= FALSE;
- data.isReadByMain[IDReportSize]:= FALSE;
- data.isReadByMain[IDReportID]:= FALSE;
- data.isReadByMain[IDReportCount]:= FALSE;
- data.next:= NIL;
- END CleanGlobalState;
- (*sets the globalState field to newValue
- * adds GlobalItemsGeneral GlobalItemRedundantlyDeclared error to errorList, if field is already declared with newValue
- * itemNr is the index of the current parsing item
- * param: errorList where to send detected error
- * globalStateField the indext on the globalState table
- * newValue the value to insert at position globalStateField in the globalState
- * itemNr used for errorList; to store information at which item an error detected, when found
- *)
- PROCEDURE SetState( VAR errorList: UsbHidErrors.ErrorList; globalStateField: LONGINT; newValue, itemNr:LONGINT);
- BEGIN
- IF((globalStateField<0) OR (globalStateField>LengthGlobalState)) THEN
- RETURN;
- END;
- IF(globalState.isReadByMain[globalStateField]=FALSE) THEN
- globalState.isReadByMain[globalStateField]:= TRUE;
- globalState.state[globalStateField] := newValue;
- ELSE
- (*ERROR already defined*)
- errorList.Add(itemNr, UsbHidErrors.GlobalItemGeneral, 0H);
- END;
- END SetState;
- (*resets all states in the global state*)
- PROCEDURE ResetGlobalStateFlags;
- VAR i : LONGINT;
- BEGIN
- FOR i:=0 TO LengthGlobalState-1 DO
- globalState.isReadByMain[i]:=FALSE;
- END;
- END ResetGlobalStateFlags;
- (*checks the global state and generates error messages, must only be called by ParseMainItem
- * errorList where to send detected error
- itemNr used for errorList; to store information at which item an error detected, when found
- * return: FALSE, if system can not continue because of fatal errors
- * TRUE, otherwise
- *)
- PROCEDURE VerifyGlobalState( VAR errorList: UsbHidErrors.ErrorList; itemNr: LONGINT):BOOLEAN;
- VAR
- minReportSize, maxReportSize: LONGINT;
- mustStop: BOOLEAN;
- BEGIN
- mustStop:= FALSE;
- IF((globalState.state[IDUsagePage] = UndefinedState) OR
- (globalState.state[IDLogicalMinimum] = UndefinedState) OR
- (globalState.state[IDLogicalMaximum] = UndefinedState) OR
- (globalState.state[IDReportSize] = UndefinedState) OR
- (globalState.state[IDReportCount] = UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0H);
- mustStop:=TRUE;
- END;
- IF((globalState.state[IDPhysicalMinimum]#UndefinedState)OR(globalState.state[IDPhysicalMaximum]#UndefinedState)) THEN
- IF(globalState.state[IDPhysicalMaximum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemPhysicalMinimum, 0H);
- END;
- IF(globalState.state[IDPhysicalMinimum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemPhysicalMaximum, 0H);
- END;
- END;
- IF((globalState.state[IDReportSize]>0) & (globalState.state[IDReportSize]<=32)) THEN
- (*logicalMinimum and logicalMaximum must not exceed 4 bytes, so the reportSize must be in [1,32]*)
- minReportSize:=1;
- maxReportSize:=LSH(minReportSize,globalState.state[IDReportSize]);
- IF((globalState.state[IDLogicalMaximum]-globalState.state[IDLogicalMinimum])>=maxReportSize) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum, 0);
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum, 0);
- END;
- END;
- RETURN mustStop;
- END VerifyGlobalState;
- (*for debugging uses*)
- PROCEDURE PrintGlobalState*(data: GlobalState);
- BEGIN
- KernelLog.String("local state table:"); KernelLog.Ln;
- KernelLog.String("data.state[IDUsagePage]: "); KernelLog.Int(data.state[IDUsagePage],0); KernelLog.Ln;
- KernelLog.String("data.state[IDLogicalMinimum]: "); KernelLog.Int(data.state[IDLogicalMinimum],0); KernelLog.Ln;
- KernelLog.String("data.state[IDLogicalMaximum]: "); KernelLog.Int(data.state[IDLogicalMaximum],0); KernelLog.Ln;
- KernelLog.String("data.state[IDPhysicalMinimum]: "); KernelLog.Int(data.state[IDPhysicalMinimum],0); KernelLog.Ln;
- KernelLog.String("data.state[IDPhysicalMaximum]: "); KernelLog.Int(data.state[IDPhysicalMaximum],0); KernelLog.Ln;
- KernelLog.String("data.state[IDUnitExponent]: "); KernelLog.Int(data.state[IDUnitExponent],0); KernelLog.Ln;
- KernelLog.String("data.state[IDUnit]: "); KernelLog.Int(data.state[IDUnit],0); KernelLog.Ln;
- KernelLog.String("data.state[IDReportSize]: "); KernelLog.Int(data.state[IDReportSize],0); KernelLog.Ln;
- KernelLog.String("data.state[IDReportID]: "); KernelLog.Int(data.state[IDReportID],0); KernelLog.Ln;
- KernelLog.String("data.state[IDReportCount]: "); KernelLog.Int(data.state[IDReportCount],0); KernelLog.Ln;
- KernelLog.Ln;
- END PrintGlobalState;
- BEGIN
- NEW(globalState);
- firstGlobalState := globalState;
- CleanGlobalState(globalState);
- globalState.next := NIL;
- END GlobalStateObject;
- TYPE
- (*managing the local state*)
- LocalStateObj*=OBJECT
- VAR
- localState : LocalState;
- usageQueue: UsageQueue;
- (*returns the actual state of localState
- * param: i the i th localState, f.e. 0 means Usage
- * return: localState [i]
- *)
- PROCEDURE State(i:LONGINT):LONGINT;
- BEGIN
- IF ((i>=0) & (i < LengthLocalState)) THEN
- RETURN localState.state[i];
- ELSE
- RETURN UndefinedState;
- END;
- END State;
- (*returns an UsbHidReport.UsageDictionary
- * param:
- * return: UsbHidReport.UsageDictionary
- *)
- PROCEDURE CreateUsageDictionary(): UsbHidReport.UsageDictionary;
- BEGIN
- RETURN usageQueue.CreateUsageDictionary();
- END CreateUsageDictionary;
- (*return pointer to array of usageTuple
- * param: reportCount the number of usages to create totally
- * return: pointer to array of usageTuple
- *)
- PROCEDURE CreateUsageArray(reportCount: LONGINT;isArrayFlagSet:BOOLEAN): PtrToUsageTupleArr ;
- BEGIN
- RETURN usageQueue.CreateUsageTupleArray(reportCount,isArrayFlagSet);
- END CreateUsageArray;
- (* creates a usageQueueItem depending on LocalState(IDLocalUsageMinimum and IDLocalStateUsageMaximum) and when mainState has set flag
- * flag IsVariable to 1 then all the usages from UsageMinimum to UsageMaximum are added, means UsageMinimum,...UsageMaximum.
- * else only the first globalState.State(IDReportCount) from UsageMinimum beginning are created
- * means UsageMinimum, UsageMinimum+1,...UsageMinimum+globalState.State(IDReportCount)-1.
- * please use verifyLocalState before using CreateUsageArray
- * param: mainState the current main state
- globalState globalState object holding the current globalState
- * return: pointer to array of usageTuple
- *)
- PROCEDURE AppendUsageMinMaxArray(mainState: MainState; globalState: GlobalStateObject);
- VAR
- usageMin, usageMax: LONGINT;
- usageExt: LONGINT;
- set: SET;
- BEGIN
- (*depending on mainState[IDMainIsVariable] we do not have to allocate usageTuple for all usageMinimum to usageMaximum:
- so, if IDMainIsVariable=0 (means we have array fields and not variable fields) we only have to allocate ReportCount usageTuples*)
- set := SYSTEM.VAL(SET, mainState);
- usageMin := State(IDLocalUsageMinimum);
- usageMax := State(IDLocalUsageMaximum);
- usageExt:= Ext(IDLocalExtUsageMinimum);
- IF(IDMainIsVariable IN set) THEN
- IF ((usageMin#UndefinedState) & (usageMax#UndefinedState) & (usageMax>=usageMin)) THEN
- usageQueue.Add(usageMin, usageMax-usageMin+1, usageExt);
- ELSE
- (*Do not allocate anything, so the usageQueue is still empty*)
- END;
- ELSE
- IF ((usageMin#UndefinedState) & (usageMax#UndefinedState) & (usageMax>=usageMin)) THEN
- IF UsbHidReport.UseUsageDictionaryExt THEN
- usageQueue.Add(usageMin, usageMax-usageMin+1,usageExt);
- ELSE
- usageQueue.Add(usageMin,globalState.State(IDReportCount),usageExt);
- END;
- END;
- IF UsbHidReport.Debug THEN
- KernelLog.String("UsbHidParser::LocalStateObj.AppendUsageMinMaxArray:");
- KernelLog.String(" found Constant bit in mainState and added only ReportCount usageTuples");
- KernelLog.Ln;
- END;
- END;
- END AppendUsageMinMaxArray;
- (*set the actual state of localState[i]
- * param: i the i th localState, f.e. 0 means Usage
- value the value to store at localState[i], the higher 16bits are stored as usagePage, if i is set to Usage/UsageMin or UsageMax
- *)
- PROCEDURE SetState(i, value:LONGINT);
- BEGIN
- IF ((i>=0) & (i < LengthLocalState)) THEN
- (*as described at page 41 32bit values for Usage only the lower 16bits identify the usage, the higher 16bits define the usage page*)
- CASE i OF
- IDLocalUsage:
- localState.state[i] := value MOD 10000H;
- SetExt(IDLocalExtUsage, value DIV 10000H);
- (*KernelLog.String("usage added"); KernelLog.Ln;*)
- usageQueue.Add(value MOD 10000H,1,value DIV 10000H);
- |IDLocalUsageMinimum:
- localState.state[i] := value MOD 10000H;
- SetExt(IDLocalExtUsageMinimum, value DIV 10000H);
- (*KernelLog.String("usage min"); KernelLog.Ln;*)
- |IDLocalUsageMaximum:
- localState.state[i] := value MOD 10000H;
- SetExt(IDLocalExtUsageMaximum, value DIV 10000H);
- (*KernelLog.String("usage max"); KernelLog.Ln;*)
- ELSE
- localState.state[i] := value;
- END
- END;
- IF(i=IDLocalUsage) THEN
- END;
- END SetState;
- (*get extention i of localState
- * param: i index of extention
- *)
- PROCEDURE Ext(i:LONGINT):LONGINT;
- BEGIN
- IF ((i>=0) & (i < LengthExtLocalState)) THEN
- RETURN localState.ext[i];
- ELSE
- RETURN UndefinedState;
- END;
- END Ext;
- (*set extention i of localState
- * param: i index of extention
- * value value to store at ext[i]
- *)
- PROCEDURE SetExt(i, value:LONGINT);
- BEGIN
- IF ((i>=0) & (i < LengthExtLocalState)) THEN
- localState.ext[i] := value;
- END;
- END SetExt;
- (*clean all states and extentions of localState*)
- PROCEDURE CleanLocalState;
- BEGIN
- localState.state[IDLocalUsage]:= UndefinedState;
- localState.state[IDLocalUsageMinimum]:= UndefinedState;
- localState.state[IDLocalUsageMaximum]:= UndefinedState;
- localState.state[IDLocalDesignatorIndex]:= UndefinedState;
- localState.state[IDLocalDesignatorMinimum]:= UndefinedState;
- localState.state[IDLocalDesignatorMaximum]:= UndefinedState;
- localState.state[IDLocalStringIndex]:= UndefinedState;
- localState.state[IDLocalStringMinimum]:= UndefinedState;
- localState.state[IDLocalStringMaximum]:= UndefinedState;
- localState.state[IDLocalDelimiter]:= UndefinedState;
- localState.ext[IDLocalExtUsageMinimum]:= UndefinedState;
- localState.ext[IDLocalExtUsageMaximum]:= UndefinedState;
- usageQueue.EmptyUsageQueue();
- END CleanLocalState;
- (*print the local statem, for debugging uses
- * param: data localState to print
- *)
- PROCEDURE PrintLocalState*(data: LocalState);
- BEGIN
- KernelLog.String("global state table:"); KernelLog.Ln;
- KernelLog.String("data.Usage: "); KernelLog.Int(data.state[IDLocalUsage],0); KernelLog.Ln;
- KernelLog.String("data.UsageMinimum: "); KernelLog.Int(data.state[IDLocalUsageMinimum],0); KernelLog.Ln;
- KernelLog.String("data.UsageMaximum: "); KernelLog.Int(data.state[IDLocalUsageMaximum],0); KernelLog.Ln;
- KernelLog.String("data.DesignatorIndex: "); KernelLog.Int(data.state[IDLocalDesignatorIndex],0); KernelLog.Ln;
- KernelLog.String("data.DesignatorMinimum: "); KernelLog.Int(data.state[IDLocalDesignatorMinimum],0); KernelLog.Ln;
- KernelLog.String("data.DesignatorMaximum: ");KernelLog.Int(data.state[IDLocalDesignatorMaximum],0); KernelLog.Ln;
- KernelLog.String("data.StringIndex: "); KernelLog.Int(data.state[IDLocalStringIndex],0); KernelLog.Ln;
- KernelLog.String("data.StringMinimum: "); KernelLog.Int(data.state[IDLocalStringMinimum],0); KernelLog.Ln;
- KernelLog.String("data.StringMaximum: "); KernelLog.Int(data.state[IDLocalStringMaximum],0); KernelLog.Ln;
- KernelLog.String("data.Delimiter: "); KernelLog.Int(data.state[IDLocalDelimiter],0); KernelLog.Ln;
- KernelLog.String("ext.UsageMinimum: "); KernelLog.Int(data.ext[IDLocalExtUsageMinimum],0); KernelLog.Ln;
- KernelLog.String("data.UsageMaximum: "); KernelLog.Int(data.ext[IDLocalExtUsageMaximum],0); KernelLog.Ln;
- KernelLog.Ln;
- END PrintLocalState;
- (*checks the local state and generates error messages, must only be called by ParseMainItem
- * param: errorList where to send errors
- * itemNr for errorList; the current item number parsed
- *)
- PROCEDURE VerifyLocalState(VAR errorList: UsbHidErrors.ErrorList; itemNr: LONGINT);
- BEGIN
- IF(localState.state[IDLocalUsage]=UndefinedState) THEN
- (*check first if usageMinimum and usageMaximum is set*)
- IF((localState.state[IDLocalUsageMinimum]=UndefinedState)OR(localState.state[IDLocalUsageMaximum]=UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsage,0H);
- END;
- END;
- (*only check if at least one of UsageMinimum and UsageMaximum is set*)
- IF ((localState.state[IDLocalUsageMinimum]#UndefinedState)OR(localState.state[IDLocalUsageMaximum]#UndefinedState)) THEN
- IF(localState.state[IDLocalUsageMinimum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 0H);
- END;
- IF(localState.state[IDLocalUsageMaximum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 0H);
- END;
- IF(localState.state[IDLocalUsageMinimum]>localState.state[IDLocalUsageMaximum]) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 1H);
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 1H);
- END;
- IF(localState.ext[IDLocalExtUsageMinimum]#localState.ext[IDLocalExtUsageMaximum]) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 3H);
- errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 2H);
- END;
- END;
- IF ((localState.state[IDLocalDesignatorMinimum]#UndefinedState)OR(localState.state[IDLocalDesignatorMaximum]#UndefinedState)) THEN
- IF(localState.state[IDLocalDesignatorMinimum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMaximum, 0H);
- END;
- IF(localState.state[IDLocalDesignatorMaximum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMinimum, 0H);
- END;
- IF(localState.state[IDLocalDesignatorMinimum]>localState.state[IDLocalDesignatorMaximum]) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMaximum, 1H);
- errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMinimum, 1H);
- END;
- END;
- IF ((localState.state[IDLocalStringMinimum]#UndefinedState)OR(localState.state[IDLocalStringMaximum]#UndefinedState)) THEN
- IF(localState.state[IDLocalStringMinimum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemStringMaximum, 0H);
- END;
- IF(localState.state[IDLocalStringMaximum]=UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemStringMinimum, 0H);
- END;
- IF(localState.state[IDLocalStringMinimum]>localState.state[IDLocalStringMaximum]) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemStringMaximum, 1H);
- errorList.Add(itemNr, UsbHidErrors.LocalItemStringMinimum, 1H);
- END;
- END;
- END VerifyLocalState;
- PROCEDURE &Init*;
- BEGIN
- NEW(localState);
- NEW(usageQueue);
- CleanLocalState;
- END Init;
- END LocalStateObj;
- (* parses the hid descriptor, genererates error list*)
- ItemParser* = OBJECT
- VAR
- (** Initialized by USB driver before Connect() is called *)
- mainState : MainState;
- globalState : GlobalStateObject;
- localState : LocalStateObj;
- errorList* : UsbHidErrors.ErrorList;
- inputOutputFeatureParsed : BOOLEAN;
- depth : LONGINT;
- reportManager : UsbHidReport.HidReportManager;
- (* converts an unsigned long to a signed long, depending on the nofBytes used
- * param: nofBytes the number of bytes used
- * data the long int to convert
- *)
- PROCEDURE ToSignedLong*(nofBytes, data : LONGINT): LONGINT;
- VAR returnValue : LONGINT;
- BEGIN
- returnValue := data;
- CASE nofBytes OF
- 1:
- IF(data>=80H) THEN
- returnValue := data- 100H;
- END;
- |2:
- IF(data>=8000H) THEN
- returnValue := data- 10000H;
- END;
- |4:
- IF(data>=80000000H) THEN
- (*unhappy with that expression but could not write data - 100000000H*)
- returnValue := data- LONGINT(0FFFFFFFFH) - LONGINT(0FFFFFFFFH) - 2;
- END;
- ELSE
- returnValue := 0;
- END;
- RETURN returnValue;
- END ToSignedLong;
- (* create new hid report from globalState and localState
- * param: reportType IDMainItemInput, IDMainItemOutput or IDMainItemFeature
- * return: hidReport new created HidReport
- *)
- PROCEDURE CreateHidReport(reportType, itemNr: LONGINT):UsbHidReport.HidReport;
- VAR
- hidReport: UsbHidReport.HidReport;
- isArrayFlagSet: BOOLEAN;
- diff, maxVal: LONGINT;
- BEGIN
- ASSERT((reportType=IDMainItemInput) OR (reportType = IDMainItemFeature));
- NEW(hidReport);
- hidReport.reportID := globalState.State(IDReportID);
- hidReport.reportType := reportType;
- hidReport.reportSize := globalState.State(IDReportSize);
- hidReport.usagePage := globalState.State(IDUsagePage);
- hidReport.mainState := mainState;
- (*hidReport.reportOffset := UndefinedState;*)
- hidReport.reportCount := globalState.State(IDReportCount);
- hidReport.logicalMinimum := globalState.State(IDLogicalMinimum);
- hidReport.logicalMaximum := globalState.State(IDLogicalMaximum);
- hidReport.physicalMinimum := globalState.State(IDPhysicalMinimum);
- hidReport.physicalMaximum := globalState.State(IDPhysicalMaximum);
- hidReport.unitExponent := globalState.State(IDUnitExponent);
- hidReport.unit := globalState.State(IDUnit);
- isArrayFlagSet := {IDMainIsVariable} * SYSTEM.VAL(SET,mainState) = {};
- IF UsbHidReport.UseUsageDictionaryExt THEN
- (*only append the usageDictionary when mainState has set array flag (usageID sent but not usageValues)*)
- IF isArrayFlagSet THEN
- hidReport.supportedUsages := localState.CreateUsageDictionary();
- END;
- END;
- hidReport.usages := localState.CreateUsageArray(hidReport.reportCount, isArrayFlagSet);
- (*check the remaining possible errors*)
- (*reportSize too small*)
- IF hidReport.reportSize<32 THEN
- diff:=hidReport.logicalMaximum-hidReport.logicalMinimum;
- maxVal := SYSTEM.VAL(LONGINT,SYSTEM.VAL(SET,{hidReport.reportSize}));
- IF diff>maxVal THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum,0H);
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum,0H);
- END;
- END;
- (*array has to have logical Minimum=1 &
- logical Maximum=maxUsage*)
- IF( {IDMainIsVariable,IDMainIsConstant} * SYSTEM.VAL(SET,hidReport.mainState)={})THEN
- (*no tested device cares about this rule
- IF hidReport.logicalMinimum#1 THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum,2H);
- END;
- *)
- IF UsbHidReport.UseUsageDictionaryExt THEN
- maxVal := reportManager.DictSize(hidReport.supportedUsages);
- IF(maxVal#hidReport.logicalMaximum-hidReport.logicalMinimum+1) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum,2H);
- END;
- END;
- END;
- RETURN hidReport;
- END CreateHidReport;
- (* return reference to reportManager
- * return: reportManager where all report infos are stored
- *)
- PROCEDURE GetReportManager*(): UsbHidReport.HidReportManager;
- BEGIN
- RETURN reportManager;
- END GetReportManager;
- (*parse main item
- * param: si to get bTag, bSize and data params
- * itemNr used for errorList
- *)
- PROCEDURE ParseMainItem*(si: Item; itemNr: LONGINT);
- VAR
- checkLocalState : BOOLEAN;
- aReport: UsbHidReport.HidReport;
- PROCEDURE VerifyMainPreconditions;
- BEGIN
- IF(globalState.State(IDLogicalMinimum)>=globalState.State(IDLogicalMaximum)) THEN
- IF globalState.State(IDLogicalMinimum)#UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 3);
- END;
- END;
- IF(globalState.State(IDPhysicalMinimum)>=globalState.State(IDPhysicalMaximum)) THEN
- IF globalState.State(IDPhysicalMinimum)#UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 3);
- END;
- END;
- IF globalState.State(IDUsagePage) = UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
- IF Trace THEN KernelLog.String("Usage Page must be defined prior"); END;
- END;
- IF globalState.State(IDLogicalMinimum) = UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
- IF Trace THEN KernelLog.String("Logical Min must be defined prior"); END;
- END;
- IF globalState.State(IDLogicalMaximum) = UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
- IF Trace THEN KernelLog.String("Logical Max must be defined prior"); END;
- END;
- IF globalState.State(IDReportSize) = UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
- IF Trace THEN KernelLog.String("Report Size must be defined prior"); END;
- END;
- IF globalState.State(IDReportCount) = UndefinedState THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
- IF Trace THEN KernelLog.String("Report Count must be defined prior"); END;
- END;
- END VerifyMainPreconditions;
- BEGIN
- IF (Trace OR Debug) THEN
- HidParserExt.ParseMainItem(si.bTag,si.bSize, si.data, itemNr, depth);
- END;
- checkLocalState := TRUE;
- CASE si.bTag OF
- IDMainItemInput: (*Input Item*)
- IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
- checkLocalState := FALSE;
- END;
- inputOutputFeatureParsed := TRUE;
- mainState:= si.data;
- VerifyMainPreconditions;
- (*usages are only added to local state if mainState has not set the constant flag*)
- localState.AppendUsageMinMaxArray(mainState, globalState);
- aReport := CreateHidReport(IDMainItemInput,itemNr);
- IF ((aReport.usages = NIL) & ({IDMainIsConstant} * SYSTEM.VAL(SET,aReport.mainState)={})) THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
- END;
- reportManager.AddReport(aReport);
- |IDMainItemOutput: (*Output Item*)
- IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
- checkLocalState := FALSE;
- END;
- inputOutputFeatureParsed := TRUE;
- mainState:= si.data;
- VerifyMainPreconditions;
- (*localState.AppendUsageMinMaxArray(mainState, globalState);
- reportManager.AddReport(CreateHidReport(IDMainItemOutput));*)
- |IDMainItemFeature: (*Feature Item*)
- IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
- checkLocalState := FALSE;
- END;
- inputOutputFeatureParsed := TRUE;
- mainState:= si.data;
- VerifyMainPreconditions;
- localState.AppendUsageMinMaxArray(mainState, globalState);
- aReport := CreateHidReport(IDMainItemFeature,itemNr);
- reportManager.AddReport(aReport);
- |IDMainItemCollection: (*Collection*)
- INC(depth);
- IF (si.data>6H) THEN
- IF si.data < 8FH THEN
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
- ELSE
- (*non standard is treated as an error*)
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
- END;
- END;
- IF ((reportManager.OnTopLevel()=FALSE) & (si.data=1H)) THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemCollection, 2H);
- END;
- reportManager.BeginCollection(si.data, globalState.State(IDUsagePage), localState.State(IDLocalUsage));
- checkLocalState := FALSE;
- |IDMainItemEndCollection: (*End Collection*)
- DEC(depth);
- checkLocalState := FALSE;
- IF reportManager.OnTopLevel() THEN
- errorList.Add(itemNr, UsbHidErrors.MainItemEndCollection, 0);
- END;
- reportManager.EndCollection;
- ELSE
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
- END;
- IF (checkLocalState) THEN
- localState.VerifyLocalState(errorList, itemNr);
- IF(globalState.VerifyGlobalState(errorList, itemNr)=FALSE) THEN
- END;
- END;
- IF(inputOutputFeatureParsed=TRUE) THEN
- END;
- globalState.ResetGlobalStateFlags;
- localState.CleanLocalState;
- END ParseMainItem;
- (*parse global item
- * param: si to get bTag, bSize and data params
- * itemNr used for errorList
- *)
- PROCEDURE ParseGlobalItem*( si: Item; itemNr: LONGINT);
- VAR temp : LONGINT;
- BEGIN
- IF (Trace OR Debug) THEN
- IF((si.bTag=1H) OR (si.bTag=2H)) THEN
- temp := si.data;
- HidParserExt.ParseGlobalItem(si.bTag, si.bSize, ToSignedLong(si.bSize,temp), itemNr, depth);
- ELSE
- HidParserExt.ParseGlobalItem(si.bTag, si.bSize, si.data, itemNr, depth);
- END;
- END;
- CASE si.bTag OF
- 0H: (*Usage Page *)
- globalState.SetState(errorList, IDUsagePage, si.data, itemNr);
- IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDUsagePage)=UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 2H);
- END;
- CASE si.data OF
- (*REFERENCE: p. 4 HID Usage Tables*)
- 0H:
- (*Undefined*)
- errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 0H);
- |1H: (*Generic Desktop Controls*)
- |2H: (*Simulation Controls*)
- |3H: (*VR Controls*)
- |4H: (*Sport Controls *)
- |5H: (*Game Controls*)
- |6H: (*Generic Device Controls*)
- |7H: (*Keyboard/Keypad*)
- |8H: (*LEDs*)
- |9H: (*Button*)
- |0AH: (*Ordinal*)
- |0BH: (*Telephony*)
- |0CH: (*Consumer*)
- |0DH: (*Digitizer*)
- |0EH: (*Reserved*)
- |0FH: (*PID Page*)
- |10H: (*Unicode*)
- (*
- |11H: (*Reserved*)
- |12H: (*Reserved*)
- |13H: (*Reserved*)
- *)
- |14H: (*Alphanumeric Display*)
- (* from 15h tol 3fH
- |15H-3fH: (*Reserved*)*)
- |40: (*Medical Instruments*)
- (* from 41H tol 7fH
- |41H-7fH: (*Reserved*)*)
- |81H: (*Monitor pages*)
- |82H: (*Monitor pages*)
- |83H: (*Monitor pages*)
- |84H: (*Power pages*)
- |85H: (*Power pages*)
- |86H: (*Power pages*)
- |87H: (*Power pages*)
- (* from 88H tol 8BH
- |41H-7fH: (*Reserved*)*)
- |8CH: (*Bar Code Scanner page*)
- |8DH: (*Scale page*)
- |8EH: (*Magnetic Stripe reading (MSR) Devices*)
- |8FH: (*Reserved Point of Sale pages*)
- ELSE
- (*Reserved*)
- IF(si.data>0FFFFH) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 1H);
- END;
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
- END;
- |1H: (*Logical Minimum *)
- (*Locigal Minimum can be negative, the value needs to be interpreted as signed int 2s complement*)
- globalState.SetState(errorList, IDLogicalMinimum, ToSignedLong(si.bSize, si.data), itemNr);
- IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDLogicalMinimum)=UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum, 1H);
- END;
- |2H: (*Logical Maximum*)
- (*Locigal Maximum could be negative, the value needs to be interpreted as signed int 2s complement*)
- globalState.SetState(errorList, IDLogicalMaximum, ToSignedLong(si.bSize, si.data), itemNr);
- IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDLogicalMaximum)=UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum, 1H);
- END;
- |3H: (*Physical Minimum *)
- globalState.SetState(errorList, IDPhysicalMinimum, si.data, itemNr);
- |4H: (*Physical Maximum*)
- globalState.SetState(errorList, IDPhysicalMaximum, si.data, itemNr);
- |5H: (*Unit Exponent*)
- globalState.SetState(errorList, IDUnitExponent, si.data, itemNr);
- (*nice to have: zehner exponent decodieren gemäss seite 38*)
- |6H: (*Unit*)
- globalState.SetState(errorList, IDUnit, si.data, itemNr);
- |7H: (*Report Size*)
- globalState.SetState(errorList, IDReportSize, si.data, itemNr);
- IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDReportSize)=UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportSize, 1H);
- END;
- |8H: (*Report ID*)
- globalState.SetState(errorList, IDReportID, si.data, itemNr);
- IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDReportID)=UndefinedState)) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 2H);
- END;
- IF(si.data=0) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 0H);
- ELSE
- IF(si.data>255) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 1H);
- END;
- END;
- IF (reportManager.OnTopLevel()) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 3H);
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 4H);
- END;
- |9H: (*Report Count *)
- globalState.SetState(errorList, IDReportCount, si.data, itemNr);
- IF(si.data=0) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemReportCount, 0H);
- END;
- |10: (*Push*)
- (*do push*)
- globalState.Push;
- IF(si.bSize#0) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemPush, 1H);
- END;
- |11: (*Pop*)
- (*do pop: first check if globalState = firstGlobalState,
- then check start at firstGlobalState and find the second last element in the list, when found, delete the last*)
- IF(globalState.Pop()=FALSE) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemPop, 0H);
- END;
- IF(si.bSize#0) THEN
- errorList.Add(itemNr, UsbHidErrors.GlobalItemPop, 1H);
- END;
- ELSE
- (*Reserved*)
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
- END;
- END ParseGlobalItem;
- (*parse local item
- * param: si to get bTag, bSize and data params
- * itemNr used for errorList
- *)
- PROCEDURE ParseLocalItem*(si: Item; itemNr: LONGINT);
- BEGIN
- IF (Trace OR Debug) THEN
- HidParserExt.ParseLocalItem(si.bTag, si.bSize, si.data, itemNr, depth, globalState.State(IDUsagePage));
- END;
- (*as described in HID Parser Error Codes page 3, all local item checks for errors and warnings (except delimiter) are checked
- when the parser encounters the next main item*)
- CASE si.bTag OF
- 0H: (*Usage*)
- (*as described at page 41 32bit values for Usage only the lower 16bits identify the usage, the higher 16bits define the usage page*)
- localState.SetState(IDLocalUsage, si.data);
- |1H: (*Usage Minimum*)
- (*as described at page 41 32bit values for UsageMinimum only the lower 16bits identify the usageMinimum, the higher 16bits define the usage page*)
- localState.SetState(IDLocalUsageMinimum, si.data);
- |2H: (*Usage Maximum*)
- (*as described at page 41 32bit values for UsageMaximum only the lower 12bits identify the usageMaximum, the higher 16bits define the usage page*)
- localState.SetState(IDLocalUsageMaximum, si.data);
- |3H: (*Designator Index*)
- localState.SetState(IDLocalDesignatorIndex, si.data);
- |4H: (*Designator Minimum*)
- localState.SetState(IDLocalDesignatorMinimum, si.data);
- |5H: (*Designator Maximum*)
- localState.SetState(IDLocalDesignatorMaximum, si.data);
- (*|6H: (*RESERVED*)*)
- |7H: (*String Index*)
- localState.SetState(IDLocalStringIndex, si.data);
- |8H: (*String Minimum*)
- localState.SetState(IDLocalStringMinimum, si.data);
- |9H: (*String Maximum*)
- localState.SetState(IDLocalStringMaximum, si.data);
- |0AH: (*Delimiter*)
- CASE si.data OF
- 0: (*open set*)
- IF (localState.State(IDLocalDelimiter)#UndefinedState) THEN
- errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 1H);
- END;
- localState.SetState(IDLocalDelimiter, si.data);
- |1H: (*close set*)
- IF(localState.State(IDLocalDelimiter)=UndefinedState) THEN
- (*there is no corresponding open set*)
- errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 2H);
- END;
- localState.SetState(IDLocalDelimiter, si.data);
- ELSE (*NOT DEFINED*)
- errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 0H);
- END;
- ELSE (*RESERVED*)
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
- END;
- END ParseLocalItem;
- (*parse long item (not used in Device Class Definition for HID Version 1.11, long item is reserved; when found in hid descriptor, it is
- * ignored and simply skipped
- * param: li to get bTag and bSize params
- * reportBuffer to read data
- * len the len to read on the reportBuffer
- * startIndex position where to begin read on reportBuffer
- * itemNr used for errorList
- *)
- PROCEDURE ParseLongItem*(li: Item; reportBuffer: Usbdi.BufferPtr; len, startIndex, itemNr : LONGINT);
- BEGIN
- errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003EH);
- END ParseLongItem;
- (*parses the report descriptor
- * param: hidDescriptor the hid descriptor
- reportBuffer data of hid report descriptor
- * return: TRUE if successfull
- FALSE otherwise
- *)
- PROCEDURE ParseReportDescriptor*(hidDescriptor : UsbHid.HidDescriptor; reportBuffer : Usbdi.BufferPtr): BOOLEAN;
- VAR
- itemCounter : LONGINT;
- cur : LONGINT;
- item : POINTER TO Item;
- hidCollection: UsbHidReport.HidCollection;
- BEGIN
- NEW(item);
- itemCounter := 0;
- cur := 0;
- IF Trace THEN
- KernelLog.Ln;
- KernelLog.String("Report Descriptor Content:");
- KernelLog.Ln;
- END;
- LOOP
- (*catch report buffer overflow*)
- IF cur >= hidDescriptor.wDescriptorLength-1 THEN EXIT; END;
- (*init si*)
- item.bSize := ORD(reportBuffer[cur]) MOD 4;
- (*as defined on page 26, Device Class Definition for HID*)
- IF (item.bSize = 3) THEN INC(item.bSize); END;
- item.bType := (ORD(reportBuffer[cur]) DIV 4) MOD 4;
- item.bTag := (ORD(reportBuffer[cur]) DIV 16) MOD 16;
- INC(cur);
- (*get the data depending on si.bSize*)
- IF (item.bType # ShortItemBTypeReserved) THEN
- IF (item.bSize#0) THEN
- CASE item.bSize OF
- 1:
- item.data:= ORD(reportBuffer[cur]);
- |2:
- item.data:= ORD(reportBuffer[cur+1]);
- item.data:= 100H*item.data+ORD(reportBuffer[cur]);
- |4:
- item.data:= ORD(reportBuffer[cur+3]);
- item.data:= 100H*item.data + ORD(reportBuffer[cur+2]);
- item.data:= 100H*item.data + ORD(reportBuffer[cur+1]);
- item.data:= 100H*item.data + ORD(reportBuffer[cur]);
- END;
- IF(item.data<0) THEN
- KernelLog.String("item.data<0 at index: "); KernelLog.Int(cur,0);KernelLog.Ln;
- KernelLog.String("item.bSize is "); KernelLog.Int(item.bSize,2); KernelLog.Ln;
- END;
- ELSE
- item.data:= 0;
- END;
- (*identifying shortitem*)
- CASE (item.bType) OF
- ShortItemBTypeMain:
- (*ShortItem Main*)
- IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" main "); END;
- ParseMainItem(item^, itemCounter);
- |ShortItemBTypeGlobal:
- (*ShortItem Global*)
- IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" global"); END;
- ParseGlobalItem(item^, itemCounter);
- |ShortItemBTypeLocal:
- (*ShortItem Local*)
- IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" local "); END;
- ParseLocalItem(item^, itemCounter);
- ELSE
- RETURN FALSE;
- END;
- INC(cur, item.bSize);
- ELSE
- (*long item*)
- (*cur is at beginning of the longiten item, index of bTag, bType and bSize*)
- IF (item.bSize#0) THEN
- (*Detect reportBuffer overflow:
- cur: current position of shortItemTag,
- 1 : (shortItemTag+1) holds the dataSize,
- ORD(reportBuffer[cur+1]): the length of data to read after dataSize in Byte
- *)
- IF((cur+1+ORD(reportBuffer[cur+1]))<hidDescriptor.wDescriptorLength) THEN
- ParseLongItem(item^, reportBuffer, ORD(reportBuffer[cur+1]), cur+1, itemCounter);
- (*EvalStatusCode(hidStatusCode);*)
- END;
- INC(cur,ORD(reportBuffer[cur+1]) +1);
- END;
- END;
- INC(itemCounter);
- END; (*LOOP*)
- IF UsbHidReport.Debug THEN
- KernelLog.String("Starting report layout:"); KernelLog.Ln;
- hidCollection := reportManager.GetCollection(-1,-1);
- KernelLog.String("Searching Mouse Collection (usagePage 1 and usage 2):"); KernelLog.Ln;
- hidCollection := reportManager.GetCollection(1,2);
- IF (hidCollection#NIL) THEN
- KernelLog.String("Mouse Collection found:"); KernelLog.Ln;
- KernelLog.String("usagePage: "); KernelLog.Int(hidCollection.usagePage,0);
- KernelLog.String(", usage: "); KernelLog.Int(hidCollection.usage,0);
- ELSE
- KernelLog.String("Mouse Collection not found");
- END;
- KernelLog.Ln;
- END;
- IF (reportManager.OnTopLevel()= FALSE) THEN
- errorList.Add(itemCounter, UsbHidErrors.MainItemCollection, 0);
- END;
- RETURN TRUE;
- END ParseReportDescriptor;
- (*when detaching the device*)
- PROCEDURE Disconnect*;
- BEGIN
- errorList := NIL;
- END Disconnect;
- PROCEDURE &Init*;
- BEGIN
- NEW(globalState);
- NEW(localState);
- NEW(errorList);
- IF Debug THEN KernelLog.String("ItemParser is initialized"); KernelLog.Ln; END;
- inputOutputFeatureParsed := FALSE;
- IF Debug THEN
- depth := 1;
- ELSE
- depth := 0;
- END;
- NEW(reportManager);
- END Init;
- END ItemParser;
- END UsbHidParser.
- System.Free UsbHidParser UsbHidParserExt~
|