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(hid
);
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 %u, collection %u, usage %u, value %p, preparsed_data %p, report_buf %p, report_len %lu.\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 %u, collection %u, usage %u, value %p, preparsed_data %p, report_buf %p, report_len %lu.\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 %u, collection %u, usage %u, value_buf %p, value_len %u, "
325 "preparsed_data %p, report_buf %p, report_len %lu.\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, usage_page %u, collection %u, usages %p, usages_len %p, preparsed_data %p, "
387 "report_buf %p, report_len %lu.\n",
388 report_type
, usage_page
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
390 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
392 filter
.report_id
= report_buf
[0];
393 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage
, ¶ms
, &limit
);
394 *usages_len
= params
.usages
- usages
;
395 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
397 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
401 NTSTATUS WINAPI
HidP_GetValueCaps( HIDP_REPORT_TYPE report_type
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
402 PHIDP_PREPARSED_DATA preparsed_data
)
404 return HidP_GetSpecificValueCaps( report_type
, 0, 0, 0, caps
, caps_count
, preparsed_data
);
407 NTSTATUS WINAPI
HidP_InitializeReportForID( HIDP_REPORT_TYPE report_type
, UCHAR report_id
,
408 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
410 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
411 const struct hid_value_caps
*caps
, *end
;
414 TRACE( "report_type %d, report_id %u, preparsed_data %p, report_buf %p, report_len %lu.\n", report_type
,
415 report_id
, preparsed_data
, report_buf
, report_len
);
417 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
419 status
= get_value_caps_range( preparsed
, report_type
, report_len
, &caps
, &end
);
420 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
422 while (caps
!= end
&& (caps
->report_id
!= report_id
|| (!caps
->usage_min
&& !caps
->usage_max
))) caps
++;
423 if (caps
== end
) return HIDP_STATUS_REPORT_DOES_NOT_EXIST
;
425 memset( report_buf
, 0, report_len
);
426 report_buf
[0] = report_id
;
427 return HIDP_STATUS_SUCCESS
;
430 static NTSTATUS
get_usage_list_length( const struct hid_value_caps
*caps
, void *data
)
432 *(ULONG
*)data
+= caps
->report_count
;
433 return HIDP_STATUS_SUCCESS
;
436 ULONG WINAPI
HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, PHIDP_PREPARSED_DATA preparsed_data
)
438 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
439 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
};
443 TRACE( "report_type %d, usage_page %u, preparsed_data %p.\n", report_type
, usage_page
, preparsed_data
);
445 enum_value_caps( preparsed
, report_type
, 0, &filter
, get_usage_list_length
, &count
, &limit
);
449 static NTSTATUS
set_scaled_usage_value( const struct hid_value_caps
*caps
, void *user
)
451 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
452 struct usage_value_params
*params
= user
;
453 unsigned char *report_buf
;
454 LONG value
, log_range
, phy_range
;
456 if (caps
->logical_min
> caps
->logical_max
) return HIDP_STATUS_BAD_LOG_PHY_VALUES
;
457 if (caps
->physical_min
> caps
->physical_max
) return HIDP_STATUS_BAD_LOG_PHY_VALUES
;
459 if ((bit_count
+ 7) / 8 > sizeof(value
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
460 if (sizeof(LONG
) > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
461 value
= *(LONG
*)params
->value_buf
;
463 if (caps
->physical_min
|| caps
->physical_max
)
465 /* testing shows that this is what the function does, including all
466 * the overflows and rounding errors... */
467 log_range
= (caps
->logical_max
- caps
->logical_min
+ 1) / 2;
468 phy_range
= (caps
->physical_max
- caps
->physical_min
+ 1) / 2;
469 value
= value
- caps
->physical_min
;
470 value
= (log_range
* value
) / phy_range
;
471 value
= caps
->logical_min
+ value
;
474 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
475 copy_bits( report_buf
, (unsigned char *)&value
, bit_count
, caps
->start_bit
);
477 return HIDP_STATUS_NULL
;
480 NTSTATUS WINAPI
HidP_SetScaledUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
481 USAGE usage
, LONG value
, PHIDP_PREPARSED_DATA preparsed_data
,
482 char *report_buf
, ULONG report_len
)
484 struct usage_value_params params
= {.value_buf
= &value
, .value_len
= sizeof(value
), .report_buf
= report_buf
};
485 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
486 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
489 TRACE( "report_type %d, usage_page %u, collection %u, usage %u, value %ld, preparsed_data %p, report_buf %p, report_len %lu.\n",
490 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
492 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
494 filter
.report_id
= report_buf
[0];
495 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_scaled_usage_value
, ¶ms
, &count
);
498 static NTSTATUS
set_usage_value( const struct hid_value_caps
*caps
, void *user
)
500 struct usage_value_params
*params
= user
;
501 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
502 unsigned char *report_buf
;
504 if ((bit_count
+ 7) / 8 > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
506 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
507 copy_bits( report_buf
, params
->value_buf
, bit_count
, caps
->start_bit
);
509 return HIDP_STATUS_NULL
;
512 NTSTATUS WINAPI
HidP_SetUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE usage
,
513 ULONG value
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
515 struct usage_value_params params
= {.value_buf
= &value
, .value_len
= sizeof(value
), .report_buf
= report_buf
};
516 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
517 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
520 TRACE( "report_type %d, usage_page %u, collection %u, usage %u, value %lu, preparsed_data %p, report_buf %p, report_len %lu.\n",
521 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
523 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
525 filter
.report_id
= report_buf
[0];
526 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
529 NTSTATUS WINAPI
HidP_SetUsageValueArray( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
530 USAGE usage
, char *value_buf
, USHORT value_len
,
531 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
533 struct usage_value_params params
= {.value_buf
= value_buf
, .value_len
= value_len
, .report_buf
= report_buf
};
534 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
535 struct caps_filter filter
= {.values
= TRUE
, .array
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
538 TRACE( "report_type %d, usage_page %u, collection %u, usage %u, value_buf %p, value_len %u, "
539 "preparsed_data %p, report_buf %p, report_len %lu.\n",
540 report_type
, usage_page
, collection
, usage
, value_buf
, value_len
, preparsed_data
, report_buf
, report_len
);
542 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
544 filter
.report_id
= report_buf
[0];
545 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
548 struct set_usage_params
554 static NTSTATUS
set_usage( const struct hid_value_caps
*caps
, void *user
)
556 const struct hid_value_caps
*end
= caps
;
557 struct set_usage_params
*params
= user
;
558 ULONG index_min
, bit
, last
;
559 unsigned char *report_buf
;
561 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
563 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
565 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
566 index_min
= end
- caps
+ 1;
568 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
570 if (report_buf
[bit
/ 8]) continue;
571 report_buf
[bit
/ 8] = index_min
+ params
->usage
- caps
->usage_min
;
575 if (bit
> last
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
576 return HIDP_STATUS_NULL
;
579 bit
= caps
->start_bit
+ params
->usage
- caps
->usage_min
;
580 report_buf
[bit
/ 8] |= (1 << (bit
% 8));
581 return HIDP_STATUS_NULL
;
584 NTSTATUS WINAPI
HidP_SetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
585 ULONG
*usage_count
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
587 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
588 struct set_usage_params params
= {.report_buf
= report_buf
};
589 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
592 ULONG i
, count
= *usage_count
;
594 TRACE( "report_type %d, usage_page %u, collection %u, usages %p, usage_count %p, preparsed_data %p, "
595 "report_buf %p, report_len %lu.\n",
596 report_type
, usage_page
, collection
, usages
, usage_count
, preparsed_data
, report_buf
, report_len
);
598 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
600 filter
.report_id
= report_buf
[0];
601 for (i
= 0; i
< count
; ++i
)
603 params
.usage
= filter
.usage
= usages
[i
];
604 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage
, ¶ms
, &limit
);
605 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
608 return HIDP_STATUS_SUCCESS
;
611 struct unset_usage_params
618 static NTSTATUS
unset_usage( const struct hid_value_caps
*caps
, void *user
)
620 ULONG index
, index_min
, index_max
, bit
, last
;
621 const struct hid_value_caps
*end
= caps
;
622 struct unset_usage_params
*params
= user
;
623 unsigned char *report_buf
;
625 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
627 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
629 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
630 index_min
= end
- caps
+ 1;
631 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
633 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
635 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
636 report_buf
[bit
/ 8] = 0;
637 params
->found
= TRUE
;
641 return HIDP_STATUS_NULL
;
644 bit
= caps
->start_bit
+ params
->usage
- caps
->usage_min
;
645 if (report_buf
[bit
/ 8] & (1 << (bit
% 8))) params
->found
= TRUE
;
646 report_buf
[bit
/ 8] &= ~(1 << (bit
% 8));
647 return HIDP_STATUS_NULL
;
650 NTSTATUS WINAPI
HidP_UnsetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
651 ULONG
*usage_count
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
653 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
654 struct unset_usage_params params
= {.report_buf
= report_buf
, .found
= FALSE
};
655 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
658 ULONG i
, count
= *usage_count
;
660 TRACE( "report_type %d, usage_page %u, collection %u, usages %p, usage_count %p, preparsed_data %p, "
661 "report_buf %p, report_len %lu.\n",
662 report_type
, usage_page
, collection
, usages
, usage_count
, preparsed_data
, report_buf
, report_len
);
664 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
666 filter
.report_id
= report_buf
[0];
667 for (i
= 0; i
< count
; ++i
)
669 params
.usage
= filter
.usage
= usages
[i
];
670 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, unset_usage
, ¶ms
, &limit
);
671 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
674 if (!params
.found
) return HIDP_STATUS_BUTTON_NOT_PRESSED
;
675 return HIDP_STATUS_SUCCESS
;
678 NTSTATUS WINAPI
HidP_TranslateUsagesToI8042ScanCodes(USAGE
*ChangedUsageList
,
679 ULONG UsageListLength
, HIDP_KEYBOARD_DIRECTION KeyAction
,
680 HIDP_KEYBOARD_MODIFIER_STATE
*ModifierState
,
681 PHIDP_INSERT_SCANCODES InsertCodesProcedure
, VOID
*InsertCodesContext
)
683 FIXME( "ChangedUsageList %p, UsageListLength %lu, KeyAction %u, ModifierState %p, InsertCodesProcedure %p, InsertCodesContext %p stub!\n",
684 ChangedUsageList
, UsageListLength
, KeyAction
, ModifierState
, InsertCodesProcedure
, InsertCodesContext
);
686 return STATUS_NOT_IMPLEMENTED
;
689 static NTSTATUS
get_button_caps( const struct hid_value_caps
*caps
, void *user
)
691 HIDP_BUTTON_CAPS
**iter
= user
, *dst
= *iter
;
692 dst
->UsagePage
= caps
->usage_page
;
693 dst
->ReportID
= caps
->report_id
;
694 dst
->LinkCollection
= caps
->link_collection
;
695 dst
->LinkUsagePage
= caps
->link_usage_page
;
696 dst
->LinkUsage
= caps
->link_usage
;
697 dst
->BitField
= caps
->bit_field
;
698 dst
->IsAlias
= FALSE
;
699 dst
->IsAbsolute
= (caps
->flags
& HID_VALUE_CAPS_IS_ABSOLUTE
) ? 1 : 0;
700 dst
->IsRange
= (caps
->flags
& HID_VALUE_CAPS_IS_RANGE
) ? 1 : 0;
703 dst
->NotRange
.Usage
= caps
->usage_min
;
704 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
708 dst
->Range
.UsageMin
= caps
->usage_min
;
709 dst
->Range
.UsageMax
= caps
->usage_max
;
710 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
711 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
713 dst
->IsStringRange
= (caps
->flags
& HID_VALUE_CAPS_IS_STRING_RANGE
) ? 1 : 0;
714 if (!dst
->IsStringRange
)
715 dst
->NotRange
.StringIndex
= caps
->string_min
;
718 dst
->Range
.StringMin
= caps
->string_min
;
719 dst
->Range
.StringMax
= caps
->string_max
;
721 dst
->IsDesignatorRange
= (caps
->flags
& HID_VALUE_CAPS_IS_DESIGNATOR_RANGE
) ? 1 : 0;
722 if (!dst
->IsDesignatorRange
)
723 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
726 dst
->Range
.DesignatorMin
= caps
->designator_min
;
727 dst
->Range
.DesignatorMax
= caps
->designator_max
;
730 return HIDP_STATUS_SUCCESS
;
733 NTSTATUS WINAPI
HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
734 USAGE usage
, HIDP_BUTTON_CAPS
*caps
, USHORT
*caps_count
,
735 PHIDP_PREPARSED_DATA preparsed_data
)
737 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
738 const struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
740 TRACE( "report_type %d, usage_page %u, collection %u, usage %u, caps %p, caps_count %p, preparsed_data %p.\n",
741 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
743 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_button_caps
, &caps
, caps_count
);
746 static NTSTATUS
get_value_caps( const struct hid_value_caps
*caps
, void *user
)
748 HIDP_VALUE_CAPS
**iter
= user
, *dst
= *iter
;
749 dst
->UsagePage
= caps
->usage_page
;
750 dst
->ReportID
= caps
->report_id
;
751 dst
->LinkCollection
= caps
->link_collection
;
752 dst
->LinkUsagePage
= caps
->link_usage_page
;
753 dst
->LinkUsage
= caps
->link_usage
;
754 dst
->BitField
= caps
->bit_field
;
755 dst
->IsAlias
= FALSE
;
756 dst
->IsAbsolute
= (caps
->flags
& HID_VALUE_CAPS_IS_ABSOLUTE
) ? 1 : 0;
757 dst
->HasNull
= HID_VALUE_CAPS_HAS_NULL( caps
);
758 dst
->BitSize
= caps
->bit_size
;
759 dst
->UnitsExp
= caps
->units_exp
;
760 dst
->Units
= caps
->units
;
761 dst
->LogicalMin
= caps
->logical_min
;
762 dst
->LogicalMax
= caps
->logical_max
;
763 dst
->PhysicalMin
= caps
->physical_min
;
764 dst
->PhysicalMax
= caps
->physical_max
;
765 dst
->IsRange
= (caps
->flags
& HID_VALUE_CAPS_IS_RANGE
) ? 1 : 0;
768 dst
->ReportCount
= caps
->report_count
;
769 dst
->NotRange
.Usage
= caps
->usage_min
;
770 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
774 dst
->ReportCount
= 1;
775 dst
->Range
.UsageMin
= caps
->usage_min
;
776 dst
->Range
.UsageMax
= caps
->usage_max
;
777 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
778 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
780 dst
->IsStringRange
= (caps
->flags
& HID_VALUE_CAPS_IS_STRING_RANGE
) ? 1 : 0;
781 if (!dst
->IsStringRange
)
782 dst
->NotRange
.StringIndex
= caps
->string_min
;
785 dst
->Range
.StringMin
= caps
->string_min
;
786 dst
->Range
.StringMax
= caps
->string_max
;
788 dst
->IsDesignatorRange
= (caps
->flags
& HID_VALUE_CAPS_IS_DESIGNATOR_RANGE
) ? 1 : 0;
789 if (!dst
->IsDesignatorRange
)
790 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
793 dst
->Range
.DesignatorMin
= caps
->designator_min
;
794 dst
->Range
.DesignatorMax
= caps
->designator_max
;
797 return HIDP_STATUS_SUCCESS
;
800 NTSTATUS WINAPI
HidP_GetSpecificValueCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
801 USAGE usage
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
802 PHIDP_PREPARSED_DATA preparsed_data
)
804 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
805 const struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
807 TRACE( "report_type %d, usage_page %u, collection %u, usage %u, caps %p, caps_count %p, preparsed_data %p.\n",
808 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
810 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_value_caps
, &caps
, caps_count
);
813 struct get_usage_and_page_params
815 USAGE_AND_PAGE
*usages
;
816 USAGE_AND_PAGE
*usages_end
;
820 static NTSTATUS
get_usage_and_page( const struct hid_value_caps
*caps
, void *user
)
822 struct get_usage_and_page_params
*params
= user
;
823 const struct hid_value_caps
*end
= caps
;
824 ULONG index_min
, index_max
, bit
, last
;
825 unsigned char *report_buf
;
828 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
830 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
832 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
833 index_min
= end
- caps
+ 1;
834 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
836 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
838 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
839 if (params
->usages
< params
->usages_end
)
841 params
->usages
->UsagePage
= caps
->usage_page
;
842 params
->usages
->Usage
= caps
->usage_min
+ index
- index_min
;
846 return HIDP_STATUS_SUCCESS
;
849 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
851 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
852 if (params
->usages
< params
->usages_end
)
854 params
->usages
->UsagePage
= caps
->usage_page
;
855 params
->usages
->Usage
= caps
->usage_min
+ bit
- caps
->start_bit
;
860 return HIDP_STATUS_SUCCESS
;
863 NTSTATUS WINAPI
HidP_GetUsagesEx( HIDP_REPORT_TYPE report_type
, USHORT collection
, USAGE_AND_PAGE
*usages
,
864 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
866 struct get_usage_and_page_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
867 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
868 struct caps_filter filter
= {.buttons
= TRUE
, .collection
= collection
};
872 TRACE( "report_type %d, collection %u, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %lu.\n",
873 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
875 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
877 filter
.report_id
= report_buf
[0];
878 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_and_page
, ¶ms
, &limit
);
879 *usages_len
= params
.usages
- usages
;
880 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
882 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
886 static NTSTATUS
count_data( const struct hid_value_caps
*caps
, void *user
)
888 BOOL is_button
= caps
->flags
& HID_VALUE_CAPS_IS_BUTTON
;
889 BOOL is_range
= caps
->flags
& HID_VALUE_CAPS_IS_RANGE
;
890 if (is_range
|| is_button
) *(ULONG
*)user
+= caps
->report_count
;
891 else *(ULONG
*)user
+= 1;
892 return HIDP_STATUS_SUCCESS
;
895 ULONG WINAPI
HidP_MaxDataListLength( HIDP_REPORT_TYPE report_type
, PHIDP_PREPARSED_DATA preparsed_data
)
897 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
898 struct caps_filter filter
= {};
902 TRACE( "report_type %d, preparsed_data %p.\n", report_type
, preparsed_data
);
904 enum_value_caps( preparsed
, report_type
, 0, &filter
, count_data
, &count
, &limit
);
908 struct find_all_data_params
915 static NTSTATUS
find_all_data( const struct hid_value_caps
*caps
, void *user
)
917 struct find_all_data_params
*params
= user
;
918 HIDP_DATA
*data
= params
->data
, *data_end
= params
->data_end
;
919 ULONG index_min
, index_max
, bit
, last
, bit_count
;
920 const struct hid_value_caps
*end
= caps
;
921 unsigned char *report_buf
;
924 if (!caps
->bit_size
) return HIDP_STATUS_SUCCESS
;
926 report_buf
= (unsigned char *)params
->report_buf
+ caps
->start_byte
;
928 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
930 while (end
->flags
& HID_VALUE_CAPS_ARRAY_HAS_MORE
) end
++;
931 index_min
= end
- caps
+ 1;
932 index_max
= index_min
+ caps
->usage_max
- caps
->usage_min
;
934 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
936 if (!(index
= report_buf
[bit
/ 8]) || index
< index_min
|| index
> index_max
) continue;
939 data
->DataIndex
= caps
->data_index_min
+ index
- index_min
;
945 else if (caps
->flags
& HID_VALUE_CAPS_IS_BUTTON
)
947 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
949 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
952 data
->DataIndex
= caps
->data_index_min
+ bit
- caps
->start_bit
;
958 else if (caps
->report_count
== 1)
962 data
->DataIndex
= caps
->data_index_min
;
964 bit_count
= caps
->bit_size
* caps
->report_count
;
965 if ((bit_count
+ 7) / 8 > sizeof(data
->RawValue
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
966 copy_bits( (void *)&data
->RawValue
, report_buf
, bit_count
, -caps
->start_bit
);
972 return HIDP_STATUS_SUCCESS
;
975 NTSTATUS WINAPI
HidP_GetData( HIDP_REPORT_TYPE report_type
, HIDP_DATA
*data
, ULONG
*data_len
,
976 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
978 struct find_all_data_params params
= {.data
= data
, .data_end
= data
+ *data_len
, .report_buf
= report_buf
};
979 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
980 struct caps_filter filter
= {};
984 TRACE( "report_type %d, data %p, data_len %p, preparsed_data %p, report_buf %p, report_len %lu.\n",
985 report_type
, data
, data_len
, preparsed_data
, report_buf
, report_len
);
987 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
989 filter
.report_id
= report_buf
[0];
990 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, find_all_data
, ¶ms
, &limit
);
991 *data_len
= params
.data
- data
;
992 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
994 if (params
.data
> params
.data_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
995 return HIDP_STATUS_SUCCESS
;
998 NTSTATUS WINAPI
HidP_GetLinkCollectionNodes( HIDP_LINK_COLLECTION_NODE
*nodes
, ULONG
*nodes_len
, PHIDP_PREPARSED_DATA preparsed_data
)
1000 struct hid_preparsed_data
*preparsed
= (struct hid_preparsed_data
*)preparsed_data
;
1001 struct hid_collection_node
*collections
= HID_COLLECTION_NODES( preparsed
);
1002 ULONG i
, count
, capacity
= *nodes_len
;
1004 TRACE( "nodes %p, nodes_len %p, preparsed_data %p.\n", nodes
, nodes_len
, preparsed_data
);
1006 if (!preparsed
|| memcmp( preparsed
->magic
, "HidP KDR", 8 )) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
1008 count
= *nodes_len
= preparsed
->number_link_collection_nodes
;
1009 if (capacity
< count
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
1011 for (i
= 0; i
< count
; ++i
)
1013 nodes
[i
].LinkUsagePage
= collections
[i
].usage_page
;
1014 nodes
[i
].LinkUsage
= collections
[i
].usage
;
1015 nodes
[i
].Parent
= collections
[i
].parent
;
1016 nodes
[i
].CollectionType
= collections
[i
].collection_type
;
1017 nodes
[i
].FirstChild
= collections
[i
].first_child
;
1018 nodes
[i
].NextSibling
= collections
[i
].next_sibling
;
1019 nodes
[i
].NumberOfChildren
= collections
[i
].number_of_children
;
1020 nodes
[i
].IsAlias
= 0;
1023 return HIDP_STATUS_SUCCESS
;