rpcrt4: Avoid casting an object to IUnknown.
[wine.git] / dlls / winebus.sys / main.c
blobc02f786a11f2a7c4ccd1c4b76520b90c9a89e38b
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 NTSTATUS unix_device_get_report_descriptor(DEVICE_OBJECT *device, BYTE *buffer, UINT length, UINT *out_length)
124 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
125 struct device_descriptor_params params =
127 .device = ext->unix_device,
128 .buffer = buffer,
129 .length = length,
130 .out_length = out_length
132 return winebus_call(device_get_report_descriptor, &params);
135 static void unix_device_set_output_report(DEVICE_OBJECT *device, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
137 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
138 struct device_report_params params =
140 .device = ext->unix_device,
141 .packet = packet,
142 .io = io,
144 winebus_call(device_set_output_report, &params);
147 static void unix_device_get_feature_report(DEVICE_OBJECT *device, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
149 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
150 struct device_report_params params =
152 .device = ext->unix_device,
153 .packet = packet,
154 .io = io,
156 winebus_call(device_get_feature_report, &params);
159 static void unix_device_set_feature_report(DEVICE_OBJECT *device, HID_XFER_PACKET *packet, IO_STATUS_BLOCK *io)
161 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
162 struct device_report_params params =
164 .device = ext->unix_device,
165 .packet = packet,
166 .io = io,
168 winebus_call(device_set_feature_report, &params);
171 static DWORD get_device_index(struct device_desc *desc)
173 struct device_extension *ext;
174 DWORD index = 0;
176 LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry)
178 if (ext->desc.vid == desc->vid && ext->desc.pid == desc->pid && ext->desc.input == desc->input)
179 index = max(ext->index + 1, index);
182 return index;
185 static WCHAR *get_instance_id(DEVICE_OBJECT *device)
187 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
188 DWORD len = wcslen(ext->desc.serialnumber) + 33;
189 WCHAR *dst;
191 if ((dst = ExAllocatePool(PagedPool, len * sizeof(WCHAR))))
192 swprintf(dst, len, L"%i&%s&%x&%i", ext->desc.version, ext->desc.serialnumber, ext->desc.uid, ext->index);
194 return dst;
197 static WCHAR *get_device_id(DEVICE_OBJECT *device)
199 static const WCHAR input_format[] = L"&MI_%02u";
200 static const WCHAR winebus_format[] = L"WINEBUS\\VID_%04X&PID_%04X";
201 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
202 DWORD pos = 0, len = 0, input_len = 0, winebus_len = 25;
203 WCHAR *dst;
205 if (ext->desc.input != -1) input_len = 14;
207 len += winebus_len + input_len + 1;
209 if ((dst = ExAllocatePool(PagedPool, len * sizeof(WCHAR))))
211 pos += swprintf(dst + pos, len - pos, winebus_format, ext->desc.vid, ext->desc.pid);
212 if (input_len) pos += swprintf(dst + pos, len - pos, input_format, ext->desc.input);
215 return dst;
218 static WCHAR *get_hardware_ids(DEVICE_OBJECT *device)
220 static const WCHAR input_format[] = L"&MI_%02u";
221 static const WCHAR winebus_format[] = L"WINEBUS\\VID_%04X&PID_%04X";
222 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
223 DWORD pos = 0, len = 0, input_len = 0, winebus_len = 25;
224 WCHAR *dst;
226 if (ext->desc.input != -1) input_len = 14;
228 len += winebus_len + input_len + 1;
230 if ((dst = ExAllocatePool(PagedPool, (len + 1) * sizeof(WCHAR))))
232 pos += swprintf(dst + pos, len - pos, winebus_format, ext->desc.vid, ext->desc.pid);
233 if (input_len) pos += swprintf(dst + pos, len - pos, input_format, ext->desc.input);
234 pos += 1;
235 dst[pos] = 0;
238 return dst;
241 static WCHAR *get_compatible_ids(DEVICE_OBJECT *device)
243 static const WCHAR xinput_compat[] = L"WINEBUS\\WINE_COMP_XINPUT";
244 static const WCHAR hid_compat[] = L"WINEBUS\\WINE_COMP_HID";
245 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
246 DWORD size = sizeof(hid_compat);
247 WCHAR *dst;
249 if (ext->desc.is_gamepad) size += sizeof(xinput_compat);
251 if ((dst = ExAllocatePool(PagedPool, size + sizeof(WCHAR))))
253 if (ext->desc.is_gamepad) memcpy(dst, xinput_compat, sizeof(xinput_compat));
254 memcpy((char *)dst + size - sizeof(hid_compat), hid_compat, sizeof(hid_compat));
255 dst[size / sizeof(WCHAR)] = 0;
258 return dst;
261 static IRP *pop_pending_read(struct device_extension *ext)
263 IRP *pending;
265 RtlEnterCriticalSection(&ext->cs);
266 pending = ext->pending_read;
267 ext->pending_read = NULL;
268 RtlLeaveCriticalSection(&ext->cs);
270 return pending;
273 static void remove_pending_irps(DEVICE_OBJECT *device)
275 struct device_extension *ext = device->DeviceExtension;
276 IRP *pending;
278 if ((pending = pop_pending_read(ext)))
280 pending->IoStatus.Status = STATUS_DELETE_PENDING;
281 pending->IoStatus.Information = 0;
282 IoCompleteRequest(pending, IO_NO_INCREMENT);
286 static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, UINT64 unix_device)
288 struct device_extension *ext;
289 DEVICE_OBJECT *device;
290 UNICODE_STRING nameW;
291 WCHAR dev_name[256];
292 NTSTATUS status;
294 TRACE("desc %s, unix_device %#I64x\n", debugstr_device_desc(desc), unix_device);
296 swprintf(dev_name, ARRAY_SIZE(dev_name), L"\\Device\\WINEBUS#%p", unix_device);
297 RtlInitUnicodeString(&nameW, dev_name);
298 status = IoCreateDevice(driver_obj, sizeof(struct device_extension), &nameW, 0, 0, FALSE, &device);
299 if (status)
301 FIXME("failed to create device error %#lx\n", status);
302 return NULL;
305 RtlEnterCriticalSection(&device_list_cs);
307 /* fill out device_extension struct */
308 ext = (struct device_extension *)device->DeviceExtension;
309 ext->device = device;
310 ext->desc = *desc;
311 ext->index = get_device_index(desc);
312 ext->unix_device = unix_device;
313 list_init(&ext->reports);
315 InitializeCriticalSection(&ext->cs);
316 ext->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
318 /* add to list of pnp devices */
319 list_add_tail(&device_list, &ext->entry);
321 RtlLeaveCriticalSection(&device_list_cs);
323 TRACE("created device %p/%#I64x\n", device, unix_device);
324 return device;
327 static DEVICE_OBJECT *bus_find_unix_device(UINT64 unix_device)
329 struct device_extension *ext;
331 LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry)
332 if (ext->unix_device == unix_device) return ext->device;
334 return NULL;
337 static void bus_unlink_hid_device(DEVICE_OBJECT *device)
339 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
341 RtlEnterCriticalSection(&device_list_cs);
342 list_remove(&ext->entry);
343 RtlLeaveCriticalSection(&device_list_cs);
346 #ifdef __ASM_USE_FASTCALL_WRAPPER
347 extern void * WINAPI wrap_fastcall_func1(void *func, const void *a);
348 __ASM_STDCALL_FUNC(wrap_fastcall_func1, 8,
349 "popl %ecx\n\t"
350 "popl %eax\n\t"
351 "xchgl (%esp),%ecx\n\t"
352 "jmp *%eax");
353 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
354 #else
355 #define call_fastcall_func1(func,a) func(a)
356 #endif
358 static NTSTATUS build_device_relations(DEVICE_RELATIONS **devices)
360 struct device_extension *ext;
361 int i;
363 RtlEnterCriticalSection(&device_list_cs);
364 *devices = ExAllocatePool(PagedPool, offsetof(DEVICE_RELATIONS, Objects[list_count(&device_list)]));
366 if (!*devices)
368 RtlLeaveCriticalSection(&device_list_cs);
369 return STATUS_INSUFFICIENT_RESOURCES;
372 i = 0;
373 LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry)
375 (*devices)->Objects[i] = ext->device;
376 call_fastcall_func1(ObfReferenceObject, ext->device);
377 i++;
379 RtlLeaveCriticalSection(&device_list_cs);
380 (*devices)->Count = i;
381 return STATUS_SUCCESS;
384 static DWORD check_bus_option(const WCHAR *option, DWORD default_value)
386 char buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(DWORD)])];
387 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
388 UNICODE_STRING str;
389 DWORD size;
391 RtlInitUnicodeString(&str, option);
393 if (NtQueryValueKey(driver_key, &str, KeyValuePartialInformation, info, sizeof(buffer), &size) == STATUS_SUCCESS)
395 if (info->Type == REG_DWORD) return *(DWORD *)info->Data;
398 return default_value;
401 static BOOL deliver_next_report(struct device_extension *ext, IRP *irp)
403 struct hid_report *report;
404 struct list *entry;
405 ULONG i;
407 if (!(entry = list_head(&ext->reports))) return FALSE;
408 report = LIST_ENTRY(entry, struct hid_report, entry);
409 list_remove(&report->entry);
411 memcpy(irp->UserBuffer, report->buffer, report->length);
412 irp->IoStatus.Information = report->length;
413 irp->IoStatus.Status = STATUS_SUCCESS;
415 if (TRACE_ON(hid))
417 TRACE("device %p/%#I64x input report length %lu:\n", ext->device, ext->unix_device, report->length);
418 for (i = 0; i < report->length;)
420 char buffer[256], *buf = buffer;
421 buf += sprintf(buf, "%08lx ", i);
422 do { buf += sprintf(buf, " %02x", report->buffer[i]); }
423 while (++i % 16 && i < report->length);
424 TRACE("%s\n", buffer);
428 RtlFreeHeap(GetProcessHeap(), 0, report);
429 return TRUE;
432 static void process_hid_report(DEVICE_OBJECT *device, BYTE *report_buf, DWORD report_len)
434 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
435 ULONG size = offsetof(struct hid_report, buffer[report_len]);
436 struct hid_report *report, *last_report;
437 IRP *irp;
439 if (!(report = RtlAllocateHeap(GetProcessHeap(), 0, size))) return;
440 memcpy(report->buffer, report_buf, report_len);
441 report->length = report_len;
443 RtlEnterCriticalSection(&ext->cs);
444 list_add_tail(&ext->reports, &report->entry);
446 if (!ext->collection_desc.ReportIDs[0].ReportID) last_report = ext->last_reports[0];
447 else last_report = ext->last_reports[report_buf[0]];
448 memcpy(last_report->buffer, report_buf, report_len);
450 if ((irp = pop_pending_read(ext)))
452 deliver_next_report(ext, irp);
453 IoCompleteRequest(irp, IO_NO_INCREMENT);
455 RtlLeaveCriticalSection(&ext->cs);
458 static NTSTATUS handle_IRP_MN_QUERY_DEVICE_RELATIONS(IRP *irp)
460 NTSTATUS status = irp->IoStatus.Status;
461 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
463 TRACE("IRP_MN_QUERY_DEVICE_RELATIONS\n");
464 switch (irpsp->Parameters.QueryDeviceRelations.Type)
466 case EjectionRelations:
467 case RemovalRelations:
468 case TargetDeviceRelation:
469 case PowerRelations:
470 FIXME("Unhandled Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type);
471 break;
472 case BusRelations:
473 status = build_device_relations((DEVICE_RELATIONS**)&irp->IoStatus.Information);
474 break;
475 default:
476 FIXME("Unknown Device Relation %x\n",irpsp->Parameters.QueryDeviceRelations.Type);
477 break;
480 return status;
483 static NTSTATUS handle_IRP_MN_QUERY_ID(DEVICE_OBJECT *device, IRP *irp)
485 NTSTATUS status = irp->IoStatus.Status;
486 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
487 BUS_QUERY_ID_TYPE type = irpsp->Parameters.QueryId.IdType;
489 TRACE("(%p, %p)\n", device, irp);
491 switch (type)
493 case BusQueryHardwareIDs:
494 TRACE("BusQueryHardwareIDs\n");
495 irp->IoStatus.Information = (ULONG_PTR)get_hardware_ids(device);
496 break;
497 case BusQueryCompatibleIDs:
498 TRACE("BusQueryCompatibleIDs\n");
499 irp->IoStatus.Information = (ULONG_PTR)get_compatible_ids(device);
500 break;
501 case BusQueryDeviceID:
502 TRACE("BusQueryDeviceID\n");
503 irp->IoStatus.Information = (ULONG_PTR)get_device_id(device);
504 break;
505 case BusQueryInstanceID:
506 TRACE("BusQueryInstanceID\n");
507 irp->IoStatus.Information = (ULONG_PTR)get_instance_id(device);
508 break;
509 default:
510 FIXME("Unhandled type %08x\n", type);
511 return status;
514 status = irp->IoStatus.Information ? STATUS_SUCCESS : STATUS_NO_MEMORY;
515 return status;
518 static void mouse_device_create(void)
520 struct device_create_params params = {{0}};
522 if (winebus_call(mouse_create, &params)) return;
523 mouse_obj = bus_create_hid_device(&params.desc, params.device);
524 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
527 static void keyboard_device_create(void)
529 struct device_create_params params = {{0}};
531 if (winebus_call(keyboard_create, &params)) return;
532 keyboard_obj = bus_create_hid_device(&params.desc, params.device);
533 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
536 static DWORD bus_count;
537 static HANDLE bus_thread[16];
539 struct bus_main_params
541 const WCHAR *name;
543 void *init_args;
544 HANDLE init_done;
545 unsigned int init_code;
546 unsigned int wait_code;
547 struct bus_event *bus_event;
550 static DWORD CALLBACK bus_main_thread(void *args)
552 struct bus_main_params bus = *(struct bus_main_params *)args;
553 DEVICE_OBJECT *device;
554 NTSTATUS status;
556 TRACE("%s main loop starting\n", debugstr_w(bus.name));
557 status = winebus_call(bus.init_code, bus.init_args);
558 SetEvent(bus.init_done);
559 TRACE("%s main loop started\n", debugstr_w(bus.name));
561 bus.bus_event->type = BUS_EVENT_TYPE_NONE;
562 if (status) WARN("%s bus init returned status %#lx\n", debugstr_w(bus.name), status);
563 else while ((status = winebus_call(bus.wait_code, bus.bus_event)) == STATUS_PENDING)
565 struct bus_event *event = bus.bus_event;
566 switch (event->type)
568 case BUS_EVENT_TYPE_NONE: break;
569 case BUS_EVENT_TYPE_DEVICE_REMOVED:
570 RtlEnterCriticalSection(&device_list_cs);
571 device = bus_find_unix_device(event->device);
572 if (!device) WARN("could not find device for %s bus device %#I64x\n", debugstr_w(bus.name), event->device);
573 else bus_unlink_hid_device(device);
574 RtlLeaveCriticalSection(&device_list_cs);
575 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
576 break;
577 case BUS_EVENT_TYPE_DEVICE_CREATED:
578 device = bus_create_hid_device(&event->device_created.desc, event->device);
579 if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations);
580 else
582 struct device_remove_params params = {.device = event->device};
583 WARN("failed to create device for %s bus device %#I64x\n", debugstr_w(bus.name), event->device);
584 winebus_call(device_remove, &params);
586 break;
587 case BUS_EVENT_TYPE_INPUT_REPORT:
588 RtlEnterCriticalSection(&device_list_cs);
589 device = bus_find_unix_device(event->device);
590 if (!device) WARN("could not find device for %s bus device %#I64x\n", debugstr_w(bus.name), event->device);
591 else process_hid_report(device, event->input_report.buffer, event->input_report.length);
592 RtlLeaveCriticalSection(&device_list_cs);
593 break;
597 if (status) WARN("%s bus wait returned status %#lx\n", debugstr_w(bus.name), status);
598 else TRACE("%s main loop exited\n", debugstr_w(bus.name));
599 RtlFreeHeap(GetProcessHeap(), 0, bus.bus_event);
600 return status;
603 static NTSTATUS bus_main_thread_start(struct bus_main_params *bus)
605 DWORD i = bus_count++, max_size;
607 if (!(bus->init_done = CreateEventW(NULL, FALSE, FALSE, NULL)))
609 ERR("failed to create %s bus init done event.\n", debugstr_w(bus->name));
610 bus_count--;
611 return STATUS_UNSUCCESSFUL;
614 max_size = offsetof(struct bus_event, input_report.buffer[0x10000]);
615 if (!(bus->bus_event = RtlAllocateHeap(GetProcessHeap(), 0, max_size)))
617 ERR("failed to allocate %s bus event.\n", debugstr_w(bus->name));
618 CloseHandle(bus->init_done);
619 bus_count--;
620 return STATUS_UNSUCCESSFUL;
623 if (!(bus_thread[i] = CreateThread(NULL, 0, bus_main_thread, bus, 0, NULL)))
625 ERR("failed to create %s bus thread.\n", debugstr_w(bus->name));
626 CloseHandle(bus->init_done);
627 bus_count--;
628 return STATUS_UNSUCCESSFUL;
631 WaitForSingleObject(bus->init_done, INFINITE);
632 CloseHandle(bus->init_done);
633 return STATUS_SUCCESS;
636 static void sdl_bus_free_mappings(struct sdl_bus_options *options)
638 DWORD count = options->mappings_count;
639 char **mappings = options->mappings;
641 while (count) RtlFreeHeap(GetProcessHeap(), 0, mappings[--count]);
642 RtlFreeHeap(GetProcessHeap(), 0, mappings);
645 static void sdl_bus_load_mappings(struct sdl_bus_options *options)
647 ULONG idx = 0, len, count = 0, capacity, info_size, info_max_size;
648 KEY_VALUE_FULL_INFORMATION *info;
649 OBJECT_ATTRIBUTES attr = {0};
650 char **mappings = NULL;
651 UNICODE_STRING path;
652 NTSTATUS status;
653 HANDLE key;
655 options->mappings_count = 0;
656 options->mappings = NULL;
658 RtlInitUnicodeString(&path, L"map");
659 InitializeObjectAttributes(&attr, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, driver_key, NULL);
660 status = NtOpenKey(&key, KEY_ALL_ACCESS, &attr);
661 if (status) return;
663 capacity = 1024;
664 mappings = RtlAllocateHeap(GetProcessHeap(), 0, capacity * sizeof(*mappings));
665 info_max_size = offsetof(KEY_VALUE_FULL_INFORMATION, Name) + 512;
666 info = RtlAllocateHeap(GetProcessHeap(), 0, info_max_size);
668 while (!status && info && mappings)
670 status = NtEnumerateValueKey(key, idx, KeyValueFullInformation, info, info_max_size, &info_size);
671 while (status == STATUS_BUFFER_OVERFLOW)
673 info_max_size = info_size;
674 if (!(info = RtlReAllocateHeap(GetProcessHeap(), 0, info, info_max_size))) break;
675 status = NtEnumerateValueKey(key, idx, KeyValueFullInformation, info, info_max_size, &info_size);
678 if (status == STATUS_NO_MORE_ENTRIES)
680 options->mappings_count = count;
681 options->mappings = mappings;
682 goto done;
685 idx++;
686 if (status) break;
687 if (info->Type != REG_SZ) continue;
689 RtlUnicodeToMultiByteSize(&len, (WCHAR *)((char *)info + info->DataOffset), info_size - info->DataOffset);
690 if (!len) continue;
692 if (!(mappings[count++] = RtlAllocateHeap(GetProcessHeap(), 0, len + 1))) break;
693 if (count > capacity)
695 capacity = capacity * 3 / 2;
696 if (!(mappings = RtlReAllocateHeap(GetProcessHeap(), 0, mappings, capacity * sizeof(*mappings))))
697 break;
700 RtlUnicodeToMultiByteN(mappings[count], len, NULL, (WCHAR *)((char *)info + info->DataOffset),
701 info_size - info->DataOffset);
702 if (mappings[len - 1]) mappings[len] = 0;
705 if (mappings) while (count) RtlFreeHeap(GetProcessHeap(), 0, mappings[--count]);
706 RtlFreeHeap(GetProcessHeap(), 0, mappings);
708 done:
709 RtlFreeHeap(GetProcessHeap(), 0, info);
710 NtClose(key);
713 static NTSTATUS sdl_driver_init(void)
715 struct sdl_bus_options bus_options;
716 struct bus_main_params bus =
718 .name = L"SDL",
719 .init_args = &bus_options,
720 .init_code = sdl_init,
721 .wait_code = sdl_wait,
723 NTSTATUS status;
725 bus_options.split_controllers = check_bus_option(L"Split Controllers", 0);
726 if (bus_options.split_controllers) TRACE("SDL controller splitting enabled\n");
727 bus_options.map_controllers = check_bus_option(L"Map Controllers", 1);
728 if (!bus_options.map_controllers) TRACE("SDL controller to XInput HID gamepad mapping disabled\n");
729 sdl_bus_load_mappings(&bus_options);
731 status = bus_main_thread_start(&bus);
732 sdl_bus_free_mappings(&bus_options);
733 return status;
736 static NTSTATUS udev_driver_init(void)
738 struct udev_bus_options bus_options;
739 struct bus_main_params bus =
741 .name = L"UDEV",
742 .init_args = &bus_options,
743 .init_code = udev_init,
744 .wait_code = udev_wait,
747 bus_options.disable_hidraw = check_bus_option(L"DisableHidraw", 0);
748 if (bus_options.disable_hidraw) TRACE("UDEV hidraw devices disabled in registry\n");
749 bus_options.disable_input = check_bus_option(L"DisableInput", 0);
750 if (bus_options.disable_input) TRACE("UDEV input devices disabled in registry\n");
751 bus_options.disable_udevd = check_bus_option(L"DisableUdevd", 0);
752 if (bus_options.disable_udevd) TRACE("UDEV udevd use disabled in registry\n");
754 return bus_main_thread_start(&bus);
757 static NTSTATUS iohid_driver_init(void)
759 struct iohid_bus_options bus_options;
760 struct bus_main_params bus =
762 .name = L"IOHID",
763 .init_args = &bus_options,
764 .init_code = iohid_init,
765 .wait_code = iohid_wait,
768 return bus_main_thread_start(&bus);
771 static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
773 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
774 NTSTATUS ret;
776 switch (irpsp->MinorFunction)
778 case IRP_MN_QUERY_DEVICE_RELATIONS:
779 irp->IoStatus.Status = handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp);
780 break;
781 case IRP_MN_START_DEVICE:
782 mouse_device_create();
783 keyboard_device_create();
785 if (!check_bus_option(L"Enable SDL", 1) || sdl_driver_init())
787 udev_driver_init();
788 iohid_driver_init();
791 irp->IoStatus.Status = STATUS_SUCCESS;
792 break;
793 case IRP_MN_SURPRISE_REMOVAL:
794 irp->IoStatus.Status = STATUS_SUCCESS;
795 break;
796 case IRP_MN_REMOVE_DEVICE:
797 winebus_call(sdl_stop, NULL);
798 winebus_call(udev_stop, NULL);
799 winebus_call(iohid_stop, NULL);
801 WaitForMultipleObjects(bus_count, bus_thread, TRUE, INFINITE);
802 while (bus_count--) CloseHandle(bus_thread[bus_count]);
804 irp->IoStatus.Status = STATUS_SUCCESS;
805 IoSkipCurrentIrpStackLocation(irp);
806 ret = IoCallDriver(bus_pdo, irp);
807 IoDetachDevice(bus_pdo);
808 IoDeleteDevice(device);
809 return ret;
810 default:
811 FIXME("Unhandled minor function %#x.\n", irpsp->MinorFunction);
814 IoSkipCurrentIrpStackLocation(irp);
815 return IoCallDriver(bus_pdo, irp);
818 static NTSTATUS pdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
820 struct device_extension *ext = device->DeviceExtension;
821 NTSTATUS status = irp->IoStatus.Status;
822 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
823 struct hid_report *report, *next;
824 HIDP_REPORT_IDS *reports;
825 ULONG i, size;
827 TRACE("device %p, irp %p, minor function %#x.\n", device, irp, irpsp->MinorFunction);
829 switch (irpsp->MinorFunction)
831 case IRP_MN_QUERY_ID:
832 status = handle_IRP_MN_QUERY_ID(device, irp);
833 break;
835 case IRP_MN_QUERY_CAPABILITIES:
836 status = STATUS_SUCCESS;
837 break;
839 case IRP_MN_START_DEVICE:
840 RtlEnterCriticalSection(&ext->cs);
841 if (ext->state != DEVICE_STATE_STOPPED) status = STATUS_SUCCESS;
842 else if (ext->state == DEVICE_STATE_REMOVED) status = STATUS_DELETE_PENDING;
843 else if ((status = unix_device_start(device)))
844 ERR("Failed to start device %p, status %#lx\n", device, status);
845 else
847 status = unix_device_get_report_descriptor(device, NULL, 0, &ext->report_desc_length);
848 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_TOO_SMALL)
849 ERR("Failed to get device %p report descriptor, status %#lx\n", device, status);
850 else if (!(ext->report_desc = RtlAllocateHeap(GetProcessHeap(), 0, ext->report_desc_length)))
851 status = STATUS_NO_MEMORY;
852 else if ((status = unix_device_get_report_descriptor(device, ext->report_desc, ext->report_desc_length,
853 &ext->report_desc_length)))
854 ERR("Failed to get device %p report descriptor, status %#lx\n", device, status);
855 else if ((status = HidP_GetCollectionDescription(ext->report_desc, ext->report_desc_length,
856 PagedPool, &ext->collection_desc)) != HIDP_STATUS_SUCCESS)
857 ERR("Failed to parse device %p report descriptor, status %#lx\n", device, status);
858 else
860 status = STATUS_SUCCESS;
861 reports = ext->collection_desc.ReportIDs;
862 for (i = 0; i < ext->collection_desc.ReportIDsLength; ++i)
864 if (!(size = reports[i].InputLength)) continue;
865 size = offsetof( struct hid_report, buffer[size] );
866 if (!(report = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, size))) status = STATUS_NO_MEMORY;
867 else
869 report->length = reports[i].InputLength;
870 report->buffer[0] = reports[i].ReportID;
871 ext->last_reports[reports[i].ReportID] = report;
874 if (!status) ext->state = DEVICE_STATE_STARTED;
877 RtlLeaveCriticalSection(&ext->cs);
878 break;
880 case IRP_MN_SURPRISE_REMOVAL:
881 RtlEnterCriticalSection(&ext->cs);
882 remove_pending_irps(device);
883 ext->state = DEVICE_STATE_REMOVED;
884 RtlLeaveCriticalSection(&ext->cs);
885 status = STATUS_SUCCESS;
886 break;
888 case IRP_MN_REMOVE_DEVICE:
889 remove_pending_irps(device);
891 bus_unlink_hid_device(device);
892 unix_device_remove(device);
894 ext->cs.DebugInfo->Spare[0] = 0;
895 DeleteCriticalSection(&ext->cs);
897 irp->IoStatus.Status = STATUS_SUCCESS;
898 IoCompleteRequest(irp, IO_NO_INCREMENT);
900 LIST_FOR_EACH_ENTRY_SAFE(report, next, &ext->reports, struct hid_report, entry)
901 RtlFreeHeap(GetProcessHeap(), 0, report);
903 reports = ext->collection_desc.ReportIDs;
904 for (i = 0; i < ext->collection_desc.ReportIDsLength; ++i)
906 if (!reports[i].InputLength) continue;
907 RtlFreeHeap(GetProcessHeap(), 0, ext->last_reports[reports[i].ReportID]);
909 HidP_FreeCollectionDescription(&ext->collection_desc);
910 RtlFreeHeap(GetProcessHeap(), 0, ext->report_desc);
912 IoDeleteDevice(device);
913 return STATUS_SUCCESS;
915 default:
916 FIXME("Unhandled function %08x\n", irpsp->MinorFunction);
917 /* fall through */
919 case IRP_MN_QUERY_DEVICE_RELATIONS:
920 break;
923 irp->IoStatus.Status = status;
924 IoCompleteRequest(irp, IO_NO_INCREMENT);
925 return status;
928 static NTSTATUS WINAPI common_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp)
930 if (device == bus_fdo)
931 return fdo_pnp_dispatch(device, irp);
932 return pdo_pnp_dispatch(device, irp);
935 static NTSTATUS hid_get_device_string(DEVICE_OBJECT *device, DWORD index, WCHAR *buffer, DWORD buffer_len)
937 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
938 DWORD len;
940 switch (index)
942 case HID_STRING_ID_IMANUFACTURER:
943 len = (wcslen(ext->desc.manufacturer) + 1) * sizeof(WCHAR);
944 if (len > buffer_len) return STATUS_BUFFER_TOO_SMALL;
945 else memcpy(buffer, ext->desc.manufacturer, len);
946 return STATUS_SUCCESS;
947 case HID_STRING_ID_IPRODUCT:
948 len = (wcslen(ext->desc.product) + 1) * sizeof(WCHAR);
949 if (len > buffer_len) return STATUS_BUFFER_TOO_SMALL;
950 else memcpy(buffer, ext->desc.product, len);
951 return STATUS_SUCCESS;
952 case HID_STRING_ID_ISERIALNUMBER:
953 len = (wcslen(ext->desc.serialnumber) + 1) * sizeof(WCHAR);
954 if (len > buffer_len) return STATUS_BUFFER_TOO_SMALL;
955 else memcpy(buffer, ext->desc.serialnumber, len);
956 return STATUS_SUCCESS;
959 return STATUS_NOT_IMPLEMENTED;
962 static NTSTATUS WINAPI hid_internal_dispatch(DEVICE_OBJECT *device, IRP *irp)
964 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
965 struct device_extension *ext = (struct device_extension *)device->DeviceExtension;
966 ULONG i, code, buffer_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
967 NTSTATUS status;
969 if (device == bus_fdo)
971 IoSkipCurrentIrpStackLocation(irp);
972 return IoCallDriver(bus_pdo, irp);
975 RtlEnterCriticalSection(&ext->cs);
977 if (ext->state == DEVICE_STATE_REMOVED)
979 RtlLeaveCriticalSection(&ext->cs);
980 irp->IoStatus.Status = STATUS_DELETE_PENDING;
981 IoCompleteRequest(irp, IO_NO_INCREMENT);
982 return STATUS_DELETE_PENDING;
985 switch ((code = irpsp->Parameters.DeviceIoControl.IoControlCode))
987 case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
989 HID_DEVICE_ATTRIBUTES *attr = (HID_DEVICE_ATTRIBUTES *)irp->UserBuffer;
990 TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
992 if (buffer_len < sizeof(*attr))
994 irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
995 break;
998 memset(attr, 0, sizeof(*attr));
999 attr->Size = sizeof(*attr);
1000 attr->VendorID = ext->desc.vid;
1001 attr->ProductID = ext->desc.pid;
1002 attr->VersionNumber = ext->desc.version;
1004 irp->IoStatus.Status = STATUS_SUCCESS;
1005 irp->IoStatus.Information = sizeof(*attr);
1006 break;
1008 case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
1010 HID_DESCRIPTOR *descriptor = (HID_DESCRIPTOR *)irp->UserBuffer;
1011 irp->IoStatus.Information = sizeof(*descriptor);
1012 if (buffer_len < sizeof(*descriptor)) irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1013 else
1015 memset(descriptor, 0, sizeof(*descriptor));
1016 descriptor->bLength = sizeof(*descriptor);
1017 descriptor->bDescriptorType = HID_HID_DESCRIPTOR_TYPE;
1018 descriptor->bcdHID = HID_REVISION;
1019 descriptor->bCountry = 0;
1020 descriptor->bNumDescriptors = 1;
1021 descriptor->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE;
1022 descriptor->DescriptorList[0].wReportLength = ext->report_desc_length;
1023 irp->IoStatus.Status = STATUS_SUCCESS;
1025 break;
1027 case IOCTL_HID_GET_REPORT_DESCRIPTOR:
1028 irp->IoStatus.Information = ext->report_desc_length;
1029 if (buffer_len < irp->IoStatus.Information)
1030 irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
1031 else
1033 memcpy(irp->UserBuffer, ext->report_desc, ext->report_desc_length);
1034 irp->IoStatus.Status = STATUS_SUCCESS;
1036 break;
1037 case IOCTL_HID_GET_STRING:
1039 UINT index = (UINT_PTR)irpsp->Parameters.DeviceIoControl.Type3InputBuffer;
1040 TRACE("IOCTL_HID_GET_STRING[%08x]\n", index);
1042 irp->IoStatus.Status = hid_get_device_string(device, index, (WCHAR *)irp->UserBuffer, buffer_len);
1043 if (irp->IoStatus.Status == STATUS_SUCCESS)
1044 irp->IoStatus.Information = (wcslen((WCHAR *)irp->UserBuffer) + 1) * sizeof(WCHAR);
1045 break;
1047 case IOCTL_HID_GET_INPUT_REPORT:
1049 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1050 struct hid_report *last_report = ext->last_reports[packet->reportId];
1051 memcpy(packet->reportBuffer, last_report->buffer, last_report->length);
1052 packet->reportBufferLen = last_report->length;
1053 irp->IoStatus.Information = packet->reportBufferLen;
1054 irp->IoStatus.Status = STATUS_SUCCESS;
1055 if (TRACE_ON(hid))
1057 TRACE("read input report id %u length %lu:\n", packet->reportId, packet->reportBufferLen);
1058 for (i = 0; i < packet->reportBufferLen;)
1060 char buffer[256], *buf = buffer;
1061 buf += sprintf(buf, "%08lx ", i);
1062 do { buf += sprintf(buf, " %02x", packet->reportBuffer[i]); }
1063 while (++i % 16 && i < packet->reportBufferLen);
1064 TRACE("%s\n", buffer);
1067 break;
1069 case IOCTL_HID_READ_REPORT:
1071 if (!deliver_next_report(ext, irp))
1073 /* hidclass.sys should guarantee this */
1074 assert(!ext->pending_read);
1075 ext->pending_read = irp;
1076 IoMarkIrpPending(irp);
1077 irp->IoStatus.Status = STATUS_PENDING;
1079 break;
1081 case IOCTL_HID_SET_OUTPUT_REPORT:
1082 case IOCTL_HID_WRITE_REPORT:
1084 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1085 if (TRACE_ON(hid))
1087 TRACE("write output report id %u length %lu:\n", packet->reportId, packet->reportBufferLen);
1088 for (i = 0; i < packet->reportBufferLen;)
1090 char buffer[256], *buf = buffer;
1091 buf += sprintf(buf, "%08lx ", i);
1092 do { buf += sprintf(buf, " %02x", packet->reportBuffer[i]); }
1093 while (++i % 16 && i < packet->reportBufferLen);
1094 TRACE("%s\n", buffer);
1097 unix_device_set_output_report(device, packet, &irp->IoStatus);
1098 break;
1100 case IOCTL_HID_GET_FEATURE:
1102 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1103 unix_device_get_feature_report(device, packet, &irp->IoStatus);
1104 if (!irp->IoStatus.Status && TRACE_ON(hid))
1106 TRACE("read feature report id %u length %lu:\n", packet->reportId, packet->reportBufferLen);
1107 for (i = 0; i < packet->reportBufferLen;)
1109 char buffer[256], *buf = buffer;
1110 buf += sprintf(buf, "%08lx ", i);
1111 do { buf += sprintf(buf, " %02x", packet->reportBuffer[i]); }
1112 while (++i % 16 && i < packet->reportBufferLen);
1113 TRACE("%s\n", buffer);
1116 break;
1118 case IOCTL_HID_SET_FEATURE:
1120 HID_XFER_PACKET *packet = (HID_XFER_PACKET *)irp->UserBuffer;
1121 if (TRACE_ON(hid))
1123 TRACE("write feature report id %u length %lu:\n", packet->reportId, packet->reportBufferLen);
1124 for (i = 0; i < packet->reportBufferLen;)
1126 char buffer[256], *buf = buffer;
1127 buf += sprintf(buf, "%08lx ", i);
1128 do { buf += sprintf(buf, " %02x", packet->reportBuffer[i]); }
1129 while (++i % 16 && i < packet->reportBufferLen);
1130 TRACE("%s\n", buffer);
1133 unix_device_set_feature_report(device, packet, &irp->IoStatus);
1134 break;
1136 default:
1137 FIXME("Unsupported ioctl %lx (device=%lx access=%lx func=%lx method=%lx)\n",
1138 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
1139 break;
1142 status = irp->IoStatus.Status;
1143 RtlLeaveCriticalSection(&ext->cs);
1145 if (status != STATUS_PENDING) IoCompleteRequest(irp, IO_NO_INCREMENT);
1146 return status;
1149 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
1151 NTSTATUS ret;
1153 TRACE("driver %p, pdo %p.\n", driver, pdo);
1155 if ((ret = IoCreateDevice(driver, 0, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &bus_fdo)))
1157 ERR("Failed to create FDO, status %#lx.\n", ret);
1158 return ret;
1161 IoAttachDeviceToDeviceStack(bus_fdo, pdo);
1162 bus_pdo = pdo;
1164 bus_fdo->Flags &= ~DO_DEVICE_INITIALIZING;
1166 return STATUS_SUCCESS;
1169 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
1171 NtClose(driver_key);
1174 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
1176 OBJECT_ATTRIBUTES attr = {0};
1177 NTSTATUS ret;
1179 TRACE( "(%p, %s)\n", driver, debugstr_w(path->Buffer) );
1181 if ((ret = __wine_init_unix_call())) return ret;
1183 attr.Length = sizeof(attr);
1184 attr.ObjectName = path;
1185 attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE;
1186 if ((ret = NtOpenKey(&driver_key, KEY_ALL_ACCESS, &attr)) != STATUS_SUCCESS)
1187 ERR("Failed to open driver key, status %#lx.\n", ret);
1189 driver_obj = driver;
1191 driver->MajorFunction[IRP_MJ_PNP] = common_pnp_dispatch;
1192 driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = hid_internal_dispatch;
1193 driver->DriverExtension->AddDevice = driver_add_device;
1194 driver->DriverUnload = driver_unload;
1196 return STATUS_SUCCESS;