include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / winebus.sys / main.c
blobf7a634dbfe2d35c7270f7e0762c0c5cb297ff1b8
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 #define HIDRAW_FIXUP_DUALSHOCK_BT 0x1
71 #define HIDRAW_FIXUP_DUALSENSE_BT 0x2
73 struct device_extension
75 struct list entry;
76 DEVICE_OBJECT *device;
78 CRITICAL_SECTION cs;
79 enum device_state state;
81 struct device_desc desc;
82 DWORD index;
84 BYTE *report_desc;
85 UINT report_desc_length;
86 HIDP_DEVICE_DESC collection_desc;
88 struct hid_report *last_reports[256];
89 struct list reports;
90 IRP *pending_read;
92 UINT32 report_fixups;
93 UINT64 unix_device;
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, &params);
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, &params);
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,
132 .packet = packet,
133 .io = io,
135 winebus_call(device_set_output_report, &params);
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,
144 .packet = packet,
145 .io = io,
147 winebus_call(device_get_feature_report, &params);
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,
156 .packet = packet,
157 .io = io,
159 winebus_call(device_set_feature_report, &params);
162 static DWORD get_device_index(struct device_desc *desc)
164 struct device_extension *ext;
165 DWORD index = 0;
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);
173 return 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;
180 WCHAR *dst;
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);
188 return dst;
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;
197 WCHAR *dst;
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);
209 return dst;
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;
218 WCHAR *dst;
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);
228 pos += 1;
229 dst[pos] = 0;
232 return dst;
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);
241 WCHAR *dst;
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;
252 return dst;
255 static IRP *pop_pending_read(struct device_extension *ext)
257 IRP *pending;
259 RtlEnterCriticalSection(&ext->cs);
260 pending = ext->pending_read;
261 ext->pending_read = NULL;
262 RtlLeaveCriticalSection(&ext->cs);
264 return pending;
267 static void remove_pending_irps(DEVICE_OBJECT *device)
269 struct device_extension *ext = device->DeviceExtension;
270 IRP *pending;
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;
285 WCHAR dev_name[256];
286 NTSTATUS status;
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);
293 if (status)
295 FIXME("failed to create device error %#lx\n", status);
296 return NULL;
299 RtlEnterCriticalSection(&device_list_cs);
301 /* fill out device_extension struct */
302 ext = (struct device_extension *)device->DeviceExtension;
303 ext->device = device;
304 ext->desc = *desc;
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);
329 return 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;
339 return NULL;
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,
354 "popl %ecx\n\t"
355 "popl %eax\n\t"
356 "xchgl (%esp),%ecx\n\t"
357 "jmp *%eax");
358 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
359 #else
360 #define call_fastcall_func1(func,a) func(a)
361 #endif
363 static NTSTATUS build_device_relations(DEVICE_RELATIONS **devices)
365 struct device_extension *ext;
366 int i;
368 RtlEnterCriticalSection(&device_list_cs);
369 *devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[list_count(&device_list)]));
371 if (!*devices)
373 RtlLeaveCriticalSection(&device_list_cs);
374 return STATUS_INSUFFICIENT_RESOURCES;
377 i = 0;
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);
382 i++;
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;
393 UNICODE_STRING str;
394 DWORD size;
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;
412 UNICODE_STRING str;
413 DWORD size;
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);
437 tmp += len + 1;
441 return prefer_hidraw;
444 static BOOL deliver_next_report(struct device_extension *ext, IRP *irp)
446 struct hid_report *report;
447 struct list *entry;
448 ULONG i;
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;
458 if (TRACE_ON(hid))
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);
472 return TRUE;
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;
480 IRP *irp;
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 */
502 report->length = 10;
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.
514 * Basic #1 report:
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)
522 BYTE trigger[2];
524 memmove(report->buffer, report->buffer + 1, 10);
525 report->buffer[0] = 1; /* fake report #1 */
526 report->length = 10;
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:
565 case PowerRelations:
566 FIXME("Unhandled Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type);
567 break;
568 case BusRelations:
569 status = build_device_relations((DEVICE_RELATIONS**)&irp->IoStatus.Information);
570 break;
571 default:
572 FIXME("Unknown Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type);
573 break;
576 return status;
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);
587 switch (type)
589 case BusQueryHardwareIDs:
590 TRACE("BusQueryHardwareIDs\n");
591 irp->IoStatus.Information = (ULONG_PTR)get_hardware_ids(device);
592 break;
593 case BusQueryCompatibleIDs:
594 TRACE("BusQueryCompatibleIDs\n");
595 irp->IoStatus.Information = (ULONG_PTR)get_compatible_ids(device);
596 break;
597 case BusQueryDeviceID:
598 TRACE("BusQueryDeviceID\n");
599 irp->IoStatus.Information = (ULONG_PTR)get_device_id(device);
600 break;
601 case BusQueryInstanceID:
602 TRACE("BusQueryInstanceID\n");
603 irp->IoStatus.Information = (ULONG_PTR)get_instance_id(device);
604 break;
605 default:
606 WARN("Unhandled type %08x\n", type);
607 return status;
610 status = irp->IoStatus.Information ? STATUS_SUCCESS : STATUS_NO_MEMORY;
611 return status;
614 static void mouse_device_create(void)
616 struct device_create_params params = {{0}};
618 if (winebus_call(mouse_create, &params)) return;
619 mouse_obj = bus_create_hid_device(&params.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, &params)) return;
628 keyboard_obj = bus_create_hid_device(&params.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,
640 NTSTATUS status;
642 status = winebus_call(device_get_report_descriptor, &params);
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);
646 return 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, &params)))
655 ERR("Failed to get device %#I64x report descriptor, status %#lx\n", unix_device, status);
656 RtlFreeHeap(GetProcessHeap(), 0, params.buffer);
657 return status;
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);
666 return status;
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;
678 BYTE *report_desc;
679 NTSTATUS status;
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);
689 return usages;
692 static DWORD bus_count;
693 static HANDLE bus_thread[16];
695 struct bus_main_params
697 const WCHAR *name;
699 void *init_args;
700 HANDLE init_done;
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;
711 NTSTATUS status;
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;
724 switch (event->type)
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);
734 break;
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, &params);
745 break;
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);
753 else
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, &params);
759 break;
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);
767 break;
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);
774 return status;
777 static NTSTATUS bus_main_thread_start(struct bus_main_params *bus)
779 DWORD i = bus_count++, max_size;
780 NTSTATUS status;
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));
785 bus_count--;
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);
794 bus_count--;
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);
803 bus_count--;
804 return STATUS_UNSUCCESSFUL;
807 WaitForSingleObject(bus->init_done, INFINITE);
808 CloseHandle(bus->init_done);
809 return status;
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;
828 NTSTATUS status;
829 HANDLE key;
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);
836 if (status) return;
838 capacity = 1024;
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;
857 goto done;
860 idx++;
861 if (status) break;
862 if (info->Type != REG_SZ) continue;
864 RtlUnicodeToMultiByteSize(&len, (WCHAR *)((char *)info + info->DataOffset), info_size - info->DataOffset);
865 if (!len) continue;
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))))
872 break;
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);
883 done:
884 RtlFreeHeap(GetProcessHeap(), 0, info);
885 NtClose(key);
888 static NTSTATUS sdl_driver_init(void)
890 struct sdl_bus_options bus_options;
891 struct bus_main_params bus =
893 .name = L"SDL",
894 .init_args = &bus_options,
895 .init_code = sdl_init,
896 .wait_code = sdl_wait,
898 NTSTATUS status;
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);
908 return status;
911 static NTSTATUS udev_driver_init(BOOL enable_sdl)
913 struct udev_bus_options bus_options;
914 struct bus_main_params bus =
916 .name = L"UDEV",
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 =
937 .name = L"IOHID",
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);
955 BOOL enable_sdl;
956 NTSTATUS ret;
958 switch (irpsp->MinorFunction)
960 case IRP_MN_QUERY_DEVICE_RELATIONS:
961 irp->IoStatus.Status = handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp);
962 break;
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);
970 iohid_driver_init();
972 irp->IoStatus.Status = STATUS_SUCCESS;
973 break;
974 case IRP_MN_SURPRISE_REMOVAL:
975 irp->IoStatus.Status = STATUS_SUCCESS;
976 break;
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);
990 return ret;
991 default:
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;
1006 ULONG i, size;
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);
1014 break;
1016 case IRP_MN_QUERY_CAPABILITIES:
1017 status = STATUS_SUCCESS;
1018 break;
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;
1036 else
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);
1046 break;
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;
1054 break;
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;
1083 default:
1084 FIXME("Unhandled function %08x\n", irpsp->MinorFunction);
1085 /* fall through */
1087 case IRP_MN_QUERY_DEVICE_RELATIONS:
1088 break;
1091 irp->IoStatus.Status = status;
1092 IoCompleteRequest(irp, IO_NO_INCREMENT);
1093 return status;
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;
1106 DWORD len;
1108 switch (index)
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;
1156 NTSTATUS status;
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;
1184 break;
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);
1195 break;
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;
1202 else
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;
1214 break;
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;
1220 else
1222 memcpy(irp->UserBuffer, ext->report_desc, ext->report_desc_length);
1223 irp->IoStatus.Status = STATUS_SUCCESS;
1225 break;
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);
1234 break;
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;
1244 if (TRACE_ON(hid))
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);
1256 break;
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;
1268 break;
1270 case IOCTL_HID_SET_OUTPUT_REPORT:
1271 case IOCTL_HID_WRITE_REPORT:
1273 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1274 if (TRACE_ON(hid))
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);
1288 break;
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);
1307 break;
1309 case IOCTL_HID_SET_FEATURE:
1311 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1312 if (TRACE_ON(hid))
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);
1326 break;
1328 default:
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);
1331 break;
1334 status = irp->IoStatus.Status;
1335 RtlLeaveCriticalSection(&ext->cs);
1337 if (status != STATUS_PENDING) IoCompleteRequest(irp, IO_NO_INCREMENT);
1338 return status;
1341 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
1343 NTSTATUS ret;
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);
1350 return ret;
1353 IoAttachDeviceToDeviceStack(bus_fdo, pdo);
1354 bus_pdo = 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};
1369 NTSTATUS ret;
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;