2 * USB root device enumerator using libusb
4 * Copyright 2020 Zebediah Figura
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
28 #define WIN32_NO_STATUS
34 #include "ddk/usbioctl.h"
36 #include "wine/debug.h"
37 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(wineusb
);
43 #ifdef __ASM_USE_FASTCALL_WRAPPER
45 extern void * WINAPI
wrap_fastcall_func1( void *func
, const void *a
);
46 __ASM_STDCALL_FUNC( wrap_fastcall_func1
, 8,
49 "xchgl (%esp),%ecx\n\t"
52 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
56 #define call_fastcall_func1(func,a) func(a)
60 #define DECLARE_CRITICAL_SECTION(cs) \
61 static CRITICAL_SECTION cs; \
62 static CRITICAL_SECTION_DEBUG cs##_debug = \
63 { 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
64 0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
65 static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
67 DECLARE_CRITICAL_SECTION(wineusb_cs
);
69 static struct list device_list
= LIST_INIT(device_list
);
76 DEVICE_OBJECT
*device_obj
;
79 uint8_t interface_index
;
81 uint8_t class, subclass
, protocol
;
83 uint16_t vendor
, product
, revision
;
85 struct unix_device
*unix_device
;
90 static DRIVER_OBJECT
*driver_obj
;
91 static DEVICE_OBJECT
*bus_fdo
, *bus_pdo
;
93 static void destroy_unix_device(struct unix_device
*unix_device
)
95 struct usb_destroy_device_params params
=
97 .device
= unix_device
,
100 WINE_UNIX_CALL(unix_usb_destroy_device
, ¶ms
);
103 static void add_unix_device(const struct usb_add_device_event
*event
)
105 static unsigned int name_index
;
106 struct usb_device
*device
;
107 DEVICE_OBJECT
*device_obj
;
108 UNICODE_STRING string
;
112 TRACE("Adding new device %p, vendor %04x, product %04x.\n", event
->device
,
113 event
->vendor
, event
->product
);
115 swprintf(name
, ARRAY_SIZE(name
), L
"\\Device\\USBPDO-%u", name_index
++);
116 RtlInitUnicodeString(&string
, name
);
117 if ((status
= IoCreateDevice(driver_obj
, sizeof(*device
), &string
,
118 FILE_DEVICE_USB
, 0, FALSE
, &device_obj
)))
120 ERR("Failed to create device, status %#lx.\n", status
);
124 device
= device_obj
->DeviceExtension
;
125 device
->device_obj
= device_obj
;
126 device
->unix_device
= event
->device
;
127 InitializeListHead(&device
->irp_list
);
128 device
->removed
= FALSE
;
130 device
->class = event
->class;
131 device
->subclass
= event
->subclass
;
132 device
->protocol
= event
->protocol
;
133 device
->vendor
= event
->vendor
;
134 device
->product
= event
->product
;
135 device
->revision
= event
->revision
;
137 EnterCriticalSection(&wineusb_cs
);
138 list_add_tail(&device_list
, &device
->entry
);
139 LeaveCriticalSection(&wineusb_cs
);
141 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
144 static void remove_unix_device(struct unix_device
*unix_device
)
146 struct usb_device
*device
;
148 TRACE("Removing device %p.\n", unix_device
);
150 EnterCriticalSection(&wineusb_cs
);
151 LIST_FOR_EACH_ENTRY(device
, &device_list
, struct usb_device
, entry
)
153 if (device
->unix_device
== unix_device
)
155 if (!device
->removed
)
157 device
->removed
= TRUE
;
158 list_remove(&device
->entry
);
163 LeaveCriticalSection(&wineusb_cs
);
165 IoInvalidateDeviceRelations(bus_pdo
, BusRelations
);
168 static HANDLE event_thread
;
170 static void complete_irp(IRP
*irp
)
172 EnterCriticalSection(&wineusb_cs
);
173 RemoveEntryList(&irp
->Tail
.Overlay
.ListEntry
);
174 LeaveCriticalSection(&wineusb_cs
);
176 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
177 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
180 static DWORD CALLBACK
event_thread_proc(void *arg
)
182 struct usb_event event
;
183 struct usb_main_loop_params params
=
188 TRACE("Starting event thread.\n");
190 if (WINE_UNIX_CALL(unix_usb_init
, NULL
) != STATUS_SUCCESS
)
193 while (WINE_UNIX_CALL(unix_usb_main_loop
, ¶ms
) == STATUS_PENDING
)
197 case USB_EVENT_ADD_DEVICE
:
198 add_unix_device(&event
.u
.added_device
);
201 case USB_EVENT_REMOVE_DEVICE
:
202 remove_unix_device(event
.u
.removed_device
);
205 case USB_EVENT_TRANSFER_COMPLETE
:
206 complete_irp(event
.u
.completed_irp
);
211 TRACE("Shutting down event thread.\n");
215 static NTSTATUS
fdo_pnp(IRP
*irp
)
217 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
220 TRACE("irp %p, minor function %#x.\n", irp
, stack
->MinorFunction
);
222 switch (stack
->MinorFunction
)
224 case IRP_MN_QUERY_DEVICE_RELATIONS
:
226 struct usb_device
*device
;
227 DEVICE_RELATIONS
*devices
;
230 if (stack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
232 FIXME("Unhandled device relations type %#x.\n", stack
->Parameters
.QueryDeviceRelations
.Type
);
236 EnterCriticalSection(&wineusb_cs
);
238 if (!(devices
= ExAllocatePool(PagedPool
,
239 offsetof(DEVICE_RELATIONS
, Objects
[list_count(&device_list
)]))))
241 LeaveCriticalSection(&wineusb_cs
);
242 irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
246 LIST_FOR_EACH_ENTRY(device
, &device_list
, struct usb_device
, entry
)
248 devices
->Objects
[i
++] = device
->device_obj
;
249 call_fastcall_func1(ObfReferenceObject
, device
->device_obj
);
252 LeaveCriticalSection(&wineusb_cs
);
255 irp
->IoStatus
.Information
= (ULONG_PTR
)devices
;
256 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
260 case IRP_MN_START_DEVICE
:
261 event_thread
= CreateThread(NULL
, 0, event_thread_proc
, NULL
, 0, NULL
);
263 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
266 case IRP_MN_SURPRISE_REMOVAL
:
267 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
270 case IRP_MN_REMOVE_DEVICE
:
272 struct usb_device
*device
, *cursor
;
274 WINE_UNIX_CALL(unix_usb_exit
, NULL
);
275 WaitForSingleObject(event_thread
, INFINITE
);
276 CloseHandle(event_thread
);
278 EnterCriticalSection(&wineusb_cs
);
279 /* Normally we unlink all devices either:
281 * - as a result of hot-unplug, which unlinks the device, and causes
282 * a subsequent IRP_MN_REMOVE_DEVICE which will free it;
284 * - if the parent is deleted (at shutdown time), in which case
285 * ntoskrnl will send us IRP_MN_SURPRISE_REMOVAL and
286 * IRP_MN_REMOVE_DEVICE unprompted.
288 * But we can get devices hotplugged between when shutdown starts
289 * and now, in which case they'll be stuck in this list and never
292 * FIXME: This is still broken, though. If a device is hotplugged
293 * and then removed, it'll be unlinked and never freed. */
294 LIST_FOR_EACH_ENTRY_SAFE(device
, cursor
, &device_list
, struct usb_device
, entry
)
296 assert(!device
->removed
);
297 destroy_unix_device(device
->unix_device
);
298 list_remove(&device
->entry
);
299 IoDeleteDevice(device
->device_obj
);
301 LeaveCriticalSection(&wineusb_cs
);
303 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
304 IoSkipCurrentIrpStackLocation(irp
);
305 ret
= IoCallDriver(bus_pdo
, irp
);
306 IoDetachDevice(bus_pdo
);
307 IoDeleteDevice(bus_fdo
);
312 FIXME("Unhandled minor function %#x.\n", stack
->MinorFunction
);
315 IoSkipCurrentIrpStackLocation(irp
);
316 return IoCallDriver(bus_pdo
, irp
);
325 static void WINAPIV
append_id(struct string_buffer
*buffer
, const WCHAR
*format
, ...)
331 __ms_va_start(args
, format
);
333 len
= _vsnwprintf(NULL
, 0, format
, args
) + 1;
334 if (!(string
= ExAllocatePool(PagedPool
, (buffer
->len
+ len
) * sizeof(WCHAR
))))
337 ExFreePool(buffer
->string
);
338 buffer
->string
= NULL
;
343 memcpy(string
, buffer
->string
, buffer
->len
* sizeof(WCHAR
));
344 ExFreePool(buffer
->string
);
346 _vsnwprintf(string
+ buffer
->len
, len
, format
, args
);
347 buffer
->string
= string
;
353 static void get_device_id(const struct usb_device
*device
, struct string_buffer
*buffer
)
355 if (device
->interface
)
356 append_id(buffer
, L
"USB\\VID_%04X&PID_%04X&MI_%02X",
357 device
->vendor
, device
->product
, device
->interface_index
);
359 append_id(buffer
, L
"USB\\VID_%04X&PID_%04X", device
->vendor
, device
->product
);
362 static void get_hardware_ids(const struct usb_device
*device
, struct string_buffer
*buffer
)
364 if (device
->interface
)
365 append_id(buffer
, L
"USB\\VID_%04X&PID_%04X&REV_%04X&MI_%02X",
366 device
->vendor
, device
->product
, device
->revision
, device
->interface_index
);
368 append_id(buffer
, L
"USB\\VID_%04X&PID_%04X&REV_%04X",
369 device
->vendor
, device
->product
, device
->revision
);
371 get_device_id(device
, buffer
);
372 append_id(buffer
, L
"");
375 static void get_compatible_ids(const struct usb_device
*device
, struct string_buffer
*buffer
)
377 append_id(buffer
, L
"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
378 device
->class, device
->subclass
, device
->protocol
);
379 append_id(buffer
, L
"USB\\Class_%02x&SubClass_%02x", device
->class, device
->subclass
);
380 append_id(buffer
, L
"USB\\Class_%02x", device
->class);
381 append_id(buffer
, L
"");
384 static NTSTATUS
query_id(struct usb_device
*device
, IRP
*irp
, BUS_QUERY_ID_TYPE type
)
386 struct string_buffer buffer
= {0};
388 TRACE("type %#x.\n", type
);
392 case BusQueryDeviceID
:
393 get_device_id(device
, &buffer
);
396 case BusQueryInstanceID
:
397 append_id(&buffer
, L
"0");
400 case BusQueryHardwareIDs
:
401 get_hardware_ids(device
, &buffer
);
404 case BusQueryCompatibleIDs
:
405 get_compatible_ids(device
, &buffer
);
409 FIXME("Unhandled ID query type %#x.\n", type
);
410 return irp
->IoStatus
.Status
;
414 return STATUS_NO_MEMORY
;
416 irp
->IoStatus
.Information
= (ULONG_PTR
)buffer
.string
;
417 return STATUS_SUCCESS
;
420 static void remove_pending_irps(struct usb_device
*device
)
425 while ((entry
= RemoveHeadList(&device
->irp_list
)) != &device
->irp_list
)
427 irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
428 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
429 irp
->IoStatus
.Information
= 0;
430 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
434 static NTSTATUS
pdo_pnp(DEVICE_OBJECT
*device_obj
, IRP
*irp
)
436 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
437 struct usb_device
*device
= device_obj
->DeviceExtension
;
438 NTSTATUS ret
= irp
->IoStatus
.Status
;
440 TRACE("device_obj %p, irp %p, minor function %#x.\n", device_obj
, irp
, stack
->MinorFunction
);
442 switch (stack
->MinorFunction
)
444 case IRP_MN_QUERY_ID
:
445 ret
= query_id(device
, irp
, stack
->Parameters
.QueryId
.IdType
);
448 case IRP_MN_QUERY_CAPABILITIES
:
450 DEVICE_CAPABILITIES
*caps
= stack
->Parameters
.DeviceCapabilities
.Capabilities
;
452 caps
->RawDeviceOK
= 1;
454 ret
= STATUS_SUCCESS
;
458 case IRP_MN_START_DEVICE
:
459 ret
= STATUS_SUCCESS
;
462 case IRP_MN_SURPRISE_REMOVAL
:
463 EnterCriticalSection(&wineusb_cs
);
464 remove_pending_irps(device
);
465 if (!device
->removed
)
467 device
->removed
= TRUE
;
468 list_remove(&device
->entry
);
470 LeaveCriticalSection(&wineusb_cs
);
471 ret
= STATUS_SUCCESS
;
474 case IRP_MN_REMOVE_DEVICE
:
475 assert(device
->removed
);
476 remove_pending_irps(device
);
478 destroy_unix_device(device
->unix_device
);
480 IoDeleteDevice(device
->device_obj
);
481 ret
= STATUS_SUCCESS
;
485 FIXME("Unhandled minor function %#x.\n", stack
->MinorFunction
);
488 irp
->IoStatus
.Status
= ret
;
489 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
493 static NTSTATUS WINAPI
driver_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
495 if (device
== bus_fdo
)
497 return pdo_pnp(device
, irp
);
500 static NTSTATUS
usb_submit_urb(struct usb_device
*device
, IRP
*irp
)
502 URB
*urb
= IoGetCurrentIrpStackLocation(irp
)->Parameters
.Others
.Argument1
;
505 TRACE("type %#x.\n", urb
->UrbHeader
.Function
);
507 switch (urb
->UrbHeader
.Function
)
509 case URB_FUNCTION_ABORT_PIPE
:
511 LIST_ENTRY
*entry
, *mark
;
513 /* The documentation states that URB_FUNCTION_ABORT_PIPE may
514 * complete before outstanding requests complete, so we don't need
515 * to wait for them. */
516 EnterCriticalSection(&wineusb_cs
);
517 mark
= &device
->irp_list
;
518 for (entry
= mark
->Flink
; entry
!= mark
; entry
= entry
->Flink
)
520 IRP
*queued_irp
= CONTAINING_RECORD(entry
, IRP
, Tail
.Overlay
.ListEntry
);
521 struct usb_cancel_transfer_params params
=
523 .transfer
= queued_irp
->Tail
.Overlay
.DriverContext
[0],
526 WINE_UNIX_CALL(unix_usb_cancel_transfer
, ¶ms
);
528 LeaveCriticalSection(&wineusb_cs
);
530 return STATUS_SUCCESS
;
533 case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
:
534 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
535 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
536 case URB_FUNCTION_SELECT_CONFIGURATION
:
537 case URB_FUNCTION_VENDOR_INTERFACE
:
539 struct usb_submit_urb_params params
=
541 .device
= device
->unix_device
,
545 switch (urb
->UrbHeader
.Function
)
547 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
:
549 struct _URB_BULK_OR_INTERRUPT_TRANSFER
*req
= &urb
->UrbBulkOrInterruptTransfer
;
550 if (req
->TransferBufferMDL
)
551 params
.transfer_buffer
= MmGetSystemAddressForMdlSafe(req
->TransferBufferMDL
, NormalPagePriority
);
553 params
.transfer_buffer
= req
->TransferBuffer
;
557 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
:
559 struct _URB_CONTROL_DESCRIPTOR_REQUEST
*req
= &urb
->UrbControlDescriptorRequest
;
560 if (req
->TransferBufferMDL
)
561 params
.transfer_buffer
= MmGetSystemAddressForMdlSafe(req
->TransferBufferMDL
, NormalPagePriority
);
563 params
.transfer_buffer
= req
->TransferBuffer
;
567 case URB_FUNCTION_VENDOR_INTERFACE
:
569 struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
*req
= &urb
->UrbControlVendorClassRequest
;
570 if (req
->TransferBufferMDL
)
571 params
.transfer_buffer
= MmGetSystemAddressForMdlSafe(req
->TransferBufferMDL
, NormalPagePriority
);
573 params
.transfer_buffer
= req
->TransferBuffer
;
578 /* Hold the wineusb lock while submitting and queuing, and
579 * similarly hold it in complete_irp(). That way, if libusb reports
580 * completion between submitting and queuing, we won't try to
581 * dequeue the IRP until it's actually been queued. */
582 EnterCriticalSection(&wineusb_cs
);
583 status
= WINE_UNIX_CALL(unix_usb_submit_urb
, ¶ms
);
584 if (status
== STATUS_PENDING
)
586 IoMarkIrpPending(irp
);
587 InsertTailList(&device
->irp_list
, &irp
->Tail
.Overlay
.ListEntry
);
589 LeaveCriticalSection(&wineusb_cs
);
595 FIXME("Unhandled function %#x.\n", urb
->UrbHeader
.Function
);
598 return STATUS_NOT_IMPLEMENTED
;
601 static NTSTATUS WINAPI
driver_internal_ioctl(DEVICE_OBJECT
*device_obj
, IRP
*irp
)
603 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
604 ULONG code
= stack
->Parameters
.DeviceIoControl
.IoControlCode
;
605 struct usb_device
*device
= device_obj
->DeviceExtension
;
606 NTSTATUS status
= STATUS_NOT_IMPLEMENTED
;
609 TRACE("device_obj %p, irp %p, code %#lx.\n", device_obj
, irp
, code
);
611 EnterCriticalSection(&wineusb_cs
);
612 removed
= device
->removed
;
613 LeaveCriticalSection(&wineusb_cs
);
617 irp
->IoStatus
.Status
= STATUS_DELETE_PENDING
;
618 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
619 return STATUS_DELETE_PENDING
;
624 case IOCTL_INTERNAL_USB_SUBMIT_URB
:
625 status
= usb_submit_urb(device
, irp
);
629 FIXME("Unhandled ioctl %#lx (device %#lx, access %#lx, function %#lx, method %#lx).\n",
630 code
, code
>> 16, (code
>> 14) & 3, (code
>> 2) & 0xfff, code
& 3);
633 if (status
!= STATUS_PENDING
)
635 irp
->IoStatus
.Status
= status
;
636 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
641 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*pdo
)
645 TRACE("driver %p, pdo %p.\n", driver
, pdo
);
647 if ((ret
= IoCreateDevice(driver
, 0, NULL
, FILE_DEVICE_BUS_EXTENDER
, 0, FALSE
, &bus_fdo
)))
649 ERR("Failed to create FDO, status %#lx.\n", ret
);
653 IoAttachDeviceToDeviceStack(bus_fdo
, pdo
);
655 bus_fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
657 return STATUS_SUCCESS
;
660 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
664 NTSTATUS WINAPI
DriverEntry(DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
668 TRACE("driver %p, path %s.\n", driver
, debugstr_w(path
->Buffer
));
670 if ((status
= __wine_init_unix_call()))
672 ERR("Failed to initialize Unix library, status %#lx.\n", status
);
678 driver
->DriverExtension
->AddDevice
= driver_add_device
;
679 driver
->DriverUnload
= driver_unload
;
680 driver
->MajorFunction
[IRP_MJ_PNP
] = driver_pnp
;
681 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = driver_internal_ioctl
;
683 return STATUS_SUCCESS
;