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 struct device_extension
73 DEVICE_OBJECT
*device
;
76 enum device_state state
;
78 struct device_desc desc
;
82 UINT report_desc_length
;
83 HIDP_DEVICE_DESC collection_desc
;
85 struct hid_report
*last_reports
[256];
92 static CRITICAL_SECTION device_list_cs
;
93 static CRITICAL_SECTION_DEBUG critsect_debug
=
95 0, 0, &device_list_cs
,
96 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
97 0, 0, { (DWORD_PTR
)(__FILE__
": device_list_cs") }
99 static CRITICAL_SECTION device_list_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
101 static struct list device_list
= LIST_INIT(device_list
);
103 static NTSTATUS
winebus_call(unsigned int code
, void *args
)
105 return WINE_UNIX_CALL(code
, args
);
108 static void unix_device_remove(DEVICE_OBJECT
*device
)
110 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
111 struct device_remove_params params
= {.device
= ext
->unix_device
};
112 winebus_call(device_remove
, ¶ms
);
115 static NTSTATUS
unix_device_start(DEVICE_OBJECT
*device
)
117 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
118 struct device_start_params params
= {.device
= ext
->unix_device
};
119 return winebus_call(device_start
, ¶ms
);
122 static void unix_device_set_output_report(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
, IO_STATUS_BLOCK
*io
)
124 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
125 struct device_report_params params
=
127 .device
= ext
->unix_device
,
131 winebus_call(device_set_output_report
, ¶ms
);
134 static void unix_device_get_feature_report(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
, IO_STATUS_BLOCK
*io
)
136 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
137 struct device_report_params params
=
139 .device
= ext
->unix_device
,
143 winebus_call(device_get_feature_report
, ¶ms
);
146 static void unix_device_set_feature_report(DEVICE_OBJECT
*device
, HID_XFER_PACKET
*packet
, IO_STATUS_BLOCK
*io
)
148 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
149 struct device_report_params params
=
151 .device
= ext
->unix_device
,
155 winebus_call(device_set_feature_report
, ¶ms
);
158 static DWORD
get_device_index(struct device_desc
*desc
)
160 struct device_extension
*ext
;
163 LIST_FOR_EACH_ENTRY(ext
, &device_list
, struct device_extension
, entry
)
165 if (ext
->desc
.vid
== desc
->vid
&& ext
->desc
.pid
== desc
->pid
&& ext
->desc
.input
== desc
->input
)
166 index
= max(ext
->index
+ 1, index
);
172 static WCHAR
*get_instance_id(DEVICE_OBJECT
*device
)
174 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
175 DWORD len
= wcslen(ext
->desc
.serialnumber
) + 33;
178 if ((dst
= ExAllocatePool(PagedPool
, len
* sizeof(WCHAR
))))
180 swprintf(dst
, len
, L
"%u&%s&%x&%u&%u", ext
->desc
.version
, ext
->desc
.serialnumber
,
181 ext
->desc
.uid
, ext
->index
, ext
->desc
.is_gamepad
);
187 static WCHAR
*get_device_id(DEVICE_OBJECT
*device
)
189 static const WCHAR input_format
[] = L
"&MI_%02u";
190 static const WCHAR winebus_format
[] = L
"WINEBUS\\VID_%04X&PID_%04X";
191 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
192 DWORD pos
= 0, len
= 0, input_len
= 0, winebus_len
= 25;
195 if (ext
->desc
.input
!= -1) input_len
= 14;
197 len
+= winebus_len
+ input_len
+ 1;
199 if ((dst
= ExAllocatePool(PagedPool
, len
* sizeof(WCHAR
))))
201 pos
+= swprintf(dst
+ pos
, len
- pos
, winebus_format
, ext
->desc
.vid
, ext
->desc
.pid
);
202 if (input_len
) pos
+= swprintf(dst
+ pos
, len
- pos
, input_format
, ext
->desc
.input
);
208 static WCHAR
*get_hardware_ids(DEVICE_OBJECT
*device
)
210 static const WCHAR input_format
[] = L
"&MI_%02u";
211 static const WCHAR winebus_format
[] = L
"WINEBUS\\VID_%04X&PID_%04X";
212 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
213 DWORD pos
= 0, len
= 0, input_len
= 0, winebus_len
= 25;
216 if (ext
->desc
.input
!= -1) input_len
= 14;
218 len
+= winebus_len
+ input_len
+ 1;
220 if ((dst
= ExAllocatePool(PagedPool
, (len
+ 1) * sizeof(WCHAR
))))
222 pos
+= swprintf(dst
+ pos
, len
- pos
, winebus_format
, ext
->desc
.vid
, ext
->desc
.pid
);
223 if (input_len
) pos
+= swprintf(dst
+ pos
, len
- pos
, input_format
, ext
->desc
.input
);
231 static WCHAR
*get_compatible_ids(DEVICE_OBJECT
*device
)
233 static const WCHAR xinput_compat
[] = L
"WINEBUS\\WINE_COMP_XINPUT";
234 static const WCHAR hid_compat
[] = L
"WINEBUS\\WINE_COMP_HID";
235 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
236 DWORD size
= sizeof(hid_compat
);
239 if (ext
->desc
.is_gamepad
) size
+= sizeof(xinput_compat
);
241 if ((dst
= ExAllocatePool(PagedPool
, size
+ sizeof(WCHAR
))))
243 if (ext
->desc
.is_gamepad
) memcpy(dst
, xinput_compat
, sizeof(xinput_compat
));
244 memcpy((char *)dst
+ size
- sizeof(hid_compat
), hid_compat
, sizeof(hid_compat
));
245 dst
[size
/ sizeof(WCHAR
)] = 0;
251 static IRP
*pop_pending_read(struct device_extension
*ext
)
255 RtlEnterCriticalSection(&ext
->cs
);
256 pending
= ext
->pending_read
;
257 ext
->pending_read
= NULL
;
258 RtlLeaveCriticalSection(&ext
->cs
);
263 static void remove_pending_irps(DEVICE_OBJECT
*device
)
265 struct device_extension
*ext
= device
->DeviceExtension
;
268 if ((pending
= pop_pending_read(ext
)))
270 pending
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
271 pending
->IoStatus
.Information
= 0;
272 IoCompleteRequest(pending
, IO_NO_INCREMENT
);
276 static DEVICE_OBJECT
*bus_create_hid_device(struct device_desc
*desc
, UINT64 unix_device
)
278 struct device_extension
*ext
;
279 DEVICE_OBJECT
*device
;
280 UNICODE_STRING nameW
;
284 TRACE("desc %s, unix_device %#I64x\n", debugstr_device_desc(desc
), unix_device
);
286 swprintf(dev_name
, ARRAY_SIZE(dev_name
), L
"\\Device\\WINEBUS#%p", unix_device
);
287 RtlInitUnicodeString(&nameW
, dev_name
);
288 status
= IoCreateDevice(driver_obj
, sizeof(struct device_extension
), &nameW
, 0, 0, FALSE
, &device
);
291 FIXME("failed to create device error %#lx\n", status
);
295 RtlEnterCriticalSection(&device_list_cs
);
297 /* fill out device_extension struct */
298 ext
= (struct device_extension
*)device
->DeviceExtension
;
299 ext
->device
= device
;
301 ext
->index
= get_device_index(desc
);
302 ext
->unix_device
= unix_device
;
303 list_init(&ext
->reports
);
305 InitializeCriticalSectionEx(&ext
->cs
, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO
);
306 ext
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
308 /* add to list of pnp devices */
309 list_add_tail(&device_list
, &ext
->entry
);
311 RtlLeaveCriticalSection(&device_list_cs
);
313 TRACE("created device %p/%#I64x\n", device
, unix_device
);
317 static DEVICE_OBJECT
*bus_find_unix_device(UINT64 unix_device
)
319 struct device_extension
*ext
;
321 LIST_FOR_EACH_ENTRY(ext
, &device_list
, struct device_extension
, entry
)
322 if (ext
->unix_device
== unix_device
) return ext
->device
;
327 static void bus_unlink_hid_device(DEVICE_OBJECT
*device
)
329 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
331 RtlEnterCriticalSection(&device_list_cs
);
332 list_remove(&ext
->entry
);
333 RtlLeaveCriticalSection(&device_list_cs
);
336 #ifdef __ASM_USE_FASTCALL_WRAPPER
337 extern void * WINAPI
wrap_fastcall_func1(void *func
, const void *a
);
338 __ASM_STDCALL_FUNC(wrap_fastcall_func1
, 8,
341 "xchgl (%esp),%ecx\n\t"
343 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
345 #define call_fastcall_func1(func,a) func(a)
348 static NTSTATUS
build_device_relations(DEVICE_RELATIONS
**devices
)
350 struct device_extension
*ext
;
353 RtlEnterCriticalSection(&device_list_cs
);
354 *devices
= ExAllocatePool(PagedPool
, offsetof(DEVICE_RELATIONS
, Objects
[list_count(&device_list
)]));
358 RtlLeaveCriticalSection(&device_list_cs
);
359 return STATUS_INSUFFICIENT_RESOURCES
;
363 LIST_FOR_EACH_ENTRY(ext
, &device_list
, struct device_extension
, entry
)
365 (*devices
)->Objects
[i
] = ext
->device
;
366 call_fastcall_func1(ObfReferenceObject
, ext
->device
);
369 RtlLeaveCriticalSection(&device_list_cs
);
370 (*devices
)->Count
= i
;
371 return STATUS_SUCCESS
;
374 static DWORD
check_bus_option(const WCHAR
*option
, DWORD default_value
)
376 char buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(DWORD
)])];
377 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
381 RtlInitUnicodeString(&str
, option
);
383 if (NtQueryValueKey(driver_key
, &str
, KeyValuePartialInformation
, info
, sizeof(buffer
), &size
) == STATUS_SUCCESS
)
385 if (info
->Type
== REG_DWORD
) return *(DWORD
*)info
->Data
;
388 return default_value
;
391 static BOOL
is_hidraw_enabled(WORD vid
, WORD pid
, const USAGE_AND_PAGE
*usages
)
393 char buffer
[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[1024])];
394 KEY_VALUE_PARTIAL_INFORMATION
*info
= (KEY_VALUE_PARTIAL_INFORMATION
*)buffer
;
395 WCHAR vidpid
[MAX_PATH
], *tmp
;
396 BOOL prefer_hidraw
= FALSE
;
400 if (check_bus_option(L
"DisableHidraw", FALSE
)) return FALSE
;
401 if (usages
->UsagePage
!= HID_USAGE_PAGE_GENERIC
) return TRUE
;
402 if (usages
->Usage
!= HID_USAGE_GENERIC_GAMEPAD
&& usages
->Usage
!= HID_USAGE_GENERIC_JOYSTICK
) return TRUE
;
404 if (!check_bus_option(L
"Enable SDL", 1) && check_bus_option(L
"DisableInput", 0))
405 prefer_hidraw
= TRUE
;
407 if (is_dualshock4_gamepad(vid
, pid
)) prefer_hidraw
= TRUE
;
408 if (is_dualsense_gamepad(vid
, pid
)) prefer_hidraw
= TRUE
;
410 RtlInitUnicodeString(&str
, L
"EnableHidraw");
411 if (!NtQueryValueKey(driver_key
, &str
, KeyValuePartialInformation
, info
,
412 sizeof(buffer
) - sizeof(WCHAR
), &size
))
414 UINT len
= swprintf(vidpid
, ARRAY_SIZE(vidpid
), L
"%04X:%04X", vid
, pid
);
415 size
-= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
[0]);
416 tmp
= (WCHAR
*)info
->Data
;
418 while (size
>= len
* sizeof(WCHAR
))
420 if (!wcsnicmp(tmp
, vidpid
, len
)) prefer_hidraw
= TRUE
;
421 size
-= (len
+ 1) * sizeof(WCHAR
);
426 return prefer_hidraw
;
429 static BOOL
deliver_next_report(struct device_extension
*ext
, IRP
*irp
)
431 struct hid_report
*report
;
435 if (!(entry
= list_head(&ext
->reports
))) return FALSE
;
436 report
= LIST_ENTRY(entry
, struct hid_report
, entry
);
437 list_remove(&report
->entry
);
439 memcpy(irp
->UserBuffer
, report
->buffer
, report
->length
);
440 irp
->IoStatus
.Information
= report
->length
;
441 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
445 TRACE("device %p/%#I64x input report length %lu:\n", ext
->device
, ext
->unix_device
, report
->length
);
446 for (i
= 0; i
< report
->length
;)
448 char buffer
[256], *buf
= buffer
;
449 buf
+= sprintf(buf
, "%08lx ", i
);
450 do { buf
+= sprintf(buf
, " %02x", report
->buffer
[i
]); }
451 while (++i
% 16 && i
< report
->length
);
452 TRACE("%s\n", buffer
);
456 RtlFreeHeap(GetProcessHeap(), 0, report
);
460 static void process_hid_report(DEVICE_OBJECT
*device
, BYTE
*report_buf
, DWORD report_len
)
462 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
463 ULONG size
= offsetof(struct hid_report
, buffer
[report_len
]);
464 struct hid_report
*report
, *last_report
;
467 if (!(report
= RtlAllocateHeap(GetProcessHeap(), 0, size
))) return;
468 memcpy(report
->buffer
, report_buf
, report_len
);
469 report
->length
= report_len
;
471 RtlEnterCriticalSection(&ext
->cs
);
472 list_add_tail(&ext
->reports
, &report
->entry
);
474 if (!ext
->collection_desc
.ReportIDs
[0].ReportID
) last_report
= ext
->last_reports
[0];
475 else last_report
= ext
->last_reports
[report_buf
[0]];
476 memcpy(last_report
->buffer
, report_buf
, report_len
);
478 if ((irp
= pop_pending_read(ext
)))
480 deliver_next_report(ext
, irp
);
481 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
483 RtlLeaveCriticalSection(&ext
->cs
);
486 static NTSTATUS
handle_IRP_MN_QUERY_DEVICE_RELATIONS(IRP
*irp
)
488 NTSTATUS status
= irp
->IoStatus
.Status
;
489 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
491 TRACE("IRP_MN_QUERY_DEVICE_RELATIONS\n");
492 switch (irpsp
->Parameters
.QueryDeviceRelations
.Type
)
494 case EjectionRelations
:
495 case RemovalRelations
:
496 case TargetDeviceRelation
:
498 FIXME("Unhandled Device Relation %x\n",irpsp
->Parameters
.QueryDeviceRelations
.Type
);
501 status
= build_device_relations((DEVICE_RELATIONS
**)&irp
->IoStatus
.Information
);
504 FIXME("Unknown Device Relation %x\n",irpsp
->Parameters
.QueryDeviceRelations
.Type
);
511 static NTSTATUS
handle_IRP_MN_QUERY_ID(DEVICE_OBJECT
*device
, IRP
*irp
)
513 NTSTATUS status
= irp
->IoStatus
.Status
;
514 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation( irp
);
515 BUS_QUERY_ID_TYPE type
= irpsp
->Parameters
.QueryId
.IdType
;
517 TRACE("(%p, %p)\n", device
, irp
);
521 case BusQueryHardwareIDs
:
522 TRACE("BusQueryHardwareIDs\n");
523 irp
->IoStatus
.Information
= (ULONG_PTR
)get_hardware_ids(device
);
525 case BusQueryCompatibleIDs
:
526 TRACE("BusQueryCompatibleIDs\n");
527 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
529 case BusQueryDeviceID
:
530 TRACE("BusQueryDeviceID\n");
531 irp
->IoStatus
.Information
= (ULONG_PTR
)get_device_id(device
);
533 case BusQueryInstanceID
:
534 TRACE("BusQueryInstanceID\n");
535 irp
->IoStatus
.Information
= (ULONG_PTR
)get_instance_id(device
);
538 WARN("Unhandled type %08x\n", type
);
542 status
= irp
->IoStatus
.Information
? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
546 static void mouse_device_create(void)
548 struct device_create_params params
= {{0}};
550 if (winebus_call(mouse_create
, ¶ms
)) return;
551 mouse_obj
= bus_create_hid_device(¶ms
.desc
, params
.device
);
552 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
555 static void keyboard_device_create(void)
557 struct device_create_params params
= {{0}};
559 if (winebus_call(keyboard_create
, ¶ms
)) return;
560 keyboard_obj
= bus_create_hid_device(¶ms
.desc
, params
.device
);
561 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
564 static NTSTATUS
get_device_descriptors(UINT64 unix_device
, BYTE
**report_desc
, UINT
*report_desc_length
,
565 HIDP_DEVICE_DESC
*device_desc
)
567 struct device_descriptor_params params
=
569 .device
= unix_device
,
570 .out_length
= report_desc_length
,
574 status
= winebus_call(device_get_report_descriptor
, ¶ms
);
575 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
577 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device
, status
);
581 if (!(params
.buffer
= RtlAllocateHeap(GetProcessHeap(), 0, *report_desc_length
)))
582 return STATUS_NO_MEMORY
;
583 params
.length
= *report_desc_length
;
585 if ((status
= winebus_call(device_get_report_descriptor
, ¶ms
)))
587 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device
, status
);
588 RtlFreeHeap(GetProcessHeap(), 0, params
.buffer
);
592 params
.length
= *report_desc_length
;
593 status
= HidP_GetCollectionDescription(params
.buffer
, params
.length
, PagedPool
, device_desc
);
594 if (status
!= HIDP_STATUS_SUCCESS
)
596 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device
, status
);
597 RtlFreeHeap(GetProcessHeap(), 0, params
.buffer
);
601 *report_desc
= params
.buffer
;
602 return STATUS_SUCCESS
;
605 static USAGE_AND_PAGE
get_hidraw_device_usages(UINT64 unix_device
)
607 HIDP_DEVICE_DESC device_desc
;
608 USAGE_AND_PAGE usages
= {0};
609 UINT report_desc_length
;
613 if (!(status
= get_device_descriptors(unix_device
, &report_desc
, &report_desc_length
, &device_desc
)))
615 usages
.UsagePage
= device_desc
.CollectionDesc
[0].UsagePage
;
616 usages
.Usage
= device_desc
.CollectionDesc
[0].Usage
;
617 HidP_FreeCollectionDescription(&device_desc
);
618 RtlFreeHeap(GetProcessHeap(), 0, report_desc
);
624 static DWORD bus_count
;
625 static HANDLE bus_thread
[16];
627 struct bus_main_params
633 NTSTATUS
*init_status
;
634 unsigned int init_code
;
635 unsigned int wait_code
;
636 struct bus_event
*bus_event
;
639 static DWORD CALLBACK
bus_main_thread(void *args
)
641 struct bus_main_params bus
= *(struct bus_main_params
*)args
;
642 DEVICE_OBJECT
*device
;
645 TRACE("%s main loop starting\n", debugstr_w(bus
.name
));
646 status
= winebus_call(bus
.init_code
, bus
.init_args
);
647 *bus
.init_status
= status
;
648 SetEvent(bus
.init_done
);
649 TRACE("%s main loop started\n", debugstr_w(bus
.name
));
651 bus
.bus_event
->type
= BUS_EVENT_TYPE_NONE
;
652 if (status
) WARN("%s bus init returned status %#lx\n", debugstr_w(bus
.name
), status
);
653 else while ((status
= winebus_call(bus
.wait_code
, bus
.bus_event
)) == STATUS_PENDING
)
655 struct bus_event
*event
= bus
.bus_event
;
658 case BUS_EVENT_TYPE_NONE
: break;
659 case BUS_EVENT_TYPE_DEVICE_REMOVED
:
660 RtlEnterCriticalSection(&device_list_cs
);
661 device
= bus_find_unix_device(event
->device
);
662 if (!device
) WARN("could not find device for %s bus device %#I64x\n", debugstr_w(bus
.name
), event
->device
);
663 else bus_unlink_hid_device(device
);
664 RtlLeaveCriticalSection(&device_list_cs
);
665 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
667 case BUS_EVENT_TYPE_DEVICE_CREATED
:
669 struct device_desc desc
= event
->device_created
.desc
;
670 if (desc
.is_hidraw
&& !desc
.usages
.UsagePage
) desc
.usages
= get_hidraw_device_usages(event
->device
);
671 if (!desc
.is_hidraw
!= !is_hidraw_enabled(desc
.vid
, desc
.pid
, &desc
.usages
))
673 struct device_remove_params params
= {.device
= event
->device
};
674 WARN("ignoring %shidraw device %04x:%04x with usages %04x:%04x\n", desc
.is_hidraw
? "" : "non-",
675 desc
.vid
, desc
.pid
, desc
.usages
.UsagePage
, desc
.usages
.Usage
);
676 winebus_call(device_remove
, ¶ms
);
680 TRACE("creating %shidraw device %04x:%04x with usages %04x:%04x\n", desc
.is_hidraw
? "" : "non-",
681 desc
.vid
, desc
.pid
, desc
.usages
.UsagePage
, desc
.usages
.Usage
);
683 device
= bus_create_hid_device(&event
->device_created
.desc
, event
->device
);
684 if (device
) IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
687 struct device_remove_params params
= {.device
= event
->device
};
688 WARN("failed to create device for %s bus device %#I64x\n", debugstr_w(bus
.name
), event
->device
);
689 winebus_call(device_remove
, ¶ms
);
693 case BUS_EVENT_TYPE_INPUT_REPORT
:
694 RtlEnterCriticalSection(&device_list_cs
);
695 device
= bus_find_unix_device(event
->device
);
696 if (!device
) WARN("could not find device for %s bus device %#I64x\n", debugstr_w(bus
.name
), event
->device
);
697 else process_hid_report(device
, event
->input_report
.buffer
, event
->input_report
.length
);
698 RtlLeaveCriticalSection(&device_list_cs
);
703 if (status
) WARN("%s bus wait returned status %#lx\n", debugstr_w(bus
.name
), status
);
704 else TRACE("%s main loop exited\n", debugstr_w(bus
.name
));
705 RtlFreeHeap(GetProcessHeap(), 0, bus
.bus_event
);
709 static NTSTATUS
bus_main_thread_start(struct bus_main_params
*bus
)
711 DWORD i
= bus_count
++, max_size
;
714 if (!(bus
->init_done
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
)))
716 ERR("failed to create %s bus init done event.\n", debugstr_w(bus
->name
));
718 return STATUS_UNSUCCESSFUL
;
721 max_size
= offsetof(struct bus_event
, input_report
.buffer
[0x10000]);
722 if (!(bus
->bus_event
= RtlAllocateHeap(GetProcessHeap(), 0, max_size
)))
724 ERR("failed to allocate %s bus event.\n", debugstr_w(bus
->name
));
725 CloseHandle(bus
->init_done
);
727 return STATUS_UNSUCCESSFUL
;
730 bus
->init_status
= &status
;
731 if (!(bus_thread
[i
] = CreateThread(NULL
, 0, bus_main_thread
, bus
, 0, NULL
)))
733 ERR("failed to create %s bus thread.\n", debugstr_w(bus
->name
));
734 CloseHandle(bus
->init_done
);
736 return STATUS_UNSUCCESSFUL
;
739 WaitForSingleObject(bus
->init_done
, INFINITE
);
740 CloseHandle(bus
->init_done
);
744 static void sdl_bus_free_mappings(struct sdl_bus_options
*options
)
746 DWORD count
= options
->mappings_count
;
747 char **mappings
= options
->mappings
;
749 while (count
) RtlFreeHeap(GetProcessHeap(), 0, mappings
[--count
]);
750 RtlFreeHeap(GetProcessHeap(), 0, mappings
);
753 static void sdl_bus_load_mappings(struct sdl_bus_options
*options
)
755 ULONG idx
= 0, len
, count
= 0, capacity
, info_size
, info_max_size
;
756 UNICODE_STRING path
= RTL_CONSTANT_STRING(L
"map");
757 KEY_VALUE_FULL_INFORMATION
*info
;
758 OBJECT_ATTRIBUTES attr
= {0};
759 char **mappings
= NULL
;
763 options
->mappings_count
= 0;
764 options
->mappings
= NULL
;
766 InitializeObjectAttributes(&attr
, &path
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, driver_key
, NULL
);
767 status
= NtOpenKey(&key
, KEY_ALL_ACCESS
, &attr
);
771 mappings
= RtlAllocateHeap(GetProcessHeap(), 0, capacity
* sizeof(*mappings
));
772 info_max_size
= offsetof(KEY_VALUE_FULL_INFORMATION
, Name
) + 512;
773 info
= RtlAllocateHeap(GetProcessHeap(), 0, info_max_size
);
775 while (!status
&& info
&& mappings
)
777 status
= NtEnumerateValueKey(key
, idx
, KeyValueFullInformation
, info
, info_max_size
, &info_size
);
778 while (status
== STATUS_BUFFER_OVERFLOW
)
780 info_max_size
= info_size
;
781 if (!(info
= RtlReAllocateHeap(GetProcessHeap(), 0, info
, info_max_size
))) break;
782 status
= NtEnumerateValueKey(key
, idx
, KeyValueFullInformation
, info
, info_max_size
, &info_size
);
785 if (status
== STATUS_NO_MORE_ENTRIES
)
787 options
->mappings_count
= count
;
788 options
->mappings
= mappings
;
794 if (info
->Type
!= REG_SZ
) continue;
796 RtlUnicodeToMultiByteSize(&len
, (WCHAR
*)((char *)info
+ info
->DataOffset
), info_size
- info
->DataOffset
);
799 if (!(mappings
[count
++] = RtlAllocateHeap(GetProcessHeap(), 0, len
+ 1))) break;
800 if (count
> capacity
)
802 capacity
= capacity
* 3 / 2;
803 if (!(mappings
= RtlReAllocateHeap(GetProcessHeap(), 0, mappings
, capacity
* sizeof(*mappings
))))
807 RtlUnicodeToMultiByteN(mappings
[count
], len
, NULL
, (WCHAR
*)((char *)info
+ info
->DataOffset
),
808 info_size
- info
->DataOffset
);
809 if (mappings
[len
- 1]) mappings
[len
] = 0;
812 if (mappings
) while (count
) RtlFreeHeap(GetProcessHeap(), 0, mappings
[--count
]);
813 RtlFreeHeap(GetProcessHeap(), 0, mappings
);
816 RtlFreeHeap(GetProcessHeap(), 0, info
);
820 static NTSTATUS
sdl_driver_init(void)
822 struct sdl_bus_options bus_options
;
823 struct bus_main_params bus
=
826 .init_args
= &bus_options
,
827 .init_code
= sdl_init
,
828 .wait_code
= sdl_wait
,
832 bus_options
.split_controllers
= check_bus_option(L
"Split Controllers", 0);
833 if (bus_options
.split_controllers
) TRACE("SDL controller splitting enabled\n");
834 bus_options
.map_controllers
= check_bus_option(L
"Map Controllers", 1);
835 if (!bus_options
.map_controllers
) TRACE("SDL controller to XInput HID gamepad mapping disabled\n");
836 sdl_bus_load_mappings(&bus_options
);
838 status
= bus_main_thread_start(&bus
);
839 sdl_bus_free_mappings(&bus_options
);
843 static NTSTATUS
udev_driver_init(BOOL enable_sdl
)
845 struct udev_bus_options bus_options
;
846 struct bus_main_params bus
=
849 .init_args
= &bus_options
,
850 .init_code
= udev_init
,
851 .wait_code
= udev_wait
,
854 bus_options
.disable_hidraw
= check_bus_option(L
"DisableHidraw", 0);
855 if (bus_options
.disable_hidraw
) TRACE("UDEV hidraw devices disabled in registry\n");
856 bus_options
.disable_input
= check_bus_option(L
"DisableInput", 0) || enable_sdl
;
857 if (bus_options
.disable_input
) TRACE("UDEV input devices disabled in registry\n");
858 bus_options
.disable_udevd
= check_bus_option(L
"DisableUdevd", 0);
859 if (bus_options
.disable_udevd
) TRACE("UDEV udevd use disabled in registry\n");
861 return bus_main_thread_start(&bus
);
864 static NTSTATUS
iohid_driver_init(void)
866 struct iohid_bus_options bus_options
;
867 struct bus_main_params bus
=
870 .init_args
= &bus_options
,
871 .init_code
= iohid_init
,
872 .wait_code
= iohid_wait
,
875 if (check_bus_option(L
"DisableHidraw", FALSE
))
877 TRACE("IOHID hidraw devices disabled in registry\n");
878 return STATUS_SUCCESS
;
881 return bus_main_thread_start(&bus
);
884 static NTSTATUS
fdo_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
886 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
890 switch (irpsp
->MinorFunction
)
892 case IRP_MN_QUERY_DEVICE_RELATIONS
:
893 irp
->IoStatus
.Status
= handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp
);
895 case IRP_MN_START_DEVICE
:
896 mouse_device_create();
897 keyboard_device_create();
899 if ((enable_sdl
= check_bus_option(L
"Enable SDL", 1)))
900 enable_sdl
= !sdl_driver_init();
901 udev_driver_init(enable_sdl
);
904 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
906 case IRP_MN_SURPRISE_REMOVAL
:
907 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
909 case IRP_MN_REMOVE_DEVICE
:
910 winebus_call(sdl_stop
, NULL
);
911 winebus_call(udev_stop
, NULL
);
912 winebus_call(iohid_stop
, NULL
);
914 WaitForMultipleObjects(bus_count
, bus_thread
, TRUE
, INFINITE
);
915 while (bus_count
--) CloseHandle(bus_thread
[bus_count
]);
917 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
918 IoSkipCurrentIrpStackLocation(irp
);
919 ret
= IoCallDriver(bus_pdo
, irp
);
920 IoDetachDevice(bus_pdo
);
921 IoDeleteDevice(device
);
924 FIXME("Unhandled minor function %#x.\n", irpsp
->MinorFunction
);
927 IoSkipCurrentIrpStackLocation(irp
);
928 return IoCallDriver(bus_pdo
, irp
);
931 static NTSTATUS
pdo_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
933 struct device_extension
*ext
= device
->DeviceExtension
;
934 NTSTATUS status
= irp
->IoStatus
.Status
;
935 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
936 struct hid_report
*report
, *next
;
937 HIDP_REPORT_IDS
*reports
;
940 TRACE("device %p, irp %p, minor function %#x.\n", device
, irp
, irpsp
->MinorFunction
);
942 switch (irpsp
->MinorFunction
)
944 case IRP_MN_QUERY_ID
:
945 status
= handle_IRP_MN_QUERY_ID(device
, irp
);
948 case IRP_MN_QUERY_CAPABILITIES
:
949 status
= STATUS_SUCCESS
;
952 case IRP_MN_START_DEVICE
:
953 RtlEnterCriticalSection(&ext
->cs
);
954 if (ext
->state
!= DEVICE_STATE_STOPPED
) status
= STATUS_SUCCESS
;
955 else if (ext
->state
== DEVICE_STATE_REMOVED
) status
= STATUS_DELETE_PENDING
;
956 else if ((status
= unix_device_start(device
)))
957 ERR("Failed to start device %p, status %#lx\n", device
, status
);
958 else if (!(status
= get_device_descriptors(ext
->unix_device
, &ext
->report_desc
, &ext
->report_desc_length
,
959 &ext
->collection_desc
)))
961 status
= STATUS_SUCCESS
;
962 reports
= ext
->collection_desc
.ReportIDs
;
963 for (i
= 0; i
< ext
->collection_desc
.ReportIDsLength
; ++i
)
965 if (!(size
= reports
[i
].InputLength
)) continue;
966 size
= offsetof( struct hid_report
, buffer
[size
] );
967 if (!(report
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
))) status
= STATUS_NO_MEMORY
;
970 report
->length
= reports
[i
].InputLength
;
971 report
->buffer
[0] = reports
[i
].ReportID
;
972 ext
->last_reports
[reports
[i
].ReportID
] = report
;
975 if (!status
) ext
->state
= DEVICE_STATE_STARTED
;
977 RtlLeaveCriticalSection(&ext
->cs
);
980 case IRP_MN_SURPRISE_REMOVAL
:
981 RtlEnterCriticalSection(&ext
->cs
);
982 remove_pending_irps(device
);
983 ext
->state
= DEVICE_STATE_REMOVED
;
984 RtlLeaveCriticalSection(&ext
->cs
);
985 status
= STATUS_SUCCESS
;
988 case IRP_MN_REMOVE_DEVICE
:
989 remove_pending_irps(device
);
991 bus_unlink_hid_device(device
);
992 unix_device_remove(device
);
994 ext
->cs
.DebugInfo
->Spare
[0] = 0;
995 DeleteCriticalSection(&ext
->cs
);
997 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
998 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1000 LIST_FOR_EACH_ENTRY_SAFE(report
, next
, &ext
->reports
, struct hid_report
, entry
)
1001 RtlFreeHeap(GetProcessHeap(), 0, report
);
1003 reports
= ext
->collection_desc
.ReportIDs
;
1004 for (i
= 0; i
< ext
->collection_desc
.ReportIDsLength
; ++i
)
1006 if (!reports
[i
].InputLength
) continue;
1007 RtlFreeHeap(GetProcessHeap(), 0, ext
->last_reports
[reports
[i
].ReportID
]);
1009 HidP_FreeCollectionDescription(&ext
->collection_desc
);
1010 RtlFreeHeap(GetProcessHeap(), 0, ext
->report_desc
);
1012 IoDeleteDevice(device
);
1013 return STATUS_SUCCESS
;
1016 FIXME("Unhandled function %08x\n", irpsp
->MinorFunction
);
1019 case IRP_MN_QUERY_DEVICE_RELATIONS
:
1023 irp
->IoStatus
.Status
= status
;
1024 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1028 static NTSTATUS WINAPI
common_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
1030 if (device
== bus_fdo
)
1031 return fdo_pnp_dispatch(device
, irp
);
1032 return pdo_pnp_dispatch(device
, irp
);
1035 static NTSTATUS
hid_get_device_string(DEVICE_OBJECT
*device
, DWORD index
, WCHAR
*buffer
, DWORD buffer_len
)
1037 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
1042 case HID_STRING_ID_IMANUFACTURER
:
1043 len
= (wcslen(ext
->desc
.manufacturer
) + 1) * sizeof(WCHAR
);
1044 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
1045 else memcpy(buffer
, ext
->desc
.manufacturer
, len
);
1046 return STATUS_SUCCESS
;
1047 case HID_STRING_ID_IPRODUCT
:
1048 len
= (wcslen(ext
->desc
.product
) + 1) * sizeof(WCHAR
);
1049 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
1050 else memcpy(buffer
, ext
->desc
.product
, len
);
1051 return STATUS_SUCCESS
;
1052 case HID_STRING_ID_ISERIALNUMBER
:
1053 len
= (wcslen(ext
->desc
.serialnumber
) + 1) * sizeof(WCHAR
);
1054 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
1055 else memcpy(buffer
, ext
->desc
.serialnumber
, len
);
1056 return STATUS_SUCCESS
;
1059 return STATUS_NOT_IMPLEMENTED
;
1062 static NTSTATUS WINAPI
hid_internal_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
1064 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
1065 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
1066 ULONG i
, code
, buffer_len
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
1069 if (device
== bus_fdo
)
1071 IoSkipCurrentIrpStackLocation(irp
);
1072 return IoCallDriver(bus_pdo
, irp
);
1075 RtlEnterCriticalSection(&ext
->cs
);
1077 if (ext
->state
== DEVICE_STATE_REMOVED
)
1079 RtlLeaveCriticalSection(&ext
->cs
);
1080 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
1081 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1082 return STATUS_DELETE_PENDING
;
1085 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
1087 case IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
1089 HID_DEVICE_ATTRIBUTES
*attr
= (HID_DEVICE_ATTRIBUTES
*)irp
->UserBuffer
;
1090 TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
1092 if (buffer_len
< sizeof(*attr
))
1094 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1098 memset(attr
, 0, sizeof(*attr
));
1099 attr
->Size
= sizeof(*attr
);
1100 attr
->VendorID
= ext
->desc
.vid
;
1101 attr
->ProductID
= ext
->desc
.pid
;
1102 attr
->VersionNumber
= ext
->desc
.version
;
1104 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1105 irp
->IoStatus
.Information
= sizeof(*attr
);
1108 case IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
1110 HID_DESCRIPTOR
*descriptor
= (HID_DESCRIPTOR
*)irp
->UserBuffer
;
1111 irp
->IoStatus
.Information
= sizeof(*descriptor
);
1112 if (buffer_len
< sizeof(*descriptor
)) irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1115 memset(descriptor
, 0, sizeof(*descriptor
));
1116 descriptor
->bLength
= sizeof(*descriptor
);
1117 descriptor
->bDescriptorType
= HID_HID_DESCRIPTOR_TYPE
;
1118 descriptor
->bcdHID
= HID_REVISION
;
1119 descriptor
->bCountry
= 0;
1120 descriptor
->bNumDescriptors
= 1;
1121 descriptor
->DescriptorList
[0].bReportType
= HID_REPORT_DESCRIPTOR_TYPE
;
1122 descriptor
->DescriptorList
[0].wReportLength
= ext
->report_desc_length
;
1123 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1127 case IOCTL_HID_GET_REPORT_DESCRIPTOR
:
1128 irp
->IoStatus
.Information
= ext
->report_desc_length
;
1129 if (buffer_len
< irp
->IoStatus
.Information
)
1130 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1133 memcpy(irp
->UserBuffer
, ext
->report_desc
, ext
->report_desc_length
);
1134 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1137 case IOCTL_HID_GET_STRING
:
1139 UINT index
= (UINT_PTR
)irpsp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1140 TRACE("IOCTL_HID_GET_STRING[%08x]\n", index
);
1142 irp
->IoStatus
.Status
= hid_get_device_string(device
, index
, (WCHAR
*)irp
->UserBuffer
, buffer_len
);
1143 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
1144 irp
->IoStatus
.Information
= (wcslen((WCHAR
*)irp
->UserBuffer
) + 1) * sizeof(WCHAR
);
1147 case IOCTL_HID_GET_INPUT_REPORT
:
1149 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1150 struct hid_report
*last_report
= ext
->last_reports
[packet
->reportId
];
1151 memcpy(packet
->reportBuffer
, last_report
->buffer
, last_report
->length
);
1152 packet
->reportBufferLen
= last_report
->length
;
1153 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
1154 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1157 TRACE("read input report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1158 for (i
= 0; i
< packet
->reportBufferLen
;)
1160 char buffer
[256], *buf
= buffer
;
1161 buf
+= sprintf(buf
, "%08lx ", i
);
1162 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1163 while (++i
% 16 && i
< packet
->reportBufferLen
);
1164 TRACE("%s\n", buffer
);
1169 case IOCTL_HID_READ_REPORT
:
1171 if (!deliver_next_report(ext
, irp
))
1173 /* hidclass.sys should guarantee this */
1174 assert(!ext
->pending_read
);
1175 ext
->pending_read
= irp
;
1176 IoMarkIrpPending(irp
);
1177 irp
->IoStatus
.Status
= STATUS_PENDING
;
1181 case IOCTL_HID_SET_OUTPUT_REPORT
:
1182 case IOCTL_HID_WRITE_REPORT
:
1184 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1187 TRACE("write output report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1188 for (i
= 0; i
< packet
->reportBufferLen
;)
1190 char buffer
[256], *buf
= buffer
;
1191 buf
+= sprintf(buf
, "%08lx ", i
);
1192 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1193 while (++i
% 16 && i
< packet
->reportBufferLen
);
1194 TRACE("%s\n", buffer
);
1197 unix_device_set_output_report(device
, packet
, &irp
->IoStatus
);
1200 case IOCTL_HID_GET_FEATURE
:
1202 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1203 unix_device_get_feature_report(device
, packet
, &irp
->IoStatus
);
1204 if (!irp
->IoStatus
.Status
&& TRACE_ON(hid
))
1206 TRACE("read feature report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1207 for (i
= 0; i
< packet
->reportBufferLen
;)
1209 char buffer
[256], *buf
= buffer
;
1210 buf
+= sprintf(buf
, "%08lx ", i
);
1211 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1212 while (++i
% 16 && i
< packet
->reportBufferLen
);
1213 TRACE("%s\n", buffer
);
1218 case IOCTL_HID_SET_FEATURE
:
1220 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1223 TRACE("write feature report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1224 for (i
= 0; i
< packet
->reportBufferLen
;)
1226 char buffer
[256], *buf
= buffer
;
1227 buf
+= sprintf(buf
, "%08lx ", i
);
1228 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1229 while (++i
% 16 && i
< packet
->reportBufferLen
);
1230 TRACE("%s\n", buffer
);
1233 unix_device_set_feature_report(device
, packet
, &irp
->IoStatus
);
1237 FIXME("Unsupported ioctl %lx (device=%lx access=%lx func=%lx method=%lx)\n",
1238 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
1242 status
= irp
->IoStatus
.Status
;
1243 RtlLeaveCriticalSection(&ext
->cs
);
1245 if (status
!= STATUS_PENDING
) IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1249 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*pdo
)
1253 TRACE("driver %p, pdo %p.\n", driver
, pdo
);
1255 if ((ret
= IoCreateDevice(driver
, 0, NULL
, FILE_DEVICE_BUS_EXTENDER
, 0, FALSE
, &bus_fdo
)))
1257 ERR("Failed to create FDO, status %#lx.\n", ret
);
1261 IoAttachDeviceToDeviceStack(bus_fdo
, pdo
);
1264 bus_fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1266 return STATUS_SUCCESS
;
1269 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
1271 NtClose(driver_key
);
1274 NTSTATUS WINAPI
DriverEntry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
1276 OBJECT_ATTRIBUTES attr
= {0};
1279 TRACE( "(%p, %s)\n", driver
, debugstr_w(path
->Buffer
) );
1281 if ((ret
= __wine_init_unix_call())) return ret
;
1283 attr
.Length
= sizeof(attr
);
1284 attr
.ObjectName
= path
;
1285 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
;
1286 if ((ret
= NtOpenKey(&driver_key
, KEY_ALL_ACCESS
, &attr
)) != STATUS_SUCCESS
)
1287 ERR("Failed to open driver key, status %#lx.\n", ret
);
1289 driver_obj
= driver
;
1291 driver
->MajorFunction
[IRP_MJ_PNP
] = common_pnp_dispatch
;
1292 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = hid_internal_dispatch
;
1293 driver
->DriverExtension
->AddDevice
= driver_add_device
;
1294 driver
->DriverUnload
= driver_unload
;
1296 return STATUS_SUCCESS
;