ucrtbase: Export _o_to{lower, upper}() as to{lower, upper}().
[wine.git] / dlls / hid / hidp.c
blob9d631912c8570f9c5567e59747316fc936617968
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;
121 NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps,
122 PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
124 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
125 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
126 WINE_HID_REPORT *report = NULL;
127 USHORT b_count = 0, r_count = 0;
128 int i,j,u;
130 TRACE("(%i, %p, %p, %p)\n",ReportType, ButtonCaps, ButtonCapsLength, PreparsedData);
132 if (data->magic != HID_MAGIC)
133 return HIDP_STATUS_INVALID_PREPARSED_DATA;
135 switch(ReportType)
137 case HidP_Input:
138 b_count = data->caps.NumberInputButtonCaps;
139 report = HID_INPUT_REPORTS(data);
140 break;
141 case HidP_Output:
142 b_count = data->caps.NumberOutputButtonCaps;
143 report = HID_OUTPUT_REPORTS(data);
144 break;
145 case HidP_Feature:
146 b_count = data->caps.NumberFeatureButtonCaps;
147 report = HID_FEATURE_REPORTS(data);
148 break;
149 default:
150 return HIDP_STATUS_INVALID_REPORT_TYPE;
152 r_count = data->reportCount[ReportType];
154 if (!r_count || !b_count)
156 *ButtonCapsLength = 0;
157 return HIDP_STATUS_SUCCESS;
160 b_count = min(b_count, *ButtonCapsLength);
162 u = 0;
163 for (j = 0; j < r_count && u < b_count; j++)
165 for (i = 0; i < report[j].elementCount && u < b_count; i++)
167 if (elems[report[j].elementIdx + i].ElementType == ButtonElement)
168 ButtonCaps[u++] = elems[report[j].elementIdx + i].caps.button;
172 *ButtonCapsLength = b_count;
173 return HIDP_STATUS_SUCCESS;
177 NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData,
178 PHIDP_CAPS Capabilities)
180 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
182 TRACE("(%p, %p)\n",PreparsedData, Capabilities);
184 if (data->magic != HID_MAGIC)
185 return HIDP_STATUS_INVALID_PREPARSED_DATA;
187 *Capabilities = data->caps;
189 return HIDP_STATUS_SUCCESS;
192 static NTSTATUS find_usage(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
193 USAGE Usage, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
194 WINE_ELEMENT_TYPE ElementType, WINE_HID_ELEMENT *element)
196 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
197 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
198 WINE_HID_REPORT *report = NULL;
199 USHORT v_count = 0, r_count = 0;
200 int i;
202 TRACE("(%i, %x, %i, %i, %p, %p)\n", ReportType, UsagePage, LinkCollection, Usage,
203 PreparsedData, Report);
205 if (data->magic != HID_MAGIC)
206 return HIDP_STATUS_INVALID_PREPARSED_DATA;
207 switch(ReportType)
209 case HidP_Input:
210 v_count = data->caps.NumberInputValueCaps;
211 break;
212 case HidP_Output:
213 v_count = data->caps.NumberOutputValueCaps;
214 break;
215 case HidP_Feature:
216 v_count = data->caps.NumberFeatureValueCaps;
217 break;
218 default:
219 return HIDP_STATUS_INVALID_REPORT_TYPE;
221 r_count = data->reportCount[ReportType];
222 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
224 if (!r_count || !v_count)
225 return HIDP_STATUS_USAGE_NOT_FOUND;
227 if (report->reportID && report->reportID != Report[0])
228 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
230 for (i = 0; i < report->elementCount; i++)
232 HIDP_VALUE_CAPS *value = &elems[report->elementIdx + i].caps.value;
234 if (elems[report->elementIdx + i].ElementType != ElementType ||
235 value->UsagePage != UsagePage)
236 continue;
238 if (value->IsRange && value->u.Range.UsageMin <= Usage && Usage <= value->u.Range.UsageMax)
240 *element = elems[report->elementIdx + i];
241 element->valueStartBit += value->BitSize * (Usage - value->u.Range.UsageMin);
242 element->bitCount = elems[report->elementIdx + i].ElementType == ValueElement ? value->BitSize: 1;
243 return HIDP_STATUS_SUCCESS;
245 else if (value->u.NotRange.Usage == Usage)
247 *element = elems[report->elementIdx + i];
248 element->bitCount = elems[report->elementIdx + i].ElementType == ValueElement ? value->BitSize : 1;
249 return HIDP_STATUS_SUCCESS;
253 return HIDP_STATUS_USAGE_NOT_FOUND;
256 static LONG sign_extend(ULONG value, const WINE_HID_ELEMENT *element)
258 UINT bit_count = element->bitCount;
260 if ((value & (1 << (bit_count - 1)))
261 && element->ElementType == ValueElement
262 && element->caps.value.LogicalMin < 0)
264 value -= (1 << bit_count);
266 return value;
269 static LONG logical_to_physical(LONG value, const WINE_HID_ELEMENT *element)
271 if (element->caps.value.PhysicalMin || element->caps.value.PhysicalMax)
273 value = (((ULONGLONG)(value - element->caps.value.LogicalMin)
274 * (element->caps.value.PhysicalMax - element->caps.value.PhysicalMin))
275 / (element->caps.value.LogicalMax - element->caps.value.LogicalMin))
276 + element->caps.value.PhysicalMin;
278 return value;
281 NTSTATUS WINAPI HidP_GetScaledUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage,
282 USHORT LinkCollection, USAGE Usage, PLONG UsageValue,
283 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength)
285 NTSTATUS rc;
286 WINE_HID_ELEMENT element;
287 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
288 PreparsedData, Report, ReportLength);
290 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
292 if (rc == HIDP_STATUS_SUCCESS)
294 ULONG rawValue;
295 rc = get_report_data((BYTE*)Report, ReportLength,
296 element.valueStartBit, element.bitCount, &rawValue);
297 if (rc != HIDP_STATUS_SUCCESS)
298 return rc;
299 *UsageValue = logical_to_physical(sign_extend(rawValue, &element), &element);
302 return rc;
306 NTSTATUS WINAPI HidP_GetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
307 USAGE Usage, PULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
308 PCHAR Report, ULONG ReportLength)
310 WINE_HID_ELEMENT element;
311 NTSTATUS rc;
313 TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
314 PreparsedData, Report, ReportLength);
316 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
318 if (rc == HIDP_STATUS_SUCCESS)
320 return get_report_data((BYTE*)Report, ReportLength,
321 element.valueStartBit, element.bitCount, UsageValue);
324 return rc;
328 NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
329 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
330 PCHAR Report, ULONG ReportLength)
332 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
333 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
334 WINE_HID_REPORT *report = NULL;
335 BOOL found = FALSE;
336 USHORT b_count = 0, r_count = 0;
337 int i,uCount;
339 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
340 UsageLength, PreparsedData, Report, ReportLength);
342 if (data->magic != HID_MAGIC)
344 *UsageLength = 0;
345 return HIDP_STATUS_INVALID_PREPARSED_DATA;
348 switch(ReportType)
350 case HidP_Input:
351 b_count = data->caps.NumberInputButtonCaps;
352 break;
353 case HidP_Output:
354 b_count = data->caps.NumberOutputButtonCaps;
355 break;
356 case HidP_Feature:
357 b_count = data->caps.NumberFeatureButtonCaps;
358 break;
359 default:
360 return HIDP_STATUS_INVALID_REPORT_TYPE;
362 r_count = data->reportCount[ReportType];
363 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
365 if (!r_count || !b_count)
366 return HIDP_STATUS_USAGE_NOT_FOUND;
368 if (report->reportID && report->reportID != Report[0])
369 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
371 uCount = 0;
372 for (i = 0; i < report->elementCount && uCount < *UsageLength; i++)
374 if (elems[report->elementIdx + i].ElementType == ButtonElement &&
375 elems[report->elementIdx + i].caps.button.UsagePage == UsagePage)
377 int k;
378 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
379 for (k=0; k < element->bitCount; k++)
381 UINT v = 0;
382 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
383 element->valueStartBit + k, 1, &v);
384 if (rc != HIDP_STATUS_SUCCESS)
385 return rc;
386 found = TRUE;
387 if (v)
389 if (uCount == *UsageLength)
390 return HIDP_STATUS_BUFFER_TOO_SMALL;
391 UsageList[uCount] = element->caps.button.u.Range.UsageMin + k;
392 uCount++;
398 *UsageLength = uCount;
400 if (!found)
401 return HIDP_STATUS_USAGE_NOT_FOUND;
403 return HIDP_STATUS_SUCCESS;
407 NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps,
408 PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
410 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
411 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
412 WINE_HID_REPORT *report = NULL;
413 USHORT v_count = 0, r_count = 0;
414 int i,j,u;
416 TRACE("(%i, %p, %p, %p)\n", ReportType, ValueCaps, ValueCapsLength, PreparsedData);
418 if (data->magic != HID_MAGIC)
419 return HIDP_STATUS_INVALID_PREPARSED_DATA;
421 switch(ReportType)
423 case HidP_Input:
424 v_count = data->caps.NumberInputValueCaps;
425 report = HID_INPUT_REPORTS(data);
426 break;
427 case HidP_Output:
428 v_count = data->caps.NumberOutputValueCaps;
429 report = HID_OUTPUT_REPORTS(data);
430 break;
431 case HidP_Feature:
432 v_count = data->caps.NumberFeatureValueCaps;
433 report = HID_FEATURE_REPORTS(data);
434 break;
435 default:
436 return HIDP_STATUS_INVALID_REPORT_TYPE;
438 r_count = data->reportCount[ReportType];
440 if (!r_count || !v_count)
442 *ValueCapsLength = 0;
443 return HIDP_STATUS_SUCCESS;
446 v_count = min(v_count, *ValueCapsLength);
448 u = 0;
449 for (j = 0; j < r_count && u < v_count; j++)
451 for (i = 0; i < report[j].elementCount && u < v_count; i++)
453 if (elems[report[j].elementIdx + i].ElementType == ValueElement)
454 ValueCaps[u++] = elems[report[j].elementIdx + i].caps.value;
458 *ValueCapsLength = v_count;
459 return HIDP_STATUS_SUCCESS;
462 NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID,
463 PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
464 ULONG ReportLength)
466 int size;
467 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
468 WINE_HID_REPORT *report = NULL;
469 int r_count;
471 TRACE("(%i, %i, %p, %p, %i)\n",ReportType, ReportID, PreparsedData, Report, ReportLength);
473 if (data->magic != HID_MAGIC)
474 return HIDP_STATUS_INVALID_PREPARSED_DATA;
476 switch(ReportType)
478 case HidP_Input:
479 size = data->caps.InputReportByteLength;
480 break;
481 case HidP_Output:
482 size = data->caps.OutputReportByteLength;
483 break;
484 case HidP_Feature:
485 size = data->caps.FeatureReportByteLength;
486 break;
487 default:
488 return HIDP_STATUS_INVALID_REPORT_TYPE;
490 r_count = data->reportCount[ReportType];
491 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
493 if (!r_count || !size)
494 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
496 if (size != ReportLength)
497 return HIDP_STATUS_INVALID_REPORT_LENGTH;
499 if (report->reportID && report->reportID != Report[0])
500 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
502 ZeroMemory(Report, size);
503 Report[0] = ReportID;
504 return HIDP_STATUS_SUCCESS;
507 ULONG WINAPI HidP_MaxUsageListLength(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, PHIDP_PREPARSED_DATA PreparsedData)
509 PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
510 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
511 WINE_HID_REPORT *report = NULL;
512 int r_count;
513 int i;
514 int count = 0;
516 TRACE("(%i, %x, %p)\n", ReportType, UsagePage, PreparsedData);
518 if (data->magic != HID_MAGIC)
519 return 0;
521 switch(ReportType)
523 case HidP_Input:
524 report = HID_INPUT_REPORTS(data);
525 break;
526 case HidP_Output:
527 report = HID_OUTPUT_REPORTS(data);
528 break;
529 case HidP_Feature:
530 report = HID_FEATURE_REPORTS(data);
531 break;
532 default:
533 return HIDP_STATUS_INVALID_REPORT_TYPE;
535 r_count = data->reportCount[ReportType];
538 if (!r_count)
539 return 0;
541 for (i = 0; i < r_count; i++)
543 int j;
544 for (j = 0; j < report[i].elementCount; j++)
546 if (elems[report[i].elementIdx + j].ElementType == ButtonElement &&
547 (UsagePage == 0 || elems[report[i].elementIdx + j].caps.button.UsagePage == UsagePage))
549 if (elems[report[i].elementIdx + j].caps.button.IsRange)
550 count += (elems[report[i].elementIdx + j].caps.button.u.Range.UsageMax -
551 elems[report[i].elementIdx + j].caps.button.u.Range.UsageMin) + 1;
552 else
553 count++;
557 return count;
560 NTSTATUS WINAPI HidP_SetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
561 USAGE Usage, ULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
562 CHAR *Report, ULONG ReportLength)
564 WINE_HID_ELEMENT element;
565 NTSTATUS rc;
567 TRACE("(%i, %x, %i, %i, %i, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
568 PreparsedData, Report, ReportLength);
570 rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, ValueElement, &element);
572 if (rc == HIDP_STATUS_SUCCESS)
574 return set_report_data((BYTE*)Report, ReportLength,
575 element.valueStartBit, element.bitCount, UsageValue);
578 return rc;
582 NTSTATUS WINAPI HidP_SetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
583 PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData,
584 PCHAR Report, ULONG ReportLength)
586 WINE_HID_ELEMENT element;
587 NTSTATUS rc;
588 ULONG i;
590 TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList,
591 UsageLength, PreparsedData, Report, ReportLength);
593 for (i = 0; i < *UsageLength; i++)
595 rc = find_usage(ReportType, UsagePage, LinkCollection,
596 UsageList[i], PreparsedData, Report, ButtonElement, &element);
597 if (rc == HIDP_STATUS_SUCCESS)
599 rc = set_report_data((BYTE*)Report, ReportLength,
600 element.valueStartBit, element.bitCount, -1);
603 if (rc != HIDP_STATUS_SUCCESS)
605 *UsageLength = i;
606 return rc;
610 return HIDP_STATUS_SUCCESS;
614 NTSTATUS WINAPI HidP_TranslateUsagesToI8042ScanCodes(USAGE *ChangedUsageList,
615 ULONG UsageListLength, HIDP_KEYBOARD_DIRECTION KeyAction,
616 HIDP_KEYBOARD_MODIFIER_STATE *ModifierState,
617 PHIDP_INSERT_SCANCODES InsertCodesProcedure, VOID *InsertCodesContext)
619 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList, UsageListLength,
620 KeyAction, ModifierState, InsertCodesProcedure, InsertCodesContext);
622 return STATUS_NOT_IMPLEMENTED;
625 NTSTATUS WINAPI HidP_GetSpecificButtonCaps(HIDP_REPORT_TYPE ReportType,
626 USAGE UsagePage, USHORT LinkCollection, USAGE Usage,
627 HIDP_BUTTON_CAPS *ButtonCaps, USHORT *ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
629 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
630 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
631 WINE_HID_REPORT *report = NULL;
632 USHORT b_count = 0, r_count = 0;
633 int i,j,u;
635 TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection,
636 Usage, ButtonCaps, ButtonCapsLength, PreparsedData);
638 if (data->magic != HID_MAGIC)
639 return HIDP_STATUS_INVALID_PREPARSED_DATA;
641 switch(ReportType)
643 case HidP_Input:
644 b_count = data->caps.NumberInputButtonCaps;
645 report = HID_INPUT_REPORTS(data);
646 break;
647 case HidP_Output:
648 b_count = data->caps.NumberOutputButtonCaps;
649 report = HID_OUTPUT_REPORTS(data);
650 break;
651 case HidP_Feature:
652 b_count = data->caps.NumberFeatureButtonCaps;
653 report = HID_FEATURE_REPORTS(data);
654 break;
655 default:
656 return HIDP_STATUS_INVALID_REPORT_TYPE;
658 r_count = data->reportCount[ReportType];
660 if (!r_count || !b_count)
662 *ButtonCapsLength = 0;
663 return HIDP_STATUS_SUCCESS;
666 b_count = min(b_count, *ButtonCapsLength);
668 u = 0;
669 for (j = 0; j < r_count && u < b_count; j++)
671 for (i = 0; i < report[j].elementCount && u < b_count; i++)
673 if (elems[report[j].elementIdx + i].ElementType == ButtonElement &&
674 (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.button.UsagePage) &&
675 (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.button.LinkCollection) &&
676 (Usage == 0 || (
677 (!elems[report[j].elementIdx + i].caps.button.IsRange &&
678 Usage == elems[report[j].elementIdx + i].caps.button.u.NotRange.Usage)) ||
679 (elems[report[j].elementIdx + i].caps.button.IsRange &&
680 Usage >= elems[report[j].elementIdx + i].caps.button.u.Range.UsageMin &&
681 Usage <= elems[report[j].elementIdx + i].caps.button.u.Range.UsageMax)))
683 ButtonCaps[u++] = elems[report[j].elementIdx + i].caps.button;
687 TRACE("Matched %i usages\n", u);
689 *ButtonCapsLength = u;
691 return HIDP_STATUS_SUCCESS;
695 NTSTATUS WINAPI HidP_GetSpecificValueCaps(HIDP_REPORT_TYPE ReportType,
696 USAGE UsagePage, USHORT LinkCollection, USAGE Usage,
697 HIDP_VALUE_CAPS *ValueCaps, USHORT *ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData)
699 WINE_HIDP_PREPARSED_DATA *data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
700 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
701 WINE_HID_REPORT *report = NULL;
702 USHORT v_count = 0, r_count = 0;
703 int i,j,u;
705 TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection,
706 Usage, ValueCaps, ValueCapsLength, PreparsedData);
708 if (data->magic != HID_MAGIC)
709 return HIDP_STATUS_INVALID_PREPARSED_DATA;
711 switch(ReportType)
713 case HidP_Input:
714 v_count = data->caps.NumberInputValueCaps;
715 report = HID_INPUT_REPORTS(data);
716 break;
717 case HidP_Output:
718 v_count = data->caps.NumberOutputValueCaps;
719 report = HID_OUTPUT_REPORTS(data);
720 break;
721 case HidP_Feature:
722 v_count = data->caps.NumberFeatureValueCaps;
723 report = HID_FEATURE_REPORTS(data);
724 break;
725 default:
726 return HIDP_STATUS_INVALID_REPORT_TYPE;
728 r_count = data->reportCount[ReportType];
730 if (!r_count || !v_count)
732 *ValueCapsLength = 0;
733 return HIDP_STATUS_SUCCESS;
736 v_count = min(v_count, *ValueCapsLength);
738 u = 0;
739 for (j = 0; j < r_count && u < v_count; j++)
741 for (i = 0; i < report[j].elementCount && u < v_count; i++)
743 if (elems[report[j].elementIdx + i].ElementType == ValueElement &&
744 (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.value.UsagePage) &&
745 (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.value.LinkCollection) &&
746 (Usage == 0 || Usage == elems[report[j].elementIdx + i].caps.value.u.NotRange.Usage))
748 ValueCaps[u++] = elems[report[j].elementIdx + i].caps.value;
752 TRACE("Matched %i usages\n", u);
754 *ValueCapsLength = u;
756 return HIDP_STATUS_SUCCESS;
759 NTSTATUS WINAPI HidP_GetUsagesEx(HIDP_REPORT_TYPE ReportType, USHORT LinkCollection, USAGE_AND_PAGE *ButtonList,
760 ULONG *UsageLength, PHIDP_PREPARSED_DATA PreparsedData, CHAR *Report, ULONG ReportLength)
762 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
763 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
764 WINE_HID_REPORT *report = NULL;
765 USHORT b_count = 0, r_count = 0;
766 int i,uCount = 0;
767 NTSTATUS rc;
769 TRACE("(%i, %i, %p, %p(%i), %p, %p, %i)\n", ReportType, LinkCollection, ButtonList,
770 UsageLength, *UsageLength, PreparsedData, Report, ReportLength);
772 if (data->magic != HID_MAGIC)
773 return HIDP_STATUS_INVALID_PREPARSED_DATA;
775 switch(ReportType)
777 case HidP_Input:
778 b_count = data->caps.NumberInputButtonCaps;
779 break;
780 case HidP_Output:
781 b_count = data->caps.NumberOutputButtonCaps;
782 break;
783 case HidP_Feature:
784 b_count = data->caps.NumberFeatureButtonCaps;
785 break;
786 default:
787 return HIDP_STATUS_INVALID_REPORT_TYPE;
789 r_count = data->reportCount[ReportType];
790 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
792 if (!r_count || !b_count)
793 return HIDP_STATUS_USAGE_NOT_FOUND;
795 if (report->reportID && report->reportID != Report[0])
796 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
798 for (i = 0; i < report->elementCount; i++)
800 if (elems[report->elementIdx + i].ElementType == ButtonElement)
802 int k;
803 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
804 for (k=0; k < element->bitCount; k++)
806 UINT v = 0;
807 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
808 element->valueStartBit + k, 1, &v);
809 if (rc != HIDP_STATUS_SUCCESS)
810 return rc;
811 if (v)
813 if (uCount < *UsageLength)
815 ButtonList[uCount].Usage = element->caps.button.u.Range.UsageMin + k;
816 ButtonList[uCount].UsagePage = element->caps.button.UsagePage;
818 uCount++;
824 TRACE("Returning %i usages\n", uCount);
826 if (*UsageLength < uCount)
827 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
828 else
829 rc = HIDP_STATUS_SUCCESS;
831 *UsageLength = uCount;
833 return rc;
836 ULONG WINAPI HidP_MaxDataListLength(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData)
838 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA *)PreparsedData;
839 TRACE("(%i, %p)\n", ReportType, PreparsedData);
840 if (data->magic != HID_MAGIC)
841 return 0;
843 switch(ReportType)
845 case HidP_Input:
846 return data->caps.NumberInputDataIndices;
847 case HidP_Output:
848 return data->caps.NumberOutputDataIndices;
849 case HidP_Feature:
850 return data->caps.NumberFeatureDataIndices;
851 default:
852 return 0;
856 NTSTATUS WINAPI HidP_GetData(HIDP_REPORT_TYPE ReportType, HIDP_DATA *DataList, ULONG *DataLength,
857 PHIDP_PREPARSED_DATA PreparsedData,CHAR *Report, ULONG ReportLength)
859 WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData;
860 WINE_HID_ELEMENT *elems = HID_ELEMS(data);
861 WINE_HID_REPORT *report = NULL;
862 USHORT r_count = 0;
863 int i,uCount = 0;
864 NTSTATUS rc;
866 TRACE("(%i, %p, %p(%i), %p, %p, %i)\n", ReportType, DataList, DataLength,
867 DataLength?*DataLength:0, PreparsedData, Report, ReportLength);
869 if (data->magic != HID_MAGIC)
870 return 0;
872 if (ReportType != HidP_Input && ReportType != HidP_Output && ReportType != HidP_Feature)
873 return HIDP_STATUS_INVALID_REPORT_TYPE;
875 r_count = data->reportCount[ReportType];
876 report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
878 if (!r_count || (report->reportID && report->reportID != Report[0]))
879 return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
881 for (i = 0; i < report->elementCount; i++)
883 WINE_HID_ELEMENT *element = &elems[report->elementIdx + i];
884 if (element->ElementType == ButtonElement)
886 int k;
887 for (k=0; k < element->bitCount; k++)
889 UINT v = 0;
890 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
891 element->valueStartBit + k, 1, &v);
892 if (rc != HIDP_STATUS_SUCCESS)
893 return rc;
894 if (v)
896 if (uCount < *DataLength)
898 DataList[uCount].DataIndex = element->caps.button.u.Range.DataIndexMin + k;
899 DataList[uCount].u.On = v;
901 uCount++;
905 else
907 if (uCount < *DataLength)
909 UINT v;
910 NTSTATUS rc = get_report_data((BYTE*)Report, ReportLength,
911 element->valueStartBit, element->bitCount, &v);
912 if (rc != HIDP_STATUS_SUCCESS)
913 return rc;
914 DataList[uCount].DataIndex = element->caps.value.u.NotRange.DataIndex;
915 DataList[uCount].u.RawValue = v;
917 uCount++;
921 if (*DataLength < uCount)
922 rc = HIDP_STATUS_BUFFER_TOO_SMALL;
923 else
924 rc = HIDP_STATUS_SUCCESS;
926 *DataLength = uCount;
928 return rc;