hid: Fix error handling in HidP_SetUsages.
[wine.git] / dlls / hid / hidp.c
blob8c046703b40b088f36fe2d2999261d71f76c9c1d
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
21 #include "config.h"
23 #include <stdarg.h>
25 #define NONAMELESSUNION
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "winioctl.h"
32 #include "ddk/wdm.h"
34 #include "hidusage.h"
35 #include "ddk/hidpi.h"
36 #include "parse.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(hidp);
41 static NTSTATUS get_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value)
44 if ((startBit + valueSize) / 8 > reportLength)
45 return HIDP_STATUS_INVALID_REPORT_LENGTH;
47 if (valueSize == 1)
49 ULONG byte_index = startBit / 8;
50 ULONG bit_index = startBit - (byte_index * 8);
51 INT mask = (1 << bit_index);
52 *value = !!(report[byte_index] & mask);
54 else
56 ULONG remaining_bits = valueSize;
57 ULONG byte_index = startBit / 8;
58 ULONG bit_index = startBit % 8;
59 ULONG data = 0;
60 ULONG shift = 0;
61 while (remaining_bits)
63 ULONG copy_bits = 8 - bit_index;
64 if (remaining_bits < copy_bits)
65 copy_bits = remaining_bits;
67 data |= ((report[byte_index] >> bit_index) & ((2 << copy_bits) - 1)) << shift;
69 shift += copy_bits;
70 bit_index = 0;
71 byte_index++;
72 remaining_bits -= copy_bits;
74 *value = data;
76 return HIDP_STATUS_SUCCESS;
79 static NTSTATUS set_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, ULONG value)
81 if ((startBit + valueSize) / 8 > reportLength)
82 return HIDP_STATUS_INVALID_REPORT_LENGTH;
84 if (valueSize == 1)
86 ULONG byte_index = startBit / 8;
87 ULONG bit_index = startBit - (byte_index * 8);
88 if (value)
89 report[byte_index] |= (1 << bit_index);
90 else
91 report[byte_index] &= ~(1 << bit_index);
93 else
95 ULONG byte_index = (startBit + valueSize - 1) / 8;
96 ULONG data = value;
97 ULONG remainingBits = valueSize;
98 while (remainingBits)
100 BYTE subvalue = data & 0xff;
102 data >>= 8;
104 if (remainingBits >= 8)
106 report[byte_index] = subvalue;
107 byte_index --;
108 remainingBits -= 8;
110 else if (remainingBits > 0)
112 BYTE mask = (0xff << (8-remainingBits)) & subvalue;
113 report[byte_index] |= mask;
114 remainingBits = 0;
118 return HIDP_STATUS_SUCCESS;
122 NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps,
123 PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
125 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
126 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
127 WINE_HID_REPORT *report = NULL;
128 USHORT b_count = 0, r_count = 0;
129 int i,j,u;
131 TRACE("(%i, %p, %p, %p)\n",ReportType, ButtonCaps, ButtonCapsLength, PreparsedData);
133 if (data->magic != HID_MAGIC)
134 return HIDP_STATUS_INVALID_PREPARSED_DATA;
136 switch(ReportType)
138 case HidP_Input:
139 b_count = data->caps.NumberInputButtonCaps;
140 report = HID_INPUT_REPORTS(data);
141 break;
142 case HidP_Output:
143 b_count = data->caps.NumberOutputButtonCaps;
144 report = HID_OUTPUT_REPORTS(data);
145 break;
146 case HidP_Feature:
147 b_count = data->caps.NumberFeatureButtonCaps;
148 report = HID_FEATURE_REPORTS(data);
149 break;
150 default:
151 return HIDP_STATUS_INVALID_REPORT_TYPE;
153 r_count = data->reportCount[ReportType];
155 if (!r_count || !b_count)
157 *ButtonCapsLength = 0;
158 return HIDP_STATUS_SUCCESS;
161 b_count = min(b_count, *ButtonCapsLength);
163 u = 0;
164 for (j = 0; j < r_count && u < b_count; j++)
166 for (i = 0; i < report[j].elementCount && u < b_count; i++)
168 if (elems[report[j].elementIdx + i].ElementType == ButtonElement)
169 ButtonCaps[u++] = elems[report[j].elementIdx + i].caps.button;
173 *ButtonCapsLength = b_count;
174 return HIDP_STATUS_SUCCESS;
178 NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData,
179 PHIDP_CAPS Capabilities)
181 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
183 TRACE("(%p, %p)\n",PreparsedData, Capabilities);
185 if (data->magic != HID_MAGIC)
186 return HIDP_STATUS_INVALID_PREPARSED_DATA;
188 *Capabilities = data->caps;
190 return HIDP_STATUS_SUCCESS;
193 static NTSTATUS find_usage(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
194 USAGE Usage, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
195 WINE_ELEMENT_TYPE ElementType, WINE_HID_ELEMENT *element)
197 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
198 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
199 WINE_HID_REPORT *report = NULL;
200 USHORT v_count = 0, r_count = 0;
201 int i;
203 TRACE("(%i, %x, %i, %i, %p, %p)\n", ReportType, UsagePage, LinkCollection, Usage,
204 PreparsedData, Report);
206 if (data->magic != HID_MAGIC)
207 return HIDP_STATUS_INVALID_PREPARSED_DATA;
208 switch(ReportType)
210 case HidP_Input:
211 v_count = data->caps.NumberInputValueCaps;
212 break;
213 case HidP_Output:
214 v_count = data->caps.NumberOutputValueCaps;
215 break;
216 case HidP_Feature:
217 v_count = data->caps.NumberFeatureValueCaps;
218 break;
219 default:
220 return HIDP_STATUS_INVALID_REPORT_TYPE;
222 r_count = data->reportCount[ReportType];
223 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
225 if (!r_count || !v_count)
226 return HIDP_STATUS_USAGE_NOT_FOUND;
228 if (report->reportID && report->reportID != Report[0])
229 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
231 for (i = 0; i < report->elementCount; i++)
233 HIDP_VALUE_CAPS *value = &elems[report->elementIdx + i].caps.value;
235 if (elems[report->elementIdx + i].ElementType != ElementType ||
236 value->UsagePage != UsagePage)
237 continue;
239 if (value->IsRange && value->u.Range.UsageMin <= Usage && Usage <= value->u.Range.UsageMax)
241 *element = elems[report->elementIdx + i];
242 element->valueStartBit += value->BitSize * (Usage - value->u.Range.UsageMin);
243 element->bitCount = elems[report->elementIdx + i].ElementType == ValueElement ? value->BitSize: 1;
244 return HIDP_STATUS_SUCCESS;
246 else if (value->u.NotRange.Usage == Usage)
248 *element = elems[report->elementIdx + i];
249 element->bitCount = elems[report->elementIdx + i].ElementType == ValueElement ? value->BitSize : 1;
250 return HIDP_STATUS_SUCCESS;
254 return HIDP_STATUS_USAGE_NOT_FOUND;
257 static LONG sign_extend(ULONG value, const WINE_HID_ELEMENT *element)
259 UINT bit_count = element->bitCount;
261 if ((value & (1 << (bit_count - 1)))
262 && element->ElementType == ValueElement
263 && element->caps.value.LogicalMin < 0)
265 value -= (1 << bit_count);
267 return value;
270 static LONG logical_to_physical(LONG value, const WINE_HID_ELEMENT *element)
272 if (element->caps.value.PhysicalMin || element->caps.value.PhysicalMax)
274 value = (((ULONGLONG)(value - element->caps.value.LogicalMin)
275 * (element->caps.value.PhysicalMax - element->caps.value.PhysicalMin))
276 / (element->caps.value.LogicalMax - element->caps.value.LogicalMin))
277 + element->caps.value.PhysicalMin;
279 return value;
282 NTSTATUS WINAPI HidP_GetScaledUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage,
283 USHORT LinkCollection, USAGE Usage, PLONG UsageValue,
284 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength)
286 NTSTATUS rc;
287 WINE_HID_ELEMENT element;
288 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
289 PreparsedData, Report, ReportLength);
291 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
293 if (rc == HIDP_STATUS_SUCCESS)
295 ULONG rawValue;
296 rc = get_report_data((BYTE*)Report, ReportLength,
297 element.valueStartBit, element.bitCount, &rawValue);
298 if (rc != HIDP_STATUS_SUCCESS)
299 return rc;
300 *UsageValue = logical_to_physical(sign_extend(rawValue, &element), &element);
303 return rc;
307 NTSTATUS WINAPI HidP_GetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
308 USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
309 PCHAR Report, ULONG ReportLength)
311 WINE_HID_ELEMENT element;
312 NTSTATUS rc;
314 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
315 PreparsedData, Report, ReportLength);
317 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
319 if (rc == HIDP_STATUS_SUCCESS)
321 return get_report_data((BYTE*)Report, ReportLength,
322 element.valueStartBit, element.bitCount, UsageValue);
325 return rc;
329 NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
330 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
331 PCHAR Report, ULONG ReportLength)
333 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
334 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
335 WINE_HID_REPORT *report = NULL;
336 BOOL found = FALSE;
337 USHORT b_count = 0, r_count = 0;
338 int i,uCount;
340 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
341 UsageLength, PreparsedData, Report, ReportLength);
343 if (data->magic != HID_MAGIC)
345 *UsageLength = 0;
346 return HIDP_STATUS_INVALID_PREPARSED_DATA;
349 switch(ReportType)
351 case HidP_Input:
352 b_count = data->caps.NumberInputButtonCaps;
353 break;
354 case HidP_Output:
355 b_count = data->caps.NumberOutputButtonCaps;
356 break;
357 case HidP_Feature:
358 b_count = data->caps.NumberFeatureButtonCaps;
359 break;
360 default:
361 return HIDP_STATUS_INVALID_REPORT_TYPE;
363 r_count = data->reportCount[ReportType];
364 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
366 if (!r_count || !b_count)
367 return HIDP_STATUS_USAGE_NOT_FOUND;
369 if (report->reportID && report->reportID != Report[0])
370 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
372 uCount = 0;
373 for (i = 0; i < report->elementCount && uCount < *UsageLength; i++)
375 if (elems[report->elementIdx + i].ElementType == ButtonElement &&
376 elems[report->elementIdx + i].caps.button.UsagePage == UsagePage)
378 int k;
379 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
380 for (k=0; k < element->bitCount; k++)
382 UINT v = 0;
383 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
384 element->valueStartBit + k, 1, &v);
385 if (rc != HIDP_STATUS_SUCCESS)
386 return rc;
387 found = TRUE;
388 if (v)
390 if (uCount == *UsageLength)
391 return HIDP_STATUS_BUFFER_TOO_SMALL;
392 UsageList[uCount] = element->caps.button.u.Range.UsageMin + k;
393 uCount++;
399 *UsageLength = uCount;
401 if (!found)
402 return HIDP_STATUS_USAGE_NOT_FOUND;
404 return HIDP_STATUS_SUCCESS;
408 NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps,
409 PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
411 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
412 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
413 WINE_HID_REPORT *report = NULL;
414 USHORT v_count = 0, r_count = 0;
415 int i,j,u;
417 TRACE("(%i, %p, %p, %p)\n", ReportType, ValueCaps, ValueCapsLength, PreparsedData);
419 if (data->magic != HID_MAGIC)
420 return HIDP_STATUS_INVALID_PREPARSED_DATA;
422 switch(ReportType)
424 case HidP_Input:
425 v_count = data->caps.NumberInputValueCaps;
426 report = HID_INPUT_REPORTS(data);
427 break;
428 case HidP_Output:
429 v_count = data->caps.NumberOutputValueCaps;
430 report = HID_OUTPUT_REPORTS(data);
431 break;
432 case HidP_Feature:
433 v_count = data->caps.NumberFeatureValueCaps;
434 report = HID_FEATURE_REPORTS(data);
435 break;
436 default:
437 return HIDP_STATUS_INVALID_REPORT_TYPE;
439 r_count = data->reportCount[ReportType];
441 if (!r_count || !v_count)
443 *ValueCapsLength = 0;
444 return HIDP_STATUS_SUCCESS;
447 v_count = min(v_count, *ValueCapsLength);
449 u = 0;
450 for (j = 0; j < r_count && u < v_count; j++)
452 for (i = 0; i < report[j].elementCount && u < v_count; i++)
454 if (elems[report->elementIdx + i].ElementType == ValueElement)
455 ValueCaps[u++] = elems[report->elementIdx + i].caps.value;
459 *ValueCapsLength = v_count;
460 return HIDP_STATUS_SUCCESS;
463 NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID,
464 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
465 ULONG ReportLength)
467 int size;
468 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
469 WINE_HID_REPORT *report = NULL;
470 int r_count;
472 TRACE("(%i, %i, %p, %p, %i)\n",ReportType, ReportID, PreparsedData, Report, ReportLength);
474 if (data->magic != HID_MAGIC)
475 return HIDP_STATUS_INVALID_PREPARSED_DATA;
477 switch(ReportType)
479 case HidP_Input:
480 size = data->caps.InputReportByteLength;
481 break;
482 case HidP_Output:
483 size = data->caps.OutputReportByteLength;
484 break;
485 case HidP_Feature:
486 size = data->caps.FeatureReportByteLength;
487 break;
488 default:
489 return HIDP_STATUS_INVALID_REPORT_TYPE;
491 r_count = data->reportCount[ReportType];
492 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
494 if (!r_count || !size)
495 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
497 if (size != ReportLength)
498 return HIDP_STATUS_INVALID_REPORT_LENGTH;
500 if (report->reportID && report->reportID != Report[0])
501 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
503 ZeroMemory(Report, size);
504 Report[0] = ReportID;
505 return HIDP_STATUS_SUCCESS;
508 ULONG WINAPI HidP_MaxUsageListLength(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, PHIDP_PREPARSED_DATA PreparsedData)
510 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
511 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
512 WINE_HID_REPORT *report = NULL;
513 int r_count;
514 int i;
515 int count = 0;
517 TRACE("(%i, %x, %p)\n", ReportType, UsagePage, PreparsedData);
519 if (data->magic != HID_MAGIC)
520 return 0;
522 switch(ReportType)
524 case HidP_Input:
525 report = HID_INPUT_REPORTS(data);
526 break;
527 case HidP_Output:
528 report = HID_OUTPUT_REPORTS(data);
529 break;
530 case HidP_Feature:
531 report = HID_FEATURE_REPORTS(data);
532 break;
533 default:
534 return HIDP_STATUS_INVALID_REPORT_TYPE;
536 r_count = data->reportCount[ReportType];
539 if (!r_count)
540 return 0;
542 for (i = 0; i < r_count; i++)
544 int j;
545 for (j = 0; j < report[i].elementCount; j++)
547 if (elems[report[i].elementIdx + j].ElementType == ButtonElement &&
548 (UsagePage == 0 || elems[report[i].elementIdx + j].caps.button.UsagePage == UsagePage))
550 if (elems[report[i].elementIdx + j].caps.button.IsRange)
551 count += (elems[report[i].elementIdx + j].caps.button.u.Range.UsageMax -
552 elems[report[i].elementIdx + j].caps.button.u.Range.UsageMin) + 1;
553 else
554 count++;
558 return count;
561 NTSTATUS WINAPI HidP_SetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
562 USAGE Usage, ULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
563 CHAR *Report, ULONG ReportLength)
565 WINE_HID_ELEMENT element;
566 NTSTATUS rc;
568 TRACE("(%i, %x, %i, %i, %i, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
569 PreparsedData, Report, ReportLength);
571 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
573 if (rc == HIDP_STATUS_SUCCESS)
575 return set_report_data((BYTE*)Report, ReportLength,
576 element.valueStartBit, element.bitCount, UsageValue);
579 return rc;
583 NTSTATUS WINAPI HidP_SetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
584 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
585 PCHAR Report, ULONG ReportLength)
587 WINE_HID_ELEMENT element;
588 NTSTATUS rc;
589 ULONG i;
591 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
592 UsageLength, PreparsedData, Report, ReportLength);
594 for (i = 0; i < *UsageLength; i++)
596 rc = find_usage(ReportType, UsagePage, LinkCollection,
597 UsageList[i], PreparsedData, Report, ButtonElement, &element);
598 if (rc == HIDP_STATUS_SUCCESS)
600 rc = set_report_data((BYTE*)Report, ReportLength,
601 element.valueStartBit, element.bitCount, -1);
604 if (rc != HIDP_STATUS_SUCCESS)
606 *UsageLength = i;
607 return rc;
611 return HIDP_STATUS_SUCCESS;
615 NTSTATUS WINAPI HidP_TranslateUsagesToI8042ScanCodes(USAGE *ChangedUsageList,
616 ULONG UsageListLength, HIDP_KEYBOARD_DIRECTION KeyAction,
617 HIDP_KEYBOARD_MODIFIER_STATE *ModifierState,
618 PHIDP_INSERT_SCANCODES InsertCodesProcedure, VOID *InsertCodesContext)
620 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList, UsageListLength,
621 KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
623 return STATUS_NOT_IMPLEMENTED;
626 NTSTATUS WINAPI HidP_GetSpecificButtonCaps(HIDP_REPORT_TYPE ReportType,
627 USAGE UsagePage, USHORT LinkCollection, USAGE Usage,
628 HIDP_BUTTON_CAPS *ButtonCaps, USHORT *ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
630 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
631 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
632 WINE_HID_REPORT *report = NULL;
633 USHORT b_count = 0, r_count = 0;
634 int i,j,u;
636 TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection,
637 Usage, ButtonCaps, ButtonCapsLength, PreparsedData);
639 if (data->magic != HID_MAGIC)
640 return HIDP_STATUS_INVALID_PREPARSED_DATA;
642 switch(ReportType)
644 case HidP_Input:
645 b_count = data->caps.NumberInputButtonCaps;
646 report = HID_INPUT_REPORTS(data);
647 break;
648 case HidP_Output:
649 b_count = data->caps.NumberOutputButtonCaps;
650 report = HID_OUTPUT_REPORTS(data);
651 break;
652 case HidP_Feature:
653 b_count = data->caps.NumberFeatureButtonCaps;
654 report = HID_FEATURE_REPORTS(data);
655 break;
656 default:
657 return HIDP_STATUS_INVALID_REPORT_TYPE;
659 r_count = data->reportCount[ReportType];
661 if (!r_count || !b_count)
663 *ButtonCapsLength = 0;
664 return HIDP_STATUS_SUCCESS;
667 b_count = min(b_count, *ButtonCapsLength);
669 u = 0;
670 for (j = 0; j < r_count && u < b_count; j++)
672 for (i = 0; i < report[j].elementCount && u < b_count; i++)
674 if (elems[report[j].elementIdx + i].ElementType == ButtonElement &&
675 (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.button.UsagePage) &&
676 (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.button.LinkCollection) &&
677 (Usage == 0 || (
678 (!elems[report[j].elementIdx + i].caps.button.IsRange &&
679 Usage == elems[report[j].elementIdx + i].caps.button.u.NotRange.Usage)) ||
680 (elems[report[j].elementIdx + i].caps.button.IsRange &&
681 Usage >= elems[report[j].elementIdx + i].caps.button.u.Range.UsageMin &&
682 Usage <= elems[report[j].elementIdx + i].caps.button.u.Range.UsageMax)))
684 ButtonCaps[u++] = elems[report[j].elementIdx + i].caps.button;
688 TRACE("Matched %i usages\n", u);
690 *ButtonCapsLength = u;
692 return HIDP_STATUS_SUCCESS;
696 NTSTATUS WINAPI HidP_GetSpecificValueCaps(HIDP_REPORT_TYPE ReportType,
697 USAGE UsagePage, USHORT LinkCollection, USAGE Usage,
698 HIDP_VALUE_CAPS *ValueCaps, USHORT *ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
700 WINE_HIDP_PREPARSED_DATA *data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
701 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
702 WINE_HID_REPORT *report = NULL;
703 USHORT v_count = 0, r_count = 0;
704 int i,j,u;
706 TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection,
707 Usage, ValueCaps, ValueCapsLength, PreparsedData);
709 if (data->magic != HID_MAGIC)
710 return HIDP_STATUS_INVALID_PREPARSED_DATA;
712 switch(ReportType)
714 case HidP_Input:
715 v_count = data->caps.NumberInputValueCaps;
716 report = HID_INPUT_REPORTS(data);
717 break;
718 case HidP_Output:
719 v_count = data->caps.NumberOutputValueCaps;
720 report = HID_OUTPUT_REPORTS(data);
721 break;
722 case HidP_Feature:
723 v_count = data->caps.NumberFeatureValueCaps;
724 report = HID_FEATURE_REPORTS(data);
725 break;
726 default:
727 return HIDP_STATUS_INVALID_REPORT_TYPE;
729 r_count = data->reportCount[ReportType];
731 if (!r_count || !v_count)
733 *ValueCapsLength = 0;
734 return HIDP_STATUS_SUCCESS;
737 v_count = min(v_count, *ValueCapsLength);
739 u = 0;
740 for (j = 0; j < r_count && u < v_count; j++)
742 for (i = 0; i < report[j].elementCount && u < v_count; i++)
744 if (elems[report[j].elementIdx + i].ElementType == ValueElement &&
745 (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.value.UsagePage) &&
746 (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.value.LinkCollection) &&
747 (Usage == 0 || Usage == elems[report[j].elementIdx + i].caps.value.u.NotRange.Usage))
749 ValueCaps[u++] = elems[report[j].elementIdx + i].caps.value;
753 TRACE("Matched %i usages\n", u);
755 *ValueCapsLength = u;
757 return HIDP_STATUS_SUCCESS;
760 NTSTATUS WINAPI HidP_GetUsagesEx(HIDP_REPORT_TYPE ReportType, USHORT LinkCollection, USAGE_AND_PAGE *ButtonList,
761 ULONG *UsageLength, PHIDP_PREPARSED_DATA PreparsedData, CHAR *Report, ULONG ReportLength)
763 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
764 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
765 WINE_HID_REPORT *report = NULL;
766 USHORT b_count = 0, r_count = 0;
767 int i,uCount = 0;
768 NTSTATUS rc;
770 TRACE("(%i, %i, %p, %p(%i), %p, %p, %i)\n", ReportType, LinkCollection, ButtonList,
771 UsageLength, *UsageLength, PreparsedData, Report, ReportLength);
773 if (data->magic != HID_MAGIC)
774 return HIDP_STATUS_INVALID_PREPARSED_DATA;
776 switch(ReportType)
778 case HidP_Input:
779 b_count = data->caps.NumberInputButtonCaps;
780 break;
781 case HidP_Output:
782 b_count = data->caps.NumberOutputButtonCaps;
783 break;
784 case HidP_Feature:
785 b_count = data->caps.NumberFeatureButtonCaps;
786 break;
787 default:
788 return HIDP_STATUS_INVALID_REPORT_TYPE;
790 r_count = data->reportCount[ReportType];
791 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
793 if (!r_count || !b_count)
794 return HIDP_STATUS_USAGE_NOT_FOUND;
796 if (report->reportID && report->reportID != Report[0])
797 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
799 for (i = 0; i < report->elementCount; i++)
801 if (elems[report->elementIdx + i].ElementType == ButtonElement)
803 int k;
804 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
805 for (k=0; k < element->bitCount; k++)
807 UINT v = 0;
808 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
809 element->valueStartBit + k, 1, &v);
810 if (rc != HIDP_STATUS_SUCCESS)
811 return rc;
812 if (v)
814 if (uCount < *UsageLength)
816 ButtonList[uCount].Usage = element->caps.button.u.Range.UsageMin + k;
817 ButtonList[uCount].UsagePage = element->caps.button.UsagePage;
819 uCount++;
825 TRACE("Returning %i usages\n", uCount);
827 if (*UsageLength < uCount)
828 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
829 else
830 rc = HIDP_STATUS_SUCCESS;
832 *UsageLength = uCount;
834 return rc;
837 ULONG WINAPI HidP_MaxDataListLength(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData)
839 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA *)PreparsedData;
840 TRACE("(%i, %p)\n", ReportType, PreparsedData);
841 if (data->magic != HID_MAGIC)
842 return 0;
844 switch(ReportType)
846 case HidP_Input:
847 return data->caps.NumberInputDataIndices;
848 case HidP_Output:
849 return data->caps.NumberOutputDataIndices;
850 case HidP_Feature:
851 return data->caps.NumberFeatureDataIndices;
852 default:
853 return 0;
857 NTSTATUS WINAPI HidP_GetData(HIDP_REPORT_TYPE ReportType, HIDP_DATA *DataList, ULONG *DataLength,
858 PHIDP_PREPARSED_DATA PreparsedData,CHAR *Report, ULONG ReportLength)
860 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
861 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
862 WINE_HID_REPORT *report = NULL;
863 USHORT r_count = 0;
864 int i,uCount = 0;
865 NTSTATUS rc;
867 TRACE("(%i, %p, %p(%i), %p, %p, %i)\n", ReportType, DataList, DataLength,
868 DataLength?*DataLength:0, PreparsedData, Report, ReportLength);
870 if (data->magic != HID_MAGIC)
871 return 0;
873 if (ReportType != HidP_Input && ReportType != HidP_Output && ReportType != HidP_Feature)
874 return HIDP_STATUS_INVALID_REPORT_TYPE;
876 r_count = data->reportCount[ReportType];
877 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
879 if (!r_count || (report->reportID && report->reportID != Report[0]))
880 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
882 for (i = 0; i < report->elementCount; i++)
884 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
885 if (element->ElementType == ButtonElement)
887 int k;
888 for (k=0; k < element->bitCount; k++)
890 UINT v = 0;
891 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
892 element->valueStartBit + k, 1, &v);
893 if (rc != HIDP_STATUS_SUCCESS)
894 return rc;
895 if (v)
897 if (uCount < *DataLength)
899 DataList[uCount].DataIndex = element->caps.button.u.Range.DataIndexMin + k;
900 DataList[uCount].u.On = v;
902 uCount++;
906 else
908 if (uCount < *DataLength)
910 UINT v;
911 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
912 element->valueStartBit, element->bitCount, &v);
913 if (rc != HIDP_STATUS_SUCCESS)
914 return rc;
915 DataList[uCount].DataIndex = element->caps.value.u.NotRange.DataIndex;
916 DataList[uCount].u.RawValue = v;
918 uCount++;
922 if (*DataLength < uCount)
923 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
924 else
925 rc = HIDP_STATUS_SUCCESS;
927 *DataLength = uCount;
929 return rc;