25083955b865df96320982973e5d377ddbbe2aa9
[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 UsageAndPage[ItemCount].Usage = (ReportItem->UsageMinimum & 0xFFFF);
459 UsageAndPage[ItemCount].UsagePage = CurrentUsagePage;
460 }
461 ItemCount++;
462 }
463
464 if (ItemCount > *UsageLength)
465 {
466 //
467 // list too small
468 //
469 return HIDPARSER_STATUS_BUFFER_TOO_SMALL;
470 }
471
472 if (UsagePage == HID_USAGE_PAGE_UNDEFINED)
473 {
474 //
475 // success, clear rest of array
476 //
477 Parser->Zero(&UsageAndPage[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE_AND_PAGE));
478 }
479 else
480 {
481 //
482 // success, clear rest of array
483 //
484 Parser->Zero(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE));
485 }
486
487
488 //
489 // store result size
490 //
491 *UsageLength = ItemCount;
492
493 //
494 // done
495 //
496 return HIDPARSER_STATUS_SUCCESS;
497 }
498
499 HIDPARSER_STATUS
500 HidParser_GetScaledUsageValueWithReport(
501 IN PHID_PARSER Parser,
502 IN PVOID CollectionContext,
503 IN UCHAR ReportType,
504 IN USAGE UsagePage,
505 IN USAGE Usage,
506 OUT PLONG UsageValue,
507 IN PCHAR ReportDescriptor,
508 IN ULONG ReportDescriptorLength)
509 {
510 ULONG Index;
511 PHID_REPORT Report;
512 USHORT CurrentUsagePage;
513 PHID_REPORT_ITEM ReportItem;
514 ULONG Data;
515
516 //
517 // get report
518 //
519 Report = HidParser_GetReportInCollection(CollectionContext, ReportType);
520 if (!Report)
521 {
522 //
523 // no such report
524 //
525 return HIDPARSER_STATUS_REPORT_NOT_FOUND;
526 }
527
528 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1))
529 {
530 //
531 // invalid report descriptor length
532 //
533 return HIDPARSER_STATUS_INVALID_REPORT_LENGTH;
534 }
535
536 for(Index = 0; Index < Report->ItemCount; Index++)
537 {
538 //
539 // get report item
540 //
541 ReportItem = &Report->Items[Index];
542
543 //
544 // check usage page
545 //
546 CurrentUsagePage = (ReportItem->UsageMinimum >> 16);
547
548 //
549 // does usage page match
550 //
551 if (UsagePage != CurrentUsagePage)
552 continue;
553
554 //
555 // does the usage match
556 //
557 if (Usage != (ReportItem->UsageMinimum & 0xFFFF))
558 continue;
559
560 //
561 // check if the specified usage is activated
562 //
563 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength);
564
565 //
566 // one extra shift for skipping the prepended report id
567 //
568 Data = 0;
569 Parser->Copy(&Data, &ReportDescriptor[ReportItem->ByteOffset +1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1)));
570 Data = ReportDescriptor[ReportItem->ByteOffset + 1];
571
572 //
573 // shift data
574 //
575 Data >>= ReportItem->Shift;
576
577 //
578 // clear unwanted bits
579 //
580 Data &= ReportItem->Mask;
581
582 if (ReportItem->Minimum > ReportItem->Maximum)
583 {
584 //
585 // logical boundaries are signed values
586 //
587 if ((Data & ~(ReportItem->Mask >> 1)) != 0)
588 {
589 Data |= ~ReportItem->Mask;
590 }
591 }
592
593 //
594 // store result
595 //
596 *UsageValue = Data;
597 return HIDPARSER_STATUS_SUCCESS;
598 }
599
600 //
601 // usage not found
602 //
603 return HIDPARSER_STATUS_USAGE_NOT_FOUND;
604 }
605
606 ULONG
607 HidParser_GetScanCode(
608 IN USAGE Usage)
609 {
610 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0]))
611 {
612 //
613 // valid usage
614 //
615 return KeyboardScanCodes[Usage];
616 }
617
618 //
619 // invalid usage
620 //
621 return 0;
622 }
623
624 VOID
625 HidParser_DispatchKey(
626 IN PCHAR ScanCodes,
627 IN HIDP_KEYBOARD_DIRECTION KeyAction,
628 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
629 IN PVOID InsertCodesContext)
630 {
631 ULONG Index;
632 ULONG Length = 0;
633
634 //
635 // count code length
636 //
637 for(Index = 0; Index < sizeof(ULONG); Index++)
638 {
639 if (ScanCodes[Index] == 0)
640 {
641 //
642 // last scan code
643 //
644 break;
645 }
646
647 //
648 // is this a key break
649 //
650 if (KeyAction == HidP_Keyboard_Break)
651 {
652 //
653 // add break
654 //
655 ScanCodes[Index] |= KEY_BREAK;
656 }
657
658 //
659 // more scan counts
660 //
661 Length++;
662 }
663
664 if (Length > 0)
665 {
666 //
667 // dispatch scan codes
668 //
669 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length);
670 }
671 }
672
673
674 HIDPARSER_STATUS
675 HidParser_TranslateUsage(
676 IN PHID_PARSER Parser,
677 IN USAGE Usage,
678 IN HIDP_KEYBOARD_DIRECTION KeyAction,
679 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState,
680 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure,
681 IN PVOID InsertCodesContext)
682 {
683 ULONG ScanCode;
684
685 //
686 // get scan code
687 //
688 ScanCode = HidParser_GetScanCode(Usage);
689 if (!ScanCode)
690 {
691 //
692 // invalid lookup or no scan code available
693 //
694 return HIDPARSER_STATUS_I8042_TRANS_UNKNOWN;
695 }
696
697 //
698 // FIXME: translate modifier states
699 //
700
701 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext);
702
703 //
704 // done
705 //
706 return HIDPARSER_STATUS_SUCCESS;
707 }