2 * WINE Platform native bus driver
4 * Copyright 2016 Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #define WIN32_NO_STATUS
33 #include "ddk/hidport.h"
34 #include "ddk/hidtypes.h"
35 #include "ddk/hidpddi.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "wine/unixlib.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
45 static DRIVER_OBJECT
*driver_obj
;
47 static DEVICE_OBJECT
*mouse_obj
;
48 static DEVICE_OBJECT
*keyboard_obj
;
50 /* The root-enumerated device stack. */
51 static DEVICE_OBJECT
*bus_pdo
;
52 static DEVICE_OBJECT
*bus_fdo
;
54 static HANDLE driver_key
;
70 struct device_extension
73 DEVICE_OBJECT
*device
;
76 enum device_state state
;
78 struct device_desc desc
;
82 UINT report_desc_length
;
83 HIDP_DEVICE_DESC collection_desc
;
85 struct hid_report
*last_reports
[256];
92 static CRITICAL_SECTION device_list_cs
;
93 static CRITICAL_SECTION_DEBUG critsect_debug
=
95 0, 0, &device_list_cs
,
96 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
97 0, 0, { (DWORD_PTR
)(__FILE__
": device_list_cs") }
99 static CRITICAL_SECTION device_list_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
101 static struct list device_list
= LIST_INIT(device_list
);
103 static NTSTATUS
winebus_call(unsigned int code
, void *args
)
105 return WINE_UNIX_CALL(code
, args
);
108 static void unix_device_remove(DEVICE_OBJECT
*device
)
110 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
111 struct device_remove_params params
= {.device
= ext
->unix_device
};
112 winebus_call(device_remove
, ¶ms
);
115 static NTSTATUS
unix_device_start(DEVICE_OBJECT
*device
)
117 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
118 struct device_start_params params
= {.device
= ext
->unix_device
};
119 return winebus_call(device_start
, ¶ms
);
122 static 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
,
130 .out_length
= out_length
132 return winebus_call(device_get_report_descriptor
, ¶ms
);
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
,
144 winebus_call(device_set_output_report
, ¶ms
);
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
,
156 winebus_call(device_get_feature_report
, ¶ms
);
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
,
168 winebus_call(device_set_feature_report
, ¶ms
);
171 static DWORD
get_device_index(struct device_desc
*desc
)
173 struct device_extension
*ext
;
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
);
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;
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
);
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;
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
);
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;
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
);
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
);
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;
261 static IRP
*pop_pending_read(struct device_extension
*ext
)
265 RtlEnterCriticalSection(&ext
->cs
);
266 pending
= ext
->pending_read
;
267 ext
->pending_read
= NULL
;
268 RtlLeaveCriticalSection(&ext
->cs
);
273 static void remove_pending_irps(DEVICE_OBJECT
*device
)
275 struct device_extension
*ext
= device
->DeviceExtension
;
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
;
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
);
301 FIXME("failed to create device error %#lx\n", status
);
305 RtlEnterCriticalSection(&device_list_cs
);
307 /* fill out device_extension struct */
308 ext
= (struct device_extension
*)device
->DeviceExtension
;
309 ext
->device
= device
;
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
);
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
;
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,
351 "xchgl (%esp),%ecx\n\t"
353 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
355 #define call_fastcall_func1(func,a) func(a)
358 static NTSTATUS
build_device_relations(DEVICE_RELATIONS
**devices
)
360 struct device_extension
*ext
;
363 RtlEnterCriticalSection(&device_list_cs
);
364 *devices
= ExAllocatePool(PagedPool
, offsetof(DEVICE_RELATIONS
, Objects
[list_count(&device_list
)]));
368 RtlLeaveCriticalSection(&device_list_cs
);
369 return STATUS_INSUFFICIENT_RESOURCES
;
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
);
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
;
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
;
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
;
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
);
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
;
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
:
470 FIXME("Unhandled Device Relation %x\n",irpsp
->Parameters
.QueryDeviceRelations
.Type
);
473 status
= build_device_relations((DEVICE_RELATIONS
**)&irp
->IoStatus
.Information
);
476 FIXME("Unknown Device Relation %x\n",irpsp
->Parameters
.QueryDeviceRelations
.Type
);
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
);
493 case BusQueryHardwareIDs
:
494 TRACE("BusQueryHardwareIDs\n");
495 irp
->IoStatus
.Information
= (ULONG_PTR
)get_hardware_ids(device
);
497 case BusQueryCompatibleIDs
:
498 TRACE("BusQueryCompatibleIDs\n");
499 irp
->IoStatus
.Information
= (ULONG_PTR
)get_compatible_ids(device
);
501 case BusQueryDeviceID
:
502 TRACE("BusQueryDeviceID\n");
503 irp
->IoStatus
.Information
= (ULONG_PTR
)get_device_id(device
);
505 case BusQueryInstanceID
:
506 TRACE("BusQueryInstanceID\n");
507 irp
->IoStatus
.Information
= (ULONG_PTR
)get_instance_id(device
);
510 FIXME("Unhandled type %08x\n", type
);
514 status
= irp
->IoStatus
.Information
? STATUS_SUCCESS
: STATUS_NO_MEMORY
;
518 static void mouse_device_create(void)
520 struct device_create_params params
= {{0}};
522 if (winebus_call(mouse_create
, ¶ms
)) return;
523 mouse_obj
= bus_create_hid_device(¶ms
.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
, ¶ms
)) return;
532 keyboard_obj
= bus_create_hid_device(¶ms
.desc
, params
.device
);
533 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
536 static DWORD bus_count
;
537 static HANDLE bus_thread
[16];
539 struct bus_main_params
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
;
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
;
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
);
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
);
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
, ¶ms
);
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
);
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
);
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
));
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
);
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
);
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 UNICODE_STRING path
= RTL_CONSTANT_STRING(L
"map");
649 KEY_VALUE_FULL_INFORMATION
*info
;
650 OBJECT_ATTRIBUTES attr
= {0};
651 char **mappings
= NULL
;
655 options
->mappings_count
= 0;
656 options
->mappings
= NULL
;
658 InitializeObjectAttributes(&attr
, &path
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, driver_key
, NULL
);
659 status
= NtOpenKey(&key
, KEY_ALL_ACCESS
, &attr
);
663 mappings
= RtlAllocateHeap(GetProcessHeap(), 0, capacity
* sizeof(*mappings
));
664 info_max_size
= offsetof(KEY_VALUE_FULL_INFORMATION
, Name
) + 512;
665 info
= RtlAllocateHeap(GetProcessHeap(), 0, info_max_size
);
667 while (!status
&& info
&& mappings
)
669 status
= NtEnumerateValueKey(key
, idx
, KeyValueFullInformation
, info
, info_max_size
, &info_size
);
670 while (status
== STATUS_BUFFER_OVERFLOW
)
672 info_max_size
= info_size
;
673 if (!(info
= RtlReAllocateHeap(GetProcessHeap(), 0, info
, info_max_size
))) break;
674 status
= NtEnumerateValueKey(key
, idx
, KeyValueFullInformation
, info
, info_max_size
, &info_size
);
677 if (status
== STATUS_NO_MORE_ENTRIES
)
679 options
->mappings_count
= count
;
680 options
->mappings
= mappings
;
686 if (info
->Type
!= REG_SZ
) continue;
688 RtlUnicodeToMultiByteSize(&len
, (WCHAR
*)((char *)info
+ info
->DataOffset
), info_size
- info
->DataOffset
);
691 if (!(mappings
[count
++] = RtlAllocateHeap(GetProcessHeap(), 0, len
+ 1))) break;
692 if (count
> capacity
)
694 capacity
= capacity
* 3 / 2;
695 if (!(mappings
= RtlReAllocateHeap(GetProcessHeap(), 0, mappings
, capacity
* sizeof(*mappings
))))
699 RtlUnicodeToMultiByteN(mappings
[count
], len
, NULL
, (WCHAR
*)((char *)info
+ info
->DataOffset
),
700 info_size
- info
->DataOffset
);
701 if (mappings
[len
- 1]) mappings
[len
] = 0;
704 if (mappings
) while (count
) RtlFreeHeap(GetProcessHeap(), 0, mappings
[--count
]);
705 RtlFreeHeap(GetProcessHeap(), 0, mappings
);
708 RtlFreeHeap(GetProcessHeap(), 0, info
);
712 static NTSTATUS
sdl_driver_init(void)
714 struct sdl_bus_options bus_options
;
715 struct bus_main_params bus
=
718 .init_args
= &bus_options
,
719 .init_code
= sdl_init
,
720 .wait_code
= sdl_wait
,
724 bus_options
.split_controllers
= check_bus_option(L
"Split Controllers", 0);
725 if (bus_options
.split_controllers
) TRACE("SDL controller splitting enabled\n");
726 bus_options
.map_controllers
= check_bus_option(L
"Map Controllers", 1);
727 if (!bus_options
.map_controllers
) TRACE("SDL controller to XInput HID gamepad mapping disabled\n");
728 sdl_bus_load_mappings(&bus_options
);
730 status
= bus_main_thread_start(&bus
);
731 sdl_bus_free_mappings(&bus_options
);
735 static NTSTATUS
udev_driver_init(void)
737 struct udev_bus_options bus_options
;
738 struct bus_main_params bus
=
741 .init_args
= &bus_options
,
742 .init_code
= udev_init
,
743 .wait_code
= udev_wait
,
746 bus_options
.disable_hidraw
= check_bus_option(L
"DisableHidraw", 0);
747 if (bus_options
.disable_hidraw
) TRACE("UDEV hidraw devices disabled in registry\n");
748 bus_options
.disable_input
= check_bus_option(L
"DisableInput", 0);
749 if (bus_options
.disable_input
) TRACE("UDEV input devices disabled in registry\n");
750 bus_options
.disable_udevd
= check_bus_option(L
"DisableUdevd", 0);
751 if (bus_options
.disable_udevd
) TRACE("UDEV udevd use disabled in registry\n");
753 return bus_main_thread_start(&bus
);
756 static NTSTATUS
iohid_driver_init(void)
758 struct iohid_bus_options bus_options
;
759 struct bus_main_params bus
=
762 .init_args
= &bus_options
,
763 .init_code
= iohid_init
,
764 .wait_code
= iohid_wait
,
767 return bus_main_thread_start(&bus
);
770 static NTSTATUS
fdo_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
772 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
775 switch (irpsp
->MinorFunction
)
777 case IRP_MN_QUERY_DEVICE_RELATIONS
:
778 irp
->IoStatus
.Status
= handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp
);
780 case IRP_MN_START_DEVICE
:
781 mouse_device_create();
782 keyboard_device_create();
784 if (!check_bus_option(L
"Enable SDL", 1) || sdl_driver_init())
790 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
792 case IRP_MN_SURPRISE_REMOVAL
:
793 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
795 case IRP_MN_REMOVE_DEVICE
:
796 winebus_call(sdl_stop
, NULL
);
797 winebus_call(udev_stop
, NULL
);
798 winebus_call(iohid_stop
, NULL
);
800 WaitForMultipleObjects(bus_count
, bus_thread
, TRUE
, INFINITE
);
801 while (bus_count
--) CloseHandle(bus_thread
[bus_count
]);
803 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
804 IoSkipCurrentIrpStackLocation(irp
);
805 ret
= IoCallDriver(bus_pdo
, irp
);
806 IoDetachDevice(bus_pdo
);
807 IoDeleteDevice(device
);
810 FIXME("Unhandled minor function %#x.\n", irpsp
->MinorFunction
);
813 IoSkipCurrentIrpStackLocation(irp
);
814 return IoCallDriver(bus_pdo
, irp
);
817 static NTSTATUS
pdo_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
819 struct device_extension
*ext
= device
->DeviceExtension
;
820 NTSTATUS status
= irp
->IoStatus
.Status
;
821 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
822 struct hid_report
*report
, *next
;
823 HIDP_REPORT_IDS
*reports
;
826 TRACE("device %p, irp %p, minor function %#x.\n", device
, irp
, irpsp
->MinorFunction
);
828 switch (irpsp
->MinorFunction
)
830 case IRP_MN_QUERY_ID
:
831 status
= handle_IRP_MN_QUERY_ID(device
, irp
);
834 case IRP_MN_QUERY_CAPABILITIES
:
835 status
= STATUS_SUCCESS
;
838 case IRP_MN_START_DEVICE
:
839 RtlEnterCriticalSection(&ext
->cs
);
840 if (ext
->state
!= DEVICE_STATE_STOPPED
) status
= STATUS_SUCCESS
;
841 else if (ext
->state
== DEVICE_STATE_REMOVED
) status
= STATUS_DELETE_PENDING
;
842 else if ((status
= unix_device_start(device
)))
843 ERR("Failed to start device %p, status %#lx\n", device
, status
);
846 status
= unix_device_get_report_descriptor(device
, NULL
, 0, &ext
->report_desc_length
);
847 if (status
!= STATUS_SUCCESS
&& status
!= STATUS_BUFFER_TOO_SMALL
)
848 ERR("Failed to get device %p report descriptor, status %#lx\n", device
, status
);
849 else if (!(ext
->report_desc
= RtlAllocateHeap(GetProcessHeap(), 0, ext
->report_desc_length
)))
850 status
= STATUS_NO_MEMORY
;
851 else if ((status
= unix_device_get_report_descriptor(device
, ext
->report_desc
, ext
->report_desc_length
,
852 &ext
->report_desc_length
)))
853 ERR("Failed to get device %p report descriptor, status %#lx\n", device
, status
);
854 else if ((status
= HidP_GetCollectionDescription(ext
->report_desc
, ext
->report_desc_length
,
855 PagedPool
, &ext
->collection_desc
)) != HIDP_STATUS_SUCCESS
)
856 ERR("Failed to parse device %p report descriptor, status %#lx\n", device
, status
);
859 status
= STATUS_SUCCESS
;
860 reports
= ext
->collection_desc
.ReportIDs
;
861 for (i
= 0; i
< ext
->collection_desc
.ReportIDsLength
; ++i
)
863 if (!(size
= reports
[i
].InputLength
)) continue;
864 size
= offsetof( struct hid_report
, buffer
[size
] );
865 if (!(report
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
))) status
= STATUS_NO_MEMORY
;
868 report
->length
= reports
[i
].InputLength
;
869 report
->buffer
[0] = reports
[i
].ReportID
;
870 ext
->last_reports
[reports
[i
].ReportID
] = report
;
873 if (!status
) ext
->state
= DEVICE_STATE_STARTED
;
876 RtlLeaveCriticalSection(&ext
->cs
);
879 case IRP_MN_SURPRISE_REMOVAL
:
880 RtlEnterCriticalSection(&ext
->cs
);
881 remove_pending_irps(device
);
882 ext
->state
= DEVICE_STATE_REMOVED
;
883 RtlLeaveCriticalSection(&ext
->cs
);
884 status
= STATUS_SUCCESS
;
887 case IRP_MN_REMOVE_DEVICE
:
888 remove_pending_irps(device
);
890 bus_unlink_hid_device(device
);
891 unix_device_remove(device
);
893 ext
->cs
.DebugInfo
->Spare
[0] = 0;
894 DeleteCriticalSection(&ext
->cs
);
896 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
897 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
899 LIST_FOR_EACH_ENTRY_SAFE(report
, next
, &ext
->reports
, struct hid_report
, entry
)
900 RtlFreeHeap(GetProcessHeap(), 0, report
);
902 reports
= ext
->collection_desc
.ReportIDs
;
903 for (i
= 0; i
< ext
->collection_desc
.ReportIDsLength
; ++i
)
905 if (!reports
[i
].InputLength
) continue;
906 RtlFreeHeap(GetProcessHeap(), 0, ext
->last_reports
[reports
[i
].ReportID
]);
908 HidP_FreeCollectionDescription(&ext
->collection_desc
);
909 RtlFreeHeap(GetProcessHeap(), 0, ext
->report_desc
);
911 IoDeleteDevice(device
);
912 return STATUS_SUCCESS
;
915 FIXME("Unhandled function %08x\n", irpsp
->MinorFunction
);
918 case IRP_MN_QUERY_DEVICE_RELATIONS
:
922 irp
->IoStatus
.Status
= status
;
923 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
927 static NTSTATUS WINAPI
common_pnp_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
929 if (device
== bus_fdo
)
930 return fdo_pnp_dispatch(device
, irp
);
931 return pdo_pnp_dispatch(device
, irp
);
934 static NTSTATUS
hid_get_device_string(DEVICE_OBJECT
*device
, DWORD index
, WCHAR
*buffer
, DWORD buffer_len
)
936 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
941 case HID_STRING_ID_IMANUFACTURER
:
942 len
= (wcslen(ext
->desc
.manufacturer
) + 1) * sizeof(WCHAR
);
943 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
944 else memcpy(buffer
, ext
->desc
.manufacturer
, len
);
945 return STATUS_SUCCESS
;
946 case HID_STRING_ID_IPRODUCT
:
947 len
= (wcslen(ext
->desc
.product
) + 1) * sizeof(WCHAR
);
948 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
949 else memcpy(buffer
, ext
->desc
.product
, len
);
950 return STATUS_SUCCESS
;
951 case HID_STRING_ID_ISERIALNUMBER
:
952 len
= (wcslen(ext
->desc
.serialnumber
) + 1) * sizeof(WCHAR
);
953 if (len
> buffer_len
) return STATUS_BUFFER_TOO_SMALL
;
954 else memcpy(buffer
, ext
->desc
.serialnumber
, len
);
955 return STATUS_SUCCESS
;
958 return STATUS_NOT_IMPLEMENTED
;
961 static NTSTATUS WINAPI
hid_internal_dispatch(DEVICE_OBJECT
*device
, IRP
*irp
)
963 IO_STACK_LOCATION
*irpsp
= IoGetCurrentIrpStackLocation(irp
);
964 struct device_extension
*ext
= (struct device_extension
*)device
->DeviceExtension
;
965 ULONG i
, code
, buffer_len
= irpsp
->Parameters
.DeviceIoControl
.OutputBufferLength
;
968 if (device
== bus_fdo
)
970 IoSkipCurrentIrpStackLocation(irp
);
971 return IoCallDriver(bus_pdo
, irp
);
974 RtlEnterCriticalSection(&ext
->cs
);
976 if (ext
->state
== DEVICE_STATE_REMOVED
)
978 RtlLeaveCriticalSection(&ext
->cs
);
979 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
980 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
981 return STATUS_DELETE_PENDING
;
984 switch ((code
= irpsp
->Parameters
.DeviceIoControl
.IoControlCode
))
986 case IOCTL_HID_GET_DEVICE_ATTRIBUTES
:
988 HID_DEVICE_ATTRIBUTES
*attr
= (HID_DEVICE_ATTRIBUTES
*)irp
->UserBuffer
;
989 TRACE("IOCTL_HID_GET_DEVICE_ATTRIBUTES\n");
991 if (buffer_len
< sizeof(*attr
))
993 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
997 memset(attr
, 0, sizeof(*attr
));
998 attr
->Size
= sizeof(*attr
);
999 attr
->VendorID
= ext
->desc
.vid
;
1000 attr
->ProductID
= ext
->desc
.pid
;
1001 attr
->VersionNumber
= ext
->desc
.version
;
1003 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1004 irp
->IoStatus
.Information
= sizeof(*attr
);
1007 case IOCTL_HID_GET_DEVICE_DESCRIPTOR
:
1009 HID_DESCRIPTOR
*descriptor
= (HID_DESCRIPTOR
*)irp
->UserBuffer
;
1010 irp
->IoStatus
.Information
= sizeof(*descriptor
);
1011 if (buffer_len
< sizeof(*descriptor
)) irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1014 memset(descriptor
, 0, sizeof(*descriptor
));
1015 descriptor
->bLength
= sizeof(*descriptor
);
1016 descriptor
->bDescriptorType
= HID_HID_DESCRIPTOR_TYPE
;
1017 descriptor
->bcdHID
= HID_REVISION
;
1018 descriptor
->bCountry
= 0;
1019 descriptor
->bNumDescriptors
= 1;
1020 descriptor
->DescriptorList
[0].bReportType
= HID_REPORT_DESCRIPTOR_TYPE
;
1021 descriptor
->DescriptorList
[0].wReportLength
= ext
->report_desc_length
;
1022 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1026 case IOCTL_HID_GET_REPORT_DESCRIPTOR
:
1027 irp
->IoStatus
.Information
= ext
->report_desc_length
;
1028 if (buffer_len
< irp
->IoStatus
.Information
)
1029 irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
1032 memcpy(irp
->UserBuffer
, ext
->report_desc
, ext
->report_desc_length
);
1033 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1036 case IOCTL_HID_GET_STRING
:
1038 UINT index
= (UINT_PTR
)irpsp
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
1039 TRACE("IOCTL_HID_GET_STRING[%08x]\n", index
);
1041 irp
->IoStatus
.Status
= hid_get_device_string(device
, index
, (WCHAR
*)irp
->UserBuffer
, buffer_len
);
1042 if (irp
->IoStatus
.Status
== STATUS_SUCCESS
)
1043 irp
->IoStatus
.Information
= (wcslen((WCHAR
*)irp
->UserBuffer
) + 1) * sizeof(WCHAR
);
1046 case IOCTL_HID_GET_INPUT_REPORT
:
1048 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1049 struct hid_report
*last_report
= ext
->last_reports
[packet
->reportId
];
1050 memcpy(packet
->reportBuffer
, last_report
->buffer
, last_report
->length
);
1051 packet
->reportBufferLen
= last_report
->length
;
1052 irp
->IoStatus
.Information
= packet
->reportBufferLen
;
1053 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
1056 TRACE("read input report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1057 for (i
= 0; i
< packet
->reportBufferLen
;)
1059 char buffer
[256], *buf
= buffer
;
1060 buf
+= sprintf(buf
, "%08lx ", i
);
1061 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1062 while (++i
% 16 && i
< packet
->reportBufferLen
);
1063 TRACE("%s\n", buffer
);
1068 case IOCTL_HID_READ_REPORT
:
1070 if (!deliver_next_report(ext
, irp
))
1072 /* hidclass.sys should guarantee this */
1073 assert(!ext
->pending_read
);
1074 ext
->pending_read
= irp
;
1075 IoMarkIrpPending(irp
);
1076 irp
->IoStatus
.Status
= STATUS_PENDING
;
1080 case IOCTL_HID_SET_OUTPUT_REPORT
:
1081 case IOCTL_HID_WRITE_REPORT
:
1083 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1086 TRACE("write output report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1087 for (i
= 0; i
< packet
->reportBufferLen
;)
1089 char buffer
[256], *buf
= buffer
;
1090 buf
+= sprintf(buf
, "%08lx ", i
);
1091 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1092 while (++i
% 16 && i
< packet
->reportBufferLen
);
1093 TRACE("%s\n", buffer
);
1096 unix_device_set_output_report(device
, packet
, &irp
->IoStatus
);
1099 case IOCTL_HID_GET_FEATURE
:
1101 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1102 unix_device_get_feature_report(device
, packet
, &irp
->IoStatus
);
1103 if (!irp
->IoStatus
.Status
&& TRACE_ON(hid
))
1105 TRACE("read feature report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1106 for (i
= 0; i
< packet
->reportBufferLen
;)
1108 char buffer
[256], *buf
= buffer
;
1109 buf
+= sprintf(buf
, "%08lx ", i
);
1110 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1111 while (++i
% 16 && i
< packet
->reportBufferLen
);
1112 TRACE("%s\n", buffer
);
1117 case IOCTL_HID_SET_FEATURE
:
1119 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
1122 TRACE("write feature report id %u length %lu:\n", packet
->reportId
, packet
->reportBufferLen
);
1123 for (i
= 0; i
< packet
->reportBufferLen
;)
1125 char buffer
[256], *buf
= buffer
;
1126 buf
+= sprintf(buf
, "%08lx ", i
);
1127 do { buf
+= sprintf(buf
, " %02x", packet
->reportBuffer
[i
]); }
1128 while (++i
% 16 && i
< packet
->reportBufferLen
);
1129 TRACE("%s\n", buffer
);
1132 unix_device_set_feature_report(device
, packet
, &irp
->IoStatus
);
1136 FIXME("Unsupported ioctl %lx (device=%lx access=%lx func=%lx method=%lx)\n",
1137 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
1141 status
= irp
->IoStatus
.Status
;
1142 RtlLeaveCriticalSection(&ext
->cs
);
1144 if (status
!= STATUS_PENDING
) IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1148 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*pdo
)
1152 TRACE("driver %p, pdo %p.\n", driver
, pdo
);
1154 if ((ret
= IoCreateDevice(driver
, 0, NULL
, FILE_DEVICE_BUS_EXTENDER
, 0, FALSE
, &bus_fdo
)))
1156 ERR("Failed to create FDO, status %#lx.\n", ret
);
1160 IoAttachDeviceToDeviceStack(bus_fdo
, pdo
);
1163 bus_fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
1165 return STATUS_SUCCESS
;
1168 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
1170 NtClose(driver_key
);
1173 NTSTATUS WINAPI
DriverEntry( DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
1175 OBJECT_ATTRIBUTES attr
= {0};
1178 TRACE( "(%p, %s)\n", driver
, debugstr_w(path
->Buffer
) );
1180 if ((ret
= __wine_init_unix_call())) return ret
;
1182 attr
.Length
= sizeof(attr
);
1183 attr
.ObjectName
= path
;
1184 attr
.Attributes
= OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
;
1185 if ((ret
= NtOpenKey(&driver_key
, KEY_ALL_ACCESS
, &attr
)) != STATUS_SUCCESS
)
1186 ERR("Failed to open driver key, status %#lx.\n", ret
);
1188 driver_obj
= driver
;
1190 driver
->MajorFunction
[IRP_MJ_PNP
] = common_pnp_dispatch
;
1191 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = hid_internal_dispatch
;
1192 driver
->DriverExtension
->AddDevice
= driver_add_device
;
1193 driver
->DriverUnload
= driver_unload
;
1195 return STATUS_SUCCESS
;