2 * WINE Platform native bus driver
4 * Copyright 2016 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
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
27 #define WIN32_NO_STATUS
36 #include "ddk/hidport.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(plugplay
);
44 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
49 DEVICE_OBJECT
*device
;
52 struct device_extension
54 struct pnp_device
*pnp_device
;
57 DWORD uid
, version
, index
;
60 const WCHAR
*busid
; /* Expected to be a static constant */
62 const platform_vtbl
*vtbl
;
65 DWORD last_report_size
;
66 BOOL last_report_read
;
69 CRITICAL_SECTION report_cs
;
71 BYTE platform_private
[1];
74 static CRITICAL_SECTION device_list_cs
;
75 static CRITICAL_SECTION_DEBUG critsect_debug
=
77 0, 0, &device_list_cs
,
78 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
79 0, 0, { (DWORD_PTR
)(__FILE__
": device_list_cs") }
81 static CRITICAL_SECTION device_list_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
83 static struct list pnp_devset
= LIST_INIT(pnp_devset
);
85 static const WCHAR zero_serialW
[]= {'0','0','0','0',0};
86 static const WCHAR imW
[] = {'I','M',0};
87 static const WCHAR igW
[] = {'I','G',0};
89 static inline WCHAR
*strdupW(const WCHAR
*src
)
92 if (!src
) return NULL
;
93 dst
= HeapAlloc(GetProcessHeap(), 0, (strlenW(src
) + 1)*sizeof(WCHAR
));
94 if (dst
) strcpyW(dst
, src
);
98 void *get_platform_private(DEVICE_OBJECT
*device
)
100 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
101 return ext
->platform_private
;
104 static DWORD
get_vidpid_index(WORD vid
, WORD pid
)
106 struct pnp_device
*ptr
;
109 LIST_FOR_EACH_ENTRY(ptr
, &pnp_devset
, struct pnp_device
, entry
)
111 struct device_extension
*ext
= (struct device_extension
*)ptr
->device
->DeviceExtension
;
112 if (ext
->vid
== vid
&& ext
->pid
== pid
)
113 index
= max(ext
->index
+ 1, index
);
119 static WCHAR
*get_instance_id(DEVICE_OBJECT
*device
)
121 static const WCHAR formatW
[] = {'%','s','\\','V','i','d','_','%','0','4','x','&', 'P','i','d','_','%','0','4','x','&',
122 '%','s','_','%','i','\\','%','i','&','%','s','&','%','x',0};
123 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
124 const WCHAR
*serial
= ext
->serial
? ext
->serial
: zero_serialW
;
125 DWORD len
= strlenW(ext
->busid
) + strlenW(serial
) + 64;
128 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
129 sprintfW(dst
, formatW
, ext
->busid
, ext
->vid
, ext
->pid
, ext
->is_gamepad
? igW
: imW
,
130 ext
->index
, ext
->version
, serial
, ext
->uid
);
135 static WCHAR
*get_device_id(DEVICE_OBJECT
*device
)
137 static const WCHAR formatW
[] = {'%','s','\\','V','i','d','_','%','0','4','x','&','P','i','d','_','%','0','4','x',0};
138 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
139 DWORD len
= strlenW(ext
->busid
) + 19;
142 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
143 sprintfW(dst
, formatW
, ext
->busid
, ext
->vid
, ext
->pid
);
148 static WCHAR
*get_compatible_ids(DEVICE_OBJECT
*device
)
150 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
151 WCHAR
*iid
, *did
, *dst
, *ptr
;
154 if (!(iid
= get_instance_id(device
)))
157 if (!(did
= get_device_id(device
)))
159 HeapFree(GetProcessHeap(), 0, iid
);
163 len
= strlenW(iid
) + strlenW(did
) + strlenW(ext
->busid
) + 4;
164 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
168 ptr
+= strlenW(iid
) + 1;
170 ptr
+= strlenW(did
) + 1;
171 strcpyW(ptr
, ext
->busid
);
172 ptr
+= strlenW(ext
->busid
) + 1;
176 HeapFree(GetProcessHeap(), 0, iid
);
177 HeapFree(GetProcessHeap(), 0, did
);
181 DEVICE_OBJECT
*bus_create_hid_device(DRIVER_OBJECT
*driver
, const WCHAR
*busidW
, WORD vid
, WORD pid
,
182 DWORD version
, DWORD uid
, const WCHAR
*serialW
, BOOL is_gamepad
,
183 const GUID
*class, const platform_vtbl
*vtbl
, DWORD platform_data_size
)
185 static const WCHAR device_name_fmtW
[] = {'\\','D','e','v','i','c','e','\\','%','s','#','%','p',0};
186 struct device_extension
*ext
;
187 struct pnp_device
*pnp_dev
;
188 DEVICE_OBJECT
*device
;
189 UNICODE_STRING nameW
;
195 TRACE("(%p, %s, %04x, %04x, %u, %u, %s, %u, %s, %p, %u)\n", driver
, debugstr_w(busidW
), vid
, pid
,
196 version
, uid
, debugstr_w(serialW
), is_gamepad
, debugstr_guid(class), vtbl
, platform_data_size
);
198 if (!(pnp_dev
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pnp_dev
))))
201 sprintfW(dev_name
, device_name_fmtW
, busidW
, pnp_dev
);
202 RtlInitUnicodeString(&nameW
, dev_name
);
203 length
= FIELD_OFFSET(struct device_extension
, platform_private
[platform_data_size
]);
204 status
= IoCreateDevice(driver
, length
, &nameW
, 0, 0, FALSE
, &device
);
207 FIXME("failed to create device error %x\n", status
);
208 HeapFree(GetProcessHeap(), 0, pnp_dev
);
212 EnterCriticalSection(&device_list_cs
);
214 /* fill out device_extension struct */
215 ext
= (struct device_extension
*)device
->DeviceExtension
;
216 ext
->pnp_device
= pnp_dev
;
220 ext
->version
= version
;
221 ext
->index
= get_vidpid_index(vid
, pid
);
222 ext
->is_gamepad
= is_gamepad
;
223 ext
->serial
= strdupW(serialW
);
226 ext
->last_report
= NULL
;
227 ext
->last_report_size
= 0;
228 ext
->last_report_read
= TRUE
;
229 ext
->buffer_size
= 0;
231 memset(ext
->platform_private
, 0, platform_data_size
);
233 InitializeListHead(&ext
->irp_queue
);
234 InitializeCriticalSection(&ext
->report_cs
);
235 ext
->report_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": report_cs");
237 /* add to list of pnp devices */
238 pnp_dev
->device
= device
;
239 list_add_tail(&pnp_devset
, &pnp_dev
->entry
);
241 LeaveCriticalSection(&device_list_cs
);
243 devinfo
= SetupDiGetClassDevsW(class, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
246 SP_DEVINFO_DATA data
;
249 data
.cbSize
= sizeof(data
);
250 if (!(instance
= get_instance_id(device
)))
251 ERR("failed to generate instance id\n");
252 else if (!SetupDiCreateDeviceInfoW(devinfo
, instance
, class, NULL
, NULL
, DICD_INHERIT_CLASSDRVS
, &data
))
253 ERR("failed to create device info: %x\n", GetLastError());
254 else if (!SetupDiRegisterDeviceInfo(devinfo
, &data
, 0, NULL
, NULL
, NULL
))
255 ERR("failed to register device info: %x\n", GetLastError());
257 HeapFree(GetProcessHeap(), 0, instance
);
258 SetupDiDestroyDeviceInfoList(devinfo
);
261 ERR("failed to get ClassDevs: %x\n", GetLastError());
266 DEVICE_OBJECT
*bus_find_hid_device(const platform_vtbl
*vtbl
, void *platform_dev
)
268 struct pnp_device
*dev
;
269 DEVICE_OBJECT
*ret
= NULL
;
271 TRACE("(%p, %p)\n", vtbl
, platform_dev
);
273 EnterCriticalSection(&device_list_cs
);
274 LIST_FOR_EACH_ENTRY(dev
, &pnp_devset
, struct pnp_device
, entry
)
276 struct device_extension
*ext
= (struct device_extension
*)dev
->device
->DeviceExtension
;
277 if (ext
->vtbl
!= vtbl
) continue;
278 if (ext
->vtbl
->compare_platform_device(dev
->device
, platform_dev
) == 0)
284 LeaveCriticalSection(&device_list_cs
);
286 TRACE("returning %p\n", ret
);
290 void bus_remove_hid_device(DEVICE_OBJECT
*device
)
292 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
293 struct pnp_device
*pnp_device
= ext
->pnp_device
;
297 TRACE("(%p)\n", device
);
299 EnterCriticalSection(&device_list_cs
);
300 list_remove(&pnp_device
->entry
);
301 LeaveCriticalSection(&device_list_cs
);
303 /* Cancel pending IRPs */
304 EnterCriticalSection(&ext
->report_cs
);
305 while ((entry
= RemoveHeadList(&ext
->irp_queue
)) != &ext
->irp_queue
)
307 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
308 irp
->IoStatus
.u
.Status
= STATUS_CANCELLED
;
309 irp
->IoStatus
.Information
= 0;
310 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
312 LeaveCriticalSection(&ext
->report_cs
);
314 ext
->report_cs
.DebugInfo
->Spare
[0] = 0;
315 DeleteCriticalSection(&ext
->report_cs
);
317 HeapFree(GetProcessHeap(), 0, ext
->serial
);
318 HeapFree(GetProcessHeap(), 0, ext
->last_report
);
319 IoDeleteDevice(device
);
321 /* pnp_device must be released after the device is gone */
322 HeapFree(GetProcessHeap(), 0, pnp_device
);
325 static NTSTATUS
handle_IRP_MN_QUERY_ID(DEVICE_OBJECT
*device
, IRP
*irp
)
327 NTSTATUS status
= irp
->IoStatus
.u
.Status
;
328 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
329 BUS_QUERY_ID_TYPE type
= irpsp
->Parameters
.QueryId
.IdType
;
331 TRACE("(%p, %p)\n", device
, irp
);
335 case BusQueryHardwareIDs
:
336 TRACE("BusQueryHardwareIDs\n");
337 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
339 case BusQueryCompatibleIDs
:
340 TRACE("BusQueryCompatibleIDs\n");
341 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
343 case BusQueryDeviceID
:
344 TRACE("BusQueryDeviceID\n");
345 irp
->IoStatus
.Information
= (ULONG_PTR
)get_device_id(device
);
347 case BusQueryInstanceID
:
348 TRACE("BusQueryInstanceID\n");
349 irp
->IoStatus
.Information
= (ULONG_PTR
)get_instance_id(device
);
352 FIXME("Unhandled type %08x\n", type
);
356 status
= irp
->IoStatus
.Information
? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
360 NTSTATUS WINAPI
common_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
362 NTSTATUS status
= irp
->IoStatus
.u
.Status
;
363 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
365 switch (irpsp
->MinorFunction
)
367 case IRP_MN_QUERY_DEVICE_RELATIONS
:
368 TRACE("IRP_MN_QUERY_DEVICE_RELATIONS\n");
370 case IRP_MN_QUERY_ID
:
371 TRACE("IRP_MN_QUERY_ID\n");
372 status
= handle_IRP_MN_QUERY_ID(device
, irp
);
373 irp
->IoStatus
.u
.Status
= status
;
375 case IRP_MN_QUERY_CAPABILITIES
:
376 TRACE("IRP_MN_QUERY_CAPABILITIES\n");
379 FIXME("Unhandled function %08x\n", irpsp
->MinorFunction
);
383 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
387 static NTSTATUS
deliver_last_report(struct device_extension
*ext
, DWORD buffer_length
, BYTE
* buffer
, ULONG_PTR
*out_length
)
389 if (buffer_length
< ext
->last_report_size
)
392 return STATUS_BUFFER_TOO_SMALL
;
396 if (ext
->last_report
)
397 memcpy(buffer
, ext
->last_report
, ext
->last_report_size
);
398 *out_length
= ext
->last_report_size
;
399 return STATUS_SUCCESS
;
403 NTSTATUS WINAPI
hid_internal_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
405 NTSTATUS status
= irp
->IoStatus
.u
.Status
;
406 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
407 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
409 TRACE("(%p, %p)\n", device
, irp
);
411 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
413 case IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
415 HID_DEVICE_ATTRIBUTES
*attr
= (HID_DEVICE_ATTRIBUTES
*)irp
->UserBuffer
;
416 TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
418 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(*attr
))
420 irp
->IoStatus
.u
.Status
= status
= STATUS_BUFFER_TOO_SMALL
;
424 memset(attr
, 0, sizeof(*attr
));
425 attr
->Size
= sizeof(*attr
);
426 attr
->VendorID
= ext
->vid
;
427 attr
->ProductID
= ext
->pid
;
428 attr
->VersionNumber
= ext
->version
;
430 irp
->IoStatus
.u
.Status
= status
= STATUS_SUCCESS
;
431 irp
->IoStatus
.Information
= sizeof(*attr
);
434 case IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
436 HID_DESCRIPTOR
*descriptor
= (HID_DESCRIPTOR
*)irp
->UserBuffer
;
438 TRACE("IOCTL_HID_GET_DEVICE_DESCRIPTOR\n");
440 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(*descriptor
))
442 irp
->IoStatus
.u
.Status
= status
= STATUS_BUFFER_TOO_SMALL
;
446 status
= ext
->vtbl
->get_reportdescriptor(device
, NULL
, 0, &length
);
447 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
449 WARN("Failed to get platform report descriptor length\n");
450 irp
->IoStatus
.u
.Status
= status
;
454 memset(descriptor
, 0, sizeof(*descriptor
));
455 descriptor
->bLength
= sizeof(*descriptor
);
456 descriptor
->bDescriptorType
= HID_HID_DESCRIPTOR_TYPE
;
457 descriptor
->bcdHID
= HID_REVISION
;
458 descriptor
->bCountry
= 0;
459 descriptor
->bNumDescriptors
= 1;
460 descriptor
->DescriptorList
[0].bReportType
= HID_REPORT_DESCRIPTOR_TYPE
;
461 descriptor
->DescriptorList
[0].wReportLength
= length
;
463 irp
->IoStatus
.u
.Status
= status
= STATUS_SUCCESS
;
464 irp
->IoStatus
.Information
= sizeof(*descriptor
);
467 case IOCTL_HID_GET_REPORT_DESCRIPTOR
:
469 DWORD length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
470 TRACE("IOCTL_HID_GET_REPORT_DESCRIPTOR\n");
472 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->get_reportdescriptor(device
, irp
->UserBuffer
, length
, &length
);
473 irp
->IoStatus
.Information
= length
;
476 case IOCTL_HID_GET_STRING
:
478 DWORD length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/ sizeof(WCHAR
);
479 DWORD index
= (ULONG_PTR
)irpsp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
480 TRACE("IOCTL_HID_GET_STRING[%08x]\n", index
);
482 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->get_string(device
, index
, (WCHAR
*)irp
->UserBuffer
, length
);
483 if (status
== STATUS_SUCCESS
)
484 irp
->IoStatus
.Information
= (strlenW((WCHAR
*)irp
->UserBuffer
) + 1) * sizeof(WCHAR
);
487 case IOCTL_HID_GET_INPUT_REPORT
:
489 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
490 TRACE_(hid_report
)("IOCTL_HID_GET_INPUT_REPORT\n");
491 EnterCriticalSection(&ext
->report_cs
);
492 status
= ext
->vtbl
->begin_report_processing(device
);
493 if (status
!= STATUS_SUCCESS
)
495 irp
->IoStatus
.u
.Status
= status
;
496 LeaveCriticalSection(&ext
->report_cs
);
500 irp
->IoStatus
.u
.Status
= status
= deliver_last_report(ext
,
501 packet
->reportBufferLen
, packet
->reportBuffer
,
502 &irp
->IoStatus
.Information
);
504 if (status
== STATUS_SUCCESS
)
505 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
506 LeaveCriticalSection(&ext
->report_cs
);
509 case IOCTL_HID_READ_REPORT
:
511 TRACE_(hid_report
)("IOCTL_HID_READ_REPORT\n");
512 EnterCriticalSection(&ext
->report_cs
);
513 status
= ext
->vtbl
->begin_report_processing(device
);
514 if (status
!= STATUS_SUCCESS
)
516 irp
->IoStatus
.u
.Status
= status
;
517 LeaveCriticalSection(&ext
->report_cs
);
520 if (!ext
->last_report_read
)
522 irp
->IoStatus
.u
.Status
= status
= deliver_last_report(ext
,
523 irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
,
524 irp
->UserBuffer
, &irp
->IoStatus
.Information
);
525 ext
->last_report_read
= TRUE
;
529 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.s
.ListEntry
);
530 status
= STATUS_PENDING
;
532 LeaveCriticalSection(&ext
->report_cs
);
535 case IOCTL_HID_SET_OUTPUT_REPORT
:
536 case IOCTL_HID_WRITE_REPORT
:
538 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
539 TRACE_(hid_report
)("IOCTL_HID_WRITE_REPORT / IOCTL_HID_SET_OUTPUT_REPORT\n");
540 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->set_output_report(
541 device
, packet
->reportId
, packet
->reportBuffer
,
542 packet
->reportBufferLen
, &irp
->IoStatus
.Information
);
545 case IOCTL_HID_GET_FEATURE
:
547 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
548 TRACE_(hid_report
)("IOCTL_HID_GET_FEATURE\n");
549 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->get_feature_report(
550 device
, packet
->reportId
, packet
->reportBuffer
,
551 packet
->reportBufferLen
, &irp
->IoStatus
.Information
);
552 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
555 case IOCTL_HID_SET_FEATURE
:
557 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
558 TRACE_(hid_report
)("IOCTL_HID_SET_FEATURE\n");
559 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->set_feature_report(
560 device
, packet
->reportId
, packet
->reportBuffer
,
561 packet
->reportBufferLen
, &irp
->IoStatus
.Information
);
566 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
567 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
568 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
573 if (status
!= STATUS_PENDING
)
574 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
579 void process_hid_report(DEVICE_OBJECT
*device
, BYTE
*report
, DWORD length
)
581 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
585 if (!length
|| !report
)
588 EnterCriticalSection(&ext
->report_cs
);
589 if (length
> ext
->buffer_size
)
591 HeapFree(GetProcessHeap(), 0, ext
->last_report
);
592 ext
->last_report
= HeapAlloc(GetProcessHeap(), 0, length
);
593 if (!ext
->last_report
)
595 ERR_(hid_report
)("Failed to alloc last report\n");
596 ext
->buffer_size
= 0;
597 ext
->last_report_size
= 0;
598 ext
->last_report_read
= TRUE
;
599 LeaveCriticalSection(&ext
->report_cs
);
603 ext
->buffer_size
= length
;
606 if (!ext
->last_report_read
)
607 ERR_(hid_report
)("Device reports coming in too fast, last report not read yet!\n");
609 memcpy(ext
->last_report
, report
, length
);
610 ext
->last_report_size
= length
;
611 ext
->last_report_read
= FALSE
;
613 while ((entry
= RemoveHeadList(&ext
->irp_queue
)) != &ext
->irp_queue
)
615 IO_STACK_LOCATION
*irpsp
;
616 TRACE_(hid_report
)("Processing Request\n");
617 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
618 irpsp
= IoGetCurrentIrpStackLocation(irp
);
619 irp
->IoStatus
.u
.Status
= deliver_last_report(ext
,
620 irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
,
621 irp
->UserBuffer
, &irp
->IoStatus
.Information
);
622 ext
->last_report_read
= TRUE
;
623 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
625 LeaveCriticalSection(&ext
->report_cs
);
628 NTSTATUS WINAPI
DriverEntry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
630 static const WCHAR udevW
[] = {'\\','D','r','i','v','e','r','\\','U','D','E','V',0};
631 static UNICODE_STRING udev
= {sizeof(udevW
) - sizeof(WCHAR
), sizeof(udevW
), (WCHAR
*)udevW
};
632 static const WCHAR iohidW
[] = {'\\','D','r','i','v','e','r','\\','I','O','H','I','D',0};
633 static UNICODE_STRING iohid
= {sizeof(iohidW
) - sizeof(WCHAR
), sizeof(iohidW
), (WCHAR
*)iohidW
};
635 TRACE( "(%p, %s)\n", driver
, debugstr_w(path
->Buffer
) );
637 IoCreateDriver(&udev
, udev_driver_init
);
638 IoCreateDriver(&iohid
, iohid_driver_init
);
640 return STATUS_SUCCESS
;