Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
b7f43c99
Commit
b7f43c99
authored
Sep 14, 2015
by
Aric Stewart
Committed by
Alexandre Julliard
Sep 15, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hidclass.sys: Add USB Descriptor parsing.
parent
69d57ee7
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1186 additions
and
0 deletions
+1186
-0
Makefile.in
dlls/hidclass.sys/Makefile.in
+1
-0
descriptor.c
dlls/hidclass.sys/descriptor.c
+1145
-0
hid.h
dlls/hidclass.sys/hid.h
+3
-0
pnp.c
dlls/hidclass.sys/pnp.c
+37
-0
No files found.
dlls/hidclass.sys/Makefile.in
View file @
b7f43c99
...
...
@@ -5,6 +5,7 @@ DELAYIMPORTS = setupapi hid
C_SRCS
=
\
buffer.c
\
descriptor.c
\
device.c
\
main.c
\
pnp.c
dlls/hidclass.sys/descriptor.c
0 → 100644
View file @
b7f43c99
/*
* HID descriptor parsing
*
* Copyright (C) 2015 Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#define NONAMELESSUNION
#include "hid.h"
#include "wine/debug.h"
#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
hid
);
#define USAGE_MAX 10
enum
{
INPUT_DATA
=
0x01
,
INPUT_ARRAY
=
0x02
,
INPUT_ABS
=
0x04
,
INPUT_WRAP
=
0x08
,
INPUT_LINEAR
=
0x10
,
INPUT_PREFSTATE
=
0x20
,
INPUT_NULL
=
0x40
,
INPUT_VOLATILE
=
0x80
,
INPUT_BITFIELD
=
0x100
};
enum
{
TAG_TYPE_MAIN
=
0x0
,
TAG_TYPE_GLOBAL
,
TAG_TYPE_LOCAL
,
TAG_TYPE_RESERVED
,
};
enum
{
TAG_MAIN_INPUT
=
0x08
,
TAG_MAIN_OUTPUT
=
0x09
,
TAG_MAIN_FEATURE
=
0x0B
,
TAG_MAIN_COLLECTION
=
0x0A
,
TAG_MAIN_END_COLLECTION
=
0x0C
};
enum
{
TAG_GLOBAL_USAGE_PAGE
=
0x0
,
TAG_GLOBAL_LOGICAL_MINIMUM
,
TAG_GLOBAL_LOGICAL_MAXIMUM
,
TAG_GLOBAL_PHYSICAL_MINIMUM
,
TAG_GLOBAL_PHYSICAL_MAXIMUM
,
TAG_GLOBAL_UNIT_EXPONENT
,
TAG_GLOBAL_UNIT
,
TAG_GLOBAL_REPORT_SIZE
,
TAG_GLOBAL_REPORT_ID
,
TAG_GLOBAL_REPORT_COUNT
,
TAG_GLOBAL_PUSH
,
TAG_GLOBAL_POP
};
enum
{
TAG_LOCAL_USAGE
=
0x0
,
TAG_LOCAL_USAGE_MINIMUM
,
TAG_LOCAL_USAGE_MAXIMUM
,
TAG_LOCAL_DESIGNATOR_INDEX
,
TAG_LOCAL_DESIGNATOR_MINIMUM
,
TAG_LOCAL_DESIGNATOR_MAXIMUM
,
TAG_LOCAL_STRING_INDEX
,
TAG_LOCAL_STRING_MINIMUM
,
TAG_LOCAL_STRING_MAXIMUM
,
TAG_LOCAL_DELIMITER
};
static
const
char
*
const
feature_string
[]
=
{
"Input"
,
"Output"
,
"Feature"
};
struct
caps
{
USAGE
UsagePage
;
LONG
LogicalMin
;
LONG
LogicalMax
;
LONG
PhysicalMin
;
LONG
PhysicalMax
;
ULONG
UnitsExp
;
ULONG
Units
;
USHORT
BitSize
;
UCHAR
ReportID
;
USHORT
ReportCount
;
BOOLEAN
IsRange
;
BOOLEAN
IsStringRange
;
BOOLEAN
IsDesignatorRange
;
unsigned
int
usage_count
;
union
{
struct
{
USAGE
UsageMin
;
USAGE
UsageMax
;
USHORT
StringMin
;
USHORT
StringMax
;
USHORT
DesignatorMin
;
USHORT
DesignatorMax
;
}
Range
;
struct
{
USAGE
Usage
[
USAGE_MAX
];
USAGE
Reserved1
;
USHORT
StringIndex
;
USHORT
Reserved2
;
USHORT
DesignatorIndex
;
USHORT
Reserved3
;
}
NotRange
;
}
DUMMYUNIONNAME
;
int
Delim
;
};
struct
feature
{
struct
list
entry
;
struct
list
col_entry
;
struct
caps
caps
;
HIDP_REPORT_TYPE
type
;
BOOLEAN
isData
;
BOOLEAN
isArray
;
BOOLEAN
IsAbsolute
;
BOOLEAN
Wrap
;
BOOLEAN
Linear
;
BOOLEAN
prefState
;
BOOLEAN
HasNull
;
BOOLEAN
Volatile
;
BOOLEAN
BitField
;
unsigned
int
index
;
struct
collection
*
collection
;
};
static
const
char
*
const
collection_string
[]
=
{
"Physical"
,
"Application"
,
"Logical"
,
"Report"
,
"Named Array"
,
"Usage Switch"
,
"Usage Modifier"
,
};
struct
collection
{
struct
list
entry
;
struct
caps
caps
;
unsigned
int
index
;
unsigned
int
type
;
struct
collection
*
parent
;
struct
list
features
;
struct
list
collections
;
};
static
const
char
*
debugstr_usages
(
struct
caps
*
caps
)
{
if
(
!
caps
->
IsRange
)
{
char
out
[
12
*
USAGE_MAX
];
unsigned
int
i
;
if
(
caps
->
usage_count
==
0
)
return
"[ none ]"
;
out
[
0
]
=
0
;
for
(
i
=
0
;
i
<
caps
->
usage_count
;
i
++
)
sprintf
(
out
+
strlen
(
out
),
"0x%x "
,
caps
->
u
.
NotRange
.
Usage
[
i
]);
return
wine_dbg_sprintf
(
"[ %s] "
,
out
);
}
else
return
wine_dbg_sprintf
(
"[0x%x - 0x%x]"
,
caps
->
u
.
Range
.
UsageMin
,
caps
->
u
.
Range
.
UsageMax
);
}
static
const
char
*
debugstr_stringindex
(
struct
caps
*
caps
)
{
if
(
!
caps
->
IsStringRange
)
return
wine_dbg_sprintf
(
"%i"
,
caps
->
u
.
NotRange
.
StringIndex
);
else
return
wine_dbg_sprintf
(
"[%i - %i]"
,
caps
->
u
.
Range
.
StringMin
,
caps
->
u
.
Range
.
StringMax
);
}
static
const
char
*
debugstr_designatorindex
(
struct
caps
*
caps
)
{
if
(
!
caps
->
IsDesignatorRange
)
return
wine_dbg_sprintf
(
"%i"
,
caps
->
u
.
NotRange
.
DesignatorIndex
);
else
return
wine_dbg_sprintf
(
"[%i - %i]"
,
caps
->
u
.
Range
.
DesignatorMin
,
caps
->
u
.
Range
.
DesignatorMax
);
}
static
void
debugstr_caps
(
const
char
*
type
,
struct
caps
*
caps
)
{
if
(
!
caps
)
return
;
TRACE
(
"(%s Caps: UsagePage 0x%x; LogicalMin %i; LogicalMax %i; PhysicalMin %i; PhysicalMax %i; UnitsExp %i; Units %i; BitSize %i; ReportID %i; ReportCount %i; Usage %s; StringIndex %s; DesignatorIndex %s; Delim %i;)
\n
"
,
type
,
caps
->
UsagePage
,
caps
->
LogicalMin
,
caps
->
LogicalMax
,
caps
->
PhysicalMin
,
caps
->
PhysicalMax
,
caps
->
UnitsExp
,
caps
->
Units
,
caps
->
BitSize
,
caps
->
ReportID
,
caps
->
ReportCount
,
debugstr_usages
(
caps
),
debugstr_stringindex
(
caps
),
debugstr_designatorindex
(
caps
),
caps
->
Delim
);
}
static
void
debug_feature
(
struct
feature
*
feature
)
{
if
(
!
feature
)
return
;
TRACE
(
"[Feature type %s [%i]; %s; %s; %s; %s; %s; %s; %s; %s; %s]
\n
"
,
feature_string
[
feature
->
type
],
feature
->
index
,
(
feature
->
isData
)
?
"Data"
:
"Const"
,
(
feature
->
isArray
)
?
"Array"
:
"Var"
,
(
feature
->
IsAbsolute
)
?
"Abs"
:
"Rel"
,
(
feature
->
Wrap
)
?
"Wrap"
:
"NoWrap"
,
(
feature
->
Linear
)
?
"Linear"
:
"NonLinear"
,
(
feature
->
prefState
)
?
"PrefStat"
:
"NoPrefState"
,
(
feature
->
HasNull
)
?
"HasNull"
:
"NoNull"
,
(
feature
->
Volatile
)
?
"Volatile"
:
"NonVolatile"
,
(
feature
->
BitField
)
?
"BitField"
:
"Buffered"
);
debugstr_caps
(
"Feature"
,
&
feature
->
caps
);
}
static
void
debug_collection
(
struct
collection
*
collection
)
{
struct
feature
*
fentry
;
struct
collection
*
centry
;
if
(
TRACE_ON
(
hid
))
{
TRACE
(
"START Collection %i <<< %s, parent: %p, %i features, %i collections
\n
"
,
collection
->
index
,
collection_string
[
collection
->
type
],
collection
->
parent
,
list_count
(
&
collection
->
features
),
list_count
(
&
collection
->
collections
));
debugstr_caps
(
"Collection"
,
&
collection
->
caps
);
LIST_FOR_EACH_ENTRY
(
fentry
,
&
collection
->
features
,
struct
feature
,
col_entry
)
debug_feature
(
fentry
);
LIST_FOR_EACH_ENTRY
(
centry
,
&
collection
->
collections
,
struct
collection
,
entry
)
debug_collection
(
centry
);
TRACE
(
">>> END Collection %i
\n
"
,
collection
->
index
);
}
}
static
void
debug_print_button_cap
(
const
CHAR
*
type
,
WINE_HID_ELEMENT
*
wine_element
)
{
if
(
!
wine_element
->
caps
.
button
.
IsRange
)
TRACE
(
"%s Button: 0x%x/0x%04x: ReportId %i, startBit %i/1
\n
"
,
type
,
wine_element
->
caps
.
button
.
UsagePage
,
wine_element
->
caps
.
button
.
u
.
NotRange
.
Usage
,
wine_element
->
caps
.
value
.
ReportID
,
wine_element
->
valueStartBit
);
else
TRACE
(
"%s Button: 0x%x/[0x%04x-0x%04x]: ReportId %i, startBit %i/%i
\n
"
,
type
,
wine_element
->
caps
.
button
.
UsagePage
,
wine_element
->
caps
.
button
.
u
.
Range
.
UsageMin
,
wine_element
->
caps
.
button
.
u
.
Range
.
UsageMax
,
wine_element
->
caps
.
value
.
ReportID
,
wine_element
->
valueStartBit
,
wine_element
->
bitCount
);
}
static
void
debug_print_value_cap
(
const
CHAR
*
type
,
WINE_HID_ELEMENT
*
wine_element
)
{
TRACE
(
"%s Value: 0x%x/0x%x: ReportId %i, IsAbsolute %i, HasNull %i, "
"Bit Size %i, ReportCount %i, UnitsExp %i, Units %i, "
"LogicalMin %i, Logical Max %i, PhysicalMin %i, "
"PhysicalMax %i -- StartBit %i/%i
\n
"
,
type
,
wine_element
->
caps
.
value
.
UsagePage
,
wine_element
->
caps
.
value
.
u
.
NotRange
.
Usage
,
wine_element
->
caps
.
value
.
ReportID
,
wine_element
->
caps
.
value
.
IsAbsolute
,
wine_element
->
caps
.
value
.
HasNull
,
wine_element
->
caps
.
value
.
BitSize
,
wine_element
->
caps
.
value
.
ReportCount
,
wine_element
->
caps
.
value
.
UnitsExp
,
wine_element
->
caps
.
value
.
Units
,
wine_element
->
caps
.
value
.
LogicalMin
,
wine_element
->
caps
.
value
.
LogicalMax
,
wine_element
->
caps
.
value
.
PhysicalMin
,
wine_element
->
caps
.
value
.
PhysicalMax
,
wine_element
->
valueStartBit
,
wine_element
->
bitCount
);
}
static
void
debug_print_element
(
const
CHAR
*
type
,
WINE_HID_ELEMENT
*
wine_element
)
{
if
(
wine_element
->
ElementType
==
ButtonElement
)
debug_print_button_cap
(
type
,
wine_element
);
else
if
(
wine_element
->
ElementType
==
ValueElement
)
debug_print_value_cap
(
type
,
wine_element
);
else
TRACE
(
"%s: UNKNOWN
\n
"
,
type
);
}
static
void
debug_print_report
(
const
char
*
type
,
WINE_HID_REPORT
*
report
)
{
unsigned
int
i
;
TRACE
(
"START Report %i <<< %s report : dwSize: %i elementCount: %i
\n
"
,
report
->
reportID
,
type
,
report
->
dwSize
,
report
->
elementCount
);
for
(
i
=
0
;
i
<
report
->
elementCount
;
i
++
)
debug_print_element
(
type
,
&
report
->
Elements
[
i
]);
TRACE
(
">>> END Report %i
\n
"
,
report
->
reportID
);
}
static
void
debug_print_preparsed
(
WINE_HIDP_PREPARSED_DATA
*
data
)
{
unsigned
int
i
;
WINE_HID_REPORT
*
r
;
if
(
TRACE_ON
(
hid
))
{
TRACE
(
"START PREPARSED Data <<< dwSize: %i Usage: %i, UsagePage: %i, InputReportByteLength: %i, tOutputReportByteLength: %i, FeatureReportByteLength: %i, NumberLinkCollectionNodes: %i, NumberInputButtonCaps: %i, NumberInputValueCaps: %i,NumberInputDataIndices: %i, NumberOutputButtonCaps: %i, NumberOutputValueCaps: %i, NumberOutputDataIndices: %i, NumberFeatureButtonCaps: %i, NumberFeatureValueCaps: %i, NumberFeatureDataIndices: %i, dwInputReportCount: %i, dwOutputReportCount: %i, dwFeatureReportCount: %i, dwOutputReportOffset: %i, dwFeatureReportOffset: %i
\n
"
,
data
->
dwSize
,
data
->
caps
.
Usage
,
data
->
caps
.
UsagePage
,
data
->
caps
.
InputReportByteLength
,
data
->
caps
.
OutputReportByteLength
,
data
->
caps
.
FeatureReportByteLength
,
data
->
caps
.
NumberLinkCollectionNodes
,
data
->
caps
.
NumberInputButtonCaps
,
data
->
caps
.
NumberInputValueCaps
,
data
->
caps
.
NumberInputDataIndices
,
data
->
caps
.
NumberOutputButtonCaps
,
data
->
caps
.
NumberOutputValueCaps
,
data
->
caps
.
NumberOutputDataIndices
,
data
->
caps
.
NumberFeatureButtonCaps
,
data
->
caps
.
NumberFeatureValueCaps
,
data
->
caps
.
NumberFeatureDataIndices
,
data
->
dwInputReportCount
,
data
->
dwOutputReportCount
,
data
->
dwFeatureReportCount
,
data
->
dwOutputReportOffset
,
data
->
dwFeatureReportOffset
);
r
=
HID_INPUT_REPORTS
(
data
);
for
(
i
=
0
;
i
<
data
->
dwInputReportCount
;
i
++
)
{
debug_print_report
(
"INPUT"
,
r
);
r
=
HID_NEXT_REPORT
(
data
,
r
);
}
r
=
HID_OUTPUT_REPORTS
(
data
);
for
(
i
=
0
;
i
<
data
->
dwOutputReportCount
;
i
++
)
{
debug_print_report
(
"OUTPUT"
,
r
);
r
=
HID_NEXT_REPORT
(
data
,
r
);
}
r
=
HID_FEATURE_REPORTS
(
data
);
for
(
i
=
0
;
i
<
data
->
dwFeatureReportCount
;
i
++
)
{
debug_print_report
(
"FEATURE"
,
r
);
r
=
HID_NEXT_REPORT
(
data
,
r
);
}
TRACE
(
">>> END Preparsed Data
\n
"
);
}
}
static
int
getValue
(
int
bsize
,
int
source
)
{
int
mask
=
0xff
;
int
negative
=
0x80
;
int
outofrange
=
0x100
;
int
value
;
unsigned
int
i
;
if
(
bsize
==
4
)
return
source
;
for
(
i
=
1
;
i
<
bsize
;
i
++
)
{
mask
=
(
mask
<<
8
)
+
0xff
;
negative
=
(
negative
<<
8
);
outofrange
=
(
outofrange
<<
8
);
}
value
=
(
source
&
mask
);
if
(
value
&
negative
)
value
=
-
1
*
(
outofrange
-
value
);
return
value
;
}
void
parse_io_feature
(
unsigned
int
bSize
,
int
itemVal
,
int
bTag
,
unsigned
int
*
feature_index
,
struct
feature
*
feature
)
{
if
(
bSize
<=
0
)
{
return
;
}
else
{
if
((
itemVal
&
INPUT_DATA
)
==
0
)
feature
->
isData
=
TRUE
;
else
feature
->
isData
=
FALSE
;
/* Const */
if
((
itemVal
&
INPUT_ARRAY
)
==
0
)
feature
->
isArray
=
TRUE
;
else
feature
->
isArray
=
TRUE
;
/* Var */
if
((
itemVal
&
INPUT_ABS
)
==
0
)
feature
->
IsAbsolute
=
TRUE
;
else
feature
->
IsAbsolute
=
FALSE
;
/* Rel */
if
((
itemVal
&
INPUT_WRAP
)
==
0
)
feature
->
Wrap
=
FALSE
;
else
feature
->
Wrap
=
TRUE
;
if
((
itemVal
&
INPUT_LINEAR
)
==
0
)
feature
->
Linear
=
TRUE
;
else
feature
->
Linear
=
FALSE
;
if
((
itemVal
&
INPUT_PREFSTATE
)
==
0
)
feature
->
prefState
=
TRUE
;
else
feature
->
prefState
=
FALSE
;
if
((
itemVal
&
INPUT_NULL
)
==
0
)
feature
->
HasNull
=
FALSE
;
else
feature
->
HasNull
=
TRUE
;
if
(
bTag
!=
TAG_MAIN_INPUT
)
{
if
((
itemVal
&
INPUT_VOLATILE
)
==
0
)
feature
->
Volatile
=
FALSE
;
else
feature
->
Volatile
=
TRUE
;
}
if
(
bSize
>
1
)
{
if
((
itemVal
&
INPUT_BITFIELD
)
==
0
)
feature
->
BitField
=
TRUE
;
else
feature
->
BitField
=
FALSE
;
/* Buffered Bytes */
}
feature
->
index
=
*
feature_index
;
*
feature_index
=
*
feature_index
+
1
;
}
}
void
parse_collection
(
unsigned
int
bSize
,
int
itemVal
,
struct
collection
*
collection
)
{
if
(
bSize
<=
0
)
return
;
else
{
collection
->
type
=
itemVal
;
if
(
itemVal
>=
0x07
&&
itemVal
<=
0x7F
)
{
ERR
(
" (Reserved 0x%x )
\n
"
,
itemVal
);
}
else
if
(
itemVal
>=
0x80
&&
itemVal
<=
0xFF
)
{
ERR
(
" (Vendor Defined 0x%x )
\n
"
,
itemVal
);
}
}
}
static
void
new_caps
(
struct
caps
*
caps
)
{
caps
->
IsRange
=
0
;
caps
->
IsStringRange
=
0
;
caps
->
IsDesignatorRange
=
0
;
caps
->
usage_count
=
0
;
}
static
int
parse_descriptor
(
BYTE
*
descriptor
,
unsigned
int
index
,
unsigned
int
length
,
unsigned
int
*
feature_index
,
unsigned
int
*
collection_index
,
struct
collection
*
collection
,
struct
caps
*
caps
,
struct
list
*
features
)
{
unsigned
int
i
;
for
(
i
=
index
;
i
<
length
;)
{
BYTE
b0
=
descriptor
[
i
++
];
int
bSize
=
b0
&
0x03
;
int
bType
=
(
b0
>>
2
)
&
0x03
;
int
bTag
=
(
b0
>>
4
)
&
0x0F
;
bSize
=
(
bSize
==
3
)
?
4
:
bSize
;
if
(
bType
==
TAG_TYPE_RESERVED
&&
bTag
==
0x0F
&&
bSize
==
2
&&
i
+
2
<
length
)
{
/* Long data items: Should be unused */
ERR
(
"Long Data Item, should be unused
\n
"
);
}
else
{
int
bSizeActual
=
0
;
int
itemVal
=
0
;
unsigned
int
j
;
for
(
j
=
0
;
j
<
bSize
;
j
++
)
{
if
(
i
+
j
<
length
)
{
itemVal
+=
descriptor
[
i
+
j
]
<<
(
8
*
j
);
bSizeActual
++
;
}
}
TRACE
(
" 0x%x[%i], type %i , tag %i, size %i, val %i
\n
"
,
b0
,
i
-
1
,
bType
,
bTag
,
bSize
,
itemVal
);
if
(
bType
==
TAG_TYPE_MAIN
)
{
struct
feature
*
feature
;
switch
(
bTag
)
{
case
TAG_MAIN_INPUT
:
feature
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
*
feature
));
list_add_tail
(
&
collection
->
features
,
&
feature
->
col_entry
);
list_add_tail
(
features
,
&
feature
->
entry
);
feature
->
type
=
HidP_Input
;
parse_io_feature
(
bSize
,
itemVal
,
bTag
,
feature_index
,
feature
);
feature
->
caps
=
*
caps
;
feature
->
collection
=
collection
;
new_caps
(
caps
);
break
;
case
TAG_MAIN_OUTPUT
:
feature
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
*
feature
));
list_add_tail
(
&
collection
->
features
,
&
feature
->
col_entry
);
list_add_tail
(
features
,
&
feature
->
entry
);
feature
->
type
=
HidP_Output
;
parse_io_feature
(
bSize
,
itemVal
,
bTag
,
feature_index
,
feature
);
feature
->
caps
=
*
caps
;
feature
->
collection
=
collection
;
new_caps
(
caps
);
break
;
case
TAG_MAIN_FEATURE
:
feature
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
*
feature
));
list_add_tail
(
&
collection
->
features
,
&
feature
->
col_entry
);
list_add_tail
(
features
,
&
feature
->
entry
);
feature
->
type
=
HidP_Feature
;
parse_io_feature
(
bSize
,
itemVal
,
bTag
,
feature_index
,
feature
);
feature
->
caps
=
*
caps
;
feature
->
collection
=
collection
;
new_caps
(
caps
);
break
;
case
TAG_MAIN_COLLECTION
:
{
struct
collection
*
subcollection
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
struct
collection
));
list_add_tail
(
&
collection
->
collections
,
&
subcollection
->
entry
);
subcollection
->
parent
=
collection
;
/* Only set our collection once...
We do not properly handle composite devices yet. */
if
(
*
collection_index
==
0
)
collection
->
caps
=
*
caps
;
subcollection
->
caps
=
*
caps
;
subcollection
->
index
=
*
collection_index
;
*
collection_index
=
*
collection_index
+
1
;
list_init
(
&
subcollection
->
features
);
list_init
(
&
subcollection
->
collections
);
new_caps
(
caps
);
parse_collection
(
bSize
,
itemVal
,
subcollection
);
i
=
parse_descriptor
(
descriptor
,
i
+
1
,
length
,
feature_index
,
collection_index
,
subcollection
,
caps
,
features
);
continue
;
}
case
TAG_MAIN_END_COLLECTION
:
return
i
;
default:
ERR
(
"Unknown (bTag: 0x%x, bType: 0x%x)
\n
"
,
bTag
,
bType
);
}
}
else
if
(
bType
==
TAG_TYPE_GLOBAL
)
{
switch
(
bTag
)
{
case
TAG_GLOBAL_USAGE_PAGE
:
caps
->
UsagePage
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_LOGICAL_MINIMUM
:
caps
->
LogicalMin
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_LOGICAL_MAXIMUM
:
caps
->
LogicalMax
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_PHYSICAL_MINIMUM
:
caps
->
PhysicalMin
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_PHYSICAL_MAXIMUM
:
caps
->
PhysicalMax
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_UNIT_EXPONENT
:
caps
->
UnitsExp
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_UNIT
:
caps
->
Units
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_REPORT_SIZE
:
caps
->
BitSize
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_REPORT_ID
:
caps
->
ReportID
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_REPORT_COUNT
:
caps
->
ReportCount
=
getValue
(
bSize
,
itemVal
);
break
;
case
TAG_GLOBAL_PUSH
:
FIXME
(
"Unhandled Push
\n
"
);
break
;
case
TAG_GLOBAL_POP
:
FIXME
(
"Unhandled Pop
\n
"
);
break
;
default:
ERR
(
"Unknown (bTag: 0x%x, bType: 0x%x)
\n
"
,
bTag
,
bType
);
}
}
else
if
(
bType
==
TAG_TYPE_LOCAL
)
{
switch
(
bTag
)
{
case
TAG_LOCAL_USAGE
:
if
(
caps
->
usage_count
>=
USAGE_MAX
)
FIXME
(
"More than %i individual usages defined
\n
"
,
USAGE_MAX
);
else
{
caps
->
u
.
NotRange
.
Usage
[
caps
->
usage_count
++
]
=
getValue
(
bSize
,
itemVal
);
caps
->
IsRange
=
FALSE
;
}
break
;
case
TAG_LOCAL_USAGE_MINIMUM
:
caps
->
usage_count
=
1
;
caps
->
u
.
Range
.
UsageMin
=
getValue
(
bSize
,
itemVal
);
caps
->
IsRange
=
TRUE
;
break
;
case
TAG_LOCAL_USAGE_MAXIMUM
:
caps
->
usage_count
=
1
;
caps
->
u
.
Range
.
UsageMax
=
getValue
(
bSize
,
itemVal
);
caps
->
IsRange
=
TRUE
;
break
;
case
TAG_LOCAL_DESIGNATOR_INDEX
:
caps
->
u
.
NotRange
.
DesignatorIndex
=
getValue
(
bSize
,
itemVal
);
caps
->
IsDesignatorRange
=
FALSE
;
break
;
case
TAG_LOCAL_DESIGNATOR_MINIMUM
:
caps
->
u
.
Range
.
DesignatorMin
=
getValue
(
bSize
,
itemVal
);
caps
->
IsDesignatorRange
=
TRUE
;
break
;
case
TAG_LOCAL_DESIGNATOR_MAXIMUM
:
caps
->
u
.
Range
.
DesignatorMax
=
getValue
(
bSize
,
itemVal
);
caps
->
IsDesignatorRange
=
TRUE
;
break
;
case
TAG_LOCAL_STRING_INDEX
:
caps
->
u
.
NotRange
.
StringIndex
=
getValue
(
bSize
,
itemVal
);
caps
->
IsStringRange
=
FALSE
;
break
;
case
TAG_LOCAL_STRING_MINIMUM
:
caps
->
u
.
Range
.
StringMin
=
getValue
(
bSize
,
itemVal
);
caps
->
IsStringRange
=
TRUE
;
break
;
case
TAG_LOCAL_STRING_MAXIMUM
:
caps
->
u
.
Range
.
StringMax
=
getValue
(
bSize
,
itemVal
);
caps
->
IsStringRange
=
TRUE
;
break
;
case
TAG_LOCAL_DELIMITER
:
caps
->
Delim
=
getValue
(
bSize
,
itemVal
);
break
;
default:
ERR
(
"Unknown (bTag: 0x%x, bType: 0x%x)
\n
"
,
bTag
,
bType
);
}
}
else
ERR
(
"Unknown (bTag: 0x%x, bType: 0x%x)
\n
"
,
bTag
,
bType
);
i
+=
bSize
;
}
}
return
i
;
}
static
inline
void
new_report
(
WINE_HID_REPORT
*
wine_report
,
struct
feature
*
feature
)
{
wine_report
->
reportID
=
feature
->
caps
.
ReportID
;
wine_report
->
dwSize
=
sizeof
(
*
wine_report
)
-
sizeof
(
WINE_HID_ELEMENT
);
wine_report
->
elementCount
=
0
;
}
static
void
build_elements
(
WINE_HID_REPORT
*
wine_report
,
struct
feature
*
feature
,
DWORD
*
bitOffset
)
{
unsigned
int
i
;
if
(
!
feature
->
isData
)
{
*
bitOffset
=
*
bitOffset
+
(
feature
->
caps
.
BitSize
*
feature
->
caps
.
ReportCount
);
return
;
}
for
(
i
=
0
;
i
<
feature
->
caps
.
usage_count
;
i
++
)
{
WINE_HID_ELEMENT
*
wine_element
=
&
wine_report
->
Elements
[
wine_report
->
elementCount
];
wine_element
->
valueStartBit
=
*
bitOffset
;
if
(
feature
->
caps
.
UsagePage
==
HID_USAGE_PAGE_BUTTON
)
{
wine_element
->
ElementType
=
ButtonElement
;
wine_element
->
caps
.
button
.
UsagePage
=
feature
->
caps
.
UsagePage
;
wine_element
->
caps
.
button
.
ReportID
=
feature
->
caps
.
ReportID
;
wine_element
->
caps
.
button
.
BitField
=
feature
->
BitField
;
wine_element
->
caps
.
button
.
IsRange
=
feature
->
caps
.
IsRange
;
wine_element
->
caps
.
button
.
IsStringRange
=
feature
->
caps
.
IsStringRange
;
wine_element
->
caps
.
button
.
IsDesignatorRange
=
feature
->
caps
.
IsDesignatorRange
;
wine_element
->
caps
.
button
.
IsAbsolute
=
feature
->
IsAbsolute
;
if
(
wine_element
->
caps
.
button
.
IsRange
)
{
wine_element
->
bitCount
=
(
feature
->
caps
.
u
.
Range
.
UsageMax
-
feature
->
caps
.
u
.
Range
.
UsageMin
)
+
1
;
*
bitOffset
=
*
bitOffset
+
wine_element
->
bitCount
;
wine_element
->
caps
.
button
.
u
.
Range
.
UsageMin
=
feature
->
caps
.
u
.
Range
.
UsageMin
;
wine_element
->
caps
.
button
.
u
.
Range
.
UsageMax
=
feature
->
caps
.
u
.
Range
.
UsageMax
;
wine_element
->
caps
.
button
.
u
.
Range
.
StringMin
=
feature
->
caps
.
u
.
Range
.
StringMin
;
wine_element
->
caps
.
button
.
u
.
Range
.
StringMax
=
feature
->
caps
.
u
.
Range
.
StringMax
;
wine_element
->
caps
.
button
.
u
.
Range
.
DesignatorMin
=
feature
->
caps
.
u
.
Range
.
DesignatorMin
;
wine_element
->
caps
.
button
.
u
.
Range
.
DesignatorMax
=
feature
->
caps
.
u
.
Range
.
DesignatorMax
;
}
else
{
*
bitOffset
=
*
bitOffset
+
1
;
wine_element
->
bitCount
=
1
;
wine_element
->
caps
.
button
.
u
.
NotRange
.
Usage
=
feature
->
caps
.
u
.
NotRange
.
Usage
[
i
];
wine_element
->
caps
.
button
.
u
.
NotRange
.
StringIndex
=
feature
->
caps
.
u
.
NotRange
.
StringIndex
;
wine_element
->
caps
.
button
.
u
.
NotRange
.
DesignatorIndex
=
feature
->
caps
.
u
.
NotRange
.
DesignatorIndex
;
}
}
else
{
wine_element
->
ElementType
=
ValueElement
;
wine_element
->
caps
.
value
.
UsagePage
=
feature
->
caps
.
UsagePage
;
wine_element
->
caps
.
value
.
ReportID
=
feature
->
caps
.
ReportID
;
wine_element
->
caps
.
value
.
BitField
=
feature
->
BitField
;
wine_element
->
caps
.
value
.
IsRange
=
feature
->
caps
.
IsRange
;
wine_element
->
caps
.
value
.
IsStringRange
=
feature
->
caps
.
IsStringRange
;
wine_element
->
caps
.
value
.
IsDesignatorRange
=
feature
->
caps
.
IsDesignatorRange
;
wine_element
->
caps
.
value
.
IsAbsolute
=
feature
->
IsAbsolute
;
wine_element
->
caps
.
value
.
HasNull
=
feature
->
HasNull
;
wine_element
->
caps
.
value
.
BitSize
=
feature
->
caps
.
BitSize
;
if
(
feature
->
caps
.
usage_count
>
1
)
wine_element
->
caps
.
value
.
ReportCount
=
1
;
else
wine_element
->
caps
.
value
.
ReportCount
=
feature
->
caps
.
ReportCount
;
wine_element
->
bitCount
=
(
feature
->
caps
.
BitSize
*
wine_element
->
caps
.
value
.
ReportCount
);
*
bitOffset
=
*
bitOffset
+
wine_element
->
bitCount
;
wine_element
->
caps
.
value
.
UnitsExp
=
feature
->
caps
.
UnitsExp
;
wine_element
->
caps
.
value
.
Units
=
feature
->
caps
.
Units
;
wine_element
->
caps
.
value
.
LogicalMin
=
feature
->
caps
.
LogicalMin
;
wine_element
->
caps
.
value
.
LogicalMax
=
feature
->
caps
.
LogicalMax
;
wine_element
->
caps
.
value
.
PhysicalMin
=
feature
->
caps
.
PhysicalMin
;
wine_element
->
caps
.
value
.
PhysicalMax
=
feature
->
caps
.
PhysicalMax
;
if
(
wine_element
->
caps
.
value
.
IsRange
)
{
wine_element
->
caps
.
value
.
u
.
Range
.
UsageMin
=
feature
->
caps
.
u
.
Range
.
UsageMin
;
wine_element
->
caps
.
value
.
u
.
Range
.
UsageMax
=
feature
->
caps
.
u
.
Range
.
UsageMax
;
wine_element
->
caps
.
value
.
u
.
Range
.
StringMin
=
feature
->
caps
.
u
.
Range
.
StringMin
;
wine_element
->
caps
.
value
.
u
.
Range
.
StringMax
=
feature
->
caps
.
u
.
Range
.
StringMax
;
wine_element
->
caps
.
value
.
u
.
Range
.
DesignatorMin
=
feature
->
caps
.
u
.
Range
.
DesignatorMin
;
wine_element
->
caps
.
value
.
u
.
Range
.
DesignatorMax
=
feature
->
caps
.
u
.
Range
.
DesignatorMax
;
}
else
{
wine_element
->
caps
.
value
.
u
.
NotRange
.
Usage
=
feature
->
caps
.
u
.
NotRange
.
Usage
[
i
];
wine_element
->
caps
.
value
.
u
.
NotRange
.
StringIndex
=
feature
->
caps
.
u
.
NotRange
.
StringIndex
;
wine_element
->
caps
.
value
.
u
.
NotRange
.
DesignatorIndex
=
feature
->
caps
.
u
.
NotRange
.
DesignatorIndex
;
}
}
wine_report
->
elementCount
++
;
}
}
static
void
count_elements
(
struct
feature
*
feature
,
USHORT
*
buttons
,
USHORT
*
values
)
{
if
(
feature
->
caps
.
UsagePage
==
HID_USAGE_PAGE_BUTTON
)
{
if
(
feature
->
caps
.
IsRange
)
*
buttons
=
*
buttons
+
1
;
else
*
buttons
=
*
buttons
+
feature
->
caps
.
usage_count
;
}
else
{
if
(
feature
->
caps
.
IsRange
)
*
values
=
*
values
+
1
;
else
*
values
=
*
values
+
feature
->
caps
.
usage_count
;
}
}
WINE_HIDP_PREPARSED_DATA
*
build_PreparseData
(
struct
feature
**
features
,
int
feature_count
,
struct
feature
**
input_features
,
int
i_count
,
struct
feature
**
output_features
,
int
o_count
,
struct
feature
**
feature_features
,
int
f_count
,
struct
collection
*
base_collection
)
{
WINE_HIDP_PREPARSED_DATA
*
data
;
WINE_HID_REPORT
*
wine_report
=
NULL
;
DWORD
bitOffset
,
bitLength
;
unsigned
int
report_count
=
1
;
unsigned
int
i
;
unsigned
int
element_count
;
unsigned
int
size
=
0
;
if
(
features
[
0
]
->
caps
.
ReportID
!=
0
)
{
unsigned
int
*
report_ids
;
unsigned
int
cnt
=
max
(
i_count
,
o_count
);
cnt
=
max
(
cnt
,
f_count
);
report_ids
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
report_ids
)
*
cnt
);
if
(
i_count
)
{
report_ids
[
0
]
=
input_features
[
0
]
->
caps
.
ReportID
;
for
(
i
=
1
;
i
<
i_count
;
i
++
)
{
unsigned
int
j
;
unsigned
int
found
=
FALSE
;
for
(
j
=
0
;
!
found
&&
j
<
i_count
;
j
++
)
{
if
(
report_ids
[
j
]
==
input_features
[
i
]
->
caps
.
ReportID
)
found
=
TRUE
;
}
if
(
!
found
)
{
report_ids
[
report_count
]
=
input_features
[
i
]
->
caps
.
ReportID
;
report_count
++
;
}
}
}
if
(
o_count
)
{
report_count
++
;
report_ids
[
0
]
=
output_features
[
0
]
->
caps
.
ReportID
;
for
(
i
=
1
;
i
<
o_count
;
i
++
)
{
unsigned
int
j
;
unsigned
int
found
=
FALSE
;
for
(
j
=
0
;
!
found
&&
j
<
o_count
;
j
++
)
{
if
(
report_ids
[
j
]
==
output_features
[
i
]
->
caps
.
ReportID
)
found
=
TRUE
;
}
if
(
!
found
)
{
report_ids
[
report_count
]
=
output_features
[
i
]
->
caps
.
ReportID
;
report_count
++
;
}
}
}
if
(
f_count
)
{
report_count
++
;
report_ids
[
0
]
=
feature_features
[
0
]
->
caps
.
ReportID
;
for
(
i
=
1
;
i
<
f_count
;
i
++
)
{
unsigned
int
j
;
unsigned
int
found
=
FALSE
;
for
(
j
=
0
;
!
found
&&
j
<
f_count
;
j
++
)
{
if
(
report_ids
[
j
]
==
feature_features
[
i
]
->
caps
.
ReportID
)
found
=
TRUE
;
}
if
(
!
found
)
{
report_ids
[
report_count
]
=
feature_features
[
i
]
->
caps
.
ReportID
;
report_count
++
;
}
}
}
HeapFree
(
GetProcessHeap
(),
0
,
report_ids
);
}
else
{
if
(
o_count
)
report_count
++
;
if
(
f_count
)
report_count
++
;
}
element_count
=
0
;
for
(
i
=
0
;
i
<
feature_count
;
i
++
)
element_count
+=
features
[
i
]
->
caps
.
usage_count
;
size
=
sizeof
(
WINE_HIDP_PREPARSED_DATA
)
+
(
element_count
*
sizeof
(
WINE_HID_ELEMENT
))
+
(
report_count
*
sizeof
(
WINE_HID_REPORT
));
TRACE
(
"%i reports %i elements -> size %i
\n
"
,
report_count
,
element_count
,
size
);
data
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
size
);
data
->
magic
=
HID_MAGIC
;
data
->
dwSize
=
size
;
data
->
caps
.
Usage
=
base_collection
->
caps
.
u
.
NotRange
.
Usage
[
0
];
data
->
caps
.
UsagePage
=
base_collection
->
caps
.
UsagePage
;
wine_report
=
data
->
InputReports
;
if
(
i_count
)
{
bitLength
=
0
;
new_report
(
wine_report
,
input_features
[
0
]);
data
->
dwInputReportCount
++
;
if
(
input_features
[
0
]
->
caps
.
ReportID
!=
0
)
bitOffset
=
8
;
else
bitOffset
=
0
;
for
(
i
=
0
;
i
<
i_count
;
i
++
)
{
if
(
input_features
[
i
]
->
caps
.
ReportID
!=
wine_report
->
reportID
)
{
wine_report
->
dwSize
+=
(
sizeof
(
WINE_HID_ELEMENT
)
*
wine_report
->
elementCount
);
wine_report
=
(
WINE_HID_REPORT
*
)(((
BYTE
*
)
wine_report
)
+
wine_report
->
dwSize
);
new_report
(
wine_report
,
input_features
[
i
]);
data
->
dwInputReportCount
++
;
bitLength
=
max
(
bitOffset
,
bitLength
);
if
(
input_features
[
i
]
->
caps
.
ReportID
!=
0
)
bitOffset
=
8
;
else
bitOffset
=
0
;
}
build_elements
(
wine_report
,
input_features
[
i
],
&
bitOffset
);
count_elements
(
input_features
[
i
],
&
data
->
caps
.
NumberInputButtonCaps
,
&
data
->
caps
.
NumberInputValueCaps
);
}
wine_report
->
dwSize
+=
(
sizeof
(
WINE_HID_ELEMENT
)
*
wine_report
->
elementCount
);
bitLength
=
max
(
bitOffset
,
bitLength
);
data
->
caps
.
InputReportByteLength
=
((
bitLength
+
7
)
&
~
7
)
/
8
;
}
if
(
o_count
)
{
bitLength
=
0
;
wine_report
=
(
WINE_HID_REPORT
*
)(((
BYTE
*
)
wine_report
)
+
wine_report
->
dwSize
);
data
->
dwOutputReportOffset
=
(
BYTE
*
)
wine_report
-
(
BYTE
*
)
data
->
InputReports
;
new_report
(
wine_report
,
output_features
[
0
]);
data
->
dwOutputReportCount
++
;
if
(
output_features
[
0
]
->
caps
.
ReportID
!=
0
)
bitOffset
=
8
;
else
bitOffset
=
0
;
for
(
i
=
0
;
i
<
o_count
;
i
++
)
{
if
(
output_features
[
i
]
->
caps
.
ReportID
!=
wine_report
->
reportID
)
{
wine_report
->
dwSize
+=
(
sizeof
(
WINE_HID_ELEMENT
)
*
wine_report
->
elementCount
);
wine_report
=
(
WINE_HID_REPORT
*
)(((
BYTE
*
)
wine_report
)
+
wine_report
->
dwSize
);
new_report
(
wine_report
,
output_features
[
i
]);
data
->
dwOutputReportCount
++
;
bitLength
=
max
(
bitOffset
,
bitLength
);
if
(
output_features
[
0
]
->
caps
.
ReportID
!=
0
)
bitOffset
=
8
;
else
bitOffset
=
0
;
}
build_elements
(
wine_report
,
output_features
[
i
],
&
bitOffset
);
count_elements
(
output_features
[
i
],
&
data
->
caps
.
NumberOutputButtonCaps
,
&
data
->
caps
.
NumberOutputValueCaps
);
}
wine_report
->
dwSize
+=
(
sizeof
(
WINE_HID_ELEMENT
)
*
wine_report
->
elementCount
);
bitLength
=
max
(
bitOffset
,
bitLength
);
data
->
caps
.
OutputReportByteLength
=
((
bitLength
+
7
)
&
~
7
)
/
8
;
}
if
(
f_count
)
{
bitLength
=
0
;
wine_report
=
(
WINE_HID_REPORT
*
)(((
BYTE
*
)
wine_report
)
+
wine_report
->
dwSize
);
data
->
dwFeatureReportOffset
=
(
BYTE
*
)
wine_report
-
(
BYTE
*
)
data
->
InputReports
;
new_report
(
wine_report
,
feature_features
[
0
]);
data
->
dwFeatureReportCount
++
;
if
(
feature_features
[
0
]
->
caps
.
ReportID
!=
0
)
bitOffset
=
8
;
else
bitOffset
=
0
;
for
(
i
=
0
;
i
<
f_count
;
i
++
)
{
if
(
feature_features
[
i
]
->
caps
.
ReportID
!=
wine_report
->
reportID
)
{
wine_report
->
dwSize
+=
(
sizeof
(
WINE_HID_ELEMENT
)
*
wine_report
->
elementCount
);
wine_report
=
(
WINE_HID_REPORT
*
)((
BYTE
*
)
wine_report
)
+
wine_report
->
dwSize
;
new_report
(
wine_report
,
feature_features
[
i
]);
data
->
dwFeatureReportCount
++
;
bitLength
=
max
(
bitOffset
,
bitLength
);
if
(
feature_features
[
0
]
->
caps
.
ReportID
!=
0
)
bitOffset
=
8
;
else
bitOffset
=
0
;
}
build_elements
(
wine_report
,
feature_features
[
i
],
&
bitOffset
);
count_elements
(
feature_features
[
i
],
&
data
->
caps
.
NumberFeatureButtonCaps
,
&
data
->
caps
.
NumberFeatureValueCaps
);
}
bitLength
=
max
(
bitOffset
,
bitLength
);
data
->
caps
.
FeatureReportByteLength
=
((
bitLength
+
7
)
&
~
7
)
/
8
;
}
return
data
;
}
static
void
free_collection
(
struct
collection
*
collection
)
{
struct
feature
*
fentry
,
*
fnext
;
struct
collection
*
centry
,
*
cnext
;
LIST_FOR_EACH_ENTRY_SAFE
(
centry
,
cnext
,
&
collection
->
collections
,
struct
collection
,
entry
)
{
list_remove
(
&
centry
->
entry
);
free_collection
(
centry
);
}
LIST_FOR_EACH_ENTRY_SAFE
(
fentry
,
fnext
,
&
collection
->
features
,
struct
feature
,
col_entry
)
{
list_remove
(
&
fentry
->
col_entry
);
HeapFree
(
GetProcessHeap
(),
0
,
fentry
);
}
HeapFree
(
GetProcessHeap
(),
0
,
collection
);
}
static
int
compare_reports
(
const
void
*
a
,
const
void
*
b
)
{
struct
feature
*
f1
=
*
(
struct
feature
**
)
a
;
struct
feature
*
f2
=
*
(
struct
feature
**
)
b
;
int
c
=
(
f1
->
caps
.
ReportID
-
f2
->
caps
.
ReportID
);
if
(
c
)
return
c
;
return
(
f1
->
index
-
f2
->
index
);
}
WINE_HIDP_PREPARSED_DATA
*
ParseDescriptor
(
BYTE
*
descriptor
,
unsigned
int
length
)
{
WINE_HIDP_PREPARSED_DATA
*
data
=
NULL
;
struct
collection
*
base
;
struct
caps
caps
;
struct
list
features
;
unsigned
int
feature_count
=
0
;
unsigned
int
cidx
;
if
(
TRACE_ON
(
hid
))
{
TRACE
(
"Descriptor[%i]: "
,
length
);
for
(
cidx
=
0
;
cidx
<
length
;
cidx
++
)
TRACE
(
"%x "
,
descriptor
[
cidx
]);
TRACE
(
"
\n
"
);
}
list_init
(
&
features
);
base
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
sizeof
(
*
base
));
base
->
index
=
1
;
list_init
(
&
base
->
features
);
list_init
(
&
base
->
collections
);
memset
(
&
caps
,
0
,
sizeof
(
caps
));
cidx
=
0
;
parse_descriptor
(
descriptor
,
0
,
length
,
&
feature_count
,
&
cidx
,
base
,
&
caps
,
&
features
);
debug_collection
(
base
);
cidx
=
2
;
if
(
feature_count
)
{
struct
feature
*
entry
;
struct
feature
**
sorted_features
;
struct
feature
**
input_features
;
struct
feature
**
output_features
;
struct
feature
**
feature_features
;
unsigned
int
i_count
,
o_count
,
f_count
;
unsigned
int
i
;
i_count
=
o_count
=
f_count
=
0
;
sorted_features
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
sorted_features
)
*
feature_count
);
input_features
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
input_features
)
*
feature_count
);
output_features
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
output_features
)
*
feature_count
);
feature_features
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
feature_features
)
*
feature_count
);
i
=
0
;
LIST_FOR_EACH_ENTRY
(
entry
,
&
features
,
struct
feature
,
entry
)
sorted_features
[
i
++
]
=
entry
;
/* Sort features base on report if there are multiple reports */
if
(
sorted_features
[
0
]
->
caps
.
ReportID
!=
0
)
qsort
(
sorted_features
,
feature_count
,
sizeof
(
struct
feature
*
),
compare_reports
);
for
(
i
=
0
;
i
<
feature_count
;
i
++
)
{
switch
(
sorted_features
[
i
]
->
type
)
{
case
HidP_Input
:
input_features
[
i_count
]
=
sorted_features
[
i
];
i_count
++
;
break
;
case
HidP_Output
:
output_features
[
o_count
]
=
sorted_features
[
i
];
o_count
++
;
break
;
case
HidP_Feature
:
feature_features
[
f_count
]
=
sorted_features
[
i
];
f_count
++
;
break
;
default:
ERR
(
"Unknown type %i
\n
"
,
sorted_features
[
i
]
->
type
);
}
}
if
(
TRACE_ON
(
hid
))
{
TRACE
(
"DUMP FEATURES:
\n
"
);
TRACE
(
"----INPUT----
\n
"
);
for
(
cidx
=
0
;
cidx
<
i_count
;
cidx
++
)
debug_feature
(
input_features
[
cidx
]);
TRACE
(
"----OUTPUT----
\n
"
);
for
(
cidx
=
0
;
cidx
<
o_count
;
cidx
++
)
debug_feature
(
output_features
[
cidx
]);
TRACE
(
"----FEATURE----
\n
"
);
for
(
cidx
=
0
;
cidx
<
f_count
;
cidx
++
)
debug_feature
(
feature_features
[
cidx
]);
}
data
=
build_PreparseData
(
sorted_features
,
feature_count
,
input_features
,
i_count
,
output_features
,
o_count
,
feature_features
,
f_count
,
base
);
debug_print_preparsed
(
data
);
HeapFree
(
GetProcessHeap
(),
0
,
sorted_features
);
HeapFree
(
GetProcessHeap
(),
0
,
input_features
);
HeapFree
(
GetProcessHeap
(),
0
,
output_features
);
HeapFree
(
GetProcessHeap
(),
0
,
feature_features
);
}
free_collection
(
base
);
/* We do not have to free the list as free_collection does all the work */
return
data
;
}
dlls/hidclass.sys/hid.h
View file @
b7f43c99
...
...
@@ -81,3 +81,6 @@ void HID_DeleteDevice(HID_MINIDRIVER_REGISTRATION *driver, DEVICE_OBJECT *device
/* Pseudo-Plug and Play support*/
NTSTATUS
WINAPI
PNP_AddDevice
(
DRIVER_OBJECT
*
driver
,
DEVICE_OBJECT
*
PDO
)
DECLSPEC_HIDDEN
;
void
PNP_CleanupPNP
(
DRIVER_OBJECT
*
driver
)
DECLSPEC_HIDDEN
;
/* Parsing HID Report Descriptors into preparsed data */
WINE_HIDP_PREPARSED_DATA
*
ParseDescriptor
(
BYTE
*
descriptor
,
unsigned
int
length
)
DECLSPEC_HIDDEN
;
dlls/hidclass.sys/pnp.c
View file @
b7f43c99
...
...
@@ -53,6 +53,9 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
DWORD
index
=
HID_STRING_ID_ISERIALNUMBER
;
NATIVE_DEVICE
*
tracked_device
,
*
ptr
;
INT
interface_index
=
1
;
HID_DESCRIPTOR
descriptor
;
BYTE
*
reportDescriptor
;
INT
i
;
static
const
WCHAR
ig_fmtW
[]
=
{
'I'
,
'G'
,
'_'
,
'%'
,
'i'
,
0
};
static
const
WCHAR
im_fmtW
[]
=
{
'I'
,
'M'
,
'_'
,
'%'
,
'i'
,
0
};
...
...
@@ -104,6 +107,40 @@ NTSTATUS WINAPI PNP_AddDevice(DRIVER_OBJECT *driver, DEVICE_OBJECT *PDO)
list_add_tail
(
&
tracked_devices
,
&
tracked_device
->
entry
);
status
=
call_minidriver
(
IOCTL_HID_GET_DEVICE_DESCRIPTOR
,
device
,
NULL
,
0
,
&
descriptor
,
sizeof
(
descriptor
));
if
(
status
!=
STATUS_SUCCESS
)
{
ERR
(
"Cannot get Device Descriptor(%x)
\n
"
,
status
);
HID_DeleteDevice
(
&
minidriver
->
minidriver
,
device
);
return
status
;
}
for
(
i
=
0
;
i
<
descriptor
.
bNumDescriptors
;
i
++
)
if
(
descriptor
.
DescriptorList
[
i
].
bReportType
==
HID_REPORT_DESCRIPTOR_TYPE
)
break
;
if
(
i
>=
descriptor
.
bNumDescriptors
)
{
ERR
(
"No Report Descriptor found in reply
\n
"
);
HID_DeleteDevice
(
&
minidriver
->
minidriver
,
device
);
return
status
;
}
reportDescriptor
=
HeapAlloc
(
GetProcessHeap
(),
0
,
descriptor
.
DescriptorList
[
i
].
wReportLength
);
status
=
call_minidriver
(
IOCTL_HID_GET_REPORT_DESCRIPTOR
,
device
,
NULL
,
0
,
reportDescriptor
,
descriptor
.
DescriptorList
[
i
].
wReportLength
);
if
(
status
!=
STATUS_SUCCESS
)
{
ERR
(
"Cannot get Report Descriptor(%x)
\n
"
,
status
);
HID_DeleteDevice
(
&
minidriver
->
minidriver
,
device
);
HeapFree
(
GetProcessHeap
(),
0
,
reportDescriptor
);
return
status
;
}
ext
->
preparseData
=
ParseDescriptor
(
reportDescriptor
,
descriptor
.
DescriptorList
[
0
].
wReportLength
);
ext
->
information
.
DescriptorSize
=
ext
->
preparseData
->
dwSize
;
HeapFree
(
GetProcessHeap
(),
0
,
reportDescriptor
);
serial
[
0
]
=
0
;
status
=
call_minidriver
(
IOCTL_HID_GET_STRING
,
device
,
&
index
,
sizeof
(
DWORD
),
serial
,
sizeof
(
serial
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment