UsbHidParser.Mod 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267
  1. MODULE UsbHidParser; (** AUTHOR "ottigerm"; PURPOSE "HID Items parser with error codes" *)
  2. (**
  3. * Bluebottle USB HID Items Module
  4. *
  5. * This is the module providing item parsing as described in Device Class Definition for HID Version 1.11
  6. *
  7. * Overview:
  8. *
  9. * Main Items As described on page 28
  10. * Global Items As described on page 35
  11. * Local Items As described on page 39
  12. *
  13. * History:
  14. *
  15. * 02.06.2006 History started (ottigerm)
  16. * 27.09.2006 Version 1.0
  17. *)
  18. IMPORT SYSTEM, KernelLog, UsbHid, Usbdi, UsbHidErrors, HidParserExt := UsbHidParserExt, UsbHidReport;
  19. CONST
  20. Trace* = FALSE;
  21. Debug* = FALSE;
  22. ShortItemBTypeMain = 0H;
  23. ShortItemBTypeGlobal = 1H;
  24. ShortItemBTypeLocal = 2H;
  25. ShortItemBTypeReserved = 3H;
  26. UndefinedState* = UsbHidReport.UndefinedState;
  27. StatusCodeOk* = 1;
  28. StatusCodeFailed* = 0;
  29. (*Enum for global state*)
  30. IDUsagePage = HidParserExt.ParseIDUsagePage;
  31. IDLogicalMinimum = HidParserExt.ParseIDLogicalMinimum;
  32. IDLogicalMaximum = HidParserExt.ParseIDLogicalMaximum;
  33. IDPhysicalMinimum = HidParserExt.ParseIDPhysicalMinimum;
  34. IDPhysicalMaximum = HidParserExt.ParseIDPhysicalMaximum;
  35. IDUnitExponent = HidParserExt.ParseIDUnitExponent;
  36. IDUnit = HidParserExt.ParseIDUnit;
  37. IDReportSize = HidParserExt.ParseIDReportSize;
  38. IDReportID = HidParserExt.ParseIDReportID;
  39. IDReportCount = HidParserExt.ParseIDReportCount;
  40. LengthGlobalState = 10;
  41. (*Enum for local state*)
  42. IDLocalUsage = HidParserExt.ParseIDUsage;
  43. IDLocalUsageMinimum = HidParserExt.ParseIDUsageMinimum;
  44. IDLocalUsageMaximum = HidParserExt.ParseIDUsageMaximum;
  45. IDLocalDesignatorIndex = HidParserExt.ParseIDDesignatorIndex;
  46. IDLocalDesignatorMinimum = HidParserExt.ParseIDDesignatorMinimum;
  47. IDLocalDesignatorMaximum = HidParserExt.ParseIDDesignatorMaximum;
  48. IDLocalStringIndex = HidParserExt.ParseIDStringIndex-1;
  49. IDLocalStringMinimum = HidParserExt.ParseIDStringMinimum-1;
  50. IDLocalStringMaximum = HidParserExt.ParseIDStringMaximum-1;
  51. IDLocalDelimiter = HidParserExt.ParseIDDelimiter-1;
  52. LengthLocalState = 10;
  53. IDLocalExtUsage = HidParserExt.ParseIDUsage;
  54. IDLocalExtUsageMinimum = HidParserExt.ParseIDUsageMinimum;
  55. IDLocalExtUsageMaximum = HidParserExt.ParseIDUsageMaximum;
  56. LengthExtLocalState = 3;
  57. IDLocalAddStringIndex = 4;
  58. (*Main state*)
  59. IDMainIsConstant* = HidParserExt.ParseIDDataConstant;
  60. IDMainIsVariable* = HidParserExt.ParseIDArrayVariable;
  61. IDMainIsRelative* = HidParserExt.ParseIDAbsoluteRelative;
  62. IDMainIsWrap* = HidParserExt.ParseIDNoWrapWrap;
  63. IDMainIsNonLinear* = HidParserExt.ParseIDLinearNonLinear;
  64. IDMainIsNoPreferred* = HidParserExt.ParseIDPreferdStateNoPreferd;
  65. IDMainIsNullState* = HidParserExt.ParseIDNoNullPositionNullState;
  66. IDMainIsVolatile* = HidParserExt.ParseIDNonVolatileVolatile;
  67. IDMainIsBufferedBytes* = HidParserExt.ParseIDBitFieldBufferedByte;
  68. (*Main item tag*)
  69. IDMainItemInput = 08H;
  70. IDMainItemOutput = 09H;
  71. IDMainItemFeature = 0BH;
  72. IDMainItemCollection = 0AH;
  73. IDMainItemEndCollection = 0CH;
  74. TYPE
  75. (*as defined in device class definition for HID Version 1.11, p. 26, 6.2.2 ShortItems*)
  76. Item = RECORD
  77. bSize : LONGINT; (*bit 0,1: size of data*)
  78. bType : LONGINT; (*bit 2,3: Main, Global, Local or Reserved(Longitem) Type*)
  79. bTag : LONGINT; (*bit 4-7: index in the main, global or local tag table*)
  80. data : LONGINT; (*data to read after byte 0 depending on bSize*)
  81. END;
  82. (*holding the main state*)
  83. MainState = LONGINT;
  84. (*holding the state of all possible global states*)
  85. GlobalState = POINTER TO RECORD
  86. (*UsagePage, Logical Min, Logical Max, Physical Min, Physical Max, Unit Exp, Unit, ReportSize, ReportID, ReportCount*)
  87. state : ARRAY LengthGlobalState OF LONGINT;
  88. (*for detecting erros in the hid descriptor*)
  89. isReadByMain : ARRAY LengthGlobalState OF BOOLEAN;
  90. (*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*)
  91. next : GlobalState;
  92. END;
  93. LocalState = POINTER TO RECORD
  94. (*Usage, Usage Min, Usage Max, Designator Index, Designator Maximum, String Index, String Minimum, String Maximum, Delimiter*)
  95. state : ARRAY LengthLocalState OF LONGINT;
  96. (*for detecting errors in the hid descriptor; usage Min and usage Max can have extensions*)
  97. ext : ARRAY LengthExtLocalState OF LONGINT;
  98. END;
  99. UsageQueueItem = POINTER TO RECORD
  100. usage : LONGINT;
  101. usagePage : LONGINT;
  102. arrLen : LONGINT;
  103. next : UsageQueueItem;
  104. END;
  105. PtrToUsageTupleArr = UsbHidReport.PtrToUsageTupleArr;
  106. (*Linked list for managing holding usages: there can be multiple usages between main items, so we need a dynamic datatype*)
  107. UsageQueue=OBJECT
  108. VAR
  109. first, last : UsageQueueItem;
  110. totalLen : LONGINT;
  111. (*adds the usage[0..arrLen-1] to the end of HIDUsageQueue
  112. * param: usage the usage to add
  113. * arrLen if more usages, the total number of usages
  114. * usageExt the usagePage
  115. *)
  116. PROCEDURE Add*(usage, arrLen, usageExt: LONGINT);
  117. BEGIN
  118. (*empty list*)
  119. IF (last = NIL) THEN
  120. NEW(last);
  121. first := last;
  122. ELSE
  123. NEW(last.next);
  124. last := last.next;
  125. END;
  126. last.usage := usage;
  127. last.usagePage := usageExt;
  128. last.arrLen:= arrLen;
  129. totalLen:= totalLen + arrLen;
  130. END Add;
  131. (*returns an UsbHidReport.UsageDictionary
  132. * param:
  133. * return: UsbHidReport.UsageDictionary
  134. *)
  135. PROCEDURE CreateUsageDictionary():UsbHidReport.UsageDictionary;
  136. VAR
  137. cursor: UsageQueueItem;
  138. usageQueueCounter, i: LONGINT;
  139. dict: UsbHidReport.UsageDictionary;
  140. BEGIN
  141. (*first count the length of usageQueue*)
  142. cursor := first;
  143. WHILE (cursor # NIL) DO
  144. cursor := cursor.next;
  145. usageQueueCounter := usageQueueCounter + 1;
  146. END;
  147. IF (usageQueueCounter>0) THEN
  148. NEW(dict);
  149. NEW(dict.elements,usageQueueCounter);
  150. cursor := first;
  151. FOR i:= 0 TO usageQueueCounter-1 DO
  152. dict.elements[i].firstUsageID := cursor.usage;
  153. dict.elements[i].otherUsagePage := cursor.usagePage;
  154. dict.elements[i].nofFollowing := cursor.arrLen-1;
  155. cursor := cursor.next;
  156. END;
  157. (*KernelLog.String("added usageDictionary with "); KernelLog.Int(usageQueueCounter,0); KernelLog.String(" elements."); KernelLog.Ln;*)
  158. END;
  159. RETURN dict;
  160. END CreateUsageDictionary;
  161. (*returns an array of usageTuples
  162. * param: the number of elements wanted in the array
  163. * return: pointer to the usage tuple array
  164. *)
  165. PROCEDURE CreateUsageTupleArray(reportCount: LONGINT; isArrayFlagSet:BOOLEAN): PtrToUsageTupleArr ;
  166. VAR
  167. i,index: LONGINT;
  168. cursor: UsageQueueItem;
  169. usageArr : PtrToUsageTupleArr ;
  170. BEGIN
  171. IF(totalLen>0) THEN
  172. NEW(usageArr, reportCount);
  173. cursor := first;
  174. index := 0;
  175. WHILE(cursor#NIL) DO
  176. FOR i:=0 TO cursor.arrLen-1 DO
  177. NEW(usageArr[index]);
  178. IF UsbHidReport.UseUsageDictionaryExt THEN
  179. (*depending on the array flag, we cannot predict the usageId, because the usageId will be and not the usageValue*)
  180. IF isArrayFlagSet THEN
  181. usageArr[index].usageID := UndefinedState;
  182. ELSE
  183. usageArr[index].usageID := cursor.usage+i;
  184. END;
  185. ELSE
  186. usageArr[index].usageID := cursor.usage+i;
  187. END;
  188. IF UsbHidReport.Debug THEN
  189. KernelLog.String("Created usage entry for usage "); KernelLog.Int(usageArr[index].usageID,0); KernelLog.Ln;
  190. END;
  191. IF (index>=reportCount-1) THEN
  192. RETURN usageArr;
  193. END;
  194. index := index + 1;
  195. END;
  196. (*if report count greater than the total of usages, we have to fill up the
  197. reportCount - usagesFilledUp usages with the last usage id+1, +2 +3, ...*)
  198. IF((cursor.next=NIL)&(reportCount>index)) THEN
  199. i:=0;
  200. WHILE(index<reportCount) DO
  201. NEW(usageArr[index]);
  202. usageArr[index].usageID := cursor.usage + cursor.arrLen+i;
  203. i := i + 1;
  204. index := index+1;
  205. IF Debug THEN
  206. KernelLog.String('UsbHidParser:CreateUsageTupleArray: reportCount>usages, fill up with usage '); KernelLog.Int(cursor.usage+cursor.arrLen+i-1,0);
  207. KernelLog.Ln;
  208. END;
  209. END;
  210. END;
  211. cursor := cursor.next;
  212. END;
  213. ELSE
  214. RETURN NIL;
  215. END;
  216. RETURN usageArr;
  217. END CreateUsageTupleArray;
  218. (*reset the usage queue *)
  219. PROCEDURE EmptyUsageQueue;
  220. BEGIN
  221. first:=NIL;
  222. last:=NIL;
  223. totalLen:= 0;
  224. END EmptyUsageQueue;
  225. PROCEDURE &Init*;
  226. BEGIN
  227. totalLen := 0;
  228. END Init;
  229. END UsageQueue;
  230. TYPE
  231. (*managing the global state*)
  232. GlobalStateObject* = OBJECT
  233. VAR
  234. firstGlobalState, globalState, gsCursor : GlobalState;
  235. (*returns the actual state of globalState
  236. * param: i the i th globalState, f.e. 0 means UsagePage
  237. * return: globalState [i]
  238. *)
  239. PROCEDURE State(i:SHORTINT):LONGINT;
  240. BEGIN
  241. IF ((i>=0) & (i < LengthGlobalState)) THEN
  242. RETURN globalState.state[i];
  243. ELSE
  244. RETURN UndefinedState;
  245. END;
  246. END State;
  247. (*push globalState on the stack, the new globalState is empty *)
  248. PROCEDURE Push;
  249. VAR i : LONGINT;
  250. BEGIN
  251. NEW(globalState.next);
  252. (*assign all values from globalState to globalState.next*)
  253. FOR i:= 0 TO LengthGlobalState-1 DO
  254. globalState.next.state[i] := globalState.state[i];
  255. globalState.next.isReadByMain[i] := globalState.isReadByMain[i];
  256. END;
  257. globalState:=globalState.next;
  258. END Push;
  259. (*pop globalState from stack and overwrites the current one *)
  260. PROCEDURE Pop():BOOLEAN;
  261. BEGIN
  262. IF(globalState=firstGlobalState) THEN
  263. RETURN FALSE;
  264. ELSE
  265. gsCursor := firstGlobalState;
  266. WHILE (gsCursor.next # globalState) DO
  267. gsCursor := gsCursor.next;
  268. END;
  269. globalState := gsCursor;
  270. globalState.next := NIL;
  271. RETURN TRUE;
  272. END;
  273. END Pop;
  274. (*deletes the global state
  275. * param: data the global state
  276. *)
  277. PROCEDURE CleanGlobalState(data: GlobalState);
  278. BEGIN
  279. data.state[IDUsagePage]:= UndefinedState;
  280. data.state[IDLogicalMinimum]:= UndefinedState;
  281. data.state[IDLogicalMaximum]:= UndefinedState;
  282. data.state[IDPhysicalMinimum]:= UndefinedState;
  283. data.state[IDPhysicalMaximum]:= UndefinedState;
  284. data.state[IDUnitExponent]:= UndefinedState;
  285. data.state[IDUnit]:= UndefinedState;
  286. data.state[IDReportSize]:= UndefinedState;
  287. data.state[IDReportID]:= UndefinedState;
  288. data.state[IDReportCount]:= UndefinedState;
  289. data.isReadByMain[IDUsagePage]:= FALSE;
  290. data.isReadByMain[IDLogicalMinimum]:= FALSE;
  291. data.isReadByMain[IDLogicalMaximum]:= FALSE;
  292. data.isReadByMain[IDPhysicalMinimum]:= FALSE;
  293. data.isReadByMain[IDPhysicalMaximum]:= FALSE;
  294. data.isReadByMain[IDUnitExponent]:= FALSE;
  295. data.isReadByMain[IDUnit]:= FALSE;
  296. data.isReadByMain[IDReportSize]:= FALSE;
  297. data.isReadByMain[IDReportID]:= FALSE;
  298. data.isReadByMain[IDReportCount]:= FALSE;
  299. data.next:= NIL;
  300. END CleanGlobalState;
  301. (*sets the globalState field to newValue
  302. * adds GlobalItemsGeneral GlobalItemRedundantlyDeclared error to errorList, if field is already declared with newValue
  303. * itemNr is the index of the current parsing item
  304. * param: errorList where to send detected error
  305. * globalStateField the indext on the globalState table
  306. * newValue the value to insert at position globalStateField in the globalState
  307. * itemNr used for errorList; to store information at which item an error detected, when found
  308. *)
  309. PROCEDURE SetState( VAR errorList: UsbHidErrors.ErrorList; globalStateField: LONGINT; newValue, itemNr:LONGINT);
  310. BEGIN
  311. IF((globalStateField<0) OR (globalStateField>LengthGlobalState)) THEN
  312. RETURN;
  313. END;
  314. IF(globalState.isReadByMain[globalStateField]=FALSE) THEN
  315. globalState.isReadByMain[globalStateField]:= TRUE;
  316. globalState.state[globalStateField] := newValue;
  317. ELSE
  318. (*ERROR already defined*)
  319. errorList.Add(itemNr, UsbHidErrors.GlobalItemGeneral, 0H);
  320. END;
  321. END SetState;
  322. (*resets all states in the global state*)
  323. PROCEDURE ResetGlobalStateFlags;
  324. VAR i : LONGINT;
  325. BEGIN
  326. FOR i:=0 TO LengthGlobalState-1 DO
  327. globalState.isReadByMain[i]:=FALSE;
  328. END;
  329. END ResetGlobalStateFlags;
  330. (*checks the global state and generates error messages, must only be called by ParseMainItem
  331. * errorList where to send detected error
  332. itemNr used for errorList; to store information at which item an error detected, when found
  333. * return: FALSE, if system can not continue because of fatal errors
  334. * TRUE, otherwise
  335. *)
  336. PROCEDURE VerifyGlobalState( VAR errorList: UsbHidErrors.ErrorList; itemNr: LONGINT):BOOLEAN;
  337. VAR
  338. minReportSize, maxReportSize: LONGINT;
  339. mustStop: BOOLEAN;
  340. BEGIN
  341. mustStop:= FALSE;
  342. IF((globalState.state[IDUsagePage] = UndefinedState) OR
  343. (globalState.state[IDLogicalMinimum] = UndefinedState) OR
  344. (globalState.state[IDLogicalMaximum] = UndefinedState) OR
  345. (globalState.state[IDReportSize] = UndefinedState) OR
  346. (globalState.state[IDReportCount] = UndefinedState)) THEN
  347. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0H);
  348. mustStop:=TRUE;
  349. END;
  350. IF((globalState.state[IDPhysicalMinimum]#UndefinedState)OR(globalState.state[IDPhysicalMaximum]#UndefinedState)) THEN
  351. IF(globalState.state[IDPhysicalMaximum]=UndefinedState) THEN
  352. errorList.Add(itemNr, UsbHidErrors.GlobalItemPhysicalMinimum, 0H);
  353. END;
  354. IF(globalState.state[IDPhysicalMinimum]=UndefinedState) THEN
  355. errorList.Add(itemNr, UsbHidErrors.GlobalItemPhysicalMaximum, 0H);
  356. END;
  357. END;
  358. IF((globalState.state[IDReportSize]>0) & (globalState.state[IDReportSize]<=32)) THEN
  359. (*logicalMinimum and logicalMaximum must not exceed 4 bytes, so the reportSize must be in [1,32]*)
  360. minReportSize:=1;
  361. maxReportSize:=LSH(minReportSize,globalState.state[IDReportSize]);
  362. IF((globalState.state[IDLogicalMaximum]-globalState.state[IDLogicalMinimum])>=maxReportSize) THEN
  363. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum, 0);
  364. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum, 0);
  365. END;
  366. END;
  367. RETURN mustStop;
  368. END VerifyGlobalState;
  369. (*for debugging uses*)
  370. PROCEDURE PrintGlobalState*(data: GlobalState);
  371. BEGIN
  372. KernelLog.String("local state table:"); KernelLog.Ln;
  373. KernelLog.String("data.state[IDUsagePage]: "); KernelLog.Int(data.state[IDUsagePage],0); KernelLog.Ln;
  374. KernelLog.String("data.state[IDLogicalMinimum]: "); KernelLog.Int(data.state[IDLogicalMinimum],0); KernelLog.Ln;
  375. KernelLog.String("data.state[IDLogicalMaximum]: "); KernelLog.Int(data.state[IDLogicalMaximum],0); KernelLog.Ln;
  376. KernelLog.String("data.state[IDPhysicalMinimum]: "); KernelLog.Int(data.state[IDPhysicalMinimum],0); KernelLog.Ln;
  377. KernelLog.String("data.state[IDPhysicalMaximum]: "); KernelLog.Int(data.state[IDPhysicalMaximum],0); KernelLog.Ln;
  378. KernelLog.String("data.state[IDUnitExponent]: "); KernelLog.Int(data.state[IDUnitExponent],0); KernelLog.Ln;
  379. KernelLog.String("data.state[IDUnit]: "); KernelLog.Int(data.state[IDUnit],0); KernelLog.Ln;
  380. KernelLog.String("data.state[IDReportSize]: "); KernelLog.Int(data.state[IDReportSize],0); KernelLog.Ln;
  381. KernelLog.String("data.state[IDReportID]: "); KernelLog.Int(data.state[IDReportID],0); KernelLog.Ln;
  382. KernelLog.String("data.state[IDReportCount]: "); KernelLog.Int(data.state[IDReportCount],0); KernelLog.Ln;
  383. KernelLog.Ln;
  384. END PrintGlobalState;
  385. BEGIN
  386. NEW(globalState);
  387. firstGlobalState := globalState;
  388. CleanGlobalState(globalState);
  389. globalState.next := NIL;
  390. END GlobalStateObject;
  391. TYPE
  392. (*managing the local state*)
  393. LocalStateObj*=OBJECT
  394. VAR
  395. localState : LocalState;
  396. usageQueue: UsageQueue;
  397. (*returns the actual state of localState
  398. * param: i the i th localState, f.e. 0 means Usage
  399. * return: localState [i]
  400. *)
  401. PROCEDURE State(i:LONGINT):LONGINT;
  402. BEGIN
  403. IF ((i>=0) & (i < LengthLocalState)) THEN
  404. RETURN localState.state[i];
  405. ELSE
  406. RETURN UndefinedState;
  407. END;
  408. END State;
  409. (*returns an UsbHidReport.UsageDictionary
  410. * param:
  411. * return: UsbHidReport.UsageDictionary
  412. *)
  413. PROCEDURE CreateUsageDictionary(): UsbHidReport.UsageDictionary;
  414. BEGIN
  415. RETURN usageQueue.CreateUsageDictionary();
  416. END CreateUsageDictionary;
  417. (*return pointer to array of usageTuple
  418. * param: reportCount the number of usages to create totally
  419. * return: pointer to array of usageTuple
  420. *)
  421. PROCEDURE CreateUsageArray(reportCount: LONGINT;isArrayFlagSet:BOOLEAN): PtrToUsageTupleArr ;
  422. BEGIN
  423. RETURN usageQueue.CreateUsageTupleArray(reportCount,isArrayFlagSet);
  424. END CreateUsageArray;
  425. (* creates a usageQueueItem depending on LocalState(IDLocalUsageMinimum and IDLocalStateUsageMaximum) and when mainState has set flag
  426. * flag IsVariable to 1 then all the usages from UsageMinimum to UsageMaximum are added, means UsageMinimum,...UsageMaximum.
  427. * else only the first globalState.State(IDReportCount) from UsageMinimum beginning are created
  428. * means UsageMinimum, UsageMinimum+1,...UsageMinimum+globalState.State(IDReportCount)-1.
  429. * please use verifyLocalState before using CreateUsageArray
  430. * param: mainState the current main state
  431. globalState globalState object holding the current globalState
  432. * return: pointer to array of usageTuple
  433. *)
  434. PROCEDURE AppendUsageMinMaxArray(mainState: MainState; globalState: GlobalStateObject);
  435. VAR
  436. usageMin, usageMax: LONGINT;
  437. usageExt: LONGINT;
  438. set: SET;
  439. BEGIN
  440. (*depending on mainState[IDMainIsVariable] we do not have to allocate usageTuple for all usageMinimum to usageMaximum:
  441. so, if IDMainIsVariable=0 (means we have array fields and not variable fields) we only have to allocate ReportCount usageTuples*)
  442. set := SYSTEM.VAL(SET, mainState);
  443. usageMin := State(IDLocalUsageMinimum);
  444. usageMax := State(IDLocalUsageMaximum);
  445. usageExt:= Ext(IDLocalExtUsageMinimum);
  446. IF(IDMainIsVariable IN set) THEN
  447. IF ((usageMin#UndefinedState) & (usageMax#UndefinedState) & (usageMax>=usageMin)) THEN
  448. usageQueue.Add(usageMin, usageMax-usageMin+1, usageExt);
  449. ELSE
  450. (*Do not allocate anything, so the usageQueue is still empty*)
  451. END;
  452. ELSE
  453. IF ((usageMin#UndefinedState) & (usageMax#UndefinedState) & (usageMax>=usageMin)) THEN
  454. IF UsbHidReport.UseUsageDictionaryExt THEN
  455. usageQueue.Add(usageMin, usageMax-usageMin+1,usageExt);
  456. ELSE
  457. usageQueue.Add(usageMin,globalState.State(IDReportCount),usageExt);
  458. END;
  459. END;
  460. IF UsbHidReport.Debug THEN
  461. KernelLog.String("UsbHidParser::LocalStateObj.AppendUsageMinMaxArray:");
  462. KernelLog.String(" found Constant bit in mainState and added only ReportCount usageTuples");
  463. KernelLog.Ln;
  464. END;
  465. END;
  466. END AppendUsageMinMaxArray;
  467. (*set the actual state of localState[i]
  468. * param: i the i th localState, f.e. 0 means Usage
  469. value the value to store at localState[i], the higher 16bits are stored as usagePage, if i is set to Usage/UsageMin or UsageMax
  470. *)
  471. PROCEDURE SetState(i, value:LONGINT);
  472. BEGIN
  473. IF ((i>=0) & (i < LengthLocalState)) THEN
  474. (*as described at page 41 32bit values for Usage only the lower 16bits identify the usage, the higher 16bits define the usage page*)
  475. CASE i OF
  476. IDLocalUsage:
  477. localState.state[i] := value MOD 10000H;
  478. SetExt(IDLocalExtUsage, value DIV 10000H);
  479. (*KernelLog.String("usage added"); KernelLog.Ln;*)
  480. usageQueue.Add(value MOD 10000H,1,value DIV 10000H);
  481. |IDLocalUsageMinimum:
  482. localState.state[i] := value MOD 10000H;
  483. SetExt(IDLocalExtUsageMinimum, value DIV 10000H);
  484. (*KernelLog.String("usage min"); KernelLog.Ln;*)
  485. |IDLocalUsageMaximum:
  486. localState.state[i] := value MOD 10000H;
  487. SetExt(IDLocalExtUsageMaximum, value DIV 10000H);
  488. (*KernelLog.String("usage max"); KernelLog.Ln;*)
  489. ELSE
  490. localState.state[i] := value;
  491. END
  492. END;
  493. IF(i=IDLocalUsage) THEN
  494. END;
  495. END SetState;
  496. (*get extention i of localState
  497. * param: i index of extention
  498. *)
  499. PROCEDURE Ext(i:LONGINT):LONGINT;
  500. BEGIN
  501. IF ((i>=0) & (i < LengthExtLocalState)) THEN
  502. RETURN localState.ext[i];
  503. ELSE
  504. RETURN UndefinedState;
  505. END;
  506. END Ext;
  507. (*set extention i of localState
  508. * param: i index of extention
  509. * value value to store at ext[i]
  510. *)
  511. PROCEDURE SetExt(i, value:LONGINT);
  512. BEGIN
  513. IF ((i>=0) & (i < LengthExtLocalState)) THEN
  514. localState.ext[i] := value;
  515. END;
  516. END SetExt;
  517. (*clean all states and extentions of localState*)
  518. PROCEDURE CleanLocalState;
  519. BEGIN
  520. localState.state[IDLocalUsage]:= UndefinedState;
  521. localState.state[IDLocalUsageMinimum]:= UndefinedState;
  522. localState.state[IDLocalUsageMaximum]:= UndefinedState;
  523. localState.state[IDLocalDesignatorIndex]:= UndefinedState;
  524. localState.state[IDLocalDesignatorMinimum]:= UndefinedState;
  525. localState.state[IDLocalDesignatorMaximum]:= UndefinedState;
  526. localState.state[IDLocalStringIndex]:= UndefinedState;
  527. localState.state[IDLocalStringMinimum]:= UndefinedState;
  528. localState.state[IDLocalStringMaximum]:= UndefinedState;
  529. localState.state[IDLocalDelimiter]:= UndefinedState;
  530. localState.ext[IDLocalExtUsageMinimum]:= UndefinedState;
  531. localState.ext[IDLocalExtUsageMaximum]:= UndefinedState;
  532. usageQueue.EmptyUsageQueue();
  533. END CleanLocalState;
  534. (*print the local statem, for debugging uses
  535. * param: data localState to print
  536. *)
  537. PROCEDURE PrintLocalState*(data: LocalState);
  538. BEGIN
  539. KernelLog.String("global state table:"); KernelLog.Ln;
  540. KernelLog.String("data.Usage: "); KernelLog.Int(data.state[IDLocalUsage],0); KernelLog.Ln;
  541. KernelLog.String("data.UsageMinimum: "); KernelLog.Int(data.state[IDLocalUsageMinimum],0); KernelLog.Ln;
  542. KernelLog.String("data.UsageMaximum: "); KernelLog.Int(data.state[IDLocalUsageMaximum],0); KernelLog.Ln;
  543. KernelLog.String("data.DesignatorIndex: "); KernelLog.Int(data.state[IDLocalDesignatorIndex],0); KernelLog.Ln;
  544. KernelLog.String("data.DesignatorMinimum: "); KernelLog.Int(data.state[IDLocalDesignatorMinimum],0); KernelLog.Ln;
  545. KernelLog.String("data.DesignatorMaximum: ");KernelLog.Int(data.state[IDLocalDesignatorMaximum],0); KernelLog.Ln;
  546. KernelLog.String("data.StringIndex: "); KernelLog.Int(data.state[IDLocalStringIndex],0); KernelLog.Ln;
  547. KernelLog.String("data.StringMinimum: "); KernelLog.Int(data.state[IDLocalStringMinimum],0); KernelLog.Ln;
  548. KernelLog.String("data.StringMaximum: "); KernelLog.Int(data.state[IDLocalStringMaximum],0); KernelLog.Ln;
  549. KernelLog.String("data.Delimiter: "); KernelLog.Int(data.state[IDLocalDelimiter],0); KernelLog.Ln;
  550. KernelLog.String("ext.UsageMinimum: "); KernelLog.Int(data.ext[IDLocalExtUsageMinimum],0); KernelLog.Ln;
  551. KernelLog.String("data.UsageMaximum: "); KernelLog.Int(data.ext[IDLocalExtUsageMaximum],0); KernelLog.Ln;
  552. KernelLog.Ln;
  553. END PrintLocalState;
  554. (*checks the local state and generates error messages, must only be called by ParseMainItem
  555. * param: errorList where to send errors
  556. * itemNr for errorList; the current item number parsed
  557. *)
  558. PROCEDURE VerifyLocalState(VAR errorList: UsbHidErrors.ErrorList; itemNr: LONGINT);
  559. BEGIN
  560. IF(localState.state[IDLocalUsage]=UndefinedState) THEN
  561. (*check first if usageMinimum and usageMaximum is set*)
  562. IF((localState.state[IDLocalUsageMinimum]=UndefinedState)OR(localState.state[IDLocalUsageMaximum]=UndefinedState)) THEN
  563. errorList.Add(itemNr, UsbHidErrors.LocalItemUsage,0H);
  564. END;
  565. END;
  566. (*only check if at least one of UsageMinimum and UsageMaximum is set*)
  567. IF ((localState.state[IDLocalUsageMinimum]#UndefinedState)OR(localState.state[IDLocalUsageMaximum]#UndefinedState)) THEN
  568. IF(localState.state[IDLocalUsageMinimum]=UndefinedState) THEN
  569. errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 0H);
  570. END;
  571. IF(localState.state[IDLocalUsageMaximum]=UndefinedState) THEN
  572. errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 0H);
  573. END;
  574. IF(localState.state[IDLocalUsageMinimum]>localState.state[IDLocalUsageMaximum]) THEN
  575. errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 1H);
  576. errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 1H);
  577. END;
  578. IF(localState.ext[IDLocalExtUsageMinimum]#localState.ext[IDLocalExtUsageMaximum]) THEN
  579. errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMinimum, 3H);
  580. errorList.Add(itemNr, UsbHidErrors.LocalItemUsageMaximum, 2H);
  581. END;
  582. END;
  583. IF ((localState.state[IDLocalDesignatorMinimum]#UndefinedState)OR(localState.state[IDLocalDesignatorMaximum]#UndefinedState)) THEN
  584. IF(localState.state[IDLocalDesignatorMinimum]=UndefinedState) THEN
  585. errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMaximum, 0H);
  586. END;
  587. IF(localState.state[IDLocalDesignatorMaximum]=UndefinedState) THEN
  588. errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMinimum, 0H);
  589. END;
  590. IF(localState.state[IDLocalDesignatorMinimum]>localState.state[IDLocalDesignatorMaximum]) THEN
  591. errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMaximum, 1H);
  592. errorList.Add(itemNr, UsbHidErrors.LocalItemDesignatorMinimum, 1H);
  593. END;
  594. END;
  595. IF ((localState.state[IDLocalStringMinimum]#UndefinedState)OR(localState.state[IDLocalStringMaximum]#UndefinedState)) THEN
  596. IF(localState.state[IDLocalStringMinimum]=UndefinedState) THEN
  597. errorList.Add(itemNr, UsbHidErrors.LocalItemStringMaximum, 0H);
  598. END;
  599. IF(localState.state[IDLocalStringMaximum]=UndefinedState) THEN
  600. errorList.Add(itemNr, UsbHidErrors.LocalItemStringMinimum, 0H);
  601. END;
  602. IF(localState.state[IDLocalStringMinimum]>localState.state[IDLocalStringMaximum]) THEN
  603. errorList.Add(itemNr, UsbHidErrors.LocalItemStringMaximum, 1H);
  604. errorList.Add(itemNr, UsbHidErrors.LocalItemStringMinimum, 1H);
  605. END;
  606. END;
  607. END VerifyLocalState;
  608. PROCEDURE &Init*;
  609. BEGIN
  610. NEW(localState);
  611. NEW(usageQueue);
  612. CleanLocalState;
  613. END Init;
  614. END LocalStateObj;
  615. (* parses the hid descriptor, genererates error list*)
  616. ItemParser* = OBJECT
  617. VAR
  618. (** Initialized by USB driver before Connect() is called *)
  619. mainState : MainState;
  620. globalState : GlobalStateObject;
  621. localState : LocalStateObj;
  622. errorList* : UsbHidErrors.ErrorList;
  623. inputOutputFeatureParsed : BOOLEAN;
  624. depth : LONGINT;
  625. reportManager : UsbHidReport.HidReportManager;
  626. (* converts an unsigned long to a signed long, depending on the nofBytes used
  627. * param: nofBytes the number of bytes used
  628. * data the long int to convert
  629. *)
  630. PROCEDURE ToSignedLong*(nofBytes, data : LONGINT): LONGINT;
  631. VAR returnValue : LONGINT;
  632. BEGIN
  633. returnValue := data;
  634. CASE nofBytes OF
  635. 1:
  636. IF(data>=80H) THEN
  637. returnValue := data- 100H;
  638. END;
  639. |2:
  640. IF(data>=8000H) THEN
  641. returnValue := data- 10000H;
  642. END;
  643. |4:
  644. IF(data>=80000000H) THEN
  645. (*unhappy with that expression but could not write data - 100000000H*)
  646. returnValue := data- LONGINT(0FFFFFFFFH) - LONGINT(0FFFFFFFFH) - 2;
  647. END;
  648. ELSE
  649. returnValue := 0;
  650. END;
  651. RETURN returnValue;
  652. END ToSignedLong;
  653. (* create new hid report from globalState and localState
  654. * param: reportType IDMainItemInput, IDMainItemOutput or IDMainItemFeature
  655. * return: hidReport new created HidReport
  656. *)
  657. PROCEDURE CreateHidReport(reportType, itemNr: LONGINT):UsbHidReport.HidReport;
  658. VAR
  659. hidReport: UsbHidReport.HidReport;
  660. isArrayFlagSet: BOOLEAN;
  661. diff, maxVal: LONGINT;
  662. BEGIN
  663. ASSERT((reportType=IDMainItemInput) OR (reportType = IDMainItemFeature));
  664. NEW(hidReport);
  665. hidReport.reportID := globalState.State(IDReportID);
  666. hidReport.reportType := reportType;
  667. hidReport.reportSize := globalState.State(IDReportSize);
  668. hidReport.usagePage := globalState.State(IDUsagePage);
  669. hidReport.mainState := mainState;
  670. (*hidReport.reportOffset := UndefinedState;*)
  671. hidReport.reportCount := globalState.State(IDReportCount);
  672. hidReport.logicalMinimum := globalState.State(IDLogicalMinimum);
  673. hidReport.logicalMaximum := globalState.State(IDLogicalMaximum);
  674. hidReport.physicalMinimum := globalState.State(IDPhysicalMinimum);
  675. hidReport.physicalMaximum := globalState.State(IDPhysicalMaximum);
  676. hidReport.unitExponent := globalState.State(IDUnitExponent);
  677. hidReport.unit := globalState.State(IDUnit);
  678. isArrayFlagSet := {IDMainIsVariable} * SYSTEM.VAL(SET,mainState) = {};
  679. IF UsbHidReport.UseUsageDictionaryExt THEN
  680. (*only append the usageDictionary when mainState has set array flag (usageID sent but not usageValues)*)
  681. IF isArrayFlagSet THEN
  682. hidReport.supportedUsages := localState.CreateUsageDictionary();
  683. END;
  684. END;
  685. hidReport.usages := localState.CreateUsageArray(hidReport.reportCount, isArrayFlagSet);
  686. (*check the remaining possible errors*)
  687. (*reportSize too small*)
  688. IF hidReport.reportSize<32 THEN
  689. diff:=hidReport.logicalMaximum-hidReport.logicalMinimum;
  690. maxVal := SYSTEM.VAL(LONGINT,SYSTEM.VAL(SET,{hidReport.reportSize}));
  691. IF diff>maxVal THEN
  692. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum,0H);
  693. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum,0H);
  694. END;
  695. END;
  696. (*array has to have logical Minimum=1 &
  697. logical Maximum=maxUsage*)
  698. IF( {IDMainIsVariable,IDMainIsConstant} * SYSTEM.VAL(SET,hidReport.mainState)={})THEN
  699. (*no tested device cares about this rule
  700. IF hidReport.logicalMinimum#1 THEN
  701. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum,2H);
  702. END;
  703. *)
  704. IF UsbHidReport.UseUsageDictionaryExt THEN
  705. maxVal := reportManager.DictSize(hidReport.supportedUsages);
  706. IF(maxVal#hidReport.logicalMaximum-hidReport.logicalMinimum+1) THEN
  707. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum,2H);
  708. END;
  709. END;
  710. END;
  711. RETURN hidReport;
  712. END CreateHidReport;
  713. (* return reference to reportManager
  714. * return: reportManager where all report infos are stored
  715. *)
  716. PROCEDURE GetReportManager*(): UsbHidReport.HidReportManager;
  717. BEGIN
  718. RETURN reportManager;
  719. END GetReportManager;
  720. (*parse main item
  721. * param: si to get bTag, bSize and data params
  722. * itemNr used for errorList
  723. *)
  724. PROCEDURE ParseMainItem*(si: Item; itemNr: LONGINT);
  725. VAR
  726. checkLocalState : BOOLEAN;
  727. aReport: UsbHidReport.HidReport;
  728. PROCEDURE VerifyMainPreconditions;
  729. BEGIN
  730. IF(globalState.State(IDLogicalMinimum)>=globalState.State(IDLogicalMaximum)) THEN
  731. IF globalState.State(IDLogicalMinimum)#UndefinedState THEN
  732. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 3);
  733. END;
  734. END;
  735. IF(globalState.State(IDPhysicalMinimum)>=globalState.State(IDPhysicalMaximum)) THEN
  736. IF globalState.State(IDPhysicalMinimum)#UndefinedState THEN
  737. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 3);
  738. END;
  739. END;
  740. IF globalState.State(IDUsagePage) = UndefinedState THEN
  741. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
  742. IF Trace THEN KernelLog.String("Usage Page must be defined prior"); END;
  743. END;
  744. IF globalState.State(IDLogicalMinimum) = UndefinedState THEN
  745. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
  746. IF Trace THEN KernelLog.String("Logical Min must be defined prior"); END;
  747. END;
  748. IF globalState.State(IDLogicalMaximum) = UndefinedState THEN
  749. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
  750. IF Trace THEN KernelLog.String("Logical Max must be defined prior"); END;
  751. END;
  752. IF globalState.State(IDReportSize) = UndefinedState THEN
  753. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
  754. IF Trace THEN KernelLog.String("Report Size must be defined prior"); END;
  755. END;
  756. IF globalState.State(IDReportCount) = UndefinedState THEN
  757. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
  758. IF Trace THEN KernelLog.String("Report Count must be defined prior"); END;
  759. END;
  760. END VerifyMainPreconditions;
  761. BEGIN
  762. IF (Trace OR Debug) THEN
  763. HidParserExt.ParseMainItem(si.bTag,si.bSize, si.data, itemNr, depth);
  764. END;
  765. checkLocalState := TRUE;
  766. CASE si.bTag OF
  767. IDMainItemInput: (*Input Item*)
  768. IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
  769. checkLocalState := FALSE;
  770. END;
  771. inputOutputFeatureParsed := TRUE;
  772. mainState:= si.data;
  773. VerifyMainPreconditions;
  774. (*usages are only added to local state if mainState has not set the constant flag*)
  775. localState.AppendUsageMinMaxArray(mainState, globalState);
  776. aReport := CreateHidReport(IDMainItemInput,itemNr);
  777. IF ((aReport.usages = NIL) & ({IDMainIsConstant} * SYSTEM.VAL(SET,aReport.mainState)={})) THEN
  778. errorList.Add(itemNr, UsbHidErrors.MainItemInput, 0);
  779. END;
  780. reportManager.AddReport(aReport);
  781. |IDMainItemOutput: (*Output Item*)
  782. IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
  783. checkLocalState := FALSE;
  784. END;
  785. inputOutputFeatureParsed := TRUE;
  786. mainState:= si.data;
  787. VerifyMainPreconditions;
  788. (*localState.AppendUsageMinMaxArray(mainState, globalState);
  789. reportManager.AddReport(CreateHidReport(IDMainItemOutput));*)
  790. |IDMainItemFeature: (*Feature Item*)
  791. IF IDMainIsConstant IN SYSTEM.VAL(SET, si.data) THEN
  792. checkLocalState := FALSE;
  793. END;
  794. inputOutputFeatureParsed := TRUE;
  795. mainState:= si.data;
  796. VerifyMainPreconditions;
  797. localState.AppendUsageMinMaxArray(mainState, globalState);
  798. aReport := CreateHidReport(IDMainItemFeature,itemNr);
  799. reportManager.AddReport(aReport);
  800. |IDMainItemCollection: (*Collection*)
  801. INC(depth);
  802. IF (si.data>6H) THEN
  803. IF si.data < 8FH THEN
  804. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
  805. ELSE
  806. (*non standard is treated as an error*)
  807. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
  808. END;
  809. END;
  810. IF ((reportManager.OnTopLevel()=FALSE) & (si.data=1H)) THEN
  811. errorList.Add(itemNr, UsbHidErrors.MainItemCollection, 2H);
  812. END;
  813. reportManager.BeginCollection(si.data, globalState.State(IDUsagePage), localState.State(IDLocalUsage));
  814. checkLocalState := FALSE;
  815. |IDMainItemEndCollection: (*End Collection*)
  816. DEC(depth);
  817. checkLocalState := FALSE;
  818. IF reportManager.OnTopLevel() THEN
  819. errorList.Add(itemNr, UsbHidErrors.MainItemEndCollection, 0);
  820. END;
  821. reportManager.EndCollection;
  822. ELSE
  823. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
  824. END;
  825. IF (checkLocalState) THEN
  826. localState.VerifyLocalState(errorList, itemNr);
  827. IF(globalState.VerifyGlobalState(errorList, itemNr)=FALSE) THEN
  828. END;
  829. END;
  830. IF(inputOutputFeatureParsed=TRUE) THEN
  831. END;
  832. globalState.ResetGlobalStateFlags;
  833. localState.CleanLocalState;
  834. END ParseMainItem;
  835. (*parse global item
  836. * param: si to get bTag, bSize and data params
  837. * itemNr used for errorList
  838. *)
  839. PROCEDURE ParseGlobalItem*( si: Item; itemNr: LONGINT);
  840. VAR temp : LONGINT;
  841. BEGIN
  842. IF (Trace OR Debug) THEN
  843. IF((si.bTag=1H) OR (si.bTag=2H)) THEN
  844. temp := si.data;
  845. HidParserExt.ParseGlobalItem(si.bTag, si.bSize, ToSignedLong(si.bSize,temp), itemNr, depth);
  846. ELSE
  847. HidParserExt.ParseGlobalItem(si.bTag, si.bSize, si.data, itemNr, depth);
  848. END;
  849. END;
  850. CASE si.bTag OF
  851. 0H: (*Usage Page *)
  852. globalState.SetState(errorList, IDUsagePage, si.data, itemNr);
  853. IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDUsagePage)=UndefinedState)) THEN
  854. errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 2H);
  855. END;
  856. CASE si.data OF
  857. (*REFERENCE: p. 4 HID Usage Tables*)
  858. 0H:
  859. (*Undefined*)
  860. errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 0H);
  861. |1H: (*Generic Desktop Controls*)
  862. |2H: (*Simulation Controls*)
  863. |3H: (*VR Controls*)
  864. |4H: (*Sport Controls *)
  865. |5H: (*Game Controls*)
  866. |6H: (*Generic Device Controls*)
  867. |7H: (*Keyboard/Keypad*)
  868. |8H: (*LEDs*)
  869. |9H: (*Button*)
  870. |0AH: (*Ordinal*)
  871. |0BH: (*Telephony*)
  872. |0CH: (*Consumer*)
  873. |0DH: (*Digitizer*)
  874. |0EH: (*Reserved*)
  875. |0FH: (*PID Page*)
  876. |10H: (*Unicode*)
  877. (*
  878. |11H: (*Reserved*)
  879. |12H: (*Reserved*)
  880. |13H: (*Reserved*)
  881. *)
  882. |14H: (*Alphanumeric Display*)
  883. (* from 15h tol 3fH
  884. |15H-3fH: (*Reserved*)*)
  885. |40: (*Medical Instruments*)
  886. (* from 41H tol 7fH
  887. |41H-7fH: (*Reserved*)*)
  888. |81H: (*Monitor pages*)
  889. |82H: (*Monitor pages*)
  890. |83H: (*Monitor pages*)
  891. |84H: (*Power pages*)
  892. |85H: (*Power pages*)
  893. |86H: (*Power pages*)
  894. |87H: (*Power pages*)
  895. (* from 88H tol 8BH
  896. |41H-7fH: (*Reserved*)*)
  897. |8CH: (*Bar Code Scanner page*)
  898. |8DH: (*Scale page*)
  899. |8EH: (*Magnetic Stripe reading (MSR) Devices*)
  900. |8FH: (*Reserved Point of Sale pages*)
  901. ELSE
  902. (*Reserved*)
  903. IF(si.data>0FFFFH) THEN
  904. errorList.Add(itemNr, UsbHidErrors.GlobalItemUsagePage, 1H);
  905. END;
  906. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
  907. END;
  908. |1H: (*Logical Minimum *)
  909. (*Locigal Minimum can be negative, the value needs to be interpreted as signed int 2s complement*)
  910. globalState.SetState(errorList, IDLogicalMinimum, ToSignedLong(si.bSize, si.data), itemNr);
  911. IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDLogicalMinimum)=UndefinedState)) THEN
  912. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMinimum, 1H);
  913. END;
  914. |2H: (*Logical Maximum*)
  915. (*Locigal Maximum could be negative, the value needs to be interpreted as signed int 2s complement*)
  916. globalState.SetState(errorList, IDLogicalMaximum, ToSignedLong(si.bSize, si.data), itemNr);
  917. IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDLogicalMaximum)=UndefinedState)) THEN
  918. errorList.Add(itemNr, UsbHidErrors.GlobalItemLogicalMaximum, 1H);
  919. END;
  920. |3H: (*Physical Minimum *)
  921. globalState.SetState(errorList, IDPhysicalMinimum, si.data, itemNr);
  922. |4H: (*Physical Maximum*)
  923. globalState.SetState(errorList, IDPhysicalMaximum, si.data, itemNr);
  924. |5H: (*Unit Exponent*)
  925. globalState.SetState(errorList, IDUnitExponent, si.data, itemNr);
  926. (*nice to have: zehner exponent decodieren gemäss seite 38*)
  927. |6H: (*Unit*)
  928. globalState.SetState(errorList, IDUnit, si.data, itemNr);
  929. |7H: (*Report Size*)
  930. globalState.SetState(errorList, IDReportSize, si.data, itemNr);
  931. IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDReportSize)=UndefinedState)) THEN
  932. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportSize, 1H);
  933. END;
  934. |8H: (*Report ID*)
  935. globalState.SetState(errorList, IDReportID, si.data, itemNr);
  936. IF((inputOutputFeatureParsed= TRUE)&(globalState.State(IDReportID)=UndefinedState)) THEN
  937. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 2H);
  938. END;
  939. IF(si.data=0) THEN
  940. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 0H);
  941. ELSE
  942. IF(si.data>255) THEN
  943. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 1H);
  944. END;
  945. END;
  946. IF (reportManager.OnTopLevel()) THEN
  947. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 3H);
  948. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportID, 4H);
  949. END;
  950. |9H: (*Report Count *)
  951. globalState.SetState(errorList, IDReportCount, si.data, itemNr);
  952. IF(si.data=0) THEN
  953. errorList.Add(itemNr, UsbHidErrors.GlobalItemReportCount, 0H);
  954. END;
  955. |10: (*Push*)
  956. (*do push*)
  957. globalState.Push;
  958. IF(si.bSize#0) THEN
  959. errorList.Add(itemNr, UsbHidErrors.GlobalItemPush, 1H);
  960. END;
  961. |11: (*Pop*)
  962. (*do pop: first check if globalState = firstGlobalState,
  963. then check start at firstGlobalState and find the second last element in the list, when found, delete the last*)
  964. IF(globalState.Pop()=FALSE) THEN
  965. errorList.Add(itemNr, UsbHidErrors.GlobalItemPop, 0H);
  966. END;
  967. IF(si.bSize#0) THEN
  968. errorList.Add(itemNr, UsbHidErrors.GlobalItemPop, 1H);
  969. END;
  970. ELSE
  971. (*Reserved*)
  972. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
  973. END;
  974. END ParseGlobalItem;
  975. (*parse local item
  976. * param: si to get bTag, bSize and data params
  977. * itemNr used for errorList
  978. *)
  979. PROCEDURE ParseLocalItem*(si: Item; itemNr: LONGINT);
  980. BEGIN
  981. IF (Trace OR Debug) THEN
  982. HidParserExt.ParseLocalItem(si.bTag, si.bSize, si.data, itemNr, depth, globalState.State(IDUsagePage));
  983. END;
  984. (*as described in HID Parser Error Codes page 3, all local item checks for errors and warnings (except delimiter) are checked
  985. when the parser encounters the next main item*)
  986. CASE si.bTag OF
  987. 0H: (*Usage*)
  988. (*as described at page 41 32bit values for Usage only the lower 16bits identify the usage, the higher 16bits define the usage page*)
  989. localState.SetState(IDLocalUsage, si.data);
  990. |1H: (*Usage Minimum*)
  991. (*as described at page 41 32bit values for UsageMinimum only the lower 16bits identify the usageMinimum, the higher 16bits define the usage page*)
  992. localState.SetState(IDLocalUsageMinimum, si.data);
  993. |2H: (*Usage Maximum*)
  994. (*as described at page 41 32bit values for UsageMaximum only the lower 12bits identify the usageMaximum, the higher 16bits define the usage page*)
  995. localState.SetState(IDLocalUsageMaximum, si.data);
  996. |3H: (*Designator Index*)
  997. localState.SetState(IDLocalDesignatorIndex, si.data);
  998. |4H: (*Designator Minimum*)
  999. localState.SetState(IDLocalDesignatorMinimum, si.data);
  1000. |5H: (*Designator Maximum*)
  1001. localState.SetState(IDLocalDesignatorMaximum, si.data);
  1002. (*|6H: (*RESERVED*)*)
  1003. |7H: (*String Index*)
  1004. localState.SetState(IDLocalStringIndex, si.data);
  1005. |8H: (*String Minimum*)
  1006. localState.SetState(IDLocalStringMinimum, si.data);
  1007. |9H: (*String Maximum*)
  1008. localState.SetState(IDLocalStringMaximum, si.data);
  1009. |0AH: (*Delimiter*)
  1010. CASE si.data OF
  1011. 0: (*open set*)
  1012. IF (localState.State(IDLocalDelimiter)#UndefinedState) THEN
  1013. errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 1H);
  1014. END;
  1015. localState.SetState(IDLocalDelimiter, si.data);
  1016. |1H: (*close set*)
  1017. IF(localState.State(IDLocalDelimiter)=UndefinedState) THEN
  1018. (*there is no corresponding open set*)
  1019. errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 2H);
  1020. END;
  1021. localState.SetState(IDLocalDelimiter, si.data);
  1022. ELSE (*NOT DEFINED*)
  1023. errorList.Add(itemNr, UsbHidErrors.LocalItemDelimiter, 0H);
  1024. END;
  1025. ELSE (*RESERVED*)
  1026. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003FH);
  1027. END;
  1028. END ParseLocalItem;
  1029. (*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
  1030. * ignored and simply skipped
  1031. * param: li to get bTag and bSize params
  1032. * reportBuffer to read data
  1033. * len the len to read on the reportBuffer
  1034. * startIndex position where to begin read on reportBuffer
  1035. * itemNr used for errorList
  1036. *)
  1037. PROCEDURE ParseLongItem*(li: Item; reportBuffer: Usbdi.BufferPtr; len, startIndex, itemNr : LONGINT);
  1038. BEGIN
  1039. errorList.Add(itemNr, UsbHidErrors.UnknownItem, 003EH);
  1040. END ParseLongItem;
  1041. (*parses the report descriptor
  1042. * param: hidDescriptor the hid descriptor
  1043. reportBuffer data of hid report descriptor
  1044. * return: TRUE if successfull
  1045. FALSE otherwise
  1046. *)
  1047. PROCEDURE ParseReportDescriptor*(hidDescriptor : UsbHid.HidDescriptor; reportBuffer : Usbdi.BufferPtr): BOOLEAN;
  1048. VAR
  1049. itemCounter : LONGINT;
  1050. cur : LONGINT;
  1051. item : POINTER TO Item;
  1052. hidCollection: UsbHidReport.HidCollection;
  1053. BEGIN
  1054. NEW(item);
  1055. itemCounter := 0;
  1056. cur := 0;
  1057. IF Trace THEN
  1058. KernelLog.Ln;
  1059. KernelLog.String("Report Descriptor Content:");
  1060. KernelLog.Ln;
  1061. END;
  1062. LOOP
  1063. (*catch report buffer overflow*)
  1064. IF cur >= hidDescriptor.wDescriptorLength-1 THEN EXIT; END;
  1065. (*init si*)
  1066. item.bSize := ORD(reportBuffer[cur]) MOD 4;
  1067. (*as defined on page 26, Device Class Definition for HID*)
  1068. IF (item.bSize = 3) THEN INC(item.bSize); END;
  1069. item.bType := (ORD(reportBuffer[cur]) DIV 4) MOD 4;
  1070. item.bTag := (ORD(reportBuffer[cur]) DIV 16) MOD 16;
  1071. INC(cur);
  1072. (*get the data depending on si.bSize*)
  1073. IF (item.bType # ShortItemBTypeReserved) THEN
  1074. IF (item.bSize#0) THEN
  1075. CASE item.bSize OF
  1076. 1:
  1077. item.data:= ORD(reportBuffer[cur]);
  1078. |2:
  1079. item.data:= ORD(reportBuffer[cur+1]);
  1080. item.data:= 100H*item.data+ORD(reportBuffer[cur]);
  1081. |4:
  1082. item.data:= ORD(reportBuffer[cur+3]);
  1083. item.data:= 100H*item.data + ORD(reportBuffer[cur+2]);
  1084. item.data:= 100H*item.data + ORD(reportBuffer[cur+1]);
  1085. item.data:= 100H*item.data + ORD(reportBuffer[cur]);
  1086. END;
  1087. IF(item.data<0) THEN
  1088. KernelLog.String("item.data<0 at index: "); KernelLog.Int(cur,0);KernelLog.Ln;
  1089. KernelLog.String("item.bSize is "); KernelLog.Int(item.bSize,2); KernelLog.Ln;
  1090. END;
  1091. ELSE
  1092. item.data:= 0;
  1093. END;
  1094. (*identifying shortitem*)
  1095. CASE (item.bType) OF
  1096. ShortItemBTypeMain:
  1097. (*ShortItem Main*)
  1098. IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" main "); END;
  1099. ParseMainItem(item^, itemCounter);
  1100. |ShortItemBTypeGlobal:
  1101. (*ShortItem Global*)
  1102. IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" global"); END;
  1103. ParseGlobalItem(item^, itemCounter);
  1104. |ShortItemBTypeLocal:
  1105. (*ShortItem Local*)
  1106. IF Debug THEN KernelLog.Int(itemCounter, 4); KernelLog.String(" local "); END;
  1107. ParseLocalItem(item^, itemCounter);
  1108. ELSE
  1109. RETURN FALSE;
  1110. END;
  1111. INC(cur, item.bSize);
  1112. ELSE
  1113. (*long item*)
  1114. (*cur is at beginning of the longiten item, index of bTag, bType and bSize*)
  1115. IF (item.bSize#0) THEN
  1116. (*Detect reportBuffer overflow:
  1117. cur: current position of shortItemTag,
  1118. 1 : (shortItemTag+1) holds the dataSize,
  1119. ORD(reportBuffer[cur+1]): the length of data to read after dataSize in Byte
  1120. *)
  1121. IF((cur+1+ORD(reportBuffer[cur+1]))<hidDescriptor.wDescriptorLength) THEN
  1122. ParseLongItem(item^, reportBuffer, ORD(reportBuffer[cur+1]), cur+1, itemCounter);
  1123. (*EvalStatusCode(hidStatusCode);*)
  1124. END;
  1125. INC(cur,ORD(reportBuffer[cur+1]) +1);
  1126. END;
  1127. END;
  1128. INC(itemCounter);
  1129. END; (*LOOP*)
  1130. IF UsbHidReport.Debug THEN
  1131. KernelLog.String("Starting report layout:"); KernelLog.Ln;
  1132. hidCollection := reportManager.GetCollection(-1,-1);
  1133. KernelLog.String("Searching Mouse Collection (usagePage 1 and usage 2):"); KernelLog.Ln;
  1134. hidCollection := reportManager.GetCollection(1,2);
  1135. IF (hidCollection#NIL) THEN
  1136. KernelLog.String("Mouse Collection found:"); KernelLog.Ln;
  1137. KernelLog.String("usagePage: "); KernelLog.Int(hidCollection.usagePage,0);
  1138. KernelLog.String(", usage: "); KernelLog.Int(hidCollection.usage,0);
  1139. ELSE
  1140. KernelLog.String("Mouse Collection not found");
  1141. END;
  1142. KernelLog.Ln;
  1143. END;
  1144. IF (reportManager.OnTopLevel()= FALSE) THEN
  1145. errorList.Add(itemCounter, UsbHidErrors.MainItemCollection, 0);
  1146. END;
  1147. RETURN TRUE;
  1148. END ParseReportDescriptor;
  1149. (*when detaching the device*)
  1150. PROCEDURE Disconnect*;
  1151. BEGIN
  1152. errorList := NIL;
  1153. END Disconnect;
  1154. PROCEDURE &Init*;
  1155. BEGIN
  1156. NEW(globalState);
  1157. NEW(localState);
  1158. NEW(errorList);
  1159. IF Debug THEN KernelLog.String("ItemParser is initialized"); KernelLog.Ln; END;
  1160. inputOutputFeatureParsed := FALSE;
  1161. IF Debug THEN
  1162. depth := 1;
  1163. ELSE
  1164. depth := 0;
  1165. END;
  1166. NEW(reportManager);
  1167. END Init;
  1168. END ItemParser;
  1169. END UsbHidParser.
  1170. System.Free UsbHidParser UsbHidParserExt~