mf/session: Forward more events to the application.
[wine/zf.git] / dlls / hid / hidp.c
blobc4d162695a968ff371548ca531ea801c252ec016
1 /*
2 * Human Input Devices
4 * Copyright (C) 2015 Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #define NONAMELESSUNION
25 #include "ntstatus.h"
26 #define WIN32_NO_STATUS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winternl.h"
30 #include "winioctl.h"
31 #include "ddk/wdm.h"
33 #include "hidusage.h"
34 #include "ddk/hidpi.h"
35 #include "wine/hid.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(hidp);
40 static NTSTATUS get_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value)
43 if ((startBit + valueSize) / 8 > reportLength)
44 return HIDP_STATUS_INVALID_REPORT_LENGTH;
46 if (valueSize == 1)
48 ULONG byte_index = startBit / 8;
49 ULONG bit_index = startBit - (byte_index * 8);
50 INT mask = (1 << bit_index);
51 *value = !!(report[byte_index] & mask);
53 else
55 ULONG remaining_bits = valueSize;
56 ULONG byte_index = startBit / 8;
57 ULONG bit_index = startBit % 8;
58 ULONG data = 0;
59 ULONG shift = 0;
60 while (remaining_bits)
62 ULONG copy_bits = 8 - bit_index;
63 if (remaining_bits < copy_bits)
64 copy_bits = remaining_bits;
66 data |= ((report[byte_index] >> bit_index) & ((1 << copy_bits) - 1)) << shift;
68 shift += copy_bits;
69 bit_index = 0;
70 byte_index++;
71 remaining_bits -= copy_bits;
73 *value = data;
75 return HIDP_STATUS_SUCCESS;
78 static NTSTATUS set_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, ULONG value)
80 if ((startBit + valueSize) / 8 > reportLength)
81 return HIDP_STATUS_INVALID_REPORT_LENGTH;
83 if (valueSize == 1)
85 ULONG byte_index = startBit / 8;
86 ULONG bit_index = startBit - (byte_index * 8);
87 if (value)
88 report[byte_index] |= (1 << bit_index);
89 else
90 report[byte_index] &= ~(1 << bit_index);
92 else
94 ULONG byte_index = (startBit + valueSize - 1) / 8;
95 ULONG data = value;
96 ULONG remainingBits = valueSize;
97 while (remainingBits)
99 BYTE subvalue = data & 0xff;
101 data >>= 8;
103 if (remainingBits >= 8)
105 report[byte_index] = subvalue;
106 byte_index --;
107 remainingBits -= 8;
109 else if (remainingBits > 0)
111 BYTE mask = (0xff << (8-remainingBits)) & subvalue;
112 report[byte_index] |= mask;
113 remainingBits = 0;
117 return HIDP_STATUS_SUCCESS;
120 static NTSTATUS get_report_data_array(BYTE *report, UINT reportLength, UINT startBit, UINT elemSize,
121 UINT numElements, PCHAR values, UINT valuesSize)
123 BYTE byte, *end, *p = report + startBit / 8;
124 ULONG size = elemSize * numElements;
125 ULONG m, bit_index = startBit % 8;
126 BYTE *data = (BYTE*)values;
128 if ((startBit + size) / 8 > reportLength)
129 return HIDP_STATUS_INVALID_REPORT_LENGTH;
131 if (valuesSize < (size + 7) / 8)
132 return HIDP_STATUS_BUFFER_TOO_SMALL;
134 end = report + (startBit + size + 7) / 8;
136 data--;
137 byte = *p++;
138 while (p != end)
140 *(++data) = byte >> bit_index;
141 byte = *p++;
142 *data |= byte << (8 - bit_index);
145 /* Handle the end and mask out bits beyond */
146 m = (startBit + size) % 8;
147 m = m ? m : 8;
149 if (m > bit_index)
150 *(++data) = (byte >> bit_index) & ((1 << (m - bit_index)) - 1);
151 else
152 *data &= (1 << (m + 8 - bit_index)) - 1;
154 if (++data < (BYTE*)values + valuesSize)
155 memset(data, 0, (BYTE*)values + valuesSize - data);
157 return HIDP_STATUS_SUCCESS;
161 NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps,
162 PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
164 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
165 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
166 WINE_HID_REPORT *report = NULL;
167 USHORT b_count = 0, r_count = 0;
168 int i,j,u;
170 TRACE("(%i, %p, %p, %p)\n",ReportType, ButtonCaps, ButtonCapsLength, PreparsedData);
172 if (data->magic != HID_MAGIC)
173 return HIDP_STATUS_INVALID_PREPARSED_DATA;
175 switch(ReportType)
177 case HidP_Input:
178 b_count = data->caps.NumberInputButtonCaps;
179 report = HID_INPUT_REPORTS(data);
180 break;
181 case HidP_Output:
182 b_count = data->caps.NumberOutputButtonCaps;
183 report = HID_OUTPUT_REPORTS(data);
184 break;
185 case HidP_Feature:
186 b_count = data->caps.NumberFeatureButtonCaps;
187 report = HID_FEATURE_REPORTS(data);
188 break;
189 default:
190 return HIDP_STATUS_INVALID_REPORT_TYPE;
192 r_count = data->reportCount[ReportType];
194 if (!r_count || !b_count)
196 *ButtonCapsLength = 0;
197 return HIDP_STATUS_SUCCESS;
200 b_count = min(b_count, *ButtonCapsLength);
202 u = 0;
203 for (j = 0; j < r_count && u < b_count; j++)
205 for (i = 0; i < report[j].elementCount && u < b_count; i++)
207 if (elems[report[j].elementIdx + i].ElementType == ButtonElement)
208 ButtonCaps[u++] = elems[report[j].elementIdx + i].caps.button;
212 *ButtonCapsLength = b_count;
213 return HIDP_STATUS_SUCCESS;
217 NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData,
218 PHIDP_CAPS Capabilities)
220 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
222 TRACE("(%p, %p)\n",PreparsedData, Capabilities);
224 if (data->magic != HID_MAGIC)
225 return HIDP_STATUS_INVALID_PREPARSED_DATA;
227 *Capabilities = data->caps;
229 return HIDP_STATUS_SUCCESS;
232 static NTSTATUS find_usage(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
233 USAGE Usage, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
234 WINE_ELEMENT_TYPE ElementType, WINE_HID_ELEMENT *element)
236 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
237 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
238 WINE_HID_REPORT *report = NULL;
239 USHORT v_count = 0, r_count = 0;
240 int i;
242 TRACE("(%i, %x, %i, %i, %p, %p)\n", ReportType, UsagePage, LinkCollection, Usage,
243 PreparsedData, Report);
245 if (data->magic != HID_MAGIC)
246 return HIDP_STATUS_INVALID_PREPARSED_DATA;
247 switch(ReportType)
249 case HidP_Input:
250 v_count = data->caps.NumberInputValueCaps;
251 break;
252 case HidP_Output:
253 v_count = data->caps.NumberOutputValueCaps;
254 break;
255 case HidP_Feature:
256 v_count = data->caps.NumberFeatureValueCaps;
257 break;
258 default:
259 return HIDP_STATUS_INVALID_REPORT_TYPE;
261 r_count = data->reportCount[ReportType];
262 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
264 if (!r_count || !v_count)
265 return HIDP_STATUS_USAGE_NOT_FOUND;
267 if (report->reportID && report->reportID != Report[0])
268 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
270 for (i = 0; i < report->elementCount; i++)
272 HIDP_VALUE_CAPS *value = &elems[report->elementIdx + i].caps.value;
274 if (elems[report->elementIdx + i].ElementType != ElementType ||
275 value->UsagePage != UsagePage)
276 continue;
278 if (value->IsRange && value->u.Range.UsageMin <= Usage && Usage <= value->u.Range.UsageMax)
280 *element = elems[report->elementIdx + i];
281 element->valueStartBit += value->BitSize * (Usage - value->u.Range.UsageMin);
282 element->bitCount = elems[report->elementIdx + i].ElementType == ValueElement ? value->BitSize: 1;
283 return HIDP_STATUS_SUCCESS;
285 else if (value->u.NotRange.Usage == Usage)
287 *element = elems[report->elementIdx + i];
288 element->bitCount = elems[report->elementIdx + i].ElementType == ValueElement ? value->BitSize : 1;
289 return HIDP_STATUS_SUCCESS;
293 return HIDP_STATUS_USAGE_NOT_FOUND;
296 static LONG sign_extend(ULONG value, const WINE_HID_ELEMENT *element)
298 UINT bit_count = element->bitCount;
300 if ((value & (1 << (bit_count - 1)))
301 && element->ElementType == ValueElement
302 && element->caps.value.LogicalMin < 0)
304 value -= (1 << bit_count);
306 return value;
309 static LONG logical_to_physical(LONG value, const WINE_HID_ELEMENT *element)
311 if (element->caps.value.PhysicalMin || element->caps.value.PhysicalMax)
313 value = (((ULONGLONG)(value - element->caps.value.LogicalMin)
314 * (element->caps.value.PhysicalMax - element->caps.value.PhysicalMin))
315 / (element->caps.value.LogicalMax - element->caps.value.LogicalMin))
316 + element->caps.value.PhysicalMin;
318 return value;
321 NTSTATUS WINAPI HidP_GetScaledUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage,
322 USHORT LinkCollection, USAGE Usage, PLONG UsageValue,
323 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength)
325 NTSTATUS rc;
326 WINE_HID_ELEMENT element;
327 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
328 PreparsedData, Report, ReportLength);
330 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
332 if (rc == HIDP_STATUS_SUCCESS)
334 ULONG rawValue;
335 rc = get_report_data((BYTE*)Report, ReportLength,
336 element.valueStartBit, element.bitCount, &rawValue);
337 if (rc != HIDP_STATUS_SUCCESS)
338 return rc;
339 *UsageValue = logical_to_physical(sign_extend(rawValue, &element), &element);
342 return rc;
346 NTSTATUS WINAPI HidP_GetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
347 USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
348 PCHAR Report, ULONG ReportLength)
350 WINE_HID_ELEMENT element;
351 NTSTATUS rc;
353 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
354 PreparsedData, Report, ReportLength);
356 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
358 if (rc == HIDP_STATUS_SUCCESS)
360 return get_report_data((BYTE*)Report, ReportLength,
361 element.valueStartBit, element.bitCount, UsageValue);
364 return rc;
368 NTSTATUS WINAPI HidP_GetUsageValueArray(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
369 USAGE Usage, PCHAR UsageValue, USHORT UsageValueByteLength,
370 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength)
372 WINE_HID_ELEMENT element;
373 NTSTATUS rc;
375 TRACE("(%i, %x, %i, %i, %p, %u, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
376 UsageValueByteLength, PreparsedData, Report, ReportLength);
378 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
380 if (rc == HIDP_STATUS_SUCCESS)
382 if (element.caps.value.IsRange || element.caps.value.ReportCount <= 1 || !element.bitCount)
383 return HIDP_STATUS_NOT_VALUE_ARRAY;
385 return get_report_data_array((BYTE*)Report, ReportLength, element.valueStartBit, element.bitCount,
386 element.caps.value.ReportCount, UsageValue, UsageValueByteLength);
389 return rc;
393 NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
394 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
395 PCHAR Report, ULONG ReportLength)
397 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
398 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
399 WINE_HID_REPORT *report = NULL;
400 BOOL found = FALSE;
401 USHORT b_count = 0, r_count = 0;
402 int i,uCount;
404 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
405 UsageLength, PreparsedData, Report, ReportLength);
407 if (data->magic != HID_MAGIC)
409 *UsageLength = 0;
410 return HIDP_STATUS_INVALID_PREPARSED_DATA;
413 switch(ReportType)
415 case HidP_Input:
416 b_count = data->caps.NumberInputButtonCaps;
417 break;
418 case HidP_Output:
419 b_count = data->caps.NumberOutputButtonCaps;
420 break;
421 case HidP_Feature:
422 b_count = data->caps.NumberFeatureButtonCaps;
423 break;
424 default:
425 return HIDP_STATUS_INVALID_REPORT_TYPE;
427 r_count = data->reportCount[ReportType];
428 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
430 if (!r_count || !b_count)
431 return HIDP_STATUS_USAGE_NOT_FOUND;
433 if (report->reportID && report->reportID != Report[0])
434 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
436 uCount = 0;
437 for (i = 0; i < report->elementCount && uCount < *UsageLength; i++)
439 if (elems[report->elementIdx + i].ElementType == ButtonElement &&
440 elems[report->elementIdx + i].caps.button.UsagePage == UsagePage)
442 int k;
443 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
444 for (k=0; k < element->bitCount; k++)
446 UINT v = 0;
447 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
448 element->valueStartBit + k, 1, &v);
449 if (rc != HIDP_STATUS_SUCCESS)
450 return rc;
451 found = TRUE;
452 if (v)
454 if (uCount == *UsageLength)
455 return HIDP_STATUS_BUFFER_TOO_SMALL;
456 UsageList[uCount] = element->caps.button.u.Range.UsageMin + k;
457 uCount++;
463 *UsageLength = uCount;
465 if (!found)
466 return HIDP_STATUS_USAGE_NOT_FOUND;
468 return HIDP_STATUS_SUCCESS;
472 NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps,
473 PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
475 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
476 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
477 WINE_HID_REPORT *report = NULL;
478 USHORT v_count = 0, r_count = 0;
479 int i,j,u;
481 TRACE("(%i, %p, %p, %p)\n", ReportType, ValueCaps, ValueCapsLength, PreparsedData);
483 if (data->magic != HID_MAGIC)
484 return HIDP_STATUS_INVALID_PREPARSED_DATA;
486 switch(ReportType)
488 case HidP_Input:
489 v_count = data->caps.NumberInputValueCaps;
490 report = HID_INPUT_REPORTS(data);
491 break;
492 case HidP_Output:
493 v_count = data->caps.NumberOutputValueCaps;
494 report = HID_OUTPUT_REPORTS(data);
495 break;
496 case HidP_Feature:
497 v_count = data->caps.NumberFeatureValueCaps;
498 report = HID_FEATURE_REPORTS(data);
499 break;
500 default:
501 return HIDP_STATUS_INVALID_REPORT_TYPE;
503 r_count = data->reportCount[ReportType];
505 if (!r_count || !v_count)
507 *ValueCapsLength = 0;
508 return HIDP_STATUS_SUCCESS;
511 v_count = min(v_count, *ValueCapsLength);
513 u = 0;
514 for (j = 0; j < r_count && u < v_count; j++)
516 for (i = 0; i < report[j].elementCount && u < v_count; i++)
518 if (elems[report[j].elementIdx + i].ElementType == ValueElement)
519 ValueCaps[u++] = elems[report[j].elementIdx + i].caps.value;
523 *ValueCapsLength = v_count;
524 return HIDP_STATUS_SUCCESS;
527 NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID,
528 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
529 ULONG ReportLength)
531 int size;
532 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
533 WINE_HID_REPORT *report = NULL;
534 int r_count;
536 TRACE("(%i, %i, %p, %p, %i)\n",ReportType, ReportID, PreparsedData, Report, ReportLength);
538 if (data->magic != HID_MAGIC)
539 return HIDP_STATUS_INVALID_PREPARSED_DATA;
541 switch(ReportType)
543 case HidP_Input:
544 size = data->caps.InputReportByteLength;
545 break;
546 case HidP_Output:
547 size = data->caps.OutputReportByteLength;
548 break;
549 case HidP_Feature:
550 size = data->caps.FeatureReportByteLength;
551 break;
552 default:
553 return HIDP_STATUS_INVALID_REPORT_TYPE;
555 r_count = data->reportCount[ReportType];
556 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
558 if (!r_count || !size)
559 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
561 if (size != ReportLength)
562 return HIDP_STATUS_INVALID_REPORT_LENGTH;
564 if (report->reportID && report->reportID != Report[0])
565 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
567 ZeroMemory(Report, size);
568 Report[0] = ReportID;
569 return HIDP_STATUS_SUCCESS;
572 ULONG WINAPI HidP_MaxUsageListLength(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, PHIDP_PREPARSED_DATA PreparsedData)
574 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
575 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
576 WINE_HID_REPORT *report = NULL;
577 int r_count;
578 int i;
579 int count = 0;
581 TRACE("(%i, %x, %p)\n", ReportType, UsagePage, PreparsedData);
583 if (data->magic != HID_MAGIC)
584 return 0;
586 switch(ReportType)
588 case HidP_Input:
589 report = HID_INPUT_REPORTS(data);
590 break;
591 case HidP_Output:
592 report = HID_OUTPUT_REPORTS(data);
593 break;
594 case HidP_Feature:
595 report = HID_FEATURE_REPORTS(data);
596 break;
597 default:
598 return HIDP_STATUS_INVALID_REPORT_TYPE;
600 r_count = data->reportCount[ReportType];
603 if (!r_count)
604 return 0;
606 for (i = 0; i < r_count; i++)
608 int j;
609 for (j = 0; j < report[i].elementCount; j++)
611 if (elems[report[i].elementIdx + j].ElementType == ButtonElement &&
612 (UsagePage == 0 || elems[report[i].elementIdx + j].caps.button.UsagePage == UsagePage))
614 if (elems[report[i].elementIdx + j].caps.button.IsRange)
615 count += (elems[report[i].elementIdx + j].caps.button.u.Range.UsageMax -
616 elems[report[i].elementIdx + j].caps.button.u.Range.UsageMin) + 1;
617 else
618 count++;
622 return count;
625 NTSTATUS WINAPI HidP_SetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
626 USAGE Usage, ULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
627 CHAR *Report, ULONG ReportLength)
629 WINE_HID_ELEMENT element;
630 NTSTATUS rc;
632 TRACE("(%i, %x, %i, %i, %i, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
633 PreparsedData, Report, ReportLength);
635 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
637 if (rc == HIDP_STATUS_SUCCESS)
639 return set_report_data((BYTE*)Report, ReportLength,
640 element.valueStartBit, element.bitCount, UsageValue);
643 return rc;
647 NTSTATUS WINAPI HidP_SetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
648 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
649 PCHAR Report, ULONG ReportLength)
651 WINE_HID_ELEMENT element;
652 NTSTATUS rc;
653 ULONG i;
655 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
656 UsageLength, PreparsedData, Report, ReportLength);
658 for (i = 0; i < *UsageLength; i++)
660 rc = find_usage(ReportType, UsagePage, LinkCollection,
661 UsageList[i], PreparsedData, Report, ButtonElement, &element);
662 if (rc == HIDP_STATUS_SUCCESS)
664 rc = set_report_data((BYTE*)Report, ReportLength,
665 element.valueStartBit, element.bitCount, -1);
668 if (rc != HIDP_STATUS_SUCCESS)
670 *UsageLength = i;
671 return rc;
675 return HIDP_STATUS_SUCCESS;
679 NTSTATUS WINAPI HidP_TranslateUsagesToI8042ScanCodes(USAGE *ChangedUsageList,
680 ULONG UsageListLength, HIDP_KEYBOARD_DIRECTION KeyAction,
681 HIDP_KEYBOARD_MODIFIER_STATE *ModifierState,
682 PHIDP_INSERT_SCANCODES InsertCodesProcedure, VOID *InsertCodesContext)
684 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList, UsageListLength,
685 KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
687 return STATUS_NOT_IMPLEMENTED;
690 NTSTATUS WINAPI HidP_GetSpecificButtonCaps(HIDP_REPORT_TYPE ReportType,
691 USAGE UsagePage, USHORT LinkCollection, USAGE Usage,
692 HIDP_BUTTON_CAPS *ButtonCaps, USHORT *ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
694 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
695 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
696 WINE_HID_REPORT *report = NULL;
697 USHORT b_count = 0, r_count = 0;
698 int i,j,u;
700 TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection,
701 Usage, ButtonCaps, ButtonCapsLength, PreparsedData);
703 if (data->magic != HID_MAGIC)
704 return HIDP_STATUS_INVALID_PREPARSED_DATA;
706 switch(ReportType)
708 case HidP_Input:
709 b_count = data->caps.NumberInputButtonCaps;
710 report = HID_INPUT_REPORTS(data);
711 break;
712 case HidP_Output:
713 b_count = data->caps.NumberOutputButtonCaps;
714 report = HID_OUTPUT_REPORTS(data);
715 break;
716 case HidP_Feature:
717 b_count = data->caps.NumberFeatureButtonCaps;
718 report = HID_FEATURE_REPORTS(data);
719 break;
720 default:
721 return HIDP_STATUS_INVALID_REPORT_TYPE;
723 r_count = data->reportCount[ReportType];
725 if (!r_count || !b_count)
727 *ButtonCapsLength = 0;
728 return HIDP_STATUS_SUCCESS;
731 b_count = min(b_count, *ButtonCapsLength);
733 u = 0;
734 for (j = 0; j < r_count && u < b_count; j++)
736 for (i = 0; i < report[j].elementCount && u < b_count; i++)
738 if (elems[report[j].elementIdx + i].ElementType == ButtonElement &&
739 (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.button.UsagePage) &&
740 (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.button.LinkCollection) &&
741 (Usage == 0 || (
742 (!elems[report[j].elementIdx + i].caps.button.IsRange &&
743 Usage == elems[report[j].elementIdx + i].caps.button.u.NotRange.Usage)) ||
744 (elems[report[j].elementIdx + i].caps.button.IsRange &&
745 Usage >= elems[report[j].elementIdx + i].caps.button.u.Range.UsageMin &&
746 Usage <= elems[report[j].elementIdx + i].caps.button.u.Range.UsageMax)))
748 ButtonCaps[u++] = elems[report[j].elementIdx + i].caps.button;
752 TRACE("Matched %i usages\n", u);
754 *ButtonCapsLength = u;
756 return HIDP_STATUS_SUCCESS;
760 NTSTATUS WINAPI HidP_GetSpecificValueCaps(HIDP_REPORT_TYPE ReportType,
761 USAGE UsagePage, USHORT LinkCollection, USAGE Usage,
762 HIDP_VALUE_CAPS *ValueCaps, USHORT *ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
764 WINE_HIDP_PREPARSED_DATA *data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
765 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
766 WINE_HID_REPORT *report = NULL;
767 USHORT v_count = 0, r_count = 0;
768 int i,j,u;
770 TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection,
771 Usage, ValueCaps, ValueCapsLength, PreparsedData);
773 if (data->magic != HID_MAGIC)
774 return HIDP_STATUS_INVALID_PREPARSED_DATA;
776 switch(ReportType)
778 case HidP_Input:
779 v_count = data->caps.NumberInputValueCaps;
780 report = HID_INPUT_REPORTS(data);
781 break;
782 case HidP_Output:
783 v_count = data->caps.NumberOutputValueCaps;
784 report = HID_OUTPUT_REPORTS(data);
785 break;
786 case HidP_Feature:
787 v_count = data->caps.NumberFeatureValueCaps;
788 report = HID_FEATURE_REPORTS(data);
789 break;
790 default:
791 return HIDP_STATUS_INVALID_REPORT_TYPE;
793 r_count = data->reportCount[ReportType];
795 if (!r_count || !v_count)
797 *ValueCapsLength = 0;
798 return HIDP_STATUS_SUCCESS;
801 v_count = min(v_count, *ValueCapsLength);
803 u = 0;
804 for (j = 0; j < r_count && u < v_count; j++)
806 for (i = 0; i < report[j].elementCount && u < v_count; i++)
808 if (elems[report[j].elementIdx + i].ElementType == ValueElement &&
809 (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.value.UsagePage) &&
810 (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.value.LinkCollection) &&
811 (Usage == 0 || Usage == elems[report[j].elementIdx + i].caps.value.u.NotRange.Usage))
813 ValueCaps[u++] = elems[report[j].elementIdx + i].caps.value;
817 TRACE("Matched %i usages\n", u);
819 *ValueCapsLength = u;
821 return HIDP_STATUS_SUCCESS;
824 NTSTATUS WINAPI HidP_GetUsagesEx(HIDP_REPORT_TYPE ReportType, USHORT LinkCollection, USAGE_AND_PAGE *ButtonList,
825 ULONG *UsageLength, PHIDP_PREPARSED_DATA PreparsedData, CHAR *Report, ULONG ReportLength)
827 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
828 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
829 WINE_HID_REPORT *report = NULL;
830 USHORT b_count = 0, r_count = 0;
831 int i,uCount = 0;
832 NTSTATUS rc;
834 TRACE("(%i, %i, %p, %p(%i), %p, %p, %i)\n", ReportType, LinkCollection, ButtonList,
835 UsageLength, *UsageLength, PreparsedData, Report, ReportLength);
837 if (data->magic != HID_MAGIC)
838 return HIDP_STATUS_INVALID_PREPARSED_DATA;
840 switch(ReportType)
842 case HidP_Input:
843 b_count = data->caps.NumberInputButtonCaps;
844 break;
845 case HidP_Output:
846 b_count = data->caps.NumberOutputButtonCaps;
847 break;
848 case HidP_Feature:
849 b_count = data->caps.NumberFeatureButtonCaps;
850 break;
851 default:
852 return HIDP_STATUS_INVALID_REPORT_TYPE;
854 r_count = data->reportCount[ReportType];
855 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
857 if (!r_count || !b_count)
858 return HIDP_STATUS_USAGE_NOT_FOUND;
860 if (report->reportID && report->reportID != Report[0])
861 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
863 for (i = 0; i < report->elementCount; i++)
865 if (elems[report->elementIdx + i].ElementType == ButtonElement)
867 int k;
868 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
869 for (k=0; k < element->bitCount; k++)
871 UINT v = 0;
872 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
873 element->valueStartBit + k, 1, &v);
874 if (rc != HIDP_STATUS_SUCCESS)
875 return rc;
876 if (v)
878 if (uCount < *UsageLength)
880 ButtonList[uCount].Usage = element->caps.button.u.Range.UsageMin + k;
881 ButtonList[uCount].UsagePage = element->caps.button.UsagePage;
883 uCount++;
889 TRACE("Returning %i usages\n", uCount);
891 if (*UsageLength < uCount)
892 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
893 else
894 rc = HIDP_STATUS_SUCCESS;
896 *UsageLength = uCount;
898 return rc;
901 ULONG WINAPI HidP_MaxDataListLength(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData)
903 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA *)PreparsedData;
904 TRACE("(%i, %p)\n", ReportType, PreparsedData);
905 if (data->magic != HID_MAGIC)
906 return 0;
908 switch(ReportType)
910 case HidP_Input:
911 return data->caps.NumberInputDataIndices;
912 case HidP_Output:
913 return data->caps.NumberOutputDataIndices;
914 case HidP_Feature:
915 return data->caps.NumberFeatureDataIndices;
916 default:
917 return 0;
921 NTSTATUS WINAPI HidP_GetData(HIDP_REPORT_TYPE ReportType, HIDP_DATA *DataList, ULONG *DataLength,
922 PHIDP_PREPARSED_DATA PreparsedData,CHAR *Report, ULONG ReportLength)
924 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
925 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
926 WINE_HID_REPORT *report = NULL;
927 USHORT r_count = 0;
928 int i,uCount = 0;
929 NTSTATUS rc;
931 TRACE("(%i, %p, %p(%i), %p, %p, %i)\n", ReportType, DataList, DataLength,
932 DataLength?*DataLength:0, PreparsedData, Report, ReportLength);
934 if (data->magic != HID_MAGIC)
935 return 0;
937 if (ReportType != HidP_Input && ReportType != HidP_Output && ReportType != HidP_Feature)
938 return HIDP_STATUS_INVALID_REPORT_TYPE;
940 r_count = data->reportCount[ReportType];
941 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
943 if (!r_count || (report->reportID && report->reportID != Report[0]))
944 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
946 for (i = 0; i < report->elementCount; i++)
948 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
949 if (element->ElementType == ButtonElement)
951 int k;
952 for (k=0; k < element->bitCount; k++)
954 UINT v = 0;
955 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
956 element->valueStartBit + k, 1, &v);
957 if (rc != HIDP_STATUS_SUCCESS)
958 return rc;
959 if (v)
961 if (uCount < *DataLength)
963 DataList[uCount].DataIndex = element->caps.button.u.Range.DataIndexMin + k;
964 DataList[uCount].u.On = v;
966 uCount++;
970 else
972 if (uCount < *DataLength)
974 UINT v;
975 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
976 element->valueStartBit, element->bitCount, &v);
977 if (rc != HIDP_STATUS_SUCCESS)
978 return rc;
979 DataList[uCount].DataIndex = element->caps.value.u.NotRange.DataIndex;
980 DataList[uCount].u.RawValue = v;
982 uCount++;
986 if (*DataLength < uCount)
987 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
988 else
989 rc = HIDP_STATUS_SUCCESS;
991 *DataLength = uCount;
993 return rc;
996 NTSTATUS WINAPI HidP_GetLinkCollectionNodes(HIDP_LINK_COLLECTION_NODE *LinkCollectionNode,
997 ULONG *LinkCollectionNodeLength, PHIDP_PREPARSED_DATA PreparsedData)
999 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
1000 WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data);
1001 ULONG i;
1003 TRACE("(%p, %p, %p)\n", LinkCollectionNode, LinkCollectionNodeLength, PreparsedData);
1005 if (*LinkCollectionNodeLength < data->caps.NumberLinkCollectionNodes)
1006 return HIDP_STATUS_BUFFER_TOO_SMALL;
1008 for (i = 0; i < data->caps.NumberLinkCollectionNodes; ++i)
1010 LinkCollectionNode[i].LinkUsage = nodes[i].LinkUsage;
1011 LinkCollectionNode[i].LinkUsagePage = nodes[i].LinkUsagePage;
1012 LinkCollectionNode[i].Parent = nodes[i].Parent;
1013 LinkCollectionNode[i].NumberOfChildren = nodes[i].NumberOfChildren;
1014 LinkCollectionNode[i].NextSibling = nodes[i].NextSibling;
1015 LinkCollectionNode[i].FirstChild = nodes[i].FirstChild;
1016 LinkCollectionNode[i].CollectionType = nodes[i].CollectionType;
1017 LinkCollectionNode[i].IsAlias = nodes[i].IsAlias;
1019 *LinkCollectionNodeLength = data->caps.NumberLinkCollectionNodes;
1021 return HIDP_STATUS_SUCCESS;