cmd: DIR command outputs free space for the path.
[wine.git] / dlls / wineusb.sys / wineusb.c
blob801393cacf64ef17158fe7c7f410a3faefddda13
1 /*
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
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <stdlib.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winioctl.h"
31 #include "winternl.h"
32 #include "ddk/wdm.h"
33 #include "ddk/usb.h"
34 #include "ddk/usbioctl.h"
35 #include "wine/asm.h"
36 #include "wine/debug.h"
37 #include "wine/list.h"
39 #include "unixlib.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,
47 "popl %ecx\n\t"
48 "popl %eax\n\t"
49 "xchgl (%esp),%ecx\n\t"
50 "jmp *%eax" );
52 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
54 #else
56 #define call_fastcall_func1(func,a) func(a)
58 #endif
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);
71 struct usb_device
73 struct list entry;
74 BOOL removed;
76 DEVICE_OBJECT *device_obj;
78 bool interface;
79 int16_t interface_index;
81 uint8_t class, subclass, protocol, busnum, portnum;
83 uint16_t vendor, product, revision, usbver;
85 struct unix_device *unix_device;
87 LIST_ENTRY irp_list;
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, &params);
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;
109 NTSTATUS status;
110 WCHAR name[26];
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);
121 return;
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->interface = event->interface;
131 device->interface_index = event->interface_index;
133 device->class = event->class;
134 device->subclass = event->subclass;
135 device->protocol = event->protocol;
136 device->busnum = event->busnum;
137 device->portnum = event->portnum;
139 device->vendor = event->vendor;
140 device->product = event->product;
141 device->revision = event->revision;
142 device->usbver = event->usbver;
144 EnterCriticalSection(&wineusb_cs);
145 list_add_tail(&device_list, &device->entry);
146 LeaveCriticalSection(&wineusb_cs);
148 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
151 static void remove_unix_device(struct unix_device *unix_device)
153 struct usb_device *device;
155 TRACE("Removing device %p.\n", unix_device);
157 EnterCriticalSection(&wineusb_cs);
158 LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry)
160 if (device->unix_device == unix_device)
162 if (!device->removed)
164 device->removed = TRUE;
165 list_remove(&device->entry);
167 break;
170 LeaveCriticalSection(&wineusb_cs);
172 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
175 static HANDLE event_thread;
177 static void complete_irp(IRP *irp)
179 EnterCriticalSection(&wineusb_cs);
180 RemoveEntryList(&irp->Tail.Overlay.ListEntry);
181 LeaveCriticalSection(&wineusb_cs);
183 irp->IoStatus.Status = STATUS_SUCCESS;
184 IoCompleteRequest(irp, IO_NO_INCREMENT);
187 static DWORD CALLBACK event_thread_proc(void *arg)
189 struct usb_event event;
190 struct usb_main_loop_params params =
192 .event = &event,
195 TRACE("Starting event thread.\n");
197 if (WINE_UNIX_CALL(unix_usb_init, NULL) != STATUS_SUCCESS)
198 return 0;
200 while (WINE_UNIX_CALL(unix_usb_main_loop, &params) == STATUS_PENDING)
202 switch (event.type)
204 case USB_EVENT_ADD_DEVICE:
205 add_unix_device(&event.u.added_device);
206 break;
208 case USB_EVENT_REMOVE_DEVICE:
209 remove_unix_device(event.u.removed_device);
210 break;
212 case USB_EVENT_TRANSFER_COMPLETE:
213 complete_irp(event.u.completed_irp);
214 break;
218 TRACE("Shutting down event thread.\n");
219 return 0;
222 static NTSTATUS fdo_pnp(IRP *irp)
224 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
225 NTSTATUS ret;
227 TRACE("irp %p, minor function %#x.\n", irp, stack->MinorFunction);
229 switch (stack->MinorFunction)
231 case IRP_MN_QUERY_DEVICE_RELATIONS:
233 struct usb_device *device;
234 DEVICE_RELATIONS *devices;
235 unsigned int i = 0;
237 if (stack->Parameters.QueryDeviceRelations.Type != BusRelations)
239 FIXME("Unhandled device relations type %#x.\n", stack->Parameters.QueryDeviceRelations.Type);
240 break;
243 EnterCriticalSection(&wineusb_cs);
245 if (!(devices = ExAllocatePool(PagedPool,
246 offsetof(DEVICE_RELATIONS, Objects[list_count(&device_list)]))))
248 LeaveCriticalSection(&wineusb_cs);
249 irp->IoStatus.Status = STATUS_NO_MEMORY;
250 break;
253 LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry)
255 devices->Objects[i++] = device->device_obj;
256 call_fastcall_func1(ObfReferenceObject, device->device_obj);
259 LeaveCriticalSection(&wineusb_cs);
261 devices->Count = i;
262 irp->IoStatus.Information = (ULONG_PTR)devices;
263 irp->IoStatus.Status = STATUS_SUCCESS;
264 break;
267 case IRP_MN_START_DEVICE:
268 event_thread = CreateThread(NULL, 0, event_thread_proc, NULL, 0, NULL);
270 irp->IoStatus.Status = STATUS_SUCCESS;
271 break;
273 case IRP_MN_SURPRISE_REMOVAL:
274 irp->IoStatus.Status = STATUS_SUCCESS;
275 break;
277 case IRP_MN_REMOVE_DEVICE:
279 struct usb_device *device, *cursor;
281 WINE_UNIX_CALL(unix_usb_exit, NULL);
282 WaitForSingleObject(event_thread, INFINITE);
283 CloseHandle(event_thread);
285 EnterCriticalSection(&wineusb_cs);
286 /* Normally we unlink all devices either:
288 * - as a result of hot-unplug, which unlinks the device, and causes
289 * a subsequent IRP_MN_REMOVE_DEVICE which will free it;
291 * - if the parent is deleted (at shutdown time), in which case
292 * ntoskrnl will send us IRP_MN_SURPRISE_REMOVAL and
293 * IRP_MN_REMOVE_DEVICE unprompted.
295 * But we can get devices hotplugged between when shutdown starts
296 * and now, in which case they'll be stuck in this list and never
297 * freed.
299 * FIXME: This is still broken, though. If a device is hotplugged
300 * and then removed, it'll be unlinked and never freed. */
301 LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry)
303 assert(!device->removed);
304 destroy_unix_device(device->unix_device);
305 list_remove(&device->entry);
306 IoDeleteDevice(device->device_obj);
308 LeaveCriticalSection(&wineusb_cs);
310 irp->IoStatus.Status = STATUS_SUCCESS;
311 IoSkipCurrentIrpStackLocation(irp);
312 ret = IoCallDriver(bus_pdo, irp);
313 IoDetachDevice(bus_pdo);
314 IoDeleteDevice(bus_fdo);
315 return ret;
318 default:
319 FIXME("Unhandled minor function %#x.\n", stack->MinorFunction);
322 IoSkipCurrentIrpStackLocation(irp);
323 return IoCallDriver(bus_pdo, irp);
326 struct string_buffer
328 WCHAR *string;
329 size_t len;
332 static void WINAPIV append_id(struct string_buffer *buffer, const WCHAR *format, ...)
334 va_list args;
335 WCHAR *string;
336 int len;
338 va_start(args, format);
340 len = _vsnwprintf(NULL, 0, format, args) + 1;
341 if (!(string = ExAllocatePool(PagedPool, (buffer->len + len) * sizeof(WCHAR))))
343 if (buffer->string)
344 ExFreePool(buffer->string);
345 buffer->string = NULL;
346 return;
348 if (buffer->string)
350 memcpy(string, buffer->string, buffer->len * sizeof(WCHAR));
351 ExFreePool(buffer->string);
353 _vsnwprintf(string + buffer->len, len, format, args);
354 buffer->string = string;
355 buffer->len += len;
357 va_end(args);
360 static void get_device_id(const struct usb_device *device, struct string_buffer *buffer)
362 if (device->interface)
363 append_id(buffer, L"USB\\VID_%04X&PID_%04X&MI_%02X",
364 device->vendor, device->product, device->interface_index);
365 else
366 append_id(buffer, L"USB\\VID_%04X&PID_%04X", device->vendor, device->product);
369 static void get_instance_id(const struct usb_device *device, struct string_buffer *buffer)
371 append_id(buffer, L"%u&%u&%u&%u", device->usbver, device->revision, device->busnum, device->portnum);
374 static void get_hardware_ids(const struct usb_device *device, struct string_buffer *buffer)
376 if (device->interface)
377 append_id(buffer, L"USB\\VID_%04X&PID_%04X&REV_%04X&MI_%02X",
378 device->vendor, device->product, device->revision, device->interface_index);
379 else
380 append_id(buffer, L"USB\\VID_%04X&PID_%04X&REV_%04X",
381 device->vendor, device->product, device->revision);
383 get_device_id(device, buffer);
384 append_id(buffer, L"");
387 static void get_compatible_ids(const struct usb_device *device, struct string_buffer *buffer)
389 if (device->interface_index != -1)
391 append_id(buffer, L"USB\\Class_%02x&SubClass_%02x&Prot_%02x",
392 device->class, device->subclass, device->protocol);
393 append_id(buffer, L"USB\\Class_%02x&SubClass_%02x", device->class, device->subclass);
394 append_id(buffer, L"USB\\Class_%02x", device->class);
396 else
398 append_id(buffer, L"USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
399 device->class, device->subclass, device->protocol);
400 append_id(buffer, L"USB\\DevClass_%02x&SubClass_%02x", device->class, device->subclass);
401 append_id(buffer, L"USB\\DevClass_%02x", device->class);
403 append_id(buffer, L"");
406 static NTSTATUS query_id(struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type)
408 struct string_buffer buffer = {0};
410 TRACE("type %#x.\n", type);
412 switch (type)
414 case BusQueryDeviceID:
415 get_device_id(device, &buffer);
416 break;
418 case BusQueryInstanceID:
419 get_instance_id(device, &buffer);
420 break;
422 case BusQueryHardwareIDs:
423 get_hardware_ids(device, &buffer);
424 break;
426 case BusQueryCompatibleIDs:
427 get_compatible_ids(device, &buffer);
428 break;
430 default:
431 FIXME("Unhandled ID query type %#x.\n", type);
432 return irp->IoStatus.Status;
435 if (!buffer.string)
436 return STATUS_NO_MEMORY;
438 irp->IoStatus.Information = (ULONG_PTR)buffer.string;
439 return STATUS_SUCCESS;
442 static void remove_pending_irps(struct usb_device *device)
444 LIST_ENTRY *entry;
445 IRP *irp;
447 while ((entry = RemoveHeadList(&device->irp_list)) != &device->irp_list)
449 irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
450 irp->IoStatus.Status = STATUS_DELETE_PENDING;
451 irp->IoStatus.Information = 0;
452 IoCompleteRequest(irp, IO_NO_INCREMENT);
456 static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
458 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
459 struct usb_device *device = device_obj->DeviceExtension;
460 NTSTATUS ret = irp->IoStatus.Status;
462 TRACE("device_obj %p, irp %p, minor function %#x.\n", device_obj, irp, stack->MinorFunction);
464 switch (stack->MinorFunction)
466 case IRP_MN_QUERY_ID:
467 ret = query_id(device, irp, stack->Parameters.QueryId.IdType);
468 break;
470 case IRP_MN_QUERY_CAPABILITIES:
472 DEVICE_CAPABILITIES *caps = stack->Parameters.DeviceCapabilities.Capabilities;
474 caps->RawDeviceOK = 1;
476 ret = STATUS_SUCCESS;
477 break;
480 case IRP_MN_START_DEVICE:
481 ret = STATUS_SUCCESS;
482 break;
484 case IRP_MN_SURPRISE_REMOVAL:
485 EnterCriticalSection(&wineusb_cs);
486 remove_pending_irps(device);
487 if (!device->removed)
489 device->removed = TRUE;
490 list_remove(&device->entry);
492 LeaveCriticalSection(&wineusb_cs);
493 ret = STATUS_SUCCESS;
494 break;
496 case IRP_MN_REMOVE_DEVICE:
497 assert(device->removed);
498 remove_pending_irps(device);
500 destroy_unix_device(device->unix_device);
502 IoDeleteDevice(device->device_obj);
503 ret = STATUS_SUCCESS;
504 break;
506 default:
507 FIXME("Unhandled minor function %#x.\n", stack->MinorFunction);
510 irp->IoStatus.Status = ret;
511 IoCompleteRequest(irp, IO_NO_INCREMENT);
512 return ret;
515 static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
517 if (device == bus_fdo)
518 return fdo_pnp(irp);
519 return pdo_pnp(device, irp);
522 static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp)
524 URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
525 NTSTATUS status;
527 TRACE("type %#x.\n", urb->UrbHeader.Function);
529 switch (urb->UrbHeader.Function)
531 case URB_FUNCTION_ABORT_PIPE:
533 LIST_ENTRY *entry, *mark;
535 /* The documentation states that URB_FUNCTION_ABORT_PIPE may
536 * complete before outstanding requests complete, so we don't need
537 * to wait for them. */
538 EnterCriticalSection(&wineusb_cs);
539 mark = &device->irp_list;
540 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
542 IRP *queued_irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
543 struct usb_cancel_transfer_params params =
545 .transfer = queued_irp->Tail.Overlay.DriverContext[0],
548 WINE_UNIX_CALL(unix_usb_cancel_transfer, &params);
550 LeaveCriticalSection(&wineusb_cs);
552 return STATUS_SUCCESS;
555 case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
556 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
557 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
558 case URB_FUNCTION_SELECT_CONFIGURATION:
559 case URB_FUNCTION_VENDOR_INTERFACE:
561 struct usb_submit_urb_params params =
563 .device = device->unix_device,
564 .irp = irp,
567 switch (urb->UrbHeader.Function)
569 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
571 struct _URB_BULK_OR_INTERRUPT_TRANSFER *req = &urb->UrbBulkOrInterruptTransfer;
572 if (req->TransferBufferMDL)
573 params.transfer_buffer = MmGetSystemAddressForMdlSafe(req->TransferBufferMDL, NormalPagePriority);
574 else
575 params.transfer_buffer = req->TransferBuffer;
576 break;
579 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
581 struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
582 if (req->TransferBufferMDL)
583 params.transfer_buffer = MmGetSystemAddressForMdlSafe(req->TransferBufferMDL, NormalPagePriority);
584 else
585 params.transfer_buffer = req->TransferBuffer;
586 break;
589 case URB_FUNCTION_VENDOR_INTERFACE:
591 struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
592 if (req->TransferBufferMDL)
593 params.transfer_buffer = MmGetSystemAddressForMdlSafe(req->TransferBufferMDL, NormalPagePriority);
594 else
595 params.transfer_buffer = req->TransferBuffer;
596 break;
600 /* Hold the wineusb lock while submitting and queuing, and
601 * similarly hold it in complete_irp(). That way, if libusb reports
602 * completion between submitting and queuing, we won't try to
603 * dequeue the IRP until it's actually been queued. */
604 EnterCriticalSection(&wineusb_cs);
605 status = WINE_UNIX_CALL(unix_usb_submit_urb, &params);
606 if (status == STATUS_PENDING)
608 IoMarkIrpPending(irp);
609 InsertTailList(&device->irp_list, &irp->Tail.Overlay.ListEntry);
611 LeaveCriticalSection(&wineusb_cs);
613 return status;
616 default:
617 FIXME("Unhandled function %#x.\n", urb->UrbHeader.Function);
620 return STATUS_NOT_IMPLEMENTED;
623 static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device_obj, IRP *irp)
625 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
626 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
627 struct usb_device *device = device_obj->DeviceExtension;
628 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
629 BOOL removed;
631 TRACE("device_obj %p, irp %p, code %#lx.\n", device_obj, irp, code);
633 EnterCriticalSection(&wineusb_cs);
634 removed = device->removed;
635 LeaveCriticalSection(&wineusb_cs);
637 if (removed)
639 irp->IoStatus.Status = STATUS_DELETE_PENDING;
640 IoCompleteRequest(irp, IO_NO_INCREMENT);
641 return STATUS_DELETE_PENDING;
644 switch (code)
646 case IOCTL_INTERNAL_USB_SUBMIT_URB:
647 status = usb_submit_urb(device, irp);
648 break;
650 default:
651 FIXME("Unhandled ioctl %#lx (device %#lx, access %#lx, function %#lx, method %#lx).\n",
652 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
655 if (status != STATUS_PENDING)
657 irp->IoStatus.Status = status;
658 IoCompleteRequest(irp, IO_NO_INCREMENT);
660 return status;
663 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
665 NTSTATUS ret;
667 TRACE("driver %p, pdo %p.\n", driver, pdo);
669 if ((ret = IoCreateDevice(driver, 0, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &bus_fdo)))
671 ERR("Failed to create FDO, status %#lx.\n", ret);
672 return ret;
675 IoAttachDeviceToDeviceStack(bus_fdo, pdo);
676 bus_pdo = pdo;
677 bus_fdo->Flags &= ~DO_DEVICE_INITIALIZING;
679 return STATUS_SUCCESS;
682 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
686 NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
688 NTSTATUS status;
690 TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
692 if ((status = __wine_init_unix_call()))
694 ERR("Failed to initialize Unix library, status %#lx.\n", status);
695 return status;
698 driver_obj = driver;
700 driver->DriverExtension->AddDevice = driver_add_device;
701 driver->DriverUnload = driver_unload;
702 driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
703 driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl;
705 return STATUS_SUCCESS;