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
25 #define WIN32_NO_STATUS
33 #include "ddk/hidport.h"
34 #include "ddk/hidtypes.h"
35 #include "ddk/hidpddi.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "wine/unixlib.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
45 static DRIVER_OBJECT
*driver_obj
;
47 static DEVICE_OBJECT
*mouse_obj
;
48 static DEVICE_OBJECT
*keyboard_obj
;
50 /* The root-enumerated device stack. */
51 static DEVICE_OBJECT
*bus_pdo
;
52 static DEVICE_OBJECT
*bus_fdo
;
54 static HANDLE driver_key
;
70 #define HIDRAW_FIXUP_DUALSHOCK_BT 0x1
71 #define HIDRAW_FIXUP_DUALSENSE_BT 0x2
73 struct device_extension
76 DEVICE_OBJECT
*device
;
79 enum device_state state
;
81 struct device_desc desc
;
85 UINT report_desc_length
;
86 HIDP_DEVICE_DESC collection_desc
;
88 struct hid_report
*last_reports
[256];
96 static CRITICAL_SECTION device_list_cs
;
97 static CRITICAL_SECTION_DEBUG critsect_debug
=
99 0, 0, &device_list_cs
,
100 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
101 0, 0, { (DWORD_PTR
)(__FILE__
": device_list_cs") }
103 static CRITICAL_SECTION device_list_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
105 static struct list device_list
= LIST_INIT(device_list
);
107 static NTSTATUS
winebus_call(unsigned int code
, void *args
)
109 return WINE_UNIX_CALL(code
, args
);
112 static void unix_device_remove(DEVICE_OBJECT
*device
)
114 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
115 struct device_remove_params params
= {.device
= ext
->unix_device
};
116 winebus_call(device_remove
, ¶ms
);
119 static NTSTATUS
unix_device_start(DEVICE_OBJECT
*device
)
121 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
122 struct device_start_params params
= {.device
= ext
->unix_device
};
123 return winebus_call(device_start
, ¶ms
);
126 static void unix_device_set_output_report(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
, IO_STATUS_BLOCK
*io
)
128 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
129 struct device_report_params params
=
131 .device
= ext
->unix_device
,
135 winebus_call(device_set_output_report
, ¶ms
);
138 static void unix_device_get_feature_report(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
, IO_STATUS_BLOCK
*io
)
140 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
141 struct device_report_params params
=
143 .device
= ext
->unix_device
,
147 winebus_call(device_get_feature_report
, ¶ms
);
150 static void unix_device_set_feature_report(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
, IO_STATUS_BLOCK
*io
)
152 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
153 struct device_report_params params
=
155 .device
= ext
->unix_device
,
159 winebus_call(device_set_feature_report
, ¶ms
);
162 static DWORD
get_device_index(struct device_desc
*desc
)
164 struct device_extension
*ext
;
167 LIST_FOR_EACH_ENTRY(ext
, &device_list
, struct device_extension
, entry
)
169 if (ext
->desc
.vid
== desc
->vid
&& ext
->desc
.pid
== desc
->pid
&& ext
->desc
.input
== desc
->input
)
170 index
= max(ext
->index
+ 1, index
);
176 static WCHAR
*get_instance_id(DEVICE_OBJECT
*device
)
178 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
179 DWORD len
= wcslen(ext
->desc
.serialnumber
) + 33;
182 if ((dst
= ExAllocatePool(PagedPool
, len
* sizeof(WCHAR
))))
184 swprintf(dst
, len
, L
"%u&%s&%x&%u&%u", ext
->desc
.version
, ext
->desc
.serialnumber
,
185 ext
->desc
.uid
, ext
->index
, ext
->desc
.is_gamepad
);
191 static WCHAR
*get_device_id(DEVICE_OBJECT
*device
)
193 static const WCHAR input_format
[] = L
"&MI_%02u";
194 static const WCHAR winebus_format
[] = L
"WINEBUS\\VID_%04X&PID_%04X";
195 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
196 DWORD pos
= 0, len
= 0, input_len
= 0, winebus_len
= 25;
199 if (ext
->desc
.input
!= -1) input_len
= 14;
201 len
+= winebus_len
+ input_len
+ 1;
203 if ((dst
= ExAllocatePool(PagedPool
, len
* sizeof(WCHAR
))))
205 pos
+= swprintf(dst
+ pos
, len
- pos
, winebus_format
, ext
->desc
.vid
, ext
->desc
.pid
);
206 if (input_len
) pos
+= swprintf(dst
+ pos
, len
- pos
, input_format
, ext
->desc
.input
);
212 static WCHAR
*get_hardware_ids(DEVICE_OBJECT
*device
)
214 static const WCHAR input_format
[] = L
"&MI_%02u";
215 static const WCHAR winebus_format
[] = L
"WINEBUS\\VID_%04X&PID_%04X";
216 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
217 DWORD pos
= 0, len
= 0, input_len
= 0, winebus_len
= 25;
220 if (ext
->desc
.input
!= -1) input_len
= 14;
222 len
+= winebus_len
+ input_len
+ 1;
224 if ((dst
= ExAllocatePool(PagedPool
, (len
+ 1) * sizeof(WCHAR
))))
226 pos
+= swprintf(dst
+ pos
, len
- pos
, winebus_format
, ext
->desc
.vid
, ext
->desc
.pid
);
227 if (input_len
) pos
+= swprintf(dst
+ pos
, len
- pos
, input_format
, ext
->desc
.input
);
235 static WCHAR
*get_compatible_ids(DEVICE_OBJECT
*device
)
237 static const WCHAR xinput_compat
[] = L
"WINEBUS\\WINE_COMP_XINPUT";
238 static const WCHAR hid_compat
[] = L
"WINEBUS\\WINE_COMP_HID";
239 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
240 DWORD size
= sizeof(hid_compat
);
243 if (ext
->desc
.is_gamepad
) size
+= sizeof(xinput_compat
);
245 if ((dst
= ExAllocatePool(PagedPool
, size
+ sizeof(WCHAR
))))
247 if (ext
->desc
.is_gamepad
) memcpy(dst
, xinput_compat
, sizeof(xinput_compat
));
248 memcpy((char *)dst
+ size
- sizeof(hid_compat
), hid_compat
, sizeof(hid_compat
));
249 dst
[size
/ sizeof(WCHAR
)] = 0;
255 static IRP
*pop_pending_read(struct device_extension
*ext
)
259 RtlEnterCriticalSection(&ext
->cs
);
260 pending
= ext
->pending_read
;
261 ext
->pending_read
= NULL
;
262 RtlLeaveCriticalSection(&ext
->cs
);
267 static void remove_pending_irps(DEVICE_OBJECT
*device
)
269 struct device_extension
*ext
= device
->DeviceExtension
;
272 if ((pending
= pop_pending_read(ext
)))
274 pending
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
275 pending
->IoStatus
.Information
= 0;
276 IoCompleteRequest(pending
, IO_NO_INCREMENT
);
280 static DEVICE_OBJECT
*bus_create_hid_device(struct device_desc
*desc
, UINT64 unix_device
)
282 struct device_extension
*ext
;
283 DEVICE_OBJECT
*device
;
284 UNICODE_STRING nameW
;
288 TRACE("desc %s, unix_device %#I64x\n", debugstr_device_desc(desc
), unix_device
);
290 swprintf(dev_name
, ARRAY_SIZE(dev_name
), L
"\\Device\\WINEBUS#%p", unix_device
);
291 RtlInitUnicodeString(&nameW
, dev_name
);
292 status
= IoCreateDevice(driver_obj
, sizeof(struct device_extension
), &nameW
, 0, 0, FALSE
, &device
);
295 FIXME("failed to create device error %#lx\n", status
);
299 RtlEnterCriticalSection(&device_list_cs
);
301 /* fill out device_extension struct */
302 ext
= (struct device_extension
*)device
->DeviceExtension
;
303 ext
->device
= device
;
305 ext
->index
= get_device_index(desc
);
306 ext
->unix_device
= unix_device
;
307 list_init(&ext
->reports
);
309 if (desc
->is_hidraw
&& desc
->is_bluetooth
&& is_dualshock4_gamepad(desc
->vid
, desc
->pid
))
311 TRACE("Enabling report fixup for Bluetooth DualShock4 device %p\n", device
);
312 ext
->report_fixups
|= HIDRAW_FIXUP_DUALSHOCK_BT
;
314 if (desc
->is_hidraw
&& desc
->is_bluetooth
&& is_dualsense_gamepad(desc
->vid
, desc
->pid
))
316 TRACE("Enabling report fixup for Bluetooth DualSense device %p\n", device
);
317 ext
->report_fixups
|= HIDRAW_FIXUP_DUALSENSE_BT
;
320 InitializeCriticalSectionEx(&ext
->cs
, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
);
321 ext
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
323 /* add to list of pnp devices */
324 list_add_tail(&device_list
, &ext
->entry
);
326 RtlLeaveCriticalSection(&device_list_cs
);
328 TRACE("created device %p/%#I64x\n", device
, unix_device
);
332 static DEVICE_OBJECT
*bus_find_unix_device(UINT64 unix_device
)
334 struct device_extension
*ext
;
336 LIST_FOR_EACH_ENTRY(ext
, &device_list
, struct device_extension
, entry
)
337 if (ext
->unix_device
== unix_device
) return ext
->device
;
342 static void bus_unlink_hid_device(DEVICE_OBJECT
*device
)
344 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
346 RtlEnterCriticalSection(&device_list_cs
);
347 list_remove(&ext
->entry
);
348 RtlLeaveCriticalSection(&device_list_cs
);
351 #ifdef __ASM_USE_FASTCALL_WRAPPER
352 extern void * WINAPI
wrap_fastcall_func1(void *func
, const void *a
);
353 __ASM_STDCALL_FUNC(wrap_fastcall_func1
, 8,
356 "xchgl (%esp),%ecx\n\t"
358 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
360 #define call_fastcall_func1(func,a) func(a)
363 static NTSTATUS
build_device_relations(DEVICE_RELATIONS
**devices
)
365 struct device_extension
*ext
;
368 RtlEnterCriticalSection(&device_list_cs
);
369 *devices
= ExAllocatePool(PagedPool
, offsetof(DEVICE_RELATIONS
, Objects
[list_count(&device_list
)]));
373 RtlLeaveCriticalSection(&device_list_cs
);
374 return STATUS_INSUFFICIENT_RESOURCES
;
378 LIST_FOR_EACH_ENTRY(ext
, &device_list
, struct device_extension
, entry
)
380 (*devices
)->Objects
[i
] = ext
->device
;
381 call_fastcall_func1(ObfReferenceObject
, ext
->device
);
384 RtlLeaveCriticalSection(&device_list_cs
);
385 (*devices
)->Count
= i
;
386 return STATUS_SUCCESS
;
389 static DWORD
check_bus_option(const WCHAR
*option
, DWORD default_value
)
391 char buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(DWORD
)])];
392 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
396 RtlInitUnicodeString(&str
, option
);
398 if (NtQueryValueKey(driver_key
, &str
, KeyValuePartialInformation
, info
, sizeof(buffer
), &size
) == STATUS_SUCCESS
)
400 if (info
->Type
== REG_DWORD
) return *(DWORD
*)info
->Data
;
403 return default_value
;
406 static BOOL
is_hidraw_enabled(WORD vid
, WORD pid
, const USAGE_AND_PAGE
*usages
)
408 char buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024])];
409 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
410 WCHAR vidpid
[MAX_PATH
], *tmp
;
411 BOOL prefer_hidraw
= FALSE
;
415 if (check_bus_option(L
"DisableHidraw", FALSE
)) return FALSE
;
416 if (usages
->UsagePage
!= HID_USAGE_PAGE_GENERIC
) return TRUE
;
417 if (usages
->Usage
!= HID_USAGE_GENERIC_GAMEPAD
&& usages
->Usage
!= HID_USAGE_GENERIC_JOYSTICK
) return TRUE
;
419 if (!check_bus_option(L
"Enable SDL", 1) && check_bus_option(L
"DisableInput", 0))
420 prefer_hidraw
= TRUE
;
422 if (is_dualshock4_gamepad(vid
, pid
)) prefer_hidraw
= TRUE
;
423 if (is_dualsense_gamepad(vid
, pid
)) prefer_hidraw
= TRUE
;
425 RtlInitUnicodeString(&str
, L
"EnableHidraw");
426 if (!NtQueryValueKey(driver_key
, &str
, KeyValuePartialInformation
, info
,
427 sizeof(buffer
) - sizeof(WCHAR
), &size
))
429 UINT len
= swprintf(vidpid
, ARRAY_SIZE(vidpid
), L
"%04X:%04X", vid
, pid
);
430 size
-= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
431 tmp
= (WCHAR
*)info
->Data
;
433 while (size
>= len
* sizeof(WCHAR
))
435 if (!wcsnicmp(tmp
, vidpid
, len
)) prefer_hidraw
= TRUE
;
436 size
-= (len
+ 1) * sizeof(WCHAR
);
441 return prefer_hidraw
;
444 static BOOL
deliver_next_report(struct device_extension
*ext
, IRP
*irp
)
446 struct hid_report
*report
;
450 if (!(entry
= list_head(&ext
->reports
))) return FALSE
;
451 report
= LIST_ENTRY(entry
, struct hid_report
, entry
);
452 list_remove(&report
->entry
);
454 memcpy(irp
->UserBuffer
, report
->buffer
, report
->length
);
455 irp
->IoStatus
.Information
= report
->length
;
456 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
460 TRACE("device %p/%#I64x input report length %lu:\n", ext
->device
, ext
->unix_device
, report
->length
);
461 for (i
= 0; i
< report
->length
;)
463 char buffer
[256], *buf
= buffer
;
464 buf
+= sprintf(buf
, "%08lx ", i
);
465 do { buf
+= sprintf(buf
, " %02x", report
->buffer
[i
]); }
466 while (++i
% 16 && i
< report
->length
);
467 TRACE("%s\n", buffer
);
471 RtlFreeHeap(GetProcessHeap(), 0, report
);
475 static void process_hid_report(DEVICE_OBJECT
*device
, BYTE
*report_buf
, DWORD report_len
)
477 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
478 ULONG size
= offsetof(struct hid_report
, buffer
[report_len
]);
479 struct hid_report
*report
, *last_report
;
482 if (!(report
= RtlAllocateHeap(GetProcessHeap(), 0, size
))) return;
483 memcpy(report
->buffer
, report_buf
, report_len
);
484 report
->length
= report_len
;
486 if (ext
->report_fixups
& HIDRAW_FIXUP_DUALSHOCK_BT
)
488 /* As described in the Linux kernel driver, when connected over bluetooth, DS4 controllers
489 * start sending input through report #17 as soon as they receive a feature report #2, which
490 * the kernel sends anyway for calibration.
492 * Input report #17 is the same as the default input report #1, with additional gyro data and
493 * two additional bytes in front, but is only described as vendor specific in the report descriptor,
494 * and applications aren't expecting it.
496 * We have to translate it to input report #1, like native driver does.
498 if (report
->buffer
[0] == 0x11 && report
->length
>= 12)
500 memmove(report
->buffer
, report
->buffer
+ 2, 10);
501 report
->buffer
[0] = 1; /* fake report #1 */
506 if (ext
->report_fixups
& HIDRAW_FIXUP_DUALSENSE_BT
)
508 /* The behavior of DualSense is very similar to DS4 described above with a few exceptions.
510 * The report number #41 is used for the extended bluetooth input report. The report comes
511 * with only one extra byte in front and the format is not exactly the same as the one used
512 * for the report #1 so we need to shuffle a few bytes around.
515 * X Y Z RZ Buttons[3] TriggerLeft TriggerRight
517 * Extended #41 report:
518 * Prefix X Y Z Rz TriggerLeft TriggerRight Counter Buttons[3] ...
520 if (report
->buffer
[0] == 0x31 && report
->length
>= 11)
524 memmove(report
->buffer
, report
->buffer
+ 1, 10);
525 report
->buffer
[0] = 1; /* fake report #1 */
528 trigger
[0] = report
->buffer
[5]; /* TriggerLeft*/
529 trigger
[1] = report
->buffer
[6]; /* TriggerRight */
531 report
->buffer
[5] = report
->buffer
[8]; /* Buttons[0] */
532 report
->buffer
[6] = report
->buffer
[9]; /* Buttons[1] */
533 report
->buffer
[7] = report
->buffer
[10]; /* Buttons[2] */
534 report
->buffer
[8] = trigger
[0]; /* TriggerLeft */
535 report
->buffer
[9] = trigger
[1]; /* TirggerRight */
539 RtlEnterCriticalSection(&ext
->cs
);
540 list_add_tail(&ext
->reports
, &report
->entry
);
542 if (!ext
->collection_desc
.ReportIDs
[0].ReportID
) last_report
= ext
->last_reports
[0];
543 else last_report
= ext
->last_reports
[report_buf
[0]];
544 memcpy(last_report
->buffer
, report_buf
, report_len
);
546 if ((irp
= pop_pending_read(ext
)))
548 deliver_next_report(ext
, irp
);
549 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
551 RtlLeaveCriticalSection(&ext
->cs
);
554 static NTSTATUS
handle_IRP_MN_QUERY_DEVICE_RELATIONS(IRP
*irp
)
556 NTSTATUS status
= irp
->IoStatus
.Status
;
557 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
559 TRACE("IRP_MN_QUERY_DEVICE_RELATIONS\n");
560 switch (irpsp
->Parameters
.QueryDeviceRelations
.Type
)
562 case EjectionRelations
:
563 case RemovalRelations
:
564 case TargetDeviceRelation
:
566 FIXME("Unhandled Device Relation %x\n",irpsp
->Parameters
.QueryDeviceRelations
.Type
);
569 status
= build_device_relations((DEVICE_RELATIONS
**)&irp
->IoStatus
.Information
);
572 FIXME("Unknown Device Relation %x\n",irpsp
->Parameters
.QueryDeviceRelations
.Type
);
579 static NTSTATUS
handle_IRP_MN_QUERY_ID(DEVICE_OBJECT
*device
, IRP
*irp
)
581 NTSTATUS status
= irp
->IoStatus
.Status
;
582 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
583 BUS_QUERY_ID_TYPE type
= irpsp
->Parameters
.QueryId
.IdType
;
585 TRACE("(%p, %p)\n", device
, irp
);
589 case BusQueryHardwareIDs
:
590 TRACE("BusQueryHardwareIDs\n");
591 irp
->IoStatus
.Information
= (ULONG_PTR
)get_hardware_ids(device
);
593 case BusQueryCompatibleIDs
:
594 TRACE("BusQueryCompatibleIDs\n");
595 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
597 case BusQueryDeviceID
:
598 TRACE("BusQueryDeviceID\n");
599 irp
->IoStatus
.Information
= (ULONG_PTR
)get_device_id(device
);
601 case BusQueryInstanceID
:
602 TRACE("BusQueryInstanceID\n");
603 irp
->IoStatus
.Information
= (ULONG_PTR
)get_instance_id(device
);
606 WARN("Unhandled type %08x\n", type
);
610 status
= irp
->IoStatus
.Information
? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
614 static void mouse_device_create(void)
616 struct device_create_params params
= {{0}};
618 if (winebus_call(mouse_create
, ¶ms
)) return;
619 mouse_obj
= bus_create_hid_device(¶ms
.desc
, params
.device
);
620 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
623 static void keyboard_device_create(void)
625 struct device_create_params params
= {{0}};
627 if (winebus_call(keyboard_create
, ¶ms
)) return;
628 keyboard_obj
= bus_create_hid_device(¶ms
.desc
, params
.device
);
629 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
632 static NTSTATUS
get_device_descriptors(UINT64 unix_device
, BYTE
**report_desc
, UINT
*report_desc_length
,
633 HIDP_DEVICE_DESC
*device_desc
)
635 struct device_descriptor_params params
=
637 .device
= unix_device
,
638 .out_length
= report_desc_length
,
642 status
= winebus_call(device_get_report_descriptor
, ¶ms
);
643 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
645 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device
, status
);
649 if (!(params
.buffer
= RtlAllocateHeap(GetProcessHeap(), 0, *report_desc_length
)))
650 return STATUS_NO_MEMORY
;
651 params
.length
= *report_desc_length
;
653 if ((status
= winebus_call(device_get_report_descriptor
, ¶ms
)))
655 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device
, status
);
656 RtlFreeHeap(GetProcessHeap(), 0, params
.buffer
);
660 params
.length
= *report_desc_length
;
661 status
= HidP_GetCollectionDescription(params
.buffer
, params
.length
, PagedPool
, device_desc
);
662 if (status
!= HIDP_STATUS_SUCCESS
)
664 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device
, status
);
665 RtlFreeHeap(GetProcessHeap(), 0, params
.buffer
);
669 *report_desc
= params
.buffer
;
670 return STATUS_SUCCESS
;
673 static USAGE_AND_PAGE
get_hidraw_device_usages(UINT64 unix_device
)
675 HIDP_DEVICE_DESC device_desc
;
676 USAGE_AND_PAGE usages
= {0};
677 UINT report_desc_length
;
681 if (!(status
= get_device_descriptors(unix_device
, &report_desc
, &report_desc_length
, &device_desc
)))
683 usages
.UsagePage
= device_desc
.CollectionDesc
[0].UsagePage
;
684 usages
.Usage
= device_desc
.CollectionDesc
[0].Usage
;
685 HidP_FreeCollectionDescription(&device_desc
);
686 RtlFreeHeap(GetProcessHeap(), 0, report_desc
);
692 static DWORD bus_count
;
693 static HANDLE bus_thread
[16];
695 struct bus_main_params
701 NTSTATUS
*init_status
;
702 unsigned int init_code
;
703 unsigned int wait_code
;
704 struct bus_event
*bus_event
;
707 static DWORD CALLBACK
bus_main_thread(void *args
)
709 struct bus_main_params bus
= *(struct bus_main_params
*)args
;
710 DEVICE_OBJECT
*device
;
713 TRACE("%s main loop starting\n", debugstr_w(bus
.name
));
714 status
= winebus_call(bus
.init_code
, bus
.init_args
);
715 *bus
.init_status
= status
;
716 SetEvent(bus
.init_done
);
717 TRACE("%s main loop started\n", debugstr_w(bus
.name
));
719 bus
.bus_event
->type
= BUS_EVENT_TYPE_NONE
;
720 if (status
) WARN("%s bus init returned status %#lx\n", debugstr_w(bus
.name
), status
);
721 else while ((status
= winebus_call(bus
.wait_code
, bus
.bus_event
)) == STATUS_PENDING
)
723 struct bus_event
*event
= bus
.bus_event
;
726 case BUS_EVENT_TYPE_NONE
: break;
727 case BUS_EVENT_TYPE_DEVICE_REMOVED
:
728 RtlEnterCriticalSection(&device_list_cs
);
729 device
= bus_find_unix_device(event
->device
);
730 if (!device
) WARN("could not find device for %s bus device %#I64x\n", debugstr_w(bus
.name
), event
->device
);
731 else bus_unlink_hid_device(device
);
732 RtlLeaveCriticalSection(&device_list_cs
);
733 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
735 case BUS_EVENT_TYPE_DEVICE_CREATED
:
737 struct device_desc desc
= event
->device_created
.desc
;
738 if (desc
.is_hidraw
&& !desc
.usages
.UsagePage
) desc
.usages
= get_hidraw_device_usages(event
->device
);
739 if (!desc
.is_hidraw
!= !is_hidraw_enabled(desc
.vid
, desc
.pid
, &desc
.usages
))
741 struct device_remove_params params
= {.device
= event
->device
};
742 WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc
.is_hidraw
? "" : "non-",
743 desc
.vid
, desc
.pid
, desc
.usages
.UsagePage
, desc
.usages
.Usage
);
744 winebus_call(device_remove
, ¶ms
);
748 TRACE("creating %shidraw device %04x:%04x with usages %04x:%04x\n", desc
.is_hidraw
? "" : "non-",
749 desc
.vid
, desc
.pid
, desc
.usages
.UsagePage
, desc
.usages
.Usage
);
751 device
= bus_create_hid_device(&event
->device_created
.desc
, event
->device
);
752 if (device
) IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
755 struct device_remove_params params
= {.device
= event
->device
};
756 WARN("failed to create device for %s bus device %#I64x\n", debugstr_w(bus
.name
), event
->device
);
757 winebus_call(device_remove
, ¶ms
);
761 case BUS_EVENT_TYPE_INPUT_REPORT
:
762 RtlEnterCriticalSection(&device_list_cs
);
763 device
= bus_find_unix_device(event
->device
);
764 if (!device
) WARN("could not find device for %s bus device %#I64x\n", debugstr_w(bus
.name
), event
->device
);
765 else process_hid_report(device
, event
->input_report
.buffer
, event
->input_report
.length
);
766 RtlLeaveCriticalSection(&device_list_cs
);
771 if (status
) WARN("%s bus wait returned status %#lx\n", debugstr_w(bus
.name
), status
);
772 else TRACE("%s main loop exited\n", debugstr_w(bus
.name
));
773 RtlFreeHeap(GetProcessHeap(), 0, bus
.bus_event
);
777 static NTSTATUS
bus_main_thread_start(struct bus_main_params
*bus
)
779 DWORD i
= bus_count
++, max_size
;
782 if (!(bus
->init_done
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
)))
784 ERR("failed to create %s bus init done event.\n", debugstr_w(bus
->name
));
786 return STATUS_UNSUCCESSFUL
;
789 max_size
= offsetof(struct bus_event
, input_report
.buffer
[0x10000]);
790 if (!(bus
->bus_event
= RtlAllocateHeap(GetProcessHeap(), 0, max_size
)))
792 ERR("failed to allocate %s bus event.\n", debugstr_w(bus
->name
));
793 CloseHandle(bus
->init_done
);
795 return STATUS_UNSUCCESSFUL
;
798 bus
->init_status
= &status
;
799 if (!(bus_thread
[i
] = CreateThread(NULL
, 0, bus_main_thread
, bus
, 0, NULL
)))
801 ERR("failed to create %s bus thread.\n", debugstr_w(bus
->name
));
802 CloseHandle(bus
->init_done
);
804 return STATUS_UNSUCCESSFUL
;
807 WaitForSingleObject(bus
->init_done
, INFINITE
);
808 CloseHandle(bus
->init_done
);
812 static void sdl_bus_free_mappings(struct sdl_bus_options
*options
)
814 DWORD count
= options
->mappings_count
;
815 char **mappings
= options
->mappings
;
817 while (count
) RtlFreeHeap(GetProcessHeap(), 0, mappings
[--count
]);
818 RtlFreeHeap(GetProcessHeap(), 0, mappings
);
821 static void sdl_bus_load_mappings(struct sdl_bus_options
*options
)
823 ULONG idx
= 0, len
, count
= 0, capacity
, info_size
, info_max_size
;
824 UNICODE_STRING path
= RTL_CONSTANT_STRING(L
"map");
825 KEY_VALUE_FULL_INFORMATION
*info
;
826 OBJECT_ATTRIBUTES attr
= {0};
827 char **mappings
= NULL
;
831 options
->mappings_count
= 0;
832 options
->mappings
= NULL
;
834 InitializeObjectAttributes(&attr
, &path
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, driver_key
, NULL
);
835 status
= NtOpenKey(&key
, KEY_ALL_ACCESS
, &attr
);
839 mappings
= RtlAllocateHeap(GetProcessHeap(), 0, capacity
* sizeof(*mappings
));
840 info_max_size
= offsetof(KEY_VALUE_FULL_INFORMATION
, Name
) + 512;
841 info
= RtlAllocateHeap(GetProcessHeap(), 0, info_max_size
);
843 while (!status
&& info
&& mappings
)
845 status
= NtEnumerateValueKey(key
, idx
, KeyValueFullInformation
, info
, info_max_size
, &info_size
);
846 while (status
== STATUS_BUFFER_OVERFLOW
)
848 info_max_size
= info_size
;
849 if (!(info
= RtlReAllocateHeap(GetProcessHeap(), 0, info
, info_max_size
))) break;
850 status
= NtEnumerateValueKey(key
, idx
, KeyValueFullInformation
, info
, info_max_size
, &info_size
);
853 if (status
== STATUS_NO_MORE_ENTRIES
)
855 options
->mappings_count
= count
;
856 options
->mappings
= mappings
;
862 if (info
->Type
!= REG_SZ
) continue;
864 RtlUnicodeToMultiByteSize(&len
, (WCHAR
*)((char *)info
+ info
->DataOffset
), info_size
- info
->DataOffset
);
867 if (!(mappings
[count
++] = RtlAllocateHeap(GetProcessHeap(), 0, len
+ 1))) break;
868 if (count
> capacity
)
870 capacity
= capacity
* 3 / 2;
871 if (!(mappings
= RtlReAllocateHeap(GetProcessHeap(), 0, mappings
, capacity
* sizeof(*mappings
))))
875 RtlUnicodeToMultiByteN(mappings
[count
], len
, NULL
, (WCHAR
*)((char *)info
+ info
->DataOffset
),
876 info_size
- info
->DataOffset
);
877 if (mappings
[len
- 1]) mappings
[len
] = 0;
880 if (mappings
) while (count
) RtlFreeHeap(GetProcessHeap(), 0, mappings
[--count
]);
881 RtlFreeHeap(GetProcessHeap(), 0, mappings
);
884 RtlFreeHeap(GetProcessHeap(), 0, info
);
888 static NTSTATUS
sdl_driver_init(void)
890 struct sdl_bus_options bus_options
;
891 struct bus_main_params bus
=
894 .init_args
= &bus_options
,
895 .init_code
= sdl_init
,
896 .wait_code
= sdl_wait
,
900 bus_options
.split_controllers
= check_bus_option(L
"Split Controllers", 0);
901 if (bus_options
.split_controllers
) TRACE("SDL controller splitting enabled\n");
902 bus_options
.map_controllers
= check_bus_option(L
"Map Controllers", 1);
903 if (!bus_options
.map_controllers
) TRACE("SDL controller to XInput HID gamepad mapping disabled\n");
904 sdl_bus_load_mappings(&bus_options
);
906 status
= bus_main_thread_start(&bus
);
907 sdl_bus_free_mappings(&bus_options
);
911 static NTSTATUS
udev_driver_init(BOOL enable_sdl
)
913 struct udev_bus_options bus_options
;
914 struct bus_main_params bus
=
917 .init_args
= &bus_options
,
918 .init_code
= udev_init
,
919 .wait_code
= udev_wait
,
922 bus_options
.disable_hidraw
= check_bus_option(L
"DisableHidraw", 0);
923 if (bus_options
.disable_hidraw
) TRACE("UDEV hidraw devices disabled in registry\n");
924 bus_options
.disable_input
= check_bus_option(L
"DisableInput", 0) || enable_sdl
;
925 if (bus_options
.disable_input
) TRACE("UDEV input devices disabled in registry\n");
926 bus_options
.disable_udevd
= check_bus_option(L
"DisableUdevd", 0);
927 if (bus_options
.disable_udevd
) TRACE("UDEV udevd use disabled in registry\n");
929 return bus_main_thread_start(&bus
);
932 static NTSTATUS
iohid_driver_init(void)
934 struct iohid_bus_options bus_options
;
935 struct bus_main_params bus
=
938 .init_args
= &bus_options
,
939 .init_code
= iohid_init
,
940 .wait_code
= iohid_wait
,
943 if (check_bus_option(L
"DisableHidraw", FALSE
))
945 TRACE("IOHID hidraw devices disabled in registry\n");
946 return STATUS_SUCCESS
;
949 return bus_main_thread_start(&bus
);
952 static NTSTATUS
fdo_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
954 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
958 switch (irpsp
->MinorFunction
)
960 case IRP_MN_QUERY_DEVICE_RELATIONS
:
961 irp
->IoStatus
.Status
= handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp
);
963 case IRP_MN_START_DEVICE
:
964 mouse_device_create();
965 keyboard_device_create();
967 if ((enable_sdl
= check_bus_option(L
"Enable SDL", 1)))
968 enable_sdl
= !sdl_driver_init();
969 udev_driver_init(enable_sdl
);
972 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
974 case IRP_MN_SURPRISE_REMOVAL
:
975 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
977 case IRP_MN_REMOVE_DEVICE
:
978 winebus_call(sdl_stop
, NULL
);
979 winebus_call(udev_stop
, NULL
);
980 winebus_call(iohid_stop
, NULL
);
982 WaitForMultipleObjects(bus_count
, bus_thread
, TRUE
, INFINITE
);
983 while (bus_count
--) CloseHandle(bus_thread
[bus_count
]);
985 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
986 IoSkipCurrentIrpStackLocation(irp
);
987 ret
= IoCallDriver(bus_pdo
, irp
);
988 IoDetachDevice(bus_pdo
);
989 IoDeleteDevice(device
);
992 FIXME("Unhandled minor function %#x.\n", irpsp
->MinorFunction
);
995 IoSkipCurrentIrpStackLocation(irp
);
996 return IoCallDriver(bus_pdo
, irp
);
999 static NTSTATUS
pdo_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
1001 struct device_extension
*ext
= device
->DeviceExtension
;
1002 NTSTATUS status
= irp
->IoStatus
.Status
;
1003 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
1004 struct hid_report
*report
, *next
;
1005 HIDP_REPORT_IDS
*reports
;
1008 TRACE("device %p, irp %p, minor function %#x.\n", device
, irp
, irpsp
->MinorFunction
);
1010 switch (irpsp
->MinorFunction
)
1012 case IRP_MN_QUERY_ID
:
1013 status
= handle_IRP_MN_QUERY_ID(device
, irp
);
1016 case IRP_MN_QUERY_CAPABILITIES
:
1017 status
= STATUS_SUCCESS
;
1020 case IRP_MN_START_DEVICE
:
1021 RtlEnterCriticalSection(&ext
->cs
);
1022 if (ext
->state
!= DEVICE_STATE_STOPPED
) status
= STATUS_SUCCESS
;
1023 else if (ext
->state
== DEVICE_STATE_REMOVED
) status
= STATUS_DELETE_PENDING
;
1024 else if ((status
= unix_device_start(device
)))
1025 ERR("Failed to start device %p, status %#lx\n", device
, status
);
1026 else if (!(status
= get_device_descriptors(ext
->unix_device
, &ext
->report_desc
, &ext
->report_desc_length
,
1027 &ext
->collection_desc
)))
1029 status
= STATUS_SUCCESS
;
1030 reports
= ext
->collection_desc
.ReportIDs
;
1031 for (i
= 0; i
< ext
->collection_desc
.ReportIDsLength
; ++i
)
1033 if (!(size
= reports
[i
].InputLength
)) continue;
1034 size
= offsetof( struct hid_report
, buffer
[size
] );
1035 if (!(report
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
))) status
= STATUS_NO_MEMORY
;
1038 report
->length
= reports
[i
].InputLength
;
1039 report
->buffer
[0] = reports
[i
].ReportID
;
1040 ext
->last_reports
[reports
[i
].ReportID
] = report
;
1043 if (!status
) ext
->state
= DEVICE_STATE_STARTED
;
1045 RtlLeaveCriticalSection(&ext
->cs
);
1048 case IRP_MN_SURPRISE_REMOVAL
:
1049 RtlEnterCriticalSection(&ext
->cs
);
1050 remove_pending_irps(device
);
1051 ext
->state
= DEVICE_STATE_REMOVED
;
1052 RtlLeaveCriticalSection(&ext
->cs
);
1053 status
= STATUS_SUCCESS
;
1056 case IRP_MN_REMOVE_DEVICE
:
1057 remove_pending_irps(device
);
1059 bus_unlink_hid_device(device
);
1060 unix_device_remove(device
);
1062 ext
->cs
.DebugInfo
->Spare
[0] = 0;
1063 DeleteCriticalSection(&ext
->cs
);
1065 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1066 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1068 LIST_FOR_EACH_ENTRY_SAFE(report
, next
, &ext
->reports
, struct hid_report
, entry
)
1069 RtlFreeHeap(GetProcessHeap(), 0, report
);
1071 reports
= ext
->collection_desc
.ReportIDs
;
1072 for (i
= 0; i
< ext
->collection_desc
.ReportIDsLength
; ++i
)
1074 if (!reports
[i
].InputLength
) continue;
1075 RtlFreeHeap(GetProcessHeap(), 0, ext
->last_reports
[reports
[i
].ReportID
]);
1077 HidP_FreeCollectionDescription(&ext
->collection_desc
);
1078 RtlFreeHeap(GetProcessHeap(), 0, ext
->report_desc
);
1080 IoDeleteDevice(device
);
1081 return STATUS_SUCCESS
;
1084 FIXME("Unhandled function %08x\n", irpsp
->MinorFunction
);
1087 case IRP_MN_QUERY_DEVICE_RELATIONS
:
1091 irp
->IoStatus
.Status
= status
;
1092 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1096 static NTSTATUS WINAPI
common_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
1098 if (device
== bus_fdo
)
1099 return fdo_pnp_dispatch(device
, irp
);
1100 return pdo_pnp_dispatch(device
, irp
);
1103 static NTSTATUS
hid_get_device_string(DEVICE_OBJECT
*device
, DWORD index
, WCHAR
*buffer
, DWORD buffer_len
)
1105 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
1110 case HID_STRING_ID_IMANUFACTURER
:
1111 len
= (wcslen(ext
->desc
.manufacturer
) + 1) * sizeof(WCHAR
);
1112 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
1113 else memcpy(buffer
, ext
->desc
.manufacturer
, len
);
1114 return STATUS_SUCCESS
;
1115 case HID_STRING_ID_IPRODUCT
:
1116 len
= (wcslen(ext
->desc
.product
) + 1) * sizeof(WCHAR
);
1117 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
1118 else memcpy(buffer
, ext
->desc
.product
, len
);
1119 return STATUS_SUCCESS
;
1120 case HID_STRING_ID_ISERIALNUMBER
:
1121 len
= (wcslen(ext
->desc
.serialnumber
) + 1) * sizeof(WCHAR
);
1122 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
1123 else memcpy(buffer
, ext
->desc
.serialnumber
, len
);
1124 return STATUS_SUCCESS
;
1127 return STATUS_NOT_IMPLEMENTED
;
1130 static void hidraw_disable_report_fixups(DEVICE_OBJECT
*device
)
1132 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
1134 /* FIXME: we may want to validate CRC at the end of the outbound HID reports,
1135 * as controllers do not switch modes if it is incorrect.
1138 if ((ext
->report_fixups
& HIDRAW_FIXUP_DUALSHOCK_BT
))
1140 TRACE("Disabling report fixup for Bluetooth DualShock4 device %p\n", device
);
1141 ext
->report_fixups
&= ~HIDRAW_FIXUP_DUALSHOCK_BT
;
1144 if ((ext
->report_fixups
& HIDRAW_FIXUP_DUALSENSE_BT
))
1146 TRACE("Disabling report fixup for Bluetooth DualSense device %p\n", device
);
1147 ext
->report_fixups
&= ~HIDRAW_FIXUP_DUALSENSE_BT
;
1151 static NTSTATUS WINAPI
hid_internal_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
1153 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
1154 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
1155 ULONG i
, code
, buffer_len
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1158 if (device
== bus_fdo
)
1160 IoSkipCurrentIrpStackLocation(irp
);
1161 return IoCallDriver(bus_pdo
, irp
);
1164 RtlEnterCriticalSection(&ext
->cs
);
1166 if (ext
->state
== DEVICE_STATE_REMOVED
)
1168 RtlLeaveCriticalSection(&ext
->cs
);
1169 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
1170 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1171 return STATUS_DELETE_PENDING
;
1174 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
1176 case IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
1178 HID_DEVICE_ATTRIBUTES
*attr
= (HID_DEVICE_ATTRIBUTES
*)irp
->UserBuffer
;
1179 TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
1181 if (buffer_len
< sizeof(*attr
))
1183 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1187 memset(attr
, 0, sizeof(*attr
));
1188 attr
->Size
= sizeof(*attr
);
1189 attr
->VendorID
= ext
->desc
.vid
;
1190 attr
->ProductID
= ext
->desc
.pid
;
1191 attr
->VersionNumber
= ext
->desc
.version
;
1193 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1194 irp
->IoStatus
.Information
= sizeof(*attr
);
1197 case IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
1199 HID_DESCRIPTOR
*descriptor
= (HID_DESCRIPTOR
*)irp
->UserBuffer
;
1200 irp
->IoStatus
.Information
= sizeof(*descriptor
);
1201 if (buffer_len
< sizeof(*descriptor
)) irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1204 memset(descriptor
, 0, sizeof(*descriptor
));
1205 descriptor
->bLength
= sizeof(*descriptor
);
1206 descriptor
->bDescriptorType
= HID_HID_DESCRIPTOR_TYPE
;
1207 descriptor
->bcdHID
= HID_REVISION
;
1208 descriptor
->bCountry
= 0;
1209 descriptor
->bNumDescriptors
= 1;
1210 descriptor
->DescriptorList
[0].bReportType
= HID_REPORT_DESCRIPTOR_TYPE
;
1211 descriptor
->DescriptorList
[0].wReportLength
= ext
->report_desc_length
;
1212 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1216 case IOCTL_HID_GET_REPORT_DESCRIPTOR
:
1217 irp
->IoStatus
.Information
= ext
->report_desc_length
;
1218 if (buffer_len
< irp
->IoStatus
.Information
)
1219 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1222 memcpy(irp
->UserBuffer
, ext
->report_desc
, ext
->report_desc_length
);
1223 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1226 case IOCTL_HID_GET_STRING
:
1228 UINT index
= (UINT_PTR
)irpsp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1229 TRACE("IOCTL_HID_GET_STRING[%08x]\n", index
);
1231 irp
->IoStatus
.Status
= hid_get_device_string(device
, index
, (WCHAR
*)irp
->UserBuffer
, buffer_len
);
1232 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
1233 irp
->IoStatus
.Information
= (wcslen((WCHAR
*)irp
->UserBuffer
) + 1) * sizeof(WCHAR
);
1236 case IOCTL_HID_GET_INPUT_REPORT
:
1238 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1239 struct hid_report
*last_report
= ext
->last_reports
[packet
->reportId
];
1240 memcpy(packet
->reportBuffer
, last_report
->buffer
, last_report
->length
);
1241 packet
->reportBufferLen
= last_report
->length
;
1242 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
1243 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1246 TRACE("read input report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1247 for (i
= 0; i
< packet
->reportBufferLen
;)
1249 char buffer
[256], *buf
= buffer
;
1250 buf
+= sprintf(buf
, "%08lx ", i
);
1251 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1252 while (++i
% 16 && i
< packet
->reportBufferLen
);
1253 TRACE("%s\n", buffer
);
1258 case IOCTL_HID_READ_REPORT
:
1260 if (!deliver_next_report(ext
, irp
))
1262 /* hidclass.sys should guarantee this */
1263 assert(!ext
->pending_read
);
1264 ext
->pending_read
= irp
;
1265 IoMarkIrpPending(irp
);
1266 irp
->IoStatus
.Status
= STATUS_PENDING
;
1270 case IOCTL_HID_SET_OUTPUT_REPORT
:
1271 case IOCTL_HID_WRITE_REPORT
:
1273 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1276 TRACE("write output report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1277 for (i
= 0; i
< packet
->reportBufferLen
;)
1279 char buffer
[256], *buf
= buffer
;
1280 buf
+= sprintf(buf
, "%08lx ", i
);
1281 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1282 while (++i
% 16 && i
< packet
->reportBufferLen
);
1283 TRACE("%s\n", buffer
);
1286 unix_device_set_output_report(device
, packet
, &irp
->IoStatus
);
1287 if (!irp
->IoStatus
.Status
) hidraw_disable_report_fixups(device
);
1290 case IOCTL_HID_GET_FEATURE
:
1292 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1293 unix_device_get_feature_report(device
, packet
, &irp
->IoStatus
);
1294 if (!irp
->IoStatus
.Status
) hidraw_disable_report_fixups(device
);
1295 if (!irp
->IoStatus
.Status
&& TRACE_ON(hid
))
1297 TRACE("read feature report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1298 for (i
= 0; i
< packet
->reportBufferLen
;)
1300 char buffer
[256], *buf
= buffer
;
1301 buf
+= sprintf(buf
, "%08lx ", i
);
1302 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1303 while (++i
% 16 && i
< packet
->reportBufferLen
);
1304 TRACE("%s\n", buffer
);
1309 case IOCTL_HID_SET_FEATURE
:
1311 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1314 TRACE("write feature report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1315 for (i
= 0; i
< packet
->reportBufferLen
;)
1317 char buffer
[256], *buf
= buffer
;
1318 buf
+= sprintf(buf
, "%08lx ", i
);
1319 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1320 while (++i
% 16 && i
< packet
->reportBufferLen
);
1321 TRACE("%s\n", buffer
);
1324 unix_device_set_feature_report(device
, packet
, &irp
->IoStatus
);
1325 if (!irp
->IoStatus
.Status
) hidraw_disable_report_fixups(device
);
1329 FIXME("Unsupported ioctl %lx (device=%lx access=%lx func=%lx method=%lx)\n",
1330 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
1334 status
= irp
->IoStatus
.Status
;
1335 RtlLeaveCriticalSection(&ext
->cs
);
1337 if (status
!= STATUS_PENDING
) IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1341 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*pdo
)
1345 TRACE("driver %p, pdo %p.\n", driver
, pdo
);
1347 if ((ret
= IoCreateDevice(driver
, 0, NULL
, FILE_DEVICE_BUS_EXTENDER
, 0, FALSE
, &bus_fdo
)))
1349 ERR("Failed to create FDO, status %#lx.\n", ret
);
1353 IoAttachDeviceToDeviceStack(bus_fdo
, pdo
);
1356 bus_fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1358 return STATUS_SUCCESS
;
1361 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
1363 NtClose(driver_key
);
1366 NTSTATUS WINAPI
DriverEntry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
1368 OBJECT_ATTRIBUTES attr
= {0};
1371 TRACE( "(%p, %s)\n", driver
, debugstr_w(path
->Buffer
) );
1373 if ((ret
= __wine_init_unix_call())) return ret
;
1375 attr
.Length
= sizeof(attr
);
1376 attr
.ObjectName
= path
;
1377 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
;
1378 if ((ret
= NtOpenKey(&driver_key
, KEY_ALL_ACCESS
, &attr
)) != STATUS_SUCCESS
)
1379 ERR("Failed to open driver key, status %#lx.\n", ret
);
1381 driver_obj
= driver
;
1383 driver
->MajorFunction
[IRP_MJ_PNP
] = common_pnp_dispatch
;
1384 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = hid_internal_dispatch
;
1385 driver
->DriverExtension
->AddDevice
= driver_add_device
;
1386 driver
->DriverUnload
= driver_unload
;
1388 return STATUS_SUCCESS
;