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 KEY_VALUE_FULL_INFORMATION
*info
;
649 OBJECT_ATTRIBUTES attr
= {0};
650 char **mappings
= NULL
;
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
);
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
;
687 if (info
->Type
!= REG_SZ
) continue;
689 RtlUnicodeToMultiByteSize(&len
, (WCHAR
*)((char *)info
+ info
->DataOffset
), info_size
- info
->DataOffset
);
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
))))
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
);
709 RtlFreeHeap(GetProcessHeap(), 0, info
);
713 static NTSTATUS
sdl_driver_init(void)
715 struct sdl_bus_options bus_options
;
716 struct bus_main_params bus
=
719 .init_args
= &bus_options
,
720 .init_code
= sdl_init
,
721 .wait_code
= sdl_wait
,
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
);
736 static NTSTATUS
udev_driver_init(void)
738 struct udev_bus_options bus_options
;
739 struct bus_main_params bus
=
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
=
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
);
776 switch (irpsp
->MinorFunction
)
778 case IRP_MN_QUERY_DEVICE_RELATIONS
:
779 irp
->IoStatus
.Status
= handle_IRP_MN_QUERY_DEVICE_RELATIONS(irp
);
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())
791 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
793 case IRP_MN_SURPRISE_REMOVAL
:
794 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
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
);
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
;
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
);
835 case IRP_MN_QUERY_CAPABILITIES
:
836 status
= STATUS_SUCCESS
;
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
);
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
);
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
;
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
);
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
;
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
;
916 FIXME("Unhandled function %08x\n", irpsp
->MinorFunction
);
919 case IRP_MN_QUERY_DEVICE_RELATIONS
:
923 irp
->IoStatus
.Status
= status
;
924 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
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
;
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
;
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
;
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
);
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
;
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
;
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
;
1033 memcpy(irp
->UserBuffer
, ext
->report_desc
, ext
->report_desc_length
);
1034 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
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
);
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
;
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
);
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
;
1081 case IOCTL_HID_SET_OUTPUT_REPORT
:
1082 case IOCTL_HID_WRITE_REPORT
:
1084 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
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
);
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
);
1118 case IOCTL_HID_SET_FEATURE
:
1120 HID_XFER_PACKET
*packet
= (HID_XFER_PACKET
*)irp
->UserBuffer
;
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
);
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);
1142 status
= irp
->IoStatus
.Status
;
1143 RtlLeaveCriticalSection(&ext
->cs
);
1145 if (status
!= STATUS_PENDING
) IoCompleteRequest(irp
, IO_NO_INCREMENT
);
1149 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*pdo
)
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
);
1161 IoAttachDeviceToDeviceStack(bus_fdo
, 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};
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
;