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
->new_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
;
290 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; ++bit
)
292 if (!(params
->report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
293 if (params
->usages
< params
->usages_end
) *params
->usages
= caps
->usage_min
+ bit
- caps
->start_bit
;
297 return HIDP_STATUS_SUCCESS
;
300 NTSTATUS WINAPI
HidP_GetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
301 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
303 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
304 struct get_usage_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
305 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
309 TRACE( "report_type %d, collection %d, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
310 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
312 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
314 filter
.report_id
= report_buf
[0];
315 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage
, ¶ms
, &limit
);
316 *usages_len
= params
.usages
- usages
;
317 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
319 if (*usages_len
== 0) return HIDP_STATUS_USAGE_NOT_FOUND
;
320 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
324 NTSTATUS WINAPI
HidP_GetValueCaps( HIDP_REPORT_TYPE report_type
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
325 PHIDP_PREPARSED_DATA preparsed_data
)
327 return HidP_GetSpecificValueCaps( report_type
, 0, 0, 0, caps
, caps_count
, preparsed_data
);
330 NTSTATUS WINAPI
HidP_InitializeReportForID( HIDP_REPORT_TYPE report_type
, UCHAR report_id
,
331 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
333 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
334 const struct hid_value_caps
*caps
, *end
;
337 TRACE( "report_type %d, report_id %x, preparsed_data %p, report_buf %p, report_len %u.\n", report_type
,
338 report_id
, preparsed_data
, report_buf
, report_len
);
340 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
342 status
= get_value_caps_range( preparsed
, report_type
, report_len
, &caps
, &end
);
343 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
345 while (caps
!= end
&& (caps
->report_id
!= report_id
|| (!caps
->usage_min
&& !caps
->usage_max
))) caps
++;
346 if (caps
== end
) return HIDP_STATUS_REPORT_DOES_NOT_EXIST
;
348 memset( report_buf
, 0, report_len
);
349 report_buf
[0] = report_id
;
350 return HIDP_STATUS_SUCCESS
;
353 static NTSTATUS
get_usage_list_length( const struct hid_value_caps
*caps
, void *data
)
355 *(ULONG
*)data
+= caps
->report_count
;
356 return HIDP_STATUS_SUCCESS
;
359 ULONG WINAPI
HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, PHIDP_PREPARSED_DATA preparsed_data
)
361 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
362 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
};
366 TRACE( "report_type %d, usage_page %x, preparsed_data %p.\n", report_type
, usage_page
, preparsed_data
);
368 enum_value_caps( preparsed
, report_type
, 0, &filter
, get_usage_list_length
, &count
, &limit
);
372 static NTSTATUS
set_usage_value( const struct hid_value_caps
*caps
, void *user
)
374 struct usage_value_params
*params
= user
;
375 ULONG bit_count
= caps
->bit_size
* caps
->report_count
;
376 if ((bit_count
+ 7) / 8 > params
->value_len
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
377 copy_bits( params
->report_buf
, params
->value_buf
, bit_count
, caps
->start_bit
);
378 return HIDP_STATUS_NULL
;
381 NTSTATUS WINAPI
HidP_SetUsageValue( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE usage
,
382 ULONG value
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
384 struct usage_value_params params
= {.value_buf
= &value
, .value_len
= sizeof(value
), .report_buf
= report_buf
};
385 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
386 struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
389 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %u, preparsed_data %p, report_buf %p, report_len %u.\n",
390 report_type
, usage_page
, collection
, usage
, value
, preparsed_data
, report_buf
, report_len
);
392 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
394 filter
.report_id
= report_buf
[0];
395 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
398 NTSTATUS WINAPI
HidP_SetUsageValueArray( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
399 USAGE usage
, char *value_buf
, USHORT value_len
,
400 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
402 struct usage_value_params params
= {.value_buf
= value_buf
, .value_len
= value_len
, .report_buf
= report_buf
};
403 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
404 struct caps_filter filter
= {.values
= TRUE
, .array
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
407 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
408 "preparsed_data %p, report_buf %p, report_len %u.\n",
409 report_type
, usage_page
, collection
, usage
, value_buf
, value_len
, preparsed_data
, report_buf
, report_len
);
411 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
413 filter
.report_id
= report_buf
[0];
414 return enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage_value
, ¶ms
, &count
);
417 struct set_usage_params
423 static NTSTATUS
set_usage( const struct hid_value_caps
*caps
, void *user
)
425 struct set_usage_params
*params
= user
;
426 ULONG bit
= caps
->start_bit
+ params
->usage
- caps
->usage_min
;
427 params
->report_buf
[bit
/ 8] |= (1 << (bit
% 8));
428 return HIDP_STATUS_NULL
;
431 NTSTATUS WINAPI
HidP_SetUsages( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
, USAGE
*usages
,
432 ULONG
*usage_count
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
434 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
435 struct set_usage_params params
= {.report_buf
= report_buf
};
436 struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
};
439 ULONG i
, count
= *usage_count
;
441 TRACE( "report_type %d, usage_page %x, collection %d, usages %p, usage_count %p, preparsed_data %p, "
442 "report_buf %p, report_len %u.\n",
443 report_type
, usage_page
, collection
, usages
, usage_count
, preparsed_data
, report_buf
, report_len
);
445 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
447 filter
.report_id
= report_buf
[0];
448 for (i
= 0; i
< count
; ++i
)
450 params
.usage
= filter
.usage
= usages
[i
];
451 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, set_usage
, ¶ms
, &limit
);
452 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
455 return HIDP_STATUS_SUCCESS
;
459 NTSTATUS WINAPI
HidP_TranslateUsagesToI8042ScanCodes(USAGE
*ChangedUsageList
,
460 ULONG UsageListLength
, HIDP_KEYBOARD_DIRECTION KeyAction
,
461 HIDP_KEYBOARD_MODIFIER_STATE
*ModifierState
,
462 PHIDP_INSERT_SCANCODES InsertCodesProcedure
, VOID
*InsertCodesContext
)
464 FIXME("stub: %p, %i, %i, %p, %p, %p\n", ChangedUsageList
, UsageListLength
,
465 KeyAction
, ModifierState
, InsertCodesProcedure
, InsertCodesContext
);
467 return STATUS_NOT_IMPLEMENTED
;
470 static NTSTATUS
get_button_caps( const struct hid_value_caps
*caps
, void *user
)
472 HIDP_BUTTON_CAPS
**iter
= user
, *dst
= *iter
;
473 dst
->UsagePage
= caps
->usage_page
;
474 dst
->ReportID
= caps
->report_id
;
475 dst
->LinkCollection
= caps
->link_collection
;
476 dst
->LinkUsagePage
= caps
->link_usage_page
;
477 dst
->LinkUsage
= caps
->link_usage
;
478 dst
->BitField
= caps
->bit_field
;
479 dst
->IsAlias
= FALSE
;
480 dst
->IsAbsolute
= HID_VALUE_CAPS_IS_ABSOLUTE( caps
);
481 if (!(dst
->IsRange
= caps
->is_range
))
483 dst
->NotRange
.Usage
= caps
->usage_min
;
484 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
488 dst
->Range
.UsageMin
= caps
->usage_min
;
489 dst
->Range
.UsageMax
= caps
->usage_max
;
490 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
491 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
493 if (!(dst
->IsStringRange
= caps
->is_string_range
))
494 dst
->NotRange
.StringIndex
= caps
->string_min
;
497 dst
->Range
.StringMin
= caps
->string_min
;
498 dst
->Range
.StringMax
= caps
->string_max
;
500 if ((dst
->IsDesignatorRange
= caps
->is_designator_range
))
501 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
504 dst
->Range
.DesignatorMin
= caps
->designator_min
;
505 dst
->Range
.DesignatorMax
= caps
->designator_max
;
508 return HIDP_STATUS_SUCCESS
;
511 NTSTATUS WINAPI
HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
512 USAGE usage
, HIDP_BUTTON_CAPS
*caps
, USHORT
*caps_count
,
513 PHIDP_PREPARSED_DATA preparsed_data
)
515 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
516 const struct caps_filter filter
= {.buttons
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
518 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
519 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
521 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_button_caps
, &caps
, caps_count
);
524 static NTSTATUS
get_value_caps( const struct hid_value_caps
*caps
, void *user
)
526 HIDP_VALUE_CAPS
**iter
= user
, *dst
= *iter
;
527 dst
->UsagePage
= caps
->usage_page
;
528 dst
->ReportID
= caps
->report_id
;
529 dst
->LinkCollection
= caps
->link_collection
;
530 dst
->LinkUsagePage
= caps
->link_usage_page
;
531 dst
->LinkUsage
= caps
->link_usage
;
532 dst
->BitField
= caps
->bit_field
;
533 dst
->IsAlias
= FALSE
;
534 dst
->IsAbsolute
= HID_VALUE_CAPS_IS_ABSOLUTE( caps
);
535 dst
->HasNull
= HID_VALUE_CAPS_HAS_NULL( caps
);
536 dst
->BitSize
= caps
->bit_size
;
537 dst
->ReportCount
= caps
->is_range
? 1 : caps
->report_count
;
538 dst
->UnitsExp
= caps
->units_exp
;
539 dst
->Units
= caps
->units
;
540 dst
->LogicalMin
= caps
->logical_min
;
541 dst
->LogicalMax
= caps
->logical_max
;
542 dst
->PhysicalMin
= caps
->physical_min
;
543 dst
->PhysicalMax
= caps
->physical_max
;
544 if (!(dst
->IsRange
= caps
->is_range
))
546 dst
->NotRange
.Usage
= caps
->usage_min
;
547 dst
->NotRange
.DataIndex
= caps
->data_index_min
;
551 dst
->Range
.UsageMin
= caps
->usage_min
;
552 dst
->Range
.UsageMax
= caps
->usage_max
;
553 dst
->Range
.DataIndexMin
= caps
->data_index_min
;
554 dst
->Range
.DataIndexMax
= caps
->data_index_max
;
556 if (!(dst
->IsStringRange
= caps
->is_string_range
))
557 dst
->NotRange
.StringIndex
= caps
->string_min
;
560 dst
->Range
.StringMin
= caps
->string_min
;
561 dst
->Range
.StringMax
= caps
->string_max
;
563 if ((dst
->IsDesignatorRange
= caps
->is_designator_range
))
564 dst
->NotRange
.DesignatorIndex
= caps
->designator_min
;
567 dst
->Range
.DesignatorMin
= caps
->designator_min
;
568 dst
->Range
.DesignatorMax
= caps
->designator_max
;
571 return HIDP_STATUS_SUCCESS
;
574 NTSTATUS WINAPI
HidP_GetSpecificValueCaps( HIDP_REPORT_TYPE report_type
, USAGE usage_page
, USHORT collection
,
575 USAGE usage
, HIDP_VALUE_CAPS
*caps
, USHORT
*caps_count
,
576 PHIDP_PREPARSED_DATA preparsed_data
)
578 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
579 const struct caps_filter filter
= {.values
= TRUE
, .usage_page
= usage_page
, .collection
= collection
, .usage
= usage
};
581 TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n",
582 report_type
, usage_page
, collection
, usage
, caps
, caps_count
, preparsed_data
);
584 return enum_value_caps( preparsed
, report_type
, 0, &filter
, get_value_caps
, &caps
, caps_count
);
587 struct get_usage_and_page_params
589 USAGE_AND_PAGE
*usages
;
590 USAGE_AND_PAGE
*usages_end
;
594 static NTSTATUS
get_usage_and_page( const struct hid_value_caps
*caps
, void *user
)
596 struct get_usage_and_page_params
*params
= user
;
599 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
601 if (!(params
->report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
602 if (params
->usages
< params
->usages_end
)
604 params
->usages
->UsagePage
= caps
->usage_page
;
605 params
->usages
->Usage
= caps
->usage_min
+ bit
- caps
->start_bit
;
610 return HIDP_STATUS_SUCCESS
;
613 NTSTATUS WINAPI
HidP_GetUsagesEx( HIDP_REPORT_TYPE report_type
, USHORT collection
, USAGE_AND_PAGE
*usages
,
614 ULONG
*usages_len
, PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
616 struct get_usage_and_page_params params
= {.usages
= usages
, .usages_end
= usages
+ *usages_len
, .report_buf
= report_buf
};
617 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
618 struct caps_filter filter
= {.buttons
= TRUE
, .collection
= collection
};
622 TRACE( "report_type %d, collection %d, usages %p, usages_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
623 report_type
, collection
, usages
, usages_len
, preparsed_data
, report_buf
, report_len
);
625 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
627 filter
.report_id
= report_buf
[0];
628 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, get_usage_and_page
, ¶ms
, &limit
);
629 *usages_len
= params
.usages
- usages
;
630 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
632 if (*usages_len
== 0) return HIDP_STATUS_USAGE_NOT_FOUND
;
633 if (params
.usages
> params
.usages_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
637 static NTSTATUS
count_data( const struct hid_value_caps
*caps
, void *user
)
639 if (caps
->is_range
|| HID_VALUE_CAPS_IS_BUTTON( caps
)) *(ULONG
*)user
+= caps
->report_count
;
640 else *(ULONG
*)user
+= 1;
641 return HIDP_STATUS_SUCCESS
;
644 ULONG WINAPI
HidP_MaxDataListLength( HIDP_REPORT_TYPE report_type
, PHIDP_PREPARSED_DATA preparsed_data
)
646 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
647 struct caps_filter filter
= {};
651 TRACE( "report_type %d, preparsed_data %p.\n", report_type
, preparsed_data
);
653 enum_value_caps( preparsed
, report_type
, 0, &filter
, count_data
, &count
, &limit
);
657 struct find_all_data_params
664 static NTSTATUS
find_all_data( const struct hid_value_caps
*caps
, void *user
)
666 struct find_all_data_params
*params
= user
;
667 HIDP_DATA
*data
= params
->data
, *data_end
= params
->data_end
;
668 ULONG bit
, last
, bit_count
= caps
->bit_size
* caps
->report_count
;
669 char *report_buf
= params
->report_buf
;
671 if (!caps
->bit_size
) return HIDP_STATUS_SUCCESS
;
672 if (caps
->bit_size
== 1)
674 for (bit
= caps
->start_bit
, last
= bit
+ caps
->usage_max
- caps
->usage_min
; bit
<= last
; bit
++)
676 if (!(report_buf
[bit
/ 8] & (1 << (bit
% 8)))) continue;
679 data
->DataIndex
= caps
->data_index_min
+ bit
- caps
->start_bit
;
685 else if (caps
->report_count
== 1)
689 data
->DataIndex
= caps
->data_index_min
;
691 if ((bit_count
+ 7) / 8 > sizeof(data
->RawValue
)) return HIDP_STATUS_BUFFER_TOO_SMALL
;
692 copy_bits( (void *)&data
->RawValue
, (void *)report_buf
, bit_count
, -caps
->start_bit
);
698 return HIDP_STATUS_SUCCESS
;
701 NTSTATUS WINAPI
HidP_GetData( HIDP_REPORT_TYPE report_type
, HIDP_DATA
*data
, ULONG
*data_len
,
702 PHIDP_PREPARSED_DATA preparsed_data
, char *report_buf
, ULONG report_len
)
704 struct find_all_data_params params
= {.data
= data
, .data_end
= data
+ *data_len
, .report_buf
= report_buf
};
705 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
706 struct caps_filter filter
= {};
710 TRACE( "report_type %d, data %p, data_len %p, preparsed_data %p, report_buf %p, report_len %u.\n",
711 report_type
, data
, data_len
, preparsed_data
, report_buf
, report_len
);
713 if (!report_len
) return HIDP_STATUS_INVALID_REPORT_LENGTH
;
715 filter
.report_id
= report_buf
[0];
716 status
= enum_value_caps( preparsed
, report_type
, report_len
, &filter
, find_all_data
, ¶ms
, &limit
);
717 *data_len
= params
.data
- data
;
718 if (status
!= HIDP_STATUS_SUCCESS
) return status
;
720 if (params
.data
> params
.data_end
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
721 return HIDP_STATUS_SUCCESS
;
724 NTSTATUS WINAPI
HidP_GetLinkCollectionNodes( HIDP_LINK_COLLECTION_NODE
*nodes
, ULONG
*nodes_len
, PHIDP_PREPARSED_DATA preparsed_data
)
726 WINE_HIDP_PREPARSED_DATA
*preparsed
= (WINE_HIDP_PREPARSED_DATA
*)preparsed_data
;
727 struct hid_value_caps
*caps
= HID_COLLECTION_VALUE_CAPS( preparsed
);
728 ULONG i
, count
, capacity
= *nodes_len
;
730 TRACE( "nodes %p, nodes_len %p, preparsed_data %p.\n", nodes
, nodes_len
, preparsed_data
);
732 if (preparsed
->magic
!= HID_MAGIC
) return HIDP_STATUS_INVALID_PREPARSED_DATA
;
734 count
= *nodes_len
= preparsed
->caps
.NumberLinkCollectionNodes
;
735 if (capacity
< count
) return HIDP_STATUS_BUFFER_TOO_SMALL
;
737 for (i
= 0; i
< count
; ++i
)
739 nodes
[i
].LinkUsagePage
= caps
[i
].usage_page
;
740 nodes
[i
].LinkUsage
= caps
[i
].usage_min
;
741 nodes
[i
].Parent
= caps
[i
].link_collection
;
742 nodes
[i
].CollectionType
= caps
[i
].bit_field
;
743 nodes
[i
].IsAlias
= 0;
744 nodes
[i
].FirstChild
= 0;
745 nodes
[i
].NextSibling
= 0;
746 nodes
[i
].NumberOfChildren
= 0;
750 nodes
[i
].NextSibling
= nodes
[nodes
[i
].Parent
].FirstChild
;
751 nodes
[nodes
[i
].Parent
].FirstChild
= i
;
752 nodes
[nodes
[i
].Parent
].NumberOfChildren
++;
756 return HIDP_STATUS_SUCCESS
;