include: Add STORAGE_HOTPLUG_INFO structure.
[wine.git] / dlls / winebus.sys / main.c
blob8d3b72d93f1a32d2918b77a11a61a2cd4ef19a2a
1 /*
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
21 #include <stdarg.h>
22 #include <assert.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "winternl.h"
30 #include "winioctl.h"
31 #include "hidusage.h"
32 #include "ddk/wdm.h"
33 #include "ddk/hidport.h"
34 #include "ddk/hidtypes.h"
35 #include "ddk/hidpddi.h"
36 #include "wine/asm.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "wine/unixlib.h"
41 #include "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;
56 struct hid_report
58 struct list entry;
59 ULONG length;
60 BYTE buffer[1];
63 enum device_state
65 DEVICE_STATE_STOPPED,
66 DEVICE_STATE_STARTED,
67 DEVICE_STATE_REMOVED,
70 struct device_extension
72 struct list entry;
73 DEVICE_OBJECT *device;
75 CRITICAL_SECTION cs;
76 enum device_state state;
78 struct device_desc desc;
79 DWORD index;
81 BYTE *report_desc;
82 UINT report_desc_length;
83 HIDP_DEVICE_DESC collection_desc;
85 struct hid_report *last_reports[256];
86 struct list reports;
87 IRP *pending_read;
89 UINT64 unix_device;
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, &params);
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, &params);
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,
128 .packet = packet,
129 .io = io,
131 winebus_call(device_set_output_report, &params);
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,
140 .packet = packet,
141 .io = io,
143 winebus_call(device_get_feature_report, &params);
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,
152 .packet = packet,
153 .io = io,
155 winebus_call(device_set_feature_report, &params);
158 static DWORD get_device_index(struct device_desc *desc)
160 struct device_extension *ext;
161 DWORD index = 0;
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);
169 return 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;
176 WCHAR *dst;
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);
184 return dst;
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;
193 WCHAR *dst;
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);
205 return dst;
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;
214 WCHAR *dst;
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);
224 pos += 1;
225 dst[pos] = 0;
228 return dst;
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);
237 WCHAR *dst;
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;
248 return dst;
251 static IRP *pop_pending_read(struct device_extension *ext)
253 IRP *pending;
255 RtlEnterCriticalSection(&ext->cs);
256 pending = ext->pending_read;
257 ext->pending_read = NULL;
258 RtlLeaveCriticalSection(&ext->cs);
260 return pending;
263 static void remove_pending_irps(DEVICE_OBJECT *device)
265 struct device_extension *ext = device->DeviceExtension;
266 IRP *pending;
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;
281 WCHAR dev_name[256];
282 NTSTATUS status;
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);
289 if (status)
291 FIXME("failed to create device error %#lx\n", status);
292 return NULL;
295 RtlEnterCriticalSection(&device_list_cs);
297 /* fill out device_extension struct */
298 ext = (struct device_extension *)device->DeviceExtension;
299 ext->device = device;
300 ext->desc = *desc;
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);
314 return 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;
324 return NULL;
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,
339 "popl %ecx\n\t"
340 "popl %eax\n\t"
341 "xchgl (%esp),%ecx\n\t"
342 "jmp *%eax");
343 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
344 #else
345 #define call_fastcall_func1(func,a) func(a)
346 #endif
348 static NTSTATUS build_device_relations(DEVICE_RELATIONS **devices)
350 struct device_extension *ext;
351 int i;
353 RtlEnterCriticalSection(&device_list_cs);
354 *devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[list_count(&device_list)]));
356 if (!*devices)
358 RtlLeaveCriticalSection(&device_list_cs);
359 return STATUS_INSUFFICIENT_RESOURCES;
362 i = 0;
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);
367 i++;
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;
378 UNICODE_STRING str;
379 DWORD size;
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;
397 UNICODE_STRING str;
398 DWORD size;
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);
422 tmp += len + 1;
426 return prefer_hidraw;
429 static BOOL deliver_next_report(struct device_extension *ext, IRP *irp)
431 struct hid_report *report;
432 struct list *entry;
433 ULONG i;
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;
443 if (TRACE_ON(hid))
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);
457 return TRUE;
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;
465 IRP *irp;
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:
497 case PowerRelations:
498 FIXME("Unhandled Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type);
499 break;
500 case BusRelations:
501 status = build_device_relations((DEVICE_RELATIONS**)&irp->IoStatus.Information);
502 break;
503 default:
504 FIXME("Unknown Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type);
505 break;
508 return status;
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);
519 switch (type)
521 case BusQueryHardwareIDs:
522 TRACE("BusQueryHardwareIDs\n");
523 irp->IoStatus.Information = (ULONG_PTR)get_hardware_ids(device);
524 break;
525 case BusQueryCompatibleIDs:
526 TRACE("BusQueryCompatibleIDs\n");
527 irp->IoStatus.Information = (ULONG_PTR)get_compatible_ids(device);
528 break;
529 case BusQueryDeviceID:
530 TRACE("BusQueryDeviceID\n");
531 irp->IoStatus.Information = (ULONG_PTR)get_device_id(device);
532 break;
533 case BusQueryInstanceID:
534 TRACE("BusQueryInstanceID\n");
535 irp->IoStatus.Information = (ULONG_PTR)get_instance_id(device);
536 break;
537 default:
538 WARN("Unhandled type %08x\n", type);
539 return status;
542 status = irp->IoStatus.Information ? STATUS_SUCCESS : STATUS_NO_MEMORY;
543 return status;
546 static void mouse_device_create(void)
548 struct device_create_params params = {{0}};
550 if (winebus_call(mouse_create, &params)) return;
551 mouse_obj = bus_create_hid_device(&params.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, &params)) return;
560 keyboard_obj = bus_create_hid_device(&params.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,
572 NTSTATUS status;
574 status = winebus_call(device_get_report_descriptor, &params);
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);
578 return 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, &params)))
587 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device, status);
588 RtlFreeHeap(GetProcessHeap(), 0, params.buffer);
589 return status;
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);
598 return status;
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;
610 BYTE *report_desc;
611 NTSTATUS status;
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);
621 return usages;
624 static DWORD bus_count;
625 static HANDLE bus_thread[16];
627 struct bus_main_params
629 const WCHAR *name;
631 void *init_args;
632 HANDLE init_done;
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;
643 NTSTATUS status;
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;
656 switch (event->type)
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);
666 break;
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, &params);
677 break;
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);
685 else
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, &params);
691 break;
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);
699 break;
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);
706 return status;
709 static NTSTATUS bus_main_thread_start(struct bus_main_params *bus)
711 DWORD i = bus_count++, max_size;
712 NTSTATUS status;
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));
717 bus_count--;
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);
726 bus_count--;
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);
735 bus_count--;
736 return STATUS_UNSUCCESSFUL;
739 WaitForSingleObject(bus->init_done, INFINITE);
740 CloseHandle(bus->init_done);
741 return status;
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;
760 NTSTATUS status;
761 HANDLE key;
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);
768 if (status) return;
770 capacity = 1024;
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;
789 goto done;
792 idx++;
793 if (status) break;
794 if (info->Type != REG_SZ) continue;
796 RtlUnicodeToMultiByteSize(&len, (WCHAR *)((char *)info + info->DataOffset), info_size - info->DataOffset);
797 if (!len) continue;
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))))
804 break;
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);
815 done:
816 RtlFreeHeap(GetProcessHeap(), 0, info);
817 NtClose(key);
820 static NTSTATUS sdl_driver_init(void)
822 struct sdl_bus_options bus_options;
823 struct bus_main_params bus =
825 .name = L"SDL",
826 .init_args = &bus_options,
827 .init_code = sdl_init,
828 .wait_code = sdl_wait,
830 NTSTATUS status;
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);
840 return status;
843 static NTSTATUS udev_driver_init(BOOL enable_sdl)
845 struct udev_bus_options bus_options;
846 struct bus_main_params bus =
848 .name = L"UDEV",
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 =
869 .name = L"IOHID",
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);
887 BOOL enable_sdl;
888 NTSTATUS ret;
890 switch (irpsp->MinorFunction)
892 case IRP_MN_QUERY_DEVICE_RELATIONS:
893 irp->IoStatus.Status = handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp);
894 break;
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);
902 iohid_driver_init();
904 irp->IoStatus.Status = STATUS_SUCCESS;
905 break;
906 case IRP_MN_SURPRISE_REMOVAL:
907 irp->IoStatus.Status = STATUS_SUCCESS;
908 break;
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);
922 return ret;
923 default:
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;
938 ULONG i, size;
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);
946 break;
948 case IRP_MN_QUERY_CAPABILITIES:
949 status = STATUS_SUCCESS;
950 break;
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;
968 else
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);
978 break;
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;
986 break;
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;
1015 default:
1016 FIXME("Unhandled function %08x\n", irpsp->MinorFunction);
1017 /* fall through */
1019 case IRP_MN_QUERY_DEVICE_RELATIONS:
1020 break;
1023 irp->IoStatus.Status = status;
1024 IoCompleteRequest(irp, IO_NO_INCREMENT);
1025 return status;
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;
1038 DWORD len;
1040 switch (index)
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;
1067 NTSTATUS status;
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;
1095 break;
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);
1106 break;
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;
1113 else
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;
1125 break;
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;
1131 else
1133 memcpy(irp->UserBuffer, ext->report_desc, ext->report_desc_length);
1134 irp->IoStatus.Status = STATUS_SUCCESS;
1136 break;
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);
1145 break;
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;
1155 if (TRACE_ON(hid))
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);
1167 break;
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;
1179 break;
1181 case IOCTL_HID_SET_OUTPUT_REPORT:
1182 case IOCTL_HID_WRITE_REPORT:
1184 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1185 if (TRACE_ON(hid))
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);
1198 break;
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);
1216 break;
1218 case IOCTL_HID_SET_FEATURE:
1220 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1221 if (TRACE_ON(hid))
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);
1234 break;
1236 default:
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);
1239 break;
1242 status = irp->IoStatus.Status;
1243 RtlLeaveCriticalSection(&ext->cs);
1245 if (status != STATUS_PENDING) IoCompleteRequest(irp, IO_NO_INCREMENT);
1246 return status;
1249 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
1251 NTSTATUS ret;
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);
1258 return ret;
1261 IoAttachDeviceToDeviceStack(bus_fdo, pdo);
1262 bus_pdo = 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};
1277 NTSTATUS ret;
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;