[HIDPARSE]
[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 PUSAGE_AND_PAGE UsageAndPage = NULL;
349
350 //
351 // get report
352 //
353 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
354 if (!Report)
355 {
356 //
357 // no such report
358 //
359 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
360 }
361
362 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
363 {
364 //
365 // invalid report descriptor length
366 //
367 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
368 }
369
370 //
371 // cast to usage and page
372 //
373 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
374 {
375 //
376 // the caller requested any set usages
377 //
378 UsageAndPage = (PUSAGE_AND_PAGE)UsageList;
379 }
380
381 for(Index = 0; Index < Report->ItemCount; Index++)
382 {
383 //
384 // get report item
385 //
386 ReportItem = &Report->Items[Index];
387
388 //
389 // does it have data
390 //
391 if (!ReportItem->HasData)
392 continue;
393
394 //
395 // check usage page
396 //
397 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
398
399 if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
400 {
401 //
402 // does usage match
403 //
404 if (UsagePage != CurrentUsagePage)
405 continue;
406 }
407
408 //
409 // check if the specified usage is activated
410 //
411 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
412 ASSERT(ReportItem->BitCount <= 8);
413
414 //
415 // one extra shift for skipping the prepended report id
416 //
417 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
418
419 //
420 // shift data
421 //
422 Data >>= ReportItem->Shift;
423
424 //
425 // clear unwanted bits
426 //
427 Data &= ReportItem->Mask;
428
429 //
430 // is it activated
431 //
432 Activated = (Data != 0);
433
434 if (!Activated)
435 continue;
436
437 //
438 // is there enough space for the usage
439 //
440 if (ItemCount >= *UsageLength)
441 {
442 ItemCount++;
443 continue;
444 }
445
446 if (UsagePage != HID_USAGE_PAGE_UNDEFINED)
447 {
448 //
449 // store item
450 //
451 UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF);
452 }
453 else
454 {
455 //
456 // store usage and page
457 //
458 if (ReportItem->BitCount == 1)
459 {
460 //
461 // use usage minimum
462 //
463 UsageAndPage[ItemCount].Usage =(ReportItem->UsageMinimum & 0xFFFF);
464 }
465 else
466 {
467 //
468 // use value from control
469 //
470 UsageAndPage[ItemCount].Usage = (USHORT)Data;
471 }
472 UsageAndPage[ItemCount].UsagePage = CurrentUsagePage;
473 }
474 ItemCount++;
475 }
476
477 if (ItemCount > *UsageLength)
478 {
479 //
480 // list too small
481 //
482 return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
483 }
484
485 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
486 {
487 //
488 // success, clear rest of array
489 //
490 Parser->Zero(&UsageAndPage[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE_AND_PAGE));
491 }
492 else
493 {
494 //
495 // success, clear rest of array
496 //
497 Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
498 }
499
500
501 //
502 // store result size
503 //
504 *UsageLength = ItemCount;
505
506 //
507 // done
508 //
509 return HIDPARSER_STATUS_SUCCESS;
510 }
511
512 HIDPARSER_STATUS
513 HidParser_GetScaledUsageValueWithReport(
514 IN PHID_PARSER Parser,
515 IN PVOID CollectionContext,
516 IN UCHAR ReportType,
517 IN USAGE UsagePage,
518 IN USAGE Usage,
519 OUT PLONG UsageValue,
520 IN PCHAR ReportDescriptor,
521 IN ULONG ReportDescriptorLength)
522 {
523 ULONG Index;
524 PHID_REPORT Report;
525 USHORT CurrentUsagePage;
526 PHID_REPORT_ITEM ReportItem;
527 ULONG Data;
528
529 //
530 // get report
531 //
532 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
533 if (!Report)
534 {
535 //
536 // no such report
537 //
538 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
539 }
540
541 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
542 {
543 //
544 // invalid report descriptor length
545 //
546 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
547 }
548
549 for(Index = 0; Index < Report->ItemCount; Index++)
550 {
551 //
552 // get report item
553 //
554 ReportItem = &Report->Items[Index];
555
556 //
557 // check usage page
558 //
559 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
560
561 //
562 // does usage page match
563 //
564 if (UsagePage != CurrentUsagePage)
565 continue;
566
567 //
568 // does the usage match
569 //
570 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
571 continue;
572
573 //
574 // check if the specified usage is activated
575 //
576 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
577
578 //
579 // one extra shift for skipping the prepended report id
580 //
581 Data = 0;
582 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
583 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
584
585 //
586 // shift data
587 //
588 Data >>= ReportItem->Shift;
589
590 //
591 // clear unwanted bits
592 //
593 Data &= ReportItem->Mask;
594
595 if (ReportItem->Minimum > ReportItem->Maximum)
596 {
597 //
598 // logical boundaries are signed values
599 //
600 if ((Data & ~(ReportItem->Mask >> 1)) != 0)
601 {
602 Data |= ~ReportItem->Mask;
603 }
604 }
605
606 //
607 // store result
608 //
609 *UsageValue = Data;
610 return HIDPARSER_STATUS_SUCCESS;
611 }
612
613 //
614 // usage not found
615 //
616 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
617 }
618
619 ULONG
620 HidParser_GetScanCode(
621 IN USAGE Usage)
622 {
623 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
624 {
625 //
626 // valid usage
627 //
628 return KeyboardScanCodes[Usage];
629 }
630
631 //
632 // invalid usage
633 //
634 return 0;
635 }
636
637 VOID
638 HidParser_DispatchKey(
639 IN PCHAR ScanCodes,
640 IN HIDP_KEYBOARD_DIRECTION KeyAction,
641 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
642 IN PVOID InsertCodesContext)
643 {
644 ULONG Index;
645 ULONG Length = 0;
646
647 //
648 // count code length
649 //
650 for(Index = 0; Index < sizeof(ULONG); Index++)
651 {
652 if (ScanCodes[Index] == 0)
653 {
654 //
655 // last scan code
656 //
657 break;
658 }
659
660 //
661 // is this a key break
662 //
663 if (KeyAction == HidP_Keyboard_Break)
664 {
665 //
666 // add break
667 //
668 ScanCodes[Index] |= KEY_BREAK;
669 }
670
671 //
672 // more scan counts
673 //
674 Length++;
675 }
676
677 if (Length > 0)
678 {
679 //
680 // dispatch scan codes
681 //
682 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
683 }
684 }
685
686
687 HIDPARSER_STATUS
688 HidParser_TranslateUsage(
689 IN PHID_PARSER Parser,
690 IN USAGE Usage,
691 IN HIDP_KEYBOARD_DIRECTION KeyAction,
692 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
693 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
694 IN PVOID InsertCodesContext)
695 {
696 ULONG ScanCode;
697
698 //
699 // get scan code
700 //
701 ScanCode = HidParser_GetScanCode(Usage);
702 if (!ScanCode)
703 {
704 //
705 // invalid lookup or no scan code available
706 //
707 DPRINT1("No Scan code for Usage %x\n", Usage);
708 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
709 }
710
711 //
712 // FIXME: translate modifier states
713 //
714 DPRINT1("Usage %x ScanCode %x\n", Usage, ScanCode);
715 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
716
717 //
718 // done
719 //
720 return HIDPARSER_STATUS_SUCCESS;
721 }