[HIDPARSER]
[reactos.git] / lib / drivers / hidparser / api.c
1 /*
2 * PROJECT: ReactOS HID Parser Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/hidparser/api.c
5 * PURPOSE: HID Parser
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11
12 #include "parser.h"
13
14 static ULONG KeyboardScanCodes[256] =
15 {
16 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
17 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
18 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
19 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
20 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
21 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
22 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
23 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
24 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
25 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
30 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
31 150,158,159,128,136,177,178,176,142,152,173,140
32 };
33
34 HIDPARSER_STATUS
35 HidParser_GetCollectionUsagePage(
36 IN PVOID CollectionContext,
37 OUT PUSHORT Usage,
38 OUT PUSHORT UsagePage)
39 {
40 PHID_COLLECTION Collection;
41
42 //
43 // find collection
44 //
45 Collection = HidParser_GetCollectionFromContext(CollectionContext);
46 if (!Collection)
47 {
48 //
49 // collection not found
50 //
51 return HIDPARSER_STATUS_COLLECTION_NOT_FOUND;
52 }
53
54 //
55 // store result
56 //
57 *UsagePage = (Collection->Usage >> 16);
58 *Usage = (Collection->Usage & 0xFFFF);
59 return HIDPARSER_STATUS_SUCCESS;
60 }
61
62 ULONG
63 HidParser_GetReportLength(
64 IN PVOID CollectionContext,
65 IN UCHAR ReportType)
66 {
67 PHID_REPORT Report;
68 ULONG ReportLength;
69
70 //
71 // get first report
72 //
73 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
74 if (!Report)
75 {
76 //
77 // no report found
78 //
79 return 0;
80 }
81
82 //
83 // get report length
84 //
85 ReportLength = Report->ReportSize;
86
87 //
88 // done
89 //
90 if (ReportLength)
91 {
92 //
93 // byte aligned length
94 //
95 ASSERT(ReportLength % 8 == 0);
96 return ReportLength / 8;
97 }
98 return ReportLength;
99 }
100
101 ULONG
102 HidParser_GetReportItemCountFromReportType(
103 IN PVOID CollectionContext,
104 IN UCHAR ReportType)
105 {
106 PHID_REPORT Report;
107
108 //
109 // get report
110 //
111 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
112 if (!Report)
113 {
114 //
115 // no such report
116 //
117 return 0;
118 }
119
120 //
121 // return report item count
122 //
123 return Report->ItemCount;
124 }
125
126
127 ULONG
128 HidParser_GetReportItemTypeCountFromReportType(
129 IN PVOID CollectionContext,
130 IN UCHAR ReportType,
131 IN ULONG bData)
132 {
133 ULONG Index;
134 PHID_REPORT Report;
135 ULONG ItemCount = 0;
136
137 //
138 // get report
139 //
140 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
141 if (!Report)
142 {
143 //
144 // no such report
145 //
146 return 0;
147 }
148
149 //
150 // enumerate all items
151 //
152 for(Index = 0; Index < Report->ItemCount; Index++)
153 {
154 //
155 // check item type
156 //
157 if (Report->Items[Index].HasData && bData == TRUE)
158 {
159 //
160 // found data item
161 //
162 ItemCount++;
163 }
164 else if (Report->Items[Index].HasData == FALSE && bData == FALSE)
165 {
166 //
167 // found value item
168 //
169 ItemCount++;
170 }
171 }
172
173 //
174 // no report items
175 //
176 return ItemCount;
177 }
178
179
180 VOID
181 HidParser_InitParser(
182 IN PHIDPARSER_ALLOC_FUNCTION AllocFunction,
183 IN PHIDPARSER_FREE_FUNCTION FreeFunction,
184 IN PHIDPARSER_ZERO_FUNCTION ZeroFunction,
185 IN PHIDPARSER_COPY_FUNCTION CopyFunction,
186 IN PHIDPARSER_DEBUG_FUNCTION DebugFunction,
187 OUT PHID_PARSER Parser)
188 {
189 Parser->Alloc = AllocFunction;
190 Parser->Free = FreeFunction;
191 Parser->Zero = ZeroFunction;
192 Parser->Copy = CopyFunction;
193 Parser->Debug = DebugFunction;
194 }
195
196 ULONG
197 HidParser_GetMaxUsageListLengthWithReportAndPage(
198 IN PVOID CollectionContext,
199 IN UCHAR ReportType,
200 IN USAGE UsagePage OPTIONAL)
201 {
202 ULONG Index;
203 PHID_REPORT Report;
204 ULONG ItemCount = 0;
205 USHORT CurrentUsagePage;
206
207 //
208 // get report
209 //
210 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
211 if (!Report)
212 {
213 //
214 // no such report
215 //
216 return 0;
217 }
218
219 for(Index = 0; Index < Report->ItemCount; Index++)
220 {
221 //
222 // check usage page
223 //
224 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
225 if (CurrentUsagePage == UsagePage && Report->Items[Index].HasData)
226 {
227 //
228 // found item
229 //
230 ItemCount++;
231 }
232 }
233
234 //
235 // done
236 //
237 return ItemCount;
238 }
239
240 HIDPARSER_STATUS
241 HidParser_GetSpecificValueCapsWithReport(
242 IN PHID_PARSER Parser,
243 IN PVOID CollectionContext,
244 IN UCHAR ReportType,
245 IN USHORT UsagePage,
246 IN USHORT Usage,
247 OUT PHIDP_VALUE_CAPS ValueCaps,
248 IN OUT PULONG ValueCapsLength)
249 {
250 ULONG Index;
251 PHID_REPORT Report;
252 ULONG ItemCount = 0;
253 USHORT CurrentUsagePage;
254 USHORT CurrentUsage;
255
256 //
257 // get report
258 //
259 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
260 if (!Report)
261 {
262 //
263 // no such report
264 //
265 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
266 }
267
268 for(Index = 0; Index < Report->ItemCount; Index++)
269 {
270 //
271 // check usage page
272 //
273 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16);
274 CurrentUsage = (Report->Items[Index].UsageMinimum & 0xFFFF);
275
276 if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0))
277 {
278 //
279 // check if there is enough place for the caps
280 //
281 if (ItemCount < *ValueCapsLength)
282 {
283 //
284 // zero caps
285 //
286 Parser->Zero(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS));
287
288 //
289 // init caps
290 //
291 ValueCaps[ItemCount].UsagePage = CurrentUsagePage;
292 ValueCaps[ItemCount].ReportID = Report->ReportID;
293 ValueCaps[ItemCount].LogicalMin = Report->Items[Index].Minimum;
294 ValueCaps[ItemCount].LogicalMax = Report->Items[Index].Maximum;
295 ValueCaps[ItemCount].IsAbsolute = !Report->Items[Index].Relative;
296 ValueCaps[ItemCount].BitSize = Report->Items[Index].BitCount;
297
298 //
299 // FIXME: FILLMEIN
300 //
301 }
302
303
304 //
305 // found item
306 //
307 ItemCount++;
308 }
309 }
310
311 //
312 // store result
313 //
314 *ValueCapsLength = ItemCount;
315
316 if (ItemCount)
317 {
318 //
319 // success
320 //
321 return HIDPARSER_STATUS_SUCCESS;
322 }
323
324 //
325 // item not found
326 //
327 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
328 }
329
330 HIDPARSER_STATUS
331 HidParser_GetUsagesWithReport(
332 IN PHID_PARSER Parser,
333 IN PVOID CollectionContext,
334 IN UCHAR ReportType,
335 IN USAGE UsagePage,
336 OUT USAGE *UsageList,
337 IN OUT PULONG UsageLength,
338 IN PCHAR ReportDescriptor,
339 IN ULONG ReportDescriptorLength)
340 {
341 ULONG Index;
342 PHID_REPORT Report;
343 ULONG ItemCount = 0;
344 USHORT CurrentUsagePage;
345 PHID_REPORT_ITEM ReportItem;
346 UCHAR Activated;
347 ULONG Data;
348
349 //
350 // get report
351 //
352 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
353 if (!Report)
354 {
355 //
356 // no such report
357 //
358 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
359 }
360
361 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
362 {
363 //
364 // invalid report descriptor length
365 //
366 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
367 }
368
369 for(Index = 0; Index < Report->ItemCount; Index++)
370 {
371 //
372 // get report item
373 //
374 ReportItem = &Report->Items[Index];
375
376 //
377 // does it have data
378 //
379 if (!ReportItem->HasData)
380 continue;
381
382 //
383 // check usage page
384 //
385 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
386
387 //
388 // does usage match
389 //
390 if (UsagePage != CurrentUsagePage)
391 continue;
392
393 //
394 // check if the specified usage is activated
395 //
396 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
397 ASSERT(ReportItem->BitCount < 8);
398
399 //
400 // one extra shift for skipping the prepended report id
401 //
402 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
403
404 //
405 // shift data
406 //
407 Data >>= ReportItem->Shift;
408
409 //
410 // clear unwanted bits
411 //
412 Data &= ReportItem->Mask;
413
414 //
415 // is it activated
416 //
417 Activated = (Data != 0);
418
419 if (!Activated)
420 continue;
421
422 //
423 // is there enough space for the usage
424 //
425 if (ItemCount >= *UsageLength)
426 {
427 ItemCount++;
428 continue;
429 }
430
431 //
432 // store item
433 //
434 UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
435 ItemCount++;
436 }
437
438 if (ItemCount > *UsageLength)
439 {
440 //
441 // list too small
442 //
443 return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
444 }
445
446 //
447 // success, clear rest of array
448 //
449 Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
450
451 //
452 // store result size
453 //
454 *UsageLength = ItemCount;
455
456 //
457 // done
458 //
459 return HIDPARSER_STATUS_SUCCESS;
460 }
461
462 HIDPARSER_STATUS
463 HidParser_GetScaledUsageValueWithReport(
464 IN PHID_PARSER Parser,
465 IN PVOID CollectionContext,
466 IN UCHAR ReportType,
467 IN USAGE UsagePage,
468 IN USAGE Usage,
469 OUT PLONG UsageValue,
470 IN PCHAR ReportDescriptor,
471 IN ULONG ReportDescriptorLength)
472 {
473 ULONG Index;
474 PHID_REPORT Report;
475 USHORT CurrentUsagePage;
476 PHID_REPORT_ITEM ReportItem;
477 ULONG Data;
478
479 //
480 // get report
481 //
482 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
483 if (!Report)
484 {
485 //
486 // no such report
487 //
488 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
489 }
490
491 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
492 {
493 //
494 // invalid report descriptor length
495 //
496 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
497 }
498
499 for(Index = 0; Index < Report->ItemCount; Index++)
500 {
501 //
502 // get report item
503 //
504 ReportItem = &Report->Items[Index];
505
506 //
507 // check usage page
508 //
509 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
510
511 //
512 // does usage page match
513 //
514 if (UsagePage != CurrentUsagePage)
515 continue;
516
517 //
518 // does the usage match
519 //
520 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
521 continue;
522
523 //
524 // check if the specified usage is activated
525 //
526 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
527
528 //
529 // one extra shift for skipping the prepended report id
530 //
531 Data = 0;
532 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
533 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
534
535 //
536 // shift data
537 //
538 Data >>= ReportItem->Shift;
539
540 //
541 // clear unwanted bits
542 //
543 Data &= ReportItem->Mask;
544
545 if (ReportItem->Minimum > ReportItem->Maximum)
546 {
547 //
548 // logical boundaries are signed values
549 //
550 if ((Data & ~(ReportItem->Mask >> 1)) != 0)
551 {
552 Data |= ~ReportItem->Mask;
553 }
554 }
555
556 //
557 // store result
558 //
559 *UsageValue = Data;
560 return HIDPARSER_STATUS_SUCCESS;
561 }
562
563 //
564 // usage not found
565 //
566 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
567 }
568
569 ULONG
570 HidParser_GetScanCode(
571 IN USAGE Usage)
572 {
573 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
574 {
575 //
576 // valid usage
577 //
578 return KeyboardScanCodes[Usage];
579 }
580
581 //
582 // invalid usage
583 //
584 return 0;
585 }
586
587 VOID
588 HidParser_DispatchKey(
589 IN PCHAR ScanCodes,
590 IN HIDP_KEYBOARD_DIRECTION KeyAction,
591 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
592 IN PVOID InsertCodesContext)
593 {
594 ULONG Index;
595 ULONG Length = 0;
596
597 //
598 // count code length
599 //
600 for(Index = 0; Index < sizeof(ULONG); Index++)
601 {
602 if (ScanCodes[Index] == 0)
603 {
604 //
605 // last scan code
606 //
607 break;
608 }
609
610 //
611 // is this a key break
612 //
613 if (KeyAction == HidP_Keyboard_Break)
614 {
615 //
616 // add break
617 //
618 ScanCodes[Index] |= KEY_BREAK;
619 }
620
621 //
622 // more scan counts
623 //
624 Length++;
625 }
626
627 if (Length > 0)
628 {
629 //
630 // dispatch scan codes
631 //
632 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
633 }
634 }
635
636
637 HIDPARSER_STATUS
638 HidParser_TranslateUsage(
639 IN PHID_PARSER Parser,
640 IN USAGE Usage,
641 IN HIDP_KEYBOARD_DIRECTION KeyAction,
642 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
643 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
644 IN PVOID InsertCodesContext)
645 {
646 ULONG ScanCode;
647
648 //
649 // get scan code
650 //
651 ScanCode = HidParser_GetScanCode(Usage);
652 if (!ScanCode)
653 {
654 //
655 // invalid lookup or no scan code available
656 //
657 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
658 }
659
660 //
661 // FIXME: translate modifier states
662 //
663
664 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
665
666 //
667 // done
668 //
669 return HIDPARSER_STATUS_SUCCESS;
670 }