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
25 #define WIN32_NO_STATUS
33 #include "ddk/hidpi.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(hidp
);
39 static NTSTATUS
get_value_caps_range( struct hid_preparsed_data
*preparsed
, HIDP_REPORT_TYPE report_type
, ULONG report_len
,
40 const struct hid_value_caps
**caps
, const struct hid_value_caps
**caps_end
)
42 if (!preparsed
|| memcmp( preparsed
->magic
, "HidP KDR", 8 )) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
47 if (report_len
&& report_len
!= preparsed
->input_report_byte_length
)
48 return HIDP_STATUS_INVALID_REPORT_LENGTH
;
49 *caps
= HID_INPUT_VALUE_CAPS( preparsed
);
50 *caps_end
= *caps
+ preparsed
->input_caps_count
;
53 if (report_len
&& report_len
!= preparsed
->output_report_byte_length
)
54 return HIDP_STATUS_INVALID_REPORT_LENGTH
;
55 *caps
= HID_OUTPUT_VALUE_CAPS( preparsed
);
56 *caps_end
= *caps
+ preparsed
->output_caps_count
;
59 if (report_len
&& report_len
!= preparsed
->feature_report_byte_length
)
60 return HIDP_STATUS_INVALID_REPORT_LENGTH
;
61 *caps
= HID_FEATURE_VALUE_CAPS( preparsed
);
62 *caps_end
= *caps
+ preparsed
->feature_caps_count
;
65 return HIDP_STATUS_INVALID_REPORT_TYPE
;
68 return HIDP_STATUS_SUCCESS
;
82 static BOOL
match_value_caps( const struct hid_value_caps
*caps
, const struct caps_filter
*filter
)
84 if (!caps
->usage_min
&& !caps
->usage_max
) return FALSE
;
85 if (filter
->buttons
&& !(caps
->flags
& HID_VALUE_CAPS_IS_BUTTON
)) return FALSE
;
86 if (filter
->values
&& (caps
->flags
& HID_VALUE_CAPS_IS_BUTTON
)) return FALSE
;
87 if (filter
->usage_page
&& filter
->usage_page
!= caps
->usage_page
) return FALSE
;
88 if (filter
->collection
&& filter
->collection
!= caps
->link_collection
) return FALSE
;
89 if (!filter
->usage
) return TRUE
;
90 return caps
->usage_min
<= filter
->usage
&& caps
->usage_max
>= filter
->usage
;
93 typedef NTSTATUS (*enum_value_caps_callback
)( const struct hid_value_caps
*caps
, void *user
);
95 static NTSTATUS
enum_value_caps( struct hid_preparsed_data
*preparsed
, HIDP_REPORT_TYPE report_type
,
96 ULONG report_len
, const struct caps_filter
*filter
,
97 enum_value_caps_callback callback
, void *user
, USHORT
*count
)
99 const struct hid_value_caps
*caps
, *caps_end
;
100 BOOL is_range
, incompatible
= FALSE
;
101 LONG remaining
= *count
;
104 for (status
= get_value_caps_range( preparsed
, report_type
, report_len
, &caps
, &caps_end
);
105 status
== HIDP_STATUS_SUCCESS
&& caps
!= caps_end
; caps
++)
107 is_range
= caps
->flags
& HID_VALUE_CAPS_IS_RANGE
;
108 if (!match_value_caps( caps
, filter
)) continue;
109 if (filter
->report_id
&& caps
->report_id
!= filter
->report_id
) incompatible
= TRUE
;
110 else if (filter
->array
&& (is_range
|| caps
->report_count
<= 1)) return HIDP_STATUS_NOT_VALUE_ARRAY
;
111 else if (remaining
-- > 0) status
= callback( caps
, user
);
114 if (status
== HIDP_STATUS_NULL
) status
= HIDP_STATUS_SUCCESS
;
115 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
118 if (*count
== 0) return incompatible
? HIDP_STATUS_INCOMPATIBLE_REPORT_ID
: HIDP_STATUS_USAGE_NOT_FOUND
;
119 if (remaining
< 0) return HIDP_STATUS_BUFFER_TOO_SMALL
;
120 return HIDP_STATUS_SUCCESS
;
123 /* copy count bits from src, starting at (-shift) bit if < 0, to dst starting at (shift) bit if > 0 */
124 static void copy_bits( unsigned char *dst
, const unsigned char *src
, int count
, int shift
)
126 unsigned char bits
, mask
;
127 size_t src_shift
= shift
< 0 ? (-shift
& 7) : 0;
128 size_t dst_shift
= shift
> 0 ? (shift
& 7) : 0;
129 if (shift
< 0) src
+= -shift
/ 8;
130 if (shift
> 0) dst
+= shift
/ 8;
132 if (src_shift
== 0 && dst_shift
== 0)
134 memcpy( dst
, src
, count
/ 8 );
142 bits
= *dst
<< (8 - dst_shift
);
147 *dst
= bits
>> (8 - dst_shift
);
148 bits
= *(unsigned short *)src
++ >> src_shift
;
149 *dst
++ |= bits
<< dst_shift
;
153 bits
>>= (8 - dst_shift
);
154 if (count
<= 8 - src_shift
) bits
|= (*src
>> src_shift
) << dst_shift
;
155 else bits
|= (*(unsigned short *)src
>> src_shift
) << dst_shift
;
157 mask
= (1 << count
) - 1;
158 *dst
= (bits
& mask
) | (*dst
& ~mask
);
161 NTSTATUS WINAPI
HidP_GetButtonCaps( HIDP_REPORT_TYPE report_type
, HIDP_BUTTON_CAPS
*caps
, USHORT
*caps_count
,
162 PHIDP_PREPARSED_DATA preparsed_data
)
164 return HidP_GetSpecificButtonCaps( report_type
, 0, 0, 0, caps
, caps_count
, preparsed_data
);
167 NTSTATUS WINAPI
HidP_GetCaps( PHIDP_PREPARSED_DATA preparsed_data
, HIDP_CAPS
*caps
)
169 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
170 struct hid_value_caps
*it
, *end
;
172 TRACE( "preparsed_data %p, caps %p.\n", preparsed_data
, caps
);
174 if (!preparsed
|| memcmp( preparsed
->magic
, "HidP KDR", 8 )) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
176 caps
->Usage
= preparsed
->usage
;
177 caps
->UsagePage
= preparsed
->usage_page
;
178 caps
->InputReportByteLength
= preparsed
->input_report_byte_length
;
179 caps
->OutputReportByteLength
= preparsed
->output_report_byte_length
;
180 caps
->FeatureReportByteLength
= preparsed
->feature_report_byte_length
;
181 caps
->NumberLinkCollectionNodes
= preparsed
->number_link_collection_nodes
;
182 caps
->NumberInputButtonCaps
= 0;
183 caps
->NumberInputValueCaps
= 0;
184 caps
->NumberInputDataIndices
= 0;
185 caps
->NumberOutputButtonCaps
= 0;
186 caps
->NumberOutputValueCaps
= 0;
187 caps
->NumberOutputDataIndices
= 0;
188 caps
->NumberFeatureButtonCaps
= 0;
189 caps
->NumberFeatureValueCaps
= 0;
190 caps
->NumberFeatureDataIndices
= 0;
192 for (it
= HID_INPUT_VALUE_CAPS( preparsed
), end
= it
+ preparsed
->input_caps_count
;
195 if (!it
->usage_min
&& !it
->usage_max
) continue;
196 if (it
->flags
& HID_VALUE_CAPS_IS_BUTTON
) caps
->NumberInputButtonCaps
++;
197 else caps
->NumberInputValueCaps
++;
198 if (!(it
->flags
& HID_VALUE_CAPS_IS_RANGE
)) caps
->NumberInputDataIndices
++;
199 else caps
->NumberInputDataIndices
+= it
->data_index_max
- it
->data_index_min
+ 1;
202 for (it
= HID_OUTPUT_VALUE_CAPS( preparsed
), end
= it
+ preparsed
->output_caps_count
;
205 if (!it
->usage_min
&& !it
->usage_max
) continue;
206 if (it
->flags
& HID_VALUE_CAPS_IS_BUTTON
) caps
->NumberOutputButtonCaps
++;
207 else caps
->NumberOutputValueCaps
++;
208 if (!(it
->flags
& HID_VALUE_CAPS_IS_RANGE
)) caps
->NumberOutputDataIndices
++;
209 else caps
->NumberOutputDataIndices
+= it
->data_index_max
- it
->data_index_min
+ 1;
212 for (it
= HID_FEATURE_VALUE_CAPS( preparsed
), end
= it
+ preparsed
->feature_caps_count
;
215 if (!it
->usage_min
&& !it
->usage_max
) continue;
216 if (it
->flags
& HID_VALUE_CAPS_IS_BUTTON
) caps
->NumberFeatureButtonCaps
++;
217 else caps
->NumberFeatureValueCaps
++;
218 if (!(it
->flags
& HID_VALUE_CAPS_IS_RANGE
)) caps
->NumberFeatureDataIndices
++;
219 else caps
->NumberFeatureDataIndices
+= it
->data_index_max
- it
->data_index_min
+ 1;
222 return HIDP_STATUS_SUCCESS
;
225 struct usage_value_params
232 static LONG
sign_extend( ULONG value
, const struct hid_value_caps
*caps
)
234 UINT sign
= 1 << (caps
->bit_size
- 1);
235 if (sign
<= 1 || caps
->logical_min
>= 0) return value
;
236 return value
- ((value
& sign
) << 1);
239 static NTSTATUS
get_scaled_usage_value( const struct hid_value_caps
*caps
, void *user
)
241 struct usage_value_params
*params
= user
;
242 ULONG unsigned_value
= 0, bit_count
= caps
->bit_size
* caps
->report_count
;
243 LONG signed_value
, *value
= params
->value_buf
;
244 unsigned char *report_buf
;
246 if ((bit_count
+ 7) / 8 > sizeof(unsigned_value
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
247 if (sizeof(LONG
) > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
249 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
250 copy_bits( (unsigned char *)&unsigned_value
, report_buf
, bit_count
, -caps
->start_bit
);
251 signed_value
= sign_extend( unsigned_value
, caps
);
253 if (caps
->logical_min
> caps
->logical_max
|| caps
->physical_min
> caps
->physical_max
)
254 return HIDP_STATUS_BAD_LOG_PHY_VALUES
;
255 if (caps
->logical_min
> signed_value
|| caps
->logical_max
< signed_value
)
256 return HIDP_STATUS_VALUE_OUT_OF_RANGE
;
258 if (!caps
->physical_min
&& !caps
->physical_max
) *value
= signed_value
;
259 else *value
= caps
->physical_min
+ MulDiv( signed_value
- caps
->logical_min
, caps
->physical_max
- caps
->physical_min
,
260 caps
->logical_max
- caps
->logical_min
);
261 return HIDP_STATUS_NULL
;
264 NTSTATUS WINAPI
HidP_GetScaledUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
265 USAGE usage
, LONG
*value
, PHIDP_PREPARSED_DATA preparsed_data
,
266 char *report_buf
, ULONG report_len
)
268 struct usage_value_params params
= {.value_buf
= value
, .value_len
= sizeof(*value
), .report_buf
= report_buf
};
269 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
270 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
273 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %p, preparsed_data %p, report_buf %p, report_len %u.\n",
274 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
277 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
279 filter
.report_id
= report_buf
[0];
280 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_scaled_usage_value
, ¶ms
, &count
);
283 static NTSTATUS
get_usage_value( const struct hid_value_caps
*caps
, void *user
)
285 struct usage_value_params
*params
= user
;
286 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
287 unsigned char *report_buf
;
289 if ((bit_count
+ 7) / 8 > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
290 memset( params
->value_buf
, 0, params
->value_len
);
292 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
293 copy_bits( params
->value_buf
, report_buf
, bit_count
, -caps
->start_bit
);
295 return HIDP_STATUS_NULL
;
298 NTSTATUS WINAPI
HidP_GetUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE usage
,
299 ULONG
*value
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
301 struct usage_value_params params
= {.value_buf
= value
, .value_len
= sizeof(*value
), .report_buf
= report_buf
};
302 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
303 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
306 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %p, preparsed_data %p, report_buf %p, report_len %u.\n",
307 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
309 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
311 filter
.report_id
= report_buf
[0];
312 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_value
, ¶ms
, &count
);
315 NTSTATUS WINAPI
HidP_GetUsageValueArray( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
316 USAGE usage
, char *value_buf
, USHORT value_len
,
317 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
319 struct usage_value_params params
= {.value_buf
= value_buf
, .value_len
= value_len
, .report_buf
= report_buf
};
320 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
321 struct caps_filter filter
= {.values
= TRUE
, .array
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
324 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
325 "preparsed_data %p, report_buf %p, report_len %u.\n",
326 report_type
, usage_page
, collection
, usage
, value_buf
, value_len
, preparsed_data
, report_buf
, report_len
);
328 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
330 filter
.report_id
= report_buf
[0];
331 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_value
, ¶ms
, &count
);
335 struct get_usage_params
342 static NTSTATUS
get_usage( const struct hid_value_caps
*caps
, void *user
)
344 const struct hid_value_caps
*end
= caps
;
345 ULONG index_min
, index_max
, bit
, last
;
346 struct get_usage_params
*params
= user
;
347 unsigned char *report_buf
;
350 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
352 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
354 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
355 index_min
= end
- caps
+ 1;
356 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
358 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
360 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
361 if (params
->usages
< params
->usages_end
) *params
->usages
= caps
->usage_min
+ index
- index_min
;
364 return HIDP_STATUS_SUCCESS
;
367 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; ++bit
)
369 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
370 if (params
->usages
< params
->usages_end
) *params
->usages
= caps
->usage_min
+ bit
- caps
->start_bit
;
374 return HIDP_STATUS_SUCCESS
;
377 NTSTATUS WINAPI
HidP_GetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
378 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
380 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
381 struct get_usage_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
382 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
386 TRACE( "report_type %d, collection %d, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
387 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
389 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
391 filter
.report_id
= report_buf
[0];
392 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage
, ¶ms
, &limit
);
393 *usages_len
= params
.usages
- usages
;
394 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
396 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
400 NTSTATUS WINAPI
HidP_GetValueCaps( HIDP_REPORT_TYPE report_type
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
401 PHIDP_PREPARSED_DATA preparsed_data
)
403 return HidP_GetSpecificValueCaps( report_type
, 0, 0, 0, caps
, caps_count
, preparsed_data
);
406 NTSTATUS WINAPI
HidP_InitializeReportForID( HIDP_REPORT_TYPE report_type
, UCHAR report_id
,
407 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
409 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
410 const struct hid_value_caps
*caps
, *end
;
413 TRACE( "report_type %d, report_id %x, preparsed_data %p, report_buf %p, report_len %u.\n", report_type
,
414 report_id
, preparsed_data
, report_buf
, report_len
);
416 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
418 status
= get_value_caps_range( preparsed
, report_type
, report_len
, &caps
, &end
);
419 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
421 while (caps
!= end
&& (caps
->report_id
!= report_id
|| (!caps
->usage_min
&& !caps
->usage_max
))) caps
++;
422 if (caps
== end
) return HIDP_STATUS_REPORT_DOES_NOT_EXIST
;
424 memset( report_buf
, 0, report_len
);
425 report_buf
[0] = report_id
;
426 return HIDP_STATUS_SUCCESS
;
429 static NTSTATUS
get_usage_list_length( const struct hid_value_caps
*caps
, void *data
)
431 *(ULONG
*)data
+= caps
->report_count
;
432 return HIDP_STATUS_SUCCESS
;
435 ULONG WINAPI
HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, PHIDP_PREPARSED_DATA preparsed_data
)
437 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
438 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
};
442 TRACE( "report_type %d, usage_page %x, preparsed_data %p.\n", report_type
, usage_page
, preparsed_data
);
444 enum_value_caps( preparsed
, report_type
, 0, &filter
, get_usage_list_length
, &count
, &limit
);
448 static NTSTATUS
set_scaled_usage_value( const struct hid_value_caps
*caps
, void *user
)
450 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
451 struct usage_value_params
*params
= user
;
452 unsigned char *report_buf
;
453 LONG value
, log_range
, phy_range
;
455 if (caps
->logical_min
> caps
->logical_max
) return HIDP_STATUS_BAD_LOG_PHY_VALUES
;
456 if (caps
->physical_min
> caps
->physical_max
) return HIDP_STATUS_BAD_LOG_PHY_VALUES
;
458 if ((bit_count
+ 7) / 8 > sizeof(value
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
459 if (sizeof(LONG
) > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
460 value
= *(LONG
*)params
->value_buf
;
462 if (caps
->physical_min
|| caps
->physical_max
)
464 /* testing shows that this is what the function does, including all
465 * the overflows and rounding errors... */
466 log_range
= (caps
->logical_max
- caps
->logical_min
+ 1) / 2;
467 phy_range
= (caps
->physical_max
- caps
->physical_min
+ 1) / 2;
468 value
= value
- caps
->physical_min
;
469 value
= (log_range
* value
) / phy_range
;
470 value
= caps
->logical_min
+ value
;
473 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
474 copy_bits( report_buf
, (unsigned char *)&value
, bit_count
, caps
->start_bit
);
476 return HIDP_STATUS_NULL
;
479 NTSTATUS WINAPI
HidP_SetScaledUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
480 USAGE usage
, LONG value
, PHIDP_PREPARSED_DATA preparsed_data
,
481 char *report_buf
, ULONG report_len
)
483 struct usage_value_params params
= {.value_buf
= &value
, .value_len
= sizeof(value
), .report_buf
= report_buf
};
484 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
485 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
488 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %d, preparsed_data %p, report_buf %p, report_len %u.\n",
489 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
491 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
493 filter
.report_id
= report_buf
[0];
494 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_scaled_usage_value
, ¶ms
, &count
);
497 static NTSTATUS
set_usage_value( const struct hid_value_caps
*caps
, void *user
)
499 struct usage_value_params
*params
= user
;
500 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
501 unsigned char *report_buf
;
503 if ((bit_count
+ 7) / 8 > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
505 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
506 copy_bits( report_buf
, params
->value_buf
, bit_count
, caps
->start_bit
);
508 return HIDP_STATUS_NULL
;
511 NTSTATUS WINAPI
HidP_SetUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE usage
,
512 ULONG value
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
514 struct usage_value_params params
= {.value_buf
= &value
, .value_len
= sizeof(value
), .report_buf
= report_buf
};
515 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
516 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
519 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %u, preparsed_data %p, report_buf %p, report_len %u.\n",
520 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
522 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
524 filter
.report_id
= report_buf
[0];
525 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
528 NTSTATUS WINAPI
HidP_SetUsageValueArray( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
529 USAGE usage
, char *value_buf
, USHORT value_len
,
530 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
532 struct usage_value_params params
= {.value_buf
= value_buf
, .value_len
= value_len
, .report_buf
= report_buf
};
533 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
534 struct caps_filter filter
= {.values
= TRUE
, .array
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
537 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
538 "preparsed_data %p, report_buf %p, report_len %u.\n",
539 report_type
, usage_page
, collection
, usage
, value_buf
, value_len
, preparsed_data
, report_buf
, report_len
);
541 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
543 filter
.report_id
= report_buf
[0];
544 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
547 struct set_usage_params
553 static NTSTATUS
set_usage( const struct hid_value_caps
*caps
, void *user
)
555 const struct hid_value_caps
*end
= caps
;
556 struct set_usage_params
*params
= user
;
557 ULONG index_min
, bit
, last
;
558 unsigned char *report_buf
;
560 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
562 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
564 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
565 index_min
= end
- caps
+ 1;
567 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
569 if (report_buf
[bit
/ 8]) continue;
570 report_buf
[bit
/ 8] = index_min
+ params
->usage
- caps
->usage_min
;
574 if (bit
> last
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
575 return HIDP_STATUS_NULL
;
578 bit
= caps
->start_bit
+ params
->usage
- caps
->usage_min
;
579 report_buf
[bit
/ 8] |= (1 << (bit
% 8));
580 return HIDP_STATUS_NULL
;
583 NTSTATUS WINAPI
HidP_SetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
584 ULONG
*usage_count
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
586 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
587 struct set_usage_params params
= {.report_buf
= report_buf
};
588 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
591 ULONG i
, count
= *usage_count
;
593 TRACE( "report_type %d, usage_page %x, collection %d, usages %p, usage_count %p, preparsed_data %p, "
594 "report_buf %p, report_len %u.\n",
595 report_type
, usage_page
, collection
, usages
, usage_count
, preparsed_data
, report_buf
, report_len
);
597 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
599 filter
.report_id
= report_buf
[0];
600 for (i
= 0; i
< count
; ++i
)
602 params
.usage
= filter
.usage
= usages
[i
];
603 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage
, ¶ms
, &limit
);
604 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
607 return HIDP_STATUS_SUCCESS
;
610 struct unset_usage_params
617 static NTSTATUS
unset_usage( const struct hid_value_caps
*caps
, void *user
)
619 ULONG index
, index_min
, index_max
, bit
, last
;
620 const struct hid_value_caps
*end
= caps
;
621 struct unset_usage_params
*params
= user
;
622 unsigned char *report_buf
;
624 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
626 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
628 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
629 index_min
= end
- caps
+ 1;
630 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
632 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
634 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
635 report_buf
[bit
/ 8] = 0;
636 params
->found
= TRUE
;
640 return HIDP_STATUS_NULL
;
643 bit
= caps
->start_bit
+ params
->usage
- caps
->usage_min
;
644 if (report_buf
[bit
/ 8] & (1 << (bit
% 8))) params
->found
= TRUE
;
645 report_buf
[bit
/ 8] &= ~(1 << (bit
% 8));
646 return HIDP_STATUS_NULL
;
649 NTSTATUS WINAPI
HidP_UnsetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
650 ULONG
*usage_count
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
652 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
653 struct unset_usage_params params
= {.report_buf
= report_buf
, .found
= FALSE
};
654 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
657 ULONG i
, count
= *usage_count
;
659 TRACE( "report_type %d, usage_page %x, collection %d, usages %p, usage_count %p, preparsed_data %p, "
660 "report_buf %p, report_len %u.\n",
661 report_type
, usage_page
, collection
, usages
, usage_count
, preparsed_data
, report_buf
, report_len
);
663 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
665 filter
.report_id
= report_buf
[0];
666 for (i
= 0; i
< count
; ++i
)
668 params
.usage
= filter
.usage
= usages
[i
];
669 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, unset_usage
, ¶ms
, &limit
);
670 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
673 if (!params
.found
) return HIDP_STATUS_BUTTON_NOT_PRESSED
;
674 return HIDP_STATUS_SUCCESS
;
677 NTSTATUS WINAPI
HidP_TranslateUsagesToI8042ScanCodes(USAGE
*ChangedUsageList
,
678 ULONG UsageListLength
, HIDP_KEYBOARD_DIRECTION KeyAction
,
679 HIDP_KEYBOARD_MODIFIER_STATE
*ModifierState
,
680 PHIDP_INSERT_SCANCODES InsertCodesProcedure
, VOID
*InsertCodesContext
)
682 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList
, UsageListLength
,
683 KeyAction
, ModifierState
, InsertCodesProcedure
, InsertCodesContext
);
685 return STATUS_NOT_IMPLEMENTED
;
688 static NTSTATUS
get_button_caps( const struct hid_value_caps
*caps
, void *user
)
690 HIDP_BUTTON_CAPS
**iter
= user
, *dst
= *iter
;
691 dst
->UsagePage
= caps
->usage_page
;
692 dst
->ReportID
= caps
->report_id
;
693 dst
->LinkCollection
= caps
->link_collection
;
694 dst
->LinkUsagePage
= caps
->link_usage_page
;
695 dst
->LinkUsage
= caps
->link_usage
;
696 dst
->BitField
= caps
->bit_field
;
697 dst
->IsAlias
= FALSE
;
698 dst
->IsAbsolute
= (caps
->flags
& HID_VALUE_CAPS_IS_ABSOLUTE
) ? 1 : 0;
699 dst
->IsRange
= (caps
->flags
& HID_VALUE_CAPS_IS_RANGE
) ? 1 : 0;
702 dst
->NotRange
.Usage
= caps
->usage_min
;
703 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
707 dst
->Range
.UsageMin
= caps
->usage_min
;
708 dst
->Range
.UsageMax
= caps
->usage_max
;
709 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
710 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
712 dst
->IsStringRange
= (caps
->flags
& HID_VALUE_CAPS_IS_STRING_RANGE
) ? 1 : 0;
713 if (!dst
->IsStringRange
)
714 dst
->NotRange
.StringIndex
= caps
->string_min
;
717 dst
->Range
.StringMin
= caps
->string_min
;
718 dst
->Range
.StringMax
= caps
->string_max
;
720 dst
->IsDesignatorRange
= (caps
->flags
& HID_VALUE_CAPS_IS_DESIGNATOR_RANGE
) ? 1 : 0;
721 if (!dst
->IsDesignatorRange
)
722 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
725 dst
->Range
.DesignatorMin
= caps
->designator_min
;
726 dst
->Range
.DesignatorMax
= caps
->designator_max
;
729 return HIDP_STATUS_SUCCESS
;
732 NTSTATUS WINAPI
HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
733 USAGE usage
, HIDP_BUTTON_CAPS
*caps
, USHORT
*caps_count
,
734 PHIDP_PREPARSED_DATA preparsed_data
)
736 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
737 const struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
739 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
740 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
742 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_button_caps
, &caps
, caps_count
);
745 static NTSTATUS
get_value_caps( const struct hid_value_caps
*caps
, void *user
)
747 HIDP_VALUE_CAPS
**iter
= user
, *dst
= *iter
;
748 dst
->UsagePage
= caps
->usage_page
;
749 dst
->ReportID
= caps
->report_id
;
750 dst
->LinkCollection
= caps
->link_collection
;
751 dst
->LinkUsagePage
= caps
->link_usage_page
;
752 dst
->LinkUsage
= caps
->link_usage
;
753 dst
->BitField
= caps
->bit_field
;
754 dst
->IsAlias
= FALSE
;
755 dst
->IsAbsolute
= (caps
->flags
& HID_VALUE_CAPS_IS_ABSOLUTE
) ? 1 : 0;
756 dst
->HasNull
= HID_VALUE_CAPS_HAS_NULL( caps
);
757 dst
->BitSize
= caps
->bit_size
;
758 dst
->UnitsExp
= caps
->units_exp
;
759 dst
->Units
= caps
->units
;
760 dst
->LogicalMin
= caps
->logical_min
;
761 dst
->LogicalMax
= caps
->logical_max
;
762 dst
->PhysicalMin
= caps
->physical_min
;
763 dst
->PhysicalMax
= caps
->physical_max
;
764 dst
->IsRange
= (caps
->flags
& HID_VALUE_CAPS_IS_RANGE
) ? 1 : 0;
767 dst
->ReportCount
= caps
->report_count
;
768 dst
->NotRange
.Usage
= caps
->usage_min
;
769 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
773 dst
->ReportCount
= 1;
774 dst
->Range
.UsageMin
= caps
->usage_min
;
775 dst
->Range
.UsageMax
= caps
->usage_max
;
776 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
777 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
779 dst
->IsStringRange
= (caps
->flags
& HID_VALUE_CAPS_IS_STRING_RANGE
) ? 1 : 0;
780 if (!dst
->IsStringRange
)
781 dst
->NotRange
.StringIndex
= caps
->string_min
;
784 dst
->Range
.StringMin
= caps
->string_min
;
785 dst
->Range
.StringMax
= caps
->string_max
;
787 dst
->IsDesignatorRange
= (caps
->flags
& HID_VALUE_CAPS_IS_DESIGNATOR_RANGE
) ? 1 : 0;
788 if (!dst
->IsDesignatorRange
)
789 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
792 dst
->Range
.DesignatorMin
= caps
->designator_min
;
793 dst
->Range
.DesignatorMax
= caps
->designator_max
;
796 return HIDP_STATUS_SUCCESS
;
799 NTSTATUS WINAPI
HidP_GetSpecificValueCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
800 USAGE usage
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
801 PHIDP_PREPARSED_DATA preparsed_data
)
803 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
804 const struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
806 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
807 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
809 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_value_caps
, &caps
, caps_count
);
812 struct get_usage_and_page_params
814 USAGE_AND_PAGE
*usages
;
815 USAGE_AND_PAGE
*usages_end
;
819 static NTSTATUS
get_usage_and_page( const struct hid_value_caps
*caps
, void *user
)
821 struct get_usage_and_page_params
*params
= user
;
822 const struct hid_value_caps
*end
= caps
;
823 ULONG index_min
, index_max
, bit
, last
;
824 unsigned char *report_buf
;
827 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
829 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
831 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
832 index_min
= end
- caps
+ 1;
833 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
835 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
837 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
838 if (params
->usages
< params
->usages_end
)
840 params
->usages
->UsagePage
= caps
->usage_page
;
841 params
->usages
->Usage
= caps
->usage_min
+ index
- index_min
;
845 return HIDP_STATUS_SUCCESS
;
848 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
850 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
851 if (params
->usages
< params
->usages_end
)
853 params
->usages
->UsagePage
= caps
->usage_page
;
854 params
->usages
->Usage
= caps
->usage_min
+ bit
- caps
->start_bit
;
859 return HIDP_STATUS_SUCCESS
;
862 NTSTATUS WINAPI
HidP_GetUsagesEx( HIDP_REPORT_TYPE report_type
, USHORT collection
, USAGE_AND_PAGE
*usages
,
863 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
865 struct get_usage_and_page_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
866 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
867 struct caps_filter filter
= {.buttons
= TRUE
, .collection
= collection
};
871 TRACE( "report_type %d, collection %d, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
872 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
874 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
876 filter
.report_id
= report_buf
[0];
877 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_and_page
, ¶ms
, &limit
);
878 *usages_len
= params
.usages
- usages
;
879 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
881 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
885 static NTSTATUS
count_data( const struct hid_value_caps
*caps
, void *user
)
887 BOOL is_button
= caps
->flags
& HID_VALUE_CAPS_IS_BUTTON
;
888 BOOL is_range
= caps
->flags
& HID_VALUE_CAPS_IS_RANGE
;
889 if (is_range
|| is_button
) *(ULONG
*)user
+= caps
->report_count
;
890 else *(ULONG
*)user
+= 1;
891 return HIDP_STATUS_SUCCESS
;
894 ULONG WINAPI
HidP_MaxDataListLength( HIDP_REPORT_TYPE report_type
, PHIDP_PREPARSED_DATA preparsed_data
)
896 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
897 struct caps_filter filter
= {};
901 TRACE( "report_type %d, preparsed_data %p.\n", report_type
, preparsed_data
);
903 enum_value_caps( preparsed
, report_type
, 0, &filter
, count_data
, &count
, &limit
);
907 struct find_all_data_params
914 static NTSTATUS
find_all_data( const struct hid_value_caps
*caps
, void *user
)
916 struct find_all_data_params
*params
= user
;
917 HIDP_DATA
*data
= params
->data
, *data_end
= params
->data_end
;
918 ULONG index_min
, index_max
, bit
, last
, bit_count
;
919 const struct hid_value_caps
*end
= caps
;
920 unsigned char *report_buf
;
923 if (!caps
->bit_size
) return HIDP_STATUS_SUCCESS
;
925 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
927 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
929 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
930 index_min
= end
- caps
+ 1;
931 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
933 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
935 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
938 data
->DataIndex
= caps
->data_index_min
+ index
- index_min
;
944 else if (caps
->flags
& HID_VALUE_CAPS_IS_BUTTON
)
946 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
948 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
951 data
->DataIndex
= caps
->data_index_min
+ bit
- caps
->start_bit
;
957 else if (caps
->report_count
== 1)
961 data
->DataIndex
= caps
->data_index_min
;
963 bit_count
= caps
->bit_size
* caps
->report_count
;
964 if ((bit_count
+ 7) / 8 > sizeof(data
->RawValue
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
965 copy_bits( (void *)&data
->RawValue
, report_buf
, bit_count
, -caps
->start_bit
);
971 return HIDP_STATUS_SUCCESS
;
974 NTSTATUS WINAPI
HidP_GetData( HIDP_REPORT_TYPE report_type
, HIDP_DATA
*data
, ULONG
*data_len
,
975 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
977 struct find_all_data_params params
= {.data
= data
, .data_end
= data
+ *data_len
, .report_buf
= report_buf
};
978 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
979 struct caps_filter filter
= {};
983 TRACE( "report_type %d, data %p, data_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
984 report_type
, data
, data_len
, preparsed_data
, report_buf
, report_len
);
986 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
988 filter
.report_id
= report_buf
[0];
989 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, find_all_data
, ¶ms
, &limit
);
990 *data_len
= params
.data
- data
;
991 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
993 if (params
.data
> params
.data_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
994 return HIDP_STATUS_SUCCESS
;
997 NTSTATUS WINAPI
HidP_GetLinkCollectionNodes( HIDP_LINK_COLLECTION_NODE
*nodes
, ULONG
*nodes_len
, PHIDP_PREPARSED_DATA preparsed_data
)
999 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
1000 struct hid_collection_node
*collections
= HID_COLLECTION_NODES( preparsed
);
1001 ULONG i
, count
, capacity
= *nodes_len
;
1003 TRACE( "nodes %p, nodes_len %p, preparsed_data %p.\n", nodes
, nodes_len
, preparsed_data
);
1005 if (!preparsed
|| memcmp( preparsed
->magic
, "HidP KDR", 8 )) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
1007 count
= *nodes_len
= preparsed
->number_link_collection_nodes
;
1008 if (capacity
< count
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
1010 for (i
= 0; i
< count
; ++i
)
1012 nodes
[i
].LinkUsagePage
= collections
[i
].usage_page
;
1013 nodes
[i
].LinkUsage
= collections
[i
].usage
;
1014 nodes
[i
].Parent
= collections
[i
].parent
;
1015 nodes
[i
].CollectionType
= collections
[i
].collection_type
;
1016 nodes
[i
].FirstChild
= collections
[i
].first_child
;
1017 nodes
[i
].NextSibling
= collections
[i
].next_sibling
;
1018 nodes
[i
].NumberOfChildren
= collections
[i
].number_of_children
;
1019 nodes
[i
].IsAlias
= 0;
1022 return HIDP_STATUS_SUCCESS
;