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
);
46 #define VID_MICROSOFT 0x045e
48 static const WORD PID_XBOX_CONTROLLERS
[] = {
49 0x0202, /* Xbox Controller */
50 0x0285, /* Xbox Controller S */
51 0x0289, /* Xbox Controller S */
52 0x028e, /* Xbox360 Controller */
53 0x028f, /* Xbox360 Wireless Controller */
54 0x02d1, /* Xbox One Controller */
55 0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */
56 0x02e3, /* Xbox One Elite Controller */
57 0x02e6, /* Wireless XBox Controller Dongle */
58 0x02ea, /* Xbox One S Controller */
59 0x0719, /* Xbox 360 Wireless Adapter */
65 DEVICE_OBJECT
*device
;
68 struct device_extension
70 struct pnp_device
*pnp_device
;
73 DWORD uid
, version
, index
;
76 const WCHAR
*busid
; /* Expected to be a static constant */
78 const platform_vtbl
*vtbl
;
81 DWORD last_report_size
;
82 BOOL last_report_read
;
85 CRITICAL_SECTION report_cs
;
87 BYTE platform_private
[1];
90 static CRITICAL_SECTION device_list_cs
;
91 static CRITICAL_SECTION_DEBUG critsect_debug
=
93 0, 0, &device_list_cs
,
94 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
95 0, 0, { (DWORD_PTR
)(__FILE__
": device_list_cs") }
97 static CRITICAL_SECTION device_list_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
99 static struct list pnp_devset
= LIST_INIT(pnp_devset
);
101 static const WCHAR zero_serialW
[]= {'0','0','0','0',0};
102 static const WCHAR imW
[] = {'I','M',0};
103 static const WCHAR igW
[] = {'I','G',0};
105 static inline WCHAR
*strdupW(const WCHAR
*src
)
108 if (!src
) return NULL
;
109 dst
= HeapAlloc(GetProcessHeap(), 0, (strlenW(src
) + 1)*sizeof(WCHAR
));
110 if (dst
) strcpyW(dst
, src
);
114 void *get_platform_private(DEVICE_OBJECT
*device
)
116 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
117 return ext
->platform_private
;
120 static DWORD
get_vidpid_index(WORD vid
, WORD pid
)
122 struct pnp_device
*ptr
;
125 LIST_FOR_EACH_ENTRY(ptr
, &pnp_devset
, struct pnp_device
, entry
)
127 struct device_extension
*ext
= (struct device_extension
*)ptr
->device
->DeviceExtension
;
128 if (ext
->vid
== vid
&& ext
->pid
== pid
)
129 index
= max(ext
->index
+ 1, index
);
135 static WCHAR
*get_instance_id(DEVICE_OBJECT
*device
)
137 static const WCHAR formatW
[] = {'%','s','\\','V','i','d','_','%','0','4','x','&', 'P','i','d','_','%','0','4','x','&',
138 '%','s','_','%','i','\\','%','i','&','%','s','&','%','x',0};
139 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
140 const WCHAR
*serial
= ext
->serial
? ext
->serial
: zero_serialW
;
141 DWORD len
= strlenW(ext
->busid
) + strlenW(serial
) + 64;
144 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
145 sprintfW(dst
, formatW
, ext
->busid
, ext
->vid
, ext
->pid
, ext
->is_gamepad
? igW
: imW
,
146 ext
->index
, ext
->version
, serial
, ext
->uid
);
151 static WCHAR
*get_device_id(DEVICE_OBJECT
*device
)
153 static const WCHAR formatW
[] = {'%','s','\\','V','i','d','_','%','0','4','x','&','P','i','d','_','%','0','4','x',0};
154 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
155 DWORD len
= strlenW(ext
->busid
) + 19;
158 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
159 sprintfW(dst
, formatW
, ext
->busid
, ext
->vid
, ext
->pid
);
164 static WCHAR
*get_compatible_ids(DEVICE_OBJECT
*device
)
166 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
167 WCHAR
*iid
, *did
, *dst
, *ptr
;
170 if (!(iid
= get_instance_id(device
)))
173 if (!(did
= get_device_id(device
)))
175 HeapFree(GetProcessHeap(), 0, iid
);
179 len
= strlenW(iid
) + strlenW(did
) + strlenW(ext
->busid
) + 4;
180 if ((dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
184 ptr
+= strlenW(iid
) + 1;
186 ptr
+= strlenW(did
) + 1;
187 strcpyW(ptr
, ext
->busid
);
188 ptr
+= strlenW(ext
->busid
) + 1;
192 HeapFree(GetProcessHeap(), 0, iid
);
193 HeapFree(GetProcessHeap(), 0, did
);
197 DEVICE_OBJECT
*bus_create_hid_device(DRIVER_OBJECT
*driver
, const WCHAR
*busidW
, WORD vid
, WORD pid
,
198 DWORD version
, DWORD uid
, const WCHAR
*serialW
, BOOL is_gamepad
,
199 const GUID
*class, const platform_vtbl
*vtbl
, DWORD platform_data_size
)
201 static const WCHAR device_name_fmtW
[] = {'\\','D','e','v','i','c','e','\\','%','s','#','%','p',0};
202 struct device_extension
*ext
;
203 struct pnp_device
*pnp_dev
;
204 DEVICE_OBJECT
*device
;
205 UNICODE_STRING nameW
;
211 TRACE("(%p, %s, %04x, %04x, %u, %u, %s, %u, %s, %p, %u)\n", driver
, debugstr_w(busidW
), vid
, pid
,
212 version
, uid
, debugstr_w(serialW
), is_gamepad
, debugstr_guid(class), vtbl
, platform_data_size
);
214 if (!(pnp_dev
= HeapAlloc(GetProcessHeap(), 0, sizeof(*pnp_dev
))))
217 sprintfW(dev_name
, device_name_fmtW
, busidW
, pnp_dev
);
218 RtlInitUnicodeString(&nameW
, dev_name
);
219 length
= FIELD_OFFSET(struct device_extension
, platform_private
[platform_data_size
]);
220 status
= IoCreateDevice(driver
, length
, &nameW
, 0, 0, FALSE
, &device
);
223 FIXME("failed to create device error %x\n", status
);
224 HeapFree(GetProcessHeap(), 0, pnp_dev
);
228 EnterCriticalSection(&device_list_cs
);
230 /* fill out device_extension struct */
231 ext
= (struct device_extension
*)device
->DeviceExtension
;
232 ext
->pnp_device
= pnp_dev
;
236 ext
->version
= version
;
237 ext
->index
= get_vidpid_index(vid
, pid
);
238 ext
->is_gamepad
= is_gamepad
;
239 ext
->serial
= strdupW(serialW
);
242 ext
->last_report
= NULL
;
243 ext
->last_report_size
= 0;
244 ext
->last_report_read
= TRUE
;
245 ext
->buffer_size
= 0;
247 memset(ext
->platform_private
, 0, platform_data_size
);
249 InitializeListHead(&ext
->irp_queue
);
250 InitializeCriticalSection(&ext
->report_cs
);
251 ext
->report_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": report_cs");
253 /* add to list of pnp devices */
254 pnp_dev
->device
= device
;
255 list_add_tail(&pnp_devset
, &pnp_dev
->entry
);
257 LeaveCriticalSection(&device_list_cs
);
259 devinfo
= SetupDiGetClassDevsW(class, NULL
, NULL
, DIGCF_DEVICEINTERFACE
);
262 SP_DEVINFO_DATA data
;
265 data
.cbSize
= sizeof(data
);
266 if (!(instance
= get_instance_id(device
)))
267 ERR("failed to generate instance id\n");
268 else if (!SetupDiCreateDeviceInfoW(devinfo
, instance
, class, NULL
, NULL
, DICD_INHERIT_CLASSDRVS
, &data
))
269 ERR("failed to create device info: %x\n", GetLastError());
270 else if (!SetupDiRegisterDeviceInfo(devinfo
, &data
, 0, NULL
, NULL
, NULL
))
271 ERR("failed to register device info: %x\n", GetLastError());
273 HeapFree(GetProcessHeap(), 0, instance
);
274 SetupDiDestroyDeviceInfoList(devinfo
);
277 ERR("failed to get ClassDevs: %x\n", GetLastError());
282 DEVICE_OBJECT
*bus_find_hid_device(const platform_vtbl
*vtbl
, void *platform_dev
)
284 struct pnp_device
*dev
;
285 DEVICE_OBJECT
*ret
= NULL
;
287 TRACE("(%p, %p)\n", vtbl
, platform_dev
);
289 EnterCriticalSection(&device_list_cs
);
290 LIST_FOR_EACH_ENTRY(dev
, &pnp_devset
, struct pnp_device
, entry
)
292 struct device_extension
*ext
= (struct device_extension
*)dev
->device
->DeviceExtension
;
293 if (ext
->vtbl
!= vtbl
) continue;
294 if (ext
->vtbl
->compare_platform_device(dev
->device
, platform_dev
) == 0)
300 LeaveCriticalSection(&device_list_cs
);
302 TRACE("returning %p\n", ret
);
306 DEVICE_OBJECT
* bus_enumerate_hid_devices(const platform_vtbl
*vtbl
, enum_func function
, void* context
)
308 struct pnp_device
*dev
;
309 DEVICE_OBJECT
*ret
= NULL
;
311 TRACE("(%p)\n", vtbl
);
313 EnterCriticalSection(&device_list_cs
);
314 LIST_FOR_EACH_ENTRY(dev
, &pnp_devset
, struct pnp_device
, entry
)
316 struct device_extension
*ext
= (struct device_extension
*)dev
->device
->DeviceExtension
;
317 if (ext
->vtbl
!= vtbl
) continue;
318 if (function(dev
->device
, context
) == 0)
324 LeaveCriticalSection(&device_list_cs
);
328 void bus_remove_hid_device(DEVICE_OBJECT
*device
)
330 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
331 struct pnp_device
*pnp_device
= ext
->pnp_device
;
335 TRACE("(%p)\n", device
);
337 EnterCriticalSection(&device_list_cs
);
338 list_remove(&pnp_device
->entry
);
339 LeaveCriticalSection(&device_list_cs
);
341 /* Cancel pending IRPs */
342 EnterCriticalSection(&ext
->report_cs
);
343 while ((entry
= RemoveHeadList(&ext
->irp_queue
)) != &ext
->irp_queue
)
345 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
346 irp
->IoStatus
.u
.Status
= STATUS_CANCELLED
;
347 irp
->IoStatus
.Information
= 0;
348 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
350 LeaveCriticalSection(&ext
->report_cs
);
352 ext
->report_cs
.DebugInfo
->Spare
[0] = 0;
353 DeleteCriticalSection(&ext
->report_cs
);
355 HeapFree(GetProcessHeap(), 0, ext
->serial
);
356 HeapFree(GetProcessHeap(), 0, ext
->last_report
);
357 IoDeleteDevice(device
);
359 /* pnp_device must be released after the device is gone */
360 HeapFree(GetProcessHeap(), 0, pnp_device
);
363 static NTSTATUS
handle_IRP_MN_QUERY_ID(DEVICE_OBJECT
*device
, IRP
*irp
)
365 NTSTATUS status
= irp
->IoStatus
.u
.Status
;
366 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
367 BUS_QUERY_ID_TYPE type
= irpsp
->Parameters
.QueryId
.IdType
;
369 TRACE("(%p, %p)\n", device
, irp
);
373 case BusQueryHardwareIDs
:
374 TRACE("BusQueryHardwareIDs\n");
375 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
377 case BusQueryCompatibleIDs
:
378 TRACE("BusQueryCompatibleIDs\n");
379 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
381 case BusQueryDeviceID
:
382 TRACE("BusQueryDeviceID\n");
383 irp
->IoStatus
.Information
= (ULONG_PTR
)get_device_id(device
);
385 case BusQueryInstanceID
:
386 TRACE("BusQueryInstanceID\n");
387 irp
->IoStatus
.Information
= (ULONG_PTR
)get_instance_id(device
);
390 FIXME("Unhandled type %08x\n", type
);
394 status
= irp
->IoStatus
.Information
? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
398 NTSTATUS WINAPI
common_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
400 NTSTATUS status
= irp
->IoStatus
.u
.Status
;
401 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
403 switch (irpsp
->MinorFunction
)
405 case IRP_MN_QUERY_DEVICE_RELATIONS
:
406 TRACE("IRP_MN_QUERY_DEVICE_RELATIONS\n");
408 case IRP_MN_QUERY_ID
:
409 TRACE("IRP_MN_QUERY_ID\n");
410 status
= handle_IRP_MN_QUERY_ID(device
, irp
);
411 irp
->IoStatus
.u
.Status
= status
;
413 case IRP_MN_QUERY_CAPABILITIES
:
414 TRACE("IRP_MN_QUERY_CAPABILITIES\n");
417 FIXME("Unhandled function %08x\n", irpsp
->MinorFunction
);
421 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
425 static NTSTATUS
deliver_last_report(struct device_extension
*ext
, DWORD buffer_length
, BYTE
* buffer
, ULONG_PTR
*out_length
)
427 if (buffer_length
< ext
->last_report_size
)
430 return STATUS_BUFFER_TOO_SMALL
;
434 if (ext
->last_report
)
435 memcpy(buffer
, ext
->last_report
, ext
->last_report_size
);
436 *out_length
= ext
->last_report_size
;
437 return STATUS_SUCCESS
;
441 NTSTATUS WINAPI
hid_internal_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
443 NTSTATUS status
= irp
->IoStatus
.u
.Status
;
444 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
445 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
447 TRACE("(%p, %p)\n", device
, irp
);
449 switch (irpsp
->Parameters
.DeviceIoControl
.IoControlCode
)
451 case IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
453 HID_DEVICE_ATTRIBUTES
*attr
= (HID_DEVICE_ATTRIBUTES
*)irp
->UserBuffer
;
454 TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
456 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(*attr
))
458 irp
->IoStatus
.u
.Status
= status
= STATUS_BUFFER_TOO_SMALL
;
462 memset(attr
, 0, sizeof(*attr
));
463 attr
->Size
= sizeof(*attr
);
464 attr
->VendorID
= ext
->vid
;
465 attr
->ProductID
= ext
->pid
;
466 attr
->VersionNumber
= ext
->version
;
468 irp
->IoStatus
.u
.Status
= status
= STATUS_SUCCESS
;
469 irp
->IoStatus
.Information
= sizeof(*attr
);
472 case IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
474 HID_DESCRIPTOR
*descriptor
= (HID_DESCRIPTOR
*)irp
->UserBuffer
;
476 TRACE("IOCTL_HID_GET_DEVICE_DESCRIPTOR\n");
478 if (irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(*descriptor
))
480 irp
->IoStatus
.u
.Status
= status
= STATUS_BUFFER_TOO_SMALL
;
484 status
= ext
->vtbl
->get_reportdescriptor(device
, NULL
, 0, &length
);
485 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
487 WARN("Failed to get platform report descriptor length\n");
488 irp
->IoStatus
.u
.Status
= status
;
492 memset(descriptor
, 0, sizeof(*descriptor
));
493 descriptor
->bLength
= sizeof(*descriptor
);
494 descriptor
->bDescriptorType
= HID_HID_DESCRIPTOR_TYPE
;
495 descriptor
->bcdHID
= HID_REVISION
;
496 descriptor
->bCountry
= 0;
497 descriptor
->bNumDescriptors
= 1;
498 descriptor
->DescriptorList
[0].bReportType
= HID_REPORT_DESCRIPTOR_TYPE
;
499 descriptor
->DescriptorList
[0].wReportLength
= length
;
501 irp
->IoStatus
.u
.Status
= status
= STATUS_SUCCESS
;
502 irp
->IoStatus
.Information
= sizeof(*descriptor
);
505 case IOCTL_HID_GET_REPORT_DESCRIPTOR
:
507 DWORD length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
508 TRACE("IOCTL_HID_GET_REPORT_DESCRIPTOR\n");
510 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->get_reportdescriptor(device
, irp
->UserBuffer
, length
, &length
);
511 irp
->IoStatus
.Information
= length
;
514 case IOCTL_HID_GET_STRING
:
516 DWORD length
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
/ sizeof(WCHAR
);
517 DWORD index
= (ULONG_PTR
)irpsp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
518 TRACE("IOCTL_HID_GET_STRING[%08x]\n", index
);
520 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->get_string(device
, index
, (WCHAR
*)irp
->UserBuffer
, length
);
521 if (status
== STATUS_SUCCESS
)
522 irp
->IoStatus
.Information
= (strlenW((WCHAR
*)irp
->UserBuffer
) + 1) * sizeof(WCHAR
);
525 case IOCTL_HID_GET_INPUT_REPORT
:
527 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
528 TRACE_(hid_report
)("IOCTL_HID_GET_INPUT_REPORT\n");
529 EnterCriticalSection(&ext
->report_cs
);
530 status
= ext
->vtbl
->begin_report_processing(device
);
531 if (status
!= STATUS_SUCCESS
)
533 irp
->IoStatus
.u
.Status
= status
;
534 LeaveCriticalSection(&ext
->report_cs
);
538 irp
->IoStatus
.u
.Status
= status
= deliver_last_report(ext
,
539 packet
->reportBufferLen
, packet
->reportBuffer
,
540 &irp
->IoStatus
.Information
);
542 if (status
== STATUS_SUCCESS
)
543 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
544 LeaveCriticalSection(&ext
->report_cs
);
547 case IOCTL_HID_READ_REPORT
:
549 TRACE_(hid_report
)("IOCTL_HID_READ_REPORT\n");
550 EnterCriticalSection(&ext
->report_cs
);
551 status
= ext
->vtbl
->begin_report_processing(device
);
552 if (status
!= STATUS_SUCCESS
)
554 irp
->IoStatus
.u
.Status
= status
;
555 LeaveCriticalSection(&ext
->report_cs
);
558 if (!ext
->last_report_read
)
560 irp
->IoStatus
.u
.Status
= status
= deliver_last_report(ext
,
561 irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
,
562 irp
->UserBuffer
, &irp
->IoStatus
.Information
);
563 ext
->last_report_read
= TRUE
;
567 InsertTailList(&ext
->irp_queue
, &irp
->Tail
.Overlay
.s
.ListEntry
);
568 status
= STATUS_PENDING
;
570 LeaveCriticalSection(&ext
->report_cs
);
573 case IOCTL_HID_SET_OUTPUT_REPORT
:
574 case IOCTL_HID_WRITE_REPORT
:
576 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
577 TRACE_(hid_report
)("IOCTL_HID_WRITE_REPORT / IOCTL_HID_SET_OUTPUT_REPORT\n");
578 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->set_output_report(
579 device
, packet
->reportId
, packet
->reportBuffer
,
580 packet
->reportBufferLen
, &irp
->IoStatus
.Information
);
583 case IOCTL_HID_GET_FEATURE
:
585 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
586 TRACE_(hid_report
)("IOCTL_HID_GET_FEATURE\n");
587 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->get_feature_report(
588 device
, packet
->reportId
, packet
->reportBuffer
,
589 packet
->reportBufferLen
, &irp
->IoStatus
.Information
);
590 packet
->reportBufferLen
= irp
->IoStatus
.Information
;
593 case IOCTL_HID_SET_FEATURE
:
595 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)(irp
->UserBuffer
);
596 TRACE_(hid_report
)("IOCTL_HID_SET_FEATURE\n");
597 irp
->IoStatus
.u
.Status
= status
= ext
->vtbl
->set_feature_report(
598 device
, packet
->reportId
, packet
->reportBuffer
,
599 packet
->reportBufferLen
, &irp
->IoStatus
.Information
);
604 ULONG code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
;
605 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
606 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
611 if (status
!= STATUS_PENDING
)
612 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
617 void process_hid_report(DEVICE_OBJECT
*device
, BYTE
*report
, DWORD length
)
619 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
623 if (!length
|| !report
)
626 EnterCriticalSection(&ext
->report_cs
);
627 if (length
> ext
->buffer_size
)
629 HeapFree(GetProcessHeap(), 0, ext
->last_report
);
630 ext
->last_report
= HeapAlloc(GetProcessHeap(), 0, length
);
631 if (!ext
->last_report
)
633 ERR_(hid_report
)("Failed to alloc last report\n");
634 ext
->buffer_size
= 0;
635 ext
->last_report_size
= 0;
636 ext
->last_report_read
= TRUE
;
637 LeaveCriticalSection(&ext
->report_cs
);
641 ext
->buffer_size
= length
;
644 memcpy(ext
->last_report
, report
, length
);
645 ext
->last_report_size
= length
;
646 ext
->last_report_read
= FALSE
;
648 while ((entry
= RemoveHeadList(&ext
->irp_queue
)) != &ext
->irp_queue
)
650 IO_STACK_LOCATION
*irpsp
;
651 TRACE_(hid_report
)("Processing Request\n");
652 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.s
.ListEntry
);
653 irpsp
= IoGetCurrentIrpStackLocation(irp
);
654 irp
->IoStatus
.u
.Status
= deliver_last_report(ext
,
655 irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
,
656 irp
->UserBuffer
, &irp
->IoStatus
.Information
);
657 ext
->last_report_read
= TRUE
;
658 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
660 LeaveCriticalSection(&ext
->report_cs
);
663 DWORD
check_bus_option(UNICODE_STRING
*registry_path
, const UNICODE_STRING
*option
, DWORD default_value
)
665 OBJECT_ATTRIBUTES attr
;
667 DWORD output
= default_value
;
669 InitializeObjectAttributes(&attr
, registry_path
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
670 if (NtOpenKey(&key
, KEY_ALL_ACCESS
, &attr
) == STATUS_SUCCESS
)
673 char buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(DWORD
)])];
675 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
677 if (NtQueryValueKey(key
, option
, KeyValuePartialInformation
, info
, sizeof(buffer
), &size
) == STATUS_SUCCESS
)
679 if (info
->Type
== REG_DWORD
)
680 output
= *(DWORD
*)info
->Data
;
689 BOOL
is_xbox_gamepad(WORD vid
, WORD pid
)
693 if (vid
!= VID_MICROSOFT
)
696 for (i
= 0; i
< ARRAY_SIZE(PID_XBOX_CONTROLLERS
); i
++)
697 if (pid
== PID_XBOX_CONTROLLERS
[i
]) return TRUE
;
702 NTSTATUS WINAPI
DriverEntry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
704 static const WCHAR udevW
[] = {'\\','D','r','i','v','e','r','\\','U','D','E','V',0};
705 static UNICODE_STRING udev
= {sizeof(udevW
) - sizeof(WCHAR
), sizeof(udevW
), (WCHAR
*)udevW
};
706 static const WCHAR iohidW
[] = {'\\','D','r','i','v','e','r','\\','I','O','H','I','D',0};
707 static UNICODE_STRING iohid
= {sizeof(iohidW
) - sizeof(WCHAR
), sizeof(iohidW
), (WCHAR
*)iohidW
};
708 static const WCHAR sdlW
[] = {'\\','D','r','i','v','e','r','\\','S','D','L','J','O','Y',0};
709 static UNICODE_STRING sdl
= {sizeof(sdlW
) - sizeof(WCHAR
), sizeof(sdlW
), (WCHAR
*)sdlW
};
710 static const WCHAR SDL_enabledW
[] = {'E','n','a','b','l','e',' ','S','D','L',0};
711 static const UNICODE_STRING SDL_enabled
= {sizeof(SDL_enabledW
) - sizeof(WCHAR
), sizeof(SDL_enabledW
), (WCHAR
*)SDL_enabledW
};
713 TRACE( "(%p, %s)\n", driver
, debugstr_w(path
->Buffer
) );
715 if (check_bus_option(path
, &SDL_enabled
, 1))
717 if (IoCreateDriver(&sdl
, sdl_driver_init
) == STATUS_SUCCESS
)
718 return STATUS_SUCCESS
;
720 IoCreateDriver(&udev
, udev_driver_init
);
721 IoCreateDriver(&iohid
, iohid_driver_init
);
723 return STATUS_SUCCESS
;