1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         HidParser description test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #include <hidpddi.h>
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 #include "HidP.h"
15 
16 static UCHAR ExampleKeyboardDescriptor[] = {
17     0x05, 0x01,       /* Usage Page (Generic Desktop), */
18     0x09, 0x06,       /* Usage (Keyboard), */
19     0xA1, 0x01,       /* Collection (Application), */
20     0x05, 0x07,       /*   Usage Page (Key Codes); */
21     0x19, 0xE0,       /*   Usage Minimum (224), */
22     0x29, 0xE7,       /*   Usage Maximum (231), */
23     0x15, 0x00,       /*   Logical Minimum (0), */
24     0x25, 0x01,       /*   Logical Maximum (1), */
25     0x75, 0x01,       /*   Report Size (1), */
26     0x95, 0x08,       /*   Report Count (8), */
27     0x81, 0x02,       /*   Input (Data, Variable, Absolute), ;Modifier byte */
28     0x95, 0x01,       /*   Report Count (1), */
29     0x75, 0x08,       /*   Report Size (8), */
30     0x81, 0x01,       /*   Input (Constant), ;Reserved byte */
31     0x95, 0x05,       /*   Report Count (5), */
32     0x75, 0x01,       /*   Report Size (1), */
33     0x05, 0x08,       /*   Usage Page (Page# for LEDs), */
34     0x19, 0x01,       /*   Usage Minimum (1), */
35     0x29, 0x05,       /*   Usage Maximum (5), */
36     0x91, 0x02,       /*   Output (Data, Variable, Absolute), ;LED report */
37     0x95, 0x01,       /*   Report Count (1), */
38     0x75, 0x03,       /*   Report Size (3), */
39     0x91, 0x01,       /*   Output (Constant), ;LED report padding */
40     0x95, 0x06,       /*   Report Count (6), */
41     0x75, 0x08,       /*   Report Size (8), */
42     0x15, 0x00,       /*   Logical Minimum (0), */
43     0x25, 0x65,       /*   Logical Maximum (101), */
44     0x05, 0x07,       /*   Usage Page (Key Codes), */
45     0x19, 0x00,       /*   Usage Minimum (0), */
46     0x29, 0x65,       /*   Usage Maximum (101) */
47     0x81, 0x00,       /*   Input (Data, Array), ;Key arrays (6 bytes) */
48     0xC0              /* End Collection */
49 };
50 
51 static UCHAR PowerProEliteDescriptor[] = {
52     0x05, 0x01,       /* Usage Page (Generic Desktop), */
53     0x09, 0x04,       /* Usage (Joystick), */
54     0xa1, 0x01,       /* Collection (Application), */
55     0xa1, 0x02,       /*   Collection (Logical), */
56     0x85, 0x01,       /*     Report ID (1) */
57     0x75, 0x08,       /*     Report Size (8), */
58     0x95, 0x01,       /*     Report Count (1), */
59     0x15, 0x00,       /*     Logical Minimum (0), */
60     0x26, 0xff, 0x00, /*     Logical Maximum (255), */
61     0x81, 0x03,       /*     Input (Constant, Variable, Absolute), */
62     0x75, 0x01,       /*     Report Size (1), */
63     0x95, 0x13,       /*     Report Count (19), */
64     0x15, 0x00,       /*     Logical Minimum (0), */
65     0x25, 0x01,       /*     Logical Maximum (1), */
66     0x35, 0x00,       /*     Physical Minimum (0), */
67     0x45, 0x01,       /*     Physical Maximum (1), */
68     0x05, 0x09,       /*     Usage Page (Button), */
69     0x19, 0x01,       /*     Usage Minimum (1), */
70     0x29, 0x13,       /*     Usage Maximum (19), */
71     0x81, 0x02,       /*     Input (Data, Variable, Absolute), */
72     0x75, 0x01,       /*     Report Size (1), */
73     0x95, 0x0d,       /*     Report Count (13), */
74     0x06, 0x00, 0xff, /*     Usage Page (Vendor-defined FF00), */
75     0x81, 0x03,       /*     Input (Constant, Variable, Absolute), */
76     0x15, 0x00,       /*     Logical Minimum (0), */
77     0x26, 0xff, 0x00, /*     Logical Maximum (255), */
78     0x05, 0x01,       /*     Usage Page (Generic Desktop), */
79     0x09, 0x01,       /*     Usage (Pointer), */
80     0xa1, 0x00,       /*     Collection (Physical), */
81     0x75, 0x08,       /*       Report Size (8), */
82     0x95, 0x04,       /*       Report Count (4), */
83     0x35, 0x00,       /*       Physical Minimum (0), */
84     0x46, 0xff, 0x00, /*       Physical Maximum (255), */
85     0x09, 0x30,       /*       Usage (X), */
86     0x09, 0x31,       /*       Usage (Y), */
87     0x09, 0x32,       /*       Usage (Z), */
88     0x09, 0x35,       /*       Usage (Rz), */
89     0x81, 0x02,       /*       Input (Data, Variable, Absolute), */
90     0xc0,             /*     End Collection */
91     0x05, 0x01,       /*     Usage Page (Generic Desktop), */
92     0x75, 0x08,       /*     Report Size (8), */
93     0x95, 0x27,       /*     Report Count (39), */
94     0x09, 0x01,       /*     Usage (Pointer), */
95     0x81, 0x02,       /*     Input (Data, Variable, Absolute), */
96     0x75, 0x08,       /*     Report Size (8), */
97     0x95, 0x30,       /*     Report Count (48), */
98     0x09, 0x01,       /*     Usage (Pointer), */
99     0x91, 0x02,       /*     Output (Data, Variable, Absolute), */
100     0x75, 0x08,       /*     Report Size (8), */
101     0x95, 0x30,       /*     Report Count (48), */
102     0x09, 0x01,       /*     Usage (Pointer), */
103     0xb1, 0x02,       /*     Feature (Data, Variable, Absolute), */
104     0xc0,             /*   End Collection */
105 
106     0xa1, 0x02,       /*   Collection (Logical), */
107     0x85, 0x02,       /*     Report ID (2) */
108     0x75, 0x08,       /*     Report Size (8), */
109     0x95, 0x30,       /*     Report Count (48), */
110     0x09, 0x01,       /*     Usage (Pointer), */
111     0xb1, 0x02,       /*     Feature (Data, Variable, Absolute), */
112     0xc0,             /*   End Collection */
113     0xa1, 0x02,       /*   Collection (Logical), */
114     0x85, 0xee,       /*     Report ID (238) */
115     0x75, 0x08,       /*     Report Size (8), */
116     0x95, 0x30,       /*     Report Count (48), */
117     0x09, 0x01,       /*     Usage (Pointer), */
118     0xb1, 0x02,       /*     Feature (Data, Variable, Absolute), */
119     0xc0,             /*   End Collection */
120     0xa1, 0x02,       /*   Collection (Logical), */
121     0x85, 0xef,       /*     Report ID (239) */
122     0x75, 0x08,       /*     Report Size (8), */
123     0x95, 0x30,       /*     Report Count (48), */
124     0x09, 0x01,       /*     Usage (Pointer), */
125     0xb1, 0x02,       /*     Feature (Data, Variable, Absolute), */
126     0xc0,             /*   End Collection */
127     0xc0,             /* End Collection */
128 };
129 C_ASSERT(sizeof(PowerProEliteDescriptor) == 148);
130 
131 static
132 VOID
133 TestGetCollectionDescription(VOID)
134 {
135     NTSTATUS Status;
136     HIDP_DEVICE_DESC DeviceDescription;
137 
138     /* Empty report descriptor */
139     RtlFillMemory(&DeviceDescription, sizeof(DeviceDescription), 0x55);
140     Status = HidP_GetCollectionDescription(NULL,
141                                            0,
142                                            NonPagedPool,
143                                            &DeviceDescription);
144     ok_eq_hex(Status, STATUS_NO_DATA_DETECTED);
145     ok_eq_pointer(DeviceDescription.CollectionDesc, NULL);
146     ok_eq_ulong(DeviceDescription.CollectionDescLength, 0);
147     ok_eq_pointer(DeviceDescription.ReportIDs, NULL);
148     ok_eq_ulong(DeviceDescription.ReportIDsLength, 0);
149     if (NT_SUCCESS(Status)) HidP_FreeCollectionDescription(&DeviceDescription);
150 
151     /* Sample keyboard report descriptor from the HID spec */
152     Status = HidP_GetCollectionDescription(ExampleKeyboardDescriptor,
153                                            sizeof(ExampleKeyboardDescriptor),
154                                            NonPagedPool,
155                                            &DeviceDescription);
156     ok_eq_hex(Status, STATUS_SUCCESS);
157     ok_eq_ulong(DeviceDescription.CollectionDescLength, 1);
158     ok_eq_ulong(DeviceDescription.ReportIDsLength, 1);
159     if (!skip(NT_SUCCESS(Status), "Parsing failure\n"))
160     {
161         if (!skip(DeviceDescription.CollectionDescLength >= 1, "No collection\n"))
162         {
163             ok_eq_uint(DeviceDescription.CollectionDesc[0].UsagePage, HID_USAGE_PAGE_GENERIC);
164             ok_eq_uint(DeviceDescription.CollectionDesc[0].Usage, HID_USAGE_GENERIC_KEYBOARD);
165             ok_eq_uint(DeviceDescription.CollectionDesc[0].CollectionNumber, 1);
166             ok_eq_uint(DeviceDescription.CollectionDesc[0].InputLength, 9);
167             ok_eq_uint(DeviceDescription.CollectionDesc[0].OutputLength, 2);
168             ok_eq_uint(DeviceDescription.CollectionDesc[0].FeatureLength, 0);
169             ok_eq_uint(DeviceDescription.CollectionDesc[0].PreparsedDataLength, 476);
170         }
171         if (!skip(DeviceDescription.ReportIDsLength >= 1, "No report IDs\n"))
172         {
173             ok_eq_uint(DeviceDescription.ReportIDs[0].ReportID, 0);
174             ok_eq_uint(DeviceDescription.ReportIDs[0].CollectionNumber, 1);
175             ok_eq_uint(DeviceDescription.ReportIDs[0].InputLength, 8);
176             ok_eq_uint(DeviceDescription.ReportIDs[0].OutputLength, 1);
177             ok_eq_uint(DeviceDescription.ReportIDs[0].FeatureLength, 0);
178         }
179         HidP_FreeCollectionDescription(&DeviceDescription);
180     }
181 
182     /* Regression test for CORE-11538 */
183     Status = HidP_GetCollectionDescription(PowerProEliteDescriptor,
184                                            sizeof(PowerProEliteDescriptor),
185                                            NonPagedPool,
186                                            &DeviceDescription);
187     ok_eq_hex(Status, STATUS_SUCCESS);
188     ok_eq_ulong(DeviceDescription.CollectionDescLength, 1);
189     ok_eq_ulong(DeviceDescription.ReportIDsLength, 4);
190     if (!skip(NT_SUCCESS(Status), "Parsing failure\n"))
191     {
192         if (!skip(DeviceDescription.CollectionDescLength >= 1, "No collection\n"))
193         {
194             ok_eq_uint(DeviceDescription.CollectionDesc[0].UsagePage, HID_USAGE_PAGE_GENERIC);
195             ok_eq_uint(DeviceDescription.CollectionDesc[0].Usage, HID_USAGE_GENERIC_JOYSTICK);
196             ok_eq_uint(DeviceDescription.CollectionDesc[0].CollectionNumber, 1);
197             ok_eq_uint(DeviceDescription.CollectionDesc[0].InputLength, 49);
198             ok_eq_uint(DeviceDescription.CollectionDesc[0].OutputLength, 49);
199             ok_eq_uint(DeviceDescription.CollectionDesc[0].FeatureLength, 49);
200             ok_eq_uint(DeviceDescription.CollectionDesc[0].PreparsedDataLength, 1388);
201         }
202         if (!skip(DeviceDescription.ReportIDsLength >= 1, "No first report ID\n"))
203         {
204             ok_eq_uint(DeviceDescription.ReportIDs[0].ReportID, 1);
205             ok_eq_uint(DeviceDescription.ReportIDs[0].CollectionNumber, 1);
206             ok_eq_uint(DeviceDescription.ReportIDs[0].InputLength, 49);
207             ok_eq_uint(DeviceDescription.ReportIDs[0].OutputLength, 49);
208             ok_eq_uint(DeviceDescription.ReportIDs[0].FeatureLength, 49);
209         }
210         if (!skip(DeviceDescription.ReportIDsLength >= 2, "No second report ID\n"))
211         {
212             ok_eq_uint(DeviceDescription.ReportIDs[1].ReportID, 2);
213             ok_eq_uint(DeviceDescription.ReportIDs[1].CollectionNumber, 1);
214             ok_eq_uint(DeviceDescription.ReportIDs[1].InputLength, 0);
215             ok_eq_uint(DeviceDescription.ReportIDs[1].OutputLength, 0);
216             ok_eq_uint(DeviceDescription.ReportIDs[1].FeatureLength, 49);
217         }
218         if (!skip(DeviceDescription.ReportIDsLength >= 3, "No third report ID\n"))
219         {
220             ok_eq_uint(DeviceDescription.ReportIDs[2].ReportID, 238);
221             ok_eq_uint(DeviceDescription.ReportIDs[2].CollectionNumber, 1);
222             ok_eq_uint(DeviceDescription.ReportIDs[2].InputLength, 0);
223             ok_eq_uint(DeviceDescription.ReportIDs[2].OutputLength, 0);
224             ok_eq_uint(DeviceDescription.ReportIDs[2].FeatureLength, 49);
225         }
226         if (!skip(DeviceDescription.ReportIDsLength >= 4, "No fourth report ID\n"))
227         {
228             ok_eq_uint(DeviceDescription.ReportIDs[3].ReportID, 239);
229             ok_eq_uint(DeviceDescription.ReportIDs[3].CollectionNumber, 1);
230             ok_eq_uint(DeviceDescription.ReportIDs[3].InputLength, 0);
231             ok_eq_uint(DeviceDescription.ReportIDs[3].OutputLength, 0);
232             ok_eq_uint(DeviceDescription.ReportIDs[3].FeatureLength, 49);
233         }
234         HidP_FreeCollectionDescription(&DeviceDescription);
235     }
236 }
237 
238 NTSTATUS
239 TestHidPDescription(
240     IN PDEVICE_OBJECT DeviceObject,
241     IN ULONG ControlCode,
242     IN PVOID Buffer OPTIONAL,
243     IN SIZE_T InLength,
244     IN OUT PSIZE_T OutLength)
245 {
246     UNREFERENCED_PARAMETER(DeviceObject);
247     UNREFERENCED_PARAMETER(Buffer);
248     UNREFERENCED_PARAMETER(InLength);
249     UNREFERENCED_PARAMETER(OutLength);
250 
251     PAGED_CODE();
252 
253     NT_VERIFY(ControlCode == IOCTL_TEST_DESCRIPTION);
254 
255     TestGetCollectionDescription();
256 
257     return STATUS_SUCCESS;
258 }
259