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( WINE_HIDP_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
->magic
!= HID_MAGIC
) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
47 if (report_len
&& report_len
!= preparsed
->caps
.InputReportByteLength
)
48 return HIDP_STATUS_INVALID_REPORT_LENGTH
;
49 *caps
= HID_INPUT_VALUE_CAPS( preparsed
);
52 if (report_len
&& report_len
!= preparsed
->caps
.OutputReportByteLength
)
53 return HIDP_STATUS_INVALID_REPORT_LENGTH
;
54 *caps
= HID_OUTPUT_VALUE_CAPS( preparsed
);
57 if (report_len
&& report_len
!= preparsed
->caps
.FeatureReportByteLength
)
58 return HIDP_STATUS_INVALID_REPORT_LENGTH
;
59 *caps
= HID_FEATURE_VALUE_CAPS( preparsed
);
62 return HIDP_STATUS_INVALID_REPORT_TYPE
;
65 *caps_end
= *caps
+ preparsed
->value_caps_count
[report_type
];
66 return HIDP_STATUS_SUCCESS
;
80 static BOOL
match_value_caps( const struct hid_value_caps
*caps
, const struct caps_filter
*filter
)
82 if (!caps
->usage_min
&& !caps
->usage_max
) return FALSE
;
83 if (filter
->buttons
&& !HID_VALUE_CAPS_IS_BUTTON( caps
)) return FALSE
;
84 if (filter
->values
&& HID_VALUE_CAPS_IS_BUTTON( caps
)) return FALSE
;
85 if (filter
->usage_page
&& filter
->usage_page
!= caps
->usage_page
) return FALSE
;
86 if (filter
->collection
&& filter
->collection
!= caps
->link_collection
) return FALSE
;
87 if (!filter
->usage
) return TRUE
;
88 return caps
->usage_min
<= filter
->usage
&& caps
->usage_max
>= filter
->usage
;
91 typedef NTSTATUS (*enum_value_caps_callback
)( const struct hid_value_caps
*caps
, void *user
);
93 static NTSTATUS
enum_value_caps( WINE_HIDP_PREPARSED_DATA
*preparsed
, HIDP_REPORT_TYPE report_type
,
94 ULONG report_len
, const struct caps_filter
*filter
,
95 enum_value_caps_callback callback
, void *user
, USHORT
*count
)
97 const struct hid_value_caps
*caps
, *caps_end
;
99 BOOL incompatible
= FALSE
;
100 LONG remaining
= *count
;
102 for (status
= get_value_caps_range( preparsed
, report_type
, report_len
, &caps
, &caps_end
);
103 status
== HIDP_STATUS_SUCCESS
&& caps
!= caps_end
; caps
++)
105 if (!match_value_caps( caps
, filter
)) continue;
106 if (filter
->report_id
&& caps
->report_id
!= filter
->report_id
) incompatible
= TRUE
;
107 else if (filter
->array
&& (caps
->is_range
|| caps
->report_count
<= 1)) return HIDP_STATUS_NOT_VALUE_ARRAY
;
108 else if (remaining
-- > 0) status
= callback( caps
, user
);
111 if (status
== HIDP_STATUS_NULL
) status
= HIDP_STATUS_SUCCESS
;
112 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
115 if (*count
== 0) return incompatible
? HIDP_STATUS_INCOMPATIBLE_REPORT_ID
: HIDP_STATUS_USAGE_NOT_FOUND
;
116 if (remaining
< 0) return HIDP_STATUS_BUFFER_TOO_SMALL
;
117 return HIDP_STATUS_SUCCESS
;
120 /* copy count bits from src, starting at (-shift) bit if < 0, to dst starting at (shift) bit if > 0 */
121 static void copy_bits( unsigned char *dst
, const unsigned char *src
, int count
, int shift
)
123 unsigned char bits
, mask
;
124 size_t src_shift
= shift
< 0 ? (-shift
& 7) : 0;
125 size_t dst_shift
= shift
> 0 ? (shift
& 7) : 0;
126 if (shift
< 0) src
+= -shift
/ 8;
127 if (shift
> 0) dst
+= shift
/ 8;
129 if (src_shift
== 0 && dst_shift
== 0)
131 memcpy( dst
, src
, count
/ 8 );
139 bits
= *dst
<< (8 - dst_shift
);
144 *dst
= bits
>> (8 - dst_shift
);
145 bits
= *(unsigned short *)src
++ >> src_shift
;
146 *dst
++ |= bits
<< dst_shift
;
150 bits
>>= (8 - dst_shift
);
151 if (count
<= 8 - src_shift
) bits
|= (*src
>> src_shift
) << dst_shift
;
152 else bits
|= (*(unsigned short *)src
>> src_shift
) << dst_shift
;
154 mask
= (1 << count
) - 1;
155 *dst
= (bits
& mask
) | (*dst
& ~mask
);
158 NTSTATUS WINAPI
HidP_GetButtonCaps( HIDP_REPORT_TYPE report_type
, HIDP_BUTTON_CAPS
*caps
, USHORT
*caps_count
,
159 PHIDP_PREPARSED_DATA preparsed_data
)
161 return HidP_GetSpecificButtonCaps( report_type
, 0, 0, 0, caps
, caps_count
, preparsed_data
);
164 NTSTATUS WINAPI
HidP_GetCaps( PHIDP_PREPARSED_DATA preparsed_data
, HIDP_CAPS
*caps
)
166 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
168 TRACE( "preparsed_data %p, caps %p.\n", preparsed_data
, caps
);
170 if (preparsed
->magic
!= HID_MAGIC
) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
172 *caps
= preparsed
->caps
;
173 return HIDP_STATUS_SUCCESS
;
176 struct usage_value_params
183 static LONG
sign_extend( ULONG value
, const struct hid_value_caps
*caps
)
185 UINT sign
= 1 << (caps
->bit_size
- 1);
186 if (sign
<= 1 || caps
->logical_min
>= 0) return value
;
187 return value
- ((value
& sign
) << 1);
190 static NTSTATUS
get_scaled_usage_value( const struct hid_value_caps
*caps
, void *user
)
192 struct usage_value_params
*params
= user
;
193 ULONG unsigned_value
= 0, bit_count
= caps
->bit_size
* caps
->report_count
;
194 LONG signed_value
, *value
= params
->value_buf
;
196 if ((bit_count
+ 7) / 8 > sizeof(unsigned_value
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
197 if (sizeof(LONG
) > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
198 copy_bits( (unsigned char *)&unsigned_value
, params
->report_buf
, bit_count
, -caps
->start_bit
);
199 signed_value
= sign_extend( unsigned_value
, caps
);
201 if (caps
->logical_min
> caps
->logical_max
|| caps
->physical_min
> caps
->physical_max
)
202 return HIDP_STATUS_BAD_LOG_PHY_VALUES
;
203 if (caps
->logical_min
> signed_value
|| caps
->logical_max
< signed_value
)
204 return HIDP_STATUS_VALUE_OUT_OF_RANGE
;
206 if (!caps
->physical_min
&& !caps
->physical_max
) *value
= signed_value
;
207 else *value
= caps
->physical_min
+ MulDiv( signed_value
- caps
->logical_min
, caps
->physical_max
- caps
->physical_min
,
208 caps
->logical_max
- caps
->logical_min
);
209 return HIDP_STATUS_NULL
;
212 NTSTATUS WINAPI
HidP_GetScaledUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
213 USAGE usage
, LONG
*value
, PHIDP_PREPARSED_DATA preparsed_data
,
214 char *report_buf
, ULONG report_len
)
216 struct usage_value_params params
= {.value_buf
= value
, .value_len
= sizeof(*value
), .report_buf
= report_buf
};
217 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
218 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
221 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %p, preparsed_data %p, report_buf %p, report_len %u.\n",
222 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
225 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
227 filter
.report_id
= report_buf
[0];
228 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_scaled_usage_value
, ¶ms
, &count
);
231 static NTSTATUS
get_usage_value( const struct hid_value_caps
*caps
, void *user
)
233 struct usage_value_params
*params
= user
;
234 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
235 if ((bit_count
+ 7) / 8 > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
236 memset( params
->value_buf
, 0, params
->value_len
);
237 copy_bits( params
->value_buf
, params
->report_buf
, bit_count
, -caps
->start_bit
);
238 return HIDP_STATUS_NULL
;
241 NTSTATUS WINAPI
HidP_GetUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE usage
,
242 ULONG
*value
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
244 struct usage_value_params params
= {.value_buf
= value
, .value_len
= sizeof(*value
), .report_buf
= report_buf
};
245 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
246 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
249 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %p, preparsed_data %p, report_buf %p, report_len %u.\n",
250 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
252 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
254 filter
.report_id
= report_buf
[0];
255 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_value
, ¶ms
, &count
);
258 NTSTATUS WINAPI
HidP_GetUsageValueArray( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
259 USAGE usage
, char *value_buf
, USHORT value_len
,
260 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
262 struct usage_value_params params
= {.value_buf
= value_buf
, .value_len
= value_len
, .report_buf
= report_buf
};
263 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
264 struct caps_filter filter
= {.values
= TRUE
, .array
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
267 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
268 "preparsed_data %p, report_buf %p, report_len %u.\n",
269 report_type
, usage_page
, collection
, usage
, value_buf
, value_len
, preparsed_data
, report_buf
, report_len
);
271 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
273 filter
.report_id
= report_buf
[0];
274 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_value
, ¶ms
, &count
);
278 struct get_usage_params
285 static NTSTATUS
get_usage( const struct hid_value_caps
*caps
, void *user
)
287 struct get_usage_params
*params
= user
;
291 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
293 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
295 if (!(index
= params
->report_buf
[bit
/ 8])) continue;
296 if (params
->usages
< params
->usages_end
) *params
->usages
= caps
->usage_min
+ index
- caps
->start_index
;
299 return HIDP_STATUS_SUCCESS
;
302 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; ++bit
)
304 if (!(params
->report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
305 if (params
->usages
< params
->usages_end
) *params
->usages
= caps
->usage_min
+ bit
- caps
->start_bit
;
309 return HIDP_STATUS_SUCCESS
;
312 NTSTATUS WINAPI
HidP_GetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
313 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
315 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
316 struct get_usage_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
317 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
321 TRACE( "report_type %d, collection %d, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
322 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
324 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
326 filter
.report_id
= report_buf
[0];
327 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage
, ¶ms
, &limit
);
328 *usages_len
= params
.usages
- usages
;
329 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
331 if (*usages_len
== 0) return HIDP_STATUS_USAGE_NOT_FOUND
;
332 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
336 NTSTATUS WINAPI
HidP_GetValueCaps( HIDP_REPORT_TYPE report_type
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
337 PHIDP_PREPARSED_DATA preparsed_data
)
339 return HidP_GetSpecificValueCaps( report_type
, 0, 0, 0, caps
, caps_count
, preparsed_data
);
342 NTSTATUS WINAPI
HidP_InitializeReportForID( HIDP_REPORT_TYPE report_type
, UCHAR report_id
,
343 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
345 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
346 const struct hid_value_caps
*caps
, *end
;
349 TRACE( "report_type %d, report_id %x, preparsed_data %p, report_buf %p, report_len %u.\n", report_type
,
350 report_id
, preparsed_data
, report_buf
, report_len
);
352 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
354 status
= get_value_caps_range( preparsed
, report_type
, report_len
, &caps
, &end
);
355 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
357 while (caps
!= end
&& (caps
->report_id
!= report_id
|| (!caps
->usage_min
&& !caps
->usage_max
))) caps
++;
358 if (caps
== end
) return HIDP_STATUS_REPORT_DOES_NOT_EXIST
;
360 memset( report_buf
, 0, report_len
);
361 report_buf
[0] = report_id
;
362 return HIDP_STATUS_SUCCESS
;
365 static NTSTATUS
get_usage_list_length( const struct hid_value_caps
*caps
, void *data
)
367 *(ULONG
*)data
+= caps
->report_count
;
368 return HIDP_STATUS_SUCCESS
;
371 ULONG WINAPI
HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, PHIDP_PREPARSED_DATA preparsed_data
)
373 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
374 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
};
378 TRACE( "report_type %d, usage_page %x, preparsed_data %p.\n", report_type
, usage_page
, preparsed_data
);
380 enum_value_caps( preparsed
, report_type
, 0, &filter
, get_usage_list_length
, &count
, &limit
);
384 static NTSTATUS
set_usage_value( const struct hid_value_caps
*caps
, void *user
)
386 struct usage_value_params
*params
= user
;
387 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
388 if ((bit_count
+ 7) / 8 > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
389 copy_bits( params
->report_buf
, params
->value_buf
, bit_count
, caps
->start_bit
);
390 return HIDP_STATUS_NULL
;
393 NTSTATUS WINAPI
HidP_SetUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE usage
,
394 ULONG value
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
396 struct usage_value_params params
= {.value_buf
= &value
, .value_len
= sizeof(value
), .report_buf
= report_buf
};
397 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
398 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
401 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %u, preparsed_data %p, report_buf %p, report_len %u.\n",
402 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
404 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
406 filter
.report_id
= report_buf
[0];
407 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
410 NTSTATUS WINAPI
HidP_SetUsageValueArray( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
411 USAGE usage
, char *value_buf
, USHORT value_len
,
412 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
414 struct usage_value_params params
= {.value_buf
= value_buf
, .value_len
= value_len
, .report_buf
= report_buf
};
415 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
416 struct caps_filter filter
= {.values
= TRUE
, .array
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
419 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
420 "preparsed_data %p, report_buf %p, report_len %u.\n",
421 report_type
, usage_page
, collection
, usage
, value_buf
, value_len
, preparsed_data
, report_buf
, report_len
);
423 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
425 filter
.report_id
= report_buf
[0];
426 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
429 struct set_usage_params
435 static NTSTATUS
set_usage( const struct hid_value_caps
*caps
, void *user
)
437 struct set_usage_params
*params
= user
;
440 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
442 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
444 if (params
->report_buf
[bit
/ 8]) continue;
445 params
->report_buf
[bit
/ 8] = caps
->start_index
+ params
->usage
- caps
->usage_min
;
449 if (bit
> last
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
450 return HIDP_STATUS_NULL
;
453 bit
= caps
->start_bit
+ params
->usage
- caps
->usage_min
;
454 params
->report_buf
[bit
/ 8] |= (1 << (bit
% 8));
455 return HIDP_STATUS_NULL
;
458 NTSTATUS WINAPI
HidP_SetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
459 ULONG
*usage_count
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
461 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
462 struct set_usage_params params
= {.report_buf
= report_buf
};
463 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
466 ULONG i
, count
= *usage_count
;
468 TRACE( "report_type %d, usage_page %x, collection %d, usages %p, usage_count %p, preparsed_data %p, "
469 "report_buf %p, report_len %u.\n",
470 report_type
, usage_page
, collection
, usages
, usage_count
, preparsed_data
, report_buf
, report_len
);
472 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
474 filter
.report_id
= report_buf
[0];
475 for (i
= 0; i
< count
; ++i
)
477 params
.usage
= filter
.usage
= usages
[i
];
478 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage
, ¶ms
, &limit
);
479 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
482 return HIDP_STATUS_SUCCESS
;
486 NTSTATUS WINAPI
HidP_TranslateUsagesToI8042ScanCodes(USAGE
*ChangedUsageList
,
487 ULONG UsageListLength
, HIDP_KEYBOARD_DIRECTION KeyAction
,
488 HIDP_KEYBOARD_MODIFIER_STATE
*ModifierState
,
489 PHIDP_INSERT_SCANCODES InsertCodesProcedure
, VOID
*InsertCodesContext
)
491 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList
, UsageListLength
,
492 KeyAction
, ModifierState
, InsertCodesProcedure
, InsertCodesContext
);
494 return STATUS_NOT_IMPLEMENTED
;
497 static NTSTATUS
get_button_caps( const struct hid_value_caps
*caps
, void *user
)
499 HIDP_BUTTON_CAPS
**iter
= user
, *dst
= *iter
;
500 dst
->UsagePage
= caps
->usage_page
;
501 dst
->ReportID
= caps
->report_id
;
502 dst
->LinkCollection
= caps
->link_collection
;
503 dst
->LinkUsagePage
= caps
->link_usage_page
;
504 dst
->LinkUsage
= caps
->link_usage
;
505 dst
->BitField
= caps
->bit_field
;
506 dst
->IsAlias
= FALSE
;
507 dst
->IsAbsolute
= HID_VALUE_CAPS_IS_ABSOLUTE( caps
);
508 if (!(dst
->IsRange
= caps
->is_range
))
510 dst
->NotRange
.Usage
= caps
->usage_min
;
511 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
515 dst
->Range
.UsageMin
= caps
->usage_min
;
516 dst
->Range
.UsageMax
= caps
->usage_max
;
517 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
518 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
520 if (!(dst
->IsStringRange
= caps
->is_string_range
))
521 dst
->NotRange
.StringIndex
= caps
->string_min
;
524 dst
->Range
.StringMin
= caps
->string_min
;
525 dst
->Range
.StringMax
= caps
->string_max
;
527 if ((dst
->IsDesignatorRange
= caps
->is_designator_range
))
528 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
531 dst
->Range
.DesignatorMin
= caps
->designator_min
;
532 dst
->Range
.DesignatorMax
= caps
->designator_max
;
535 return HIDP_STATUS_SUCCESS
;
538 NTSTATUS WINAPI
HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
539 USAGE usage
, HIDP_BUTTON_CAPS
*caps
, USHORT
*caps_count
,
540 PHIDP_PREPARSED_DATA preparsed_data
)
542 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
543 const struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
545 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
546 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
548 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_button_caps
, &caps
, caps_count
);
551 static NTSTATUS
get_value_caps( const struct hid_value_caps
*caps
, void *user
)
553 HIDP_VALUE_CAPS
**iter
= user
, *dst
= *iter
;
554 dst
->UsagePage
= caps
->usage_page
;
555 dst
->ReportID
= caps
->report_id
;
556 dst
->LinkCollection
= caps
->link_collection
;
557 dst
->LinkUsagePage
= caps
->link_usage_page
;
558 dst
->LinkUsage
= caps
->link_usage
;
559 dst
->BitField
= caps
->bit_field
;
560 dst
->IsAlias
= FALSE
;
561 dst
->IsAbsolute
= HID_VALUE_CAPS_IS_ABSOLUTE( caps
);
562 dst
->HasNull
= HID_VALUE_CAPS_HAS_NULL( caps
);
563 dst
->BitSize
= caps
->bit_size
;
564 dst
->ReportCount
= caps
->is_range
? 1 : caps
->report_count
;
565 dst
->UnitsExp
= caps
->units_exp
;
566 dst
->Units
= caps
->units
;
567 dst
->LogicalMin
= caps
->logical_min
;
568 dst
->LogicalMax
= caps
->logical_max
;
569 dst
->PhysicalMin
= caps
->physical_min
;
570 dst
->PhysicalMax
= caps
->physical_max
;
571 if (!(dst
->IsRange
= caps
->is_range
))
573 dst
->NotRange
.Usage
= caps
->usage_min
;
574 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
578 dst
->Range
.UsageMin
= caps
->usage_min
;
579 dst
->Range
.UsageMax
= caps
->usage_max
;
580 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
581 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
583 if (!(dst
->IsStringRange
= caps
->is_string_range
))
584 dst
->NotRange
.StringIndex
= caps
->string_min
;
587 dst
->Range
.StringMin
= caps
->string_min
;
588 dst
->Range
.StringMax
= caps
->string_max
;
590 if ((dst
->IsDesignatorRange
= caps
->is_designator_range
))
591 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
594 dst
->Range
.DesignatorMin
= caps
->designator_min
;
595 dst
->Range
.DesignatorMax
= caps
->designator_max
;
598 return HIDP_STATUS_SUCCESS
;
601 NTSTATUS WINAPI
HidP_GetSpecificValueCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
602 USAGE usage
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
603 PHIDP_PREPARSED_DATA preparsed_data
)
605 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
606 const struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
608 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
609 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
611 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_value_caps
, &caps
, caps_count
);
614 struct get_usage_and_page_params
616 USAGE_AND_PAGE
*usages
;
617 USAGE_AND_PAGE
*usages_end
;
621 static NTSTATUS
get_usage_and_page( const struct hid_value_caps
*caps
, void *user
)
623 struct get_usage_and_page_params
*params
= user
;
627 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
629 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
631 if (!(index
= params
->report_buf
[bit
/ 8])) continue;
632 if (params
->usages
< params
->usages_end
)
634 params
->usages
->UsagePage
= caps
->usage_page
;
635 params
->usages
->Usage
= caps
->usage_min
+ index
- caps
->start_index
;
639 return HIDP_STATUS_SUCCESS
;
642 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
644 if (!(params
->report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
645 if (params
->usages
< params
->usages_end
)
647 params
->usages
->UsagePage
= caps
->usage_page
;
648 params
->usages
->Usage
= caps
->usage_min
+ bit
- caps
->start_bit
;
653 return HIDP_STATUS_SUCCESS
;
656 NTSTATUS WINAPI
HidP_GetUsagesEx( HIDP_REPORT_TYPE report_type
, USHORT collection
, USAGE_AND_PAGE
*usages
,
657 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
659 struct get_usage_and_page_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
660 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
661 struct caps_filter filter
= {.buttons
= TRUE
, .collection
= collection
};
665 TRACE( "report_type %d, collection %d, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
666 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
668 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
670 filter
.report_id
= report_buf
[0];
671 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_and_page
, ¶ms
, &limit
);
672 *usages_len
= params
.usages
- usages
;
673 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
675 if (*usages_len
== 0) return HIDP_STATUS_USAGE_NOT_FOUND
;
676 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
680 static NTSTATUS
count_data( const struct hid_value_caps
*caps
, void *user
)
682 if (caps
->is_range
|| HID_VALUE_CAPS_IS_BUTTON( caps
)) *(ULONG
*)user
+= caps
->report_count
;
683 else *(ULONG
*)user
+= 1;
684 return HIDP_STATUS_SUCCESS
;
687 ULONG WINAPI
HidP_MaxDataListLength( HIDP_REPORT_TYPE report_type
, PHIDP_PREPARSED_DATA preparsed_data
)
689 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
690 struct caps_filter filter
= {};
694 TRACE( "report_type %d, preparsed_data %p.\n", report_type
, preparsed_data
);
696 enum_value_caps( preparsed
, report_type
, 0, &filter
, count_data
, &count
, &limit
);
700 struct find_all_data_params
707 static NTSTATUS
find_all_data( const struct hid_value_caps
*caps
, void *user
)
709 struct find_all_data_params
*params
= user
;
710 HIDP_DATA
*data
= params
->data
, *data_end
= params
->data_end
;
711 ULONG bit
, last
, bit_count
= caps
->bit_size
* caps
->report_count
;
712 char *report_buf
= params
->report_buf
;
715 if (!caps
->bit_size
) return HIDP_STATUS_SUCCESS
;
717 if (HID_VALUE_CAPS_IS_ARRAY( caps
))
719 for (bit
= caps
->start_bit
, last
= bit
+ caps
->report_count
* caps
->bit_size
- 1; bit
<= last
; bit
+= 8)
721 if (!(index
= report_buf
[bit
/ 8])) continue;
724 data
->DataIndex
= caps
->data_index_min
+ index
- caps
->start_index
;
730 else if (HID_VALUE_CAPS_IS_BUTTON( caps
))
732 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
734 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
737 data
->DataIndex
= caps
->data_index_min
+ bit
- caps
->start_bit
;
743 else if (caps
->report_count
== 1)
747 data
->DataIndex
= caps
->data_index_min
;
749 if ((bit_count
+ 7) / 8 > sizeof(data
->RawValue
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
750 copy_bits( (void *)&data
->RawValue
, (void *)report_buf
, bit_count
, -caps
->start_bit
);
756 return HIDP_STATUS_SUCCESS
;
759 NTSTATUS WINAPI
HidP_GetData( HIDP_REPORT_TYPE report_type
, HIDP_DATA
*data
, ULONG
*data_len
,
760 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
762 struct find_all_data_params params
= {.data
= data
, .data_end
= data
+ *data_len
, .report_buf
= report_buf
};
763 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
764 struct caps_filter filter
= {};
768 TRACE( "report_type %d, data %p, data_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
769 report_type
, data
, data_len
, preparsed_data
, report_buf
, report_len
);
771 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
773 filter
.report_id
= report_buf
[0];
774 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, find_all_data
, ¶ms
, &limit
);
775 *data_len
= params
.data
- data
;
776 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
778 if (params
.data
> params
.data_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
779 return HIDP_STATUS_SUCCESS
;
782 NTSTATUS WINAPI
HidP_GetLinkCollectionNodes( HIDP_LINK_COLLECTION_NODE
*nodes
, ULONG
*nodes_len
, PHIDP_PREPARSED_DATA preparsed_data
)
784 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
785 struct hid_value_caps
*caps
= HID_COLLECTION_VALUE_CAPS( preparsed
);
786 ULONG i
, count
, capacity
= *nodes_len
;
788 TRACE( "nodes %p, nodes_len %p, preparsed_data %p.\n", nodes
, nodes_len
, preparsed_data
);
790 if (preparsed
->magic
!= HID_MAGIC
) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
792 count
= *nodes_len
= preparsed
->caps
.NumberLinkCollectionNodes
;
793 if (capacity
< count
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
795 for (i
= 0; i
< count
; ++i
)
797 nodes
[i
].LinkUsagePage
= caps
[i
].usage_page
;
798 nodes
[i
].LinkUsage
= caps
[i
].usage_min
;
799 nodes
[i
].Parent
= caps
[i
].link_collection
;
800 nodes
[i
].CollectionType
= caps
[i
].bit_field
;
801 nodes
[i
].IsAlias
= 0;
802 nodes
[i
].FirstChild
= 0;
803 nodes
[i
].NextSibling
= 0;
804 nodes
[i
].NumberOfChildren
= 0;
808 nodes
[i
].NextSibling
= nodes
[nodes
[i
].Parent
].FirstChild
;
809 nodes
[nodes
[i
].Parent
].FirstChild
= i
;
810 nodes
[nodes
[i
].Parent
].NumberOfChildren
++;
814 return HIDP_STATUS_SUCCESS
;