directmanipulation: Return S_OK form viewport_SetViewportOptions stub.
[wine/zf.git] / dlls / wineusb.sys / wineusb.c
blobf70197704b1335f545609fd5b6e0ef5c8b49d8f0
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 <stdlib.h>
24 #include <libusb.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winioctl.h"
30 #include "winternl.h"
31 #include "ddk/wdm.h"
32 #include "ddk/usb.h"
33 #include "ddk/usbioctl.h"
34 #include "wine/asm.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "wine/unicode.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(wineusb);
41 #if defined(__i386__) && !defined(_WIN32)
43 extern void * WINAPI wrap_fastcall_func1( void *func, const void *a );
44 __ASM_STDCALL_FUNC( wrap_fastcall_func1, 8,
45 "popl %ecx\n\t"
46 "popl %eax\n\t"
47 "xchgl (%esp),%ecx\n\t"
48 "jmp *%eax" );
50 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
52 #else
54 #define call_fastcall_func1(func,a) func(a)
56 #endif
58 #define DECLARE_CRITICAL_SECTION(cs) \
59 static CRITICAL_SECTION cs; \
60 static CRITICAL_SECTION_DEBUG cs##_debug = \
61 { 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
62 0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
63 static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 };
65 DECLARE_CRITICAL_SECTION(wineusb_cs);
67 static struct list device_list = LIST_INIT(device_list);
69 struct usb_device
71 struct list entry;
72 BOOL removed;
74 DEVICE_OBJECT *device_obj;
76 libusb_device *libusb_device;
77 libusb_device_handle *handle;
79 LIST_ENTRY irp_list;
82 static DRIVER_OBJECT *driver_obj;
83 static DEVICE_OBJECT *bus_fdo, *bus_pdo;
85 static libusb_hotplug_callback_handle hotplug_cb_handle;
87 static void add_usb_device(libusb_device *libusb_device)
89 static const WCHAR formatW[] = {'\\','D','e','v','i','c','e','\\','U','S','B','P','D','O','-','%','u',0};
90 struct libusb_device_descriptor device_desc;
91 static unsigned int name_index;
92 libusb_device_handle *handle;
93 struct usb_device *device;
94 DEVICE_OBJECT *device_obj;
95 UNICODE_STRING string;
96 NTSTATUS status;
97 WCHAR name[20];
98 int ret;
100 libusb_get_device_descriptor(libusb_device, &device_desc);
102 TRACE("Adding new device %p, vendor %04x, product %04x.\n", libusb_device,
103 device_desc.idVendor, device_desc.idProduct);
105 if ((ret = libusb_open(libusb_device, &handle)))
107 WARN("Failed to open device: %s\n", libusb_strerror(ret));
108 return;
111 sprintfW(name, formatW, name_index++);
112 RtlInitUnicodeString(&string, name);
113 if ((status = IoCreateDevice(driver_obj, sizeof(*device), &string,
114 FILE_DEVICE_USB, 0, FALSE, &device_obj)))
116 ERR("Failed to create device, status %#x.\n", status);
117 LeaveCriticalSection(&wineusb_cs);
118 libusb_close(handle);
119 return;
122 device = device_obj->DeviceExtension;
123 device->device_obj = device_obj;
124 device->libusb_device = libusb_ref_device(libusb_device);
125 device->handle = handle;
126 InitializeListHead(&device->irp_list);
128 EnterCriticalSection(&wineusb_cs);
129 list_add_tail(&device_list, &device->entry);
130 device->removed = FALSE;
131 LeaveCriticalSection(&wineusb_cs);
133 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
136 static void remove_usb_device(libusb_device *libusb_device)
138 struct usb_device *device;
140 TRACE("Removing device %p.\n", libusb_device);
142 EnterCriticalSection(&wineusb_cs);
143 LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry)
145 if (device->libusb_device == libusb_device)
147 list_remove(&device->entry);
148 device->removed = TRUE;
149 break;
152 LeaveCriticalSection(&wineusb_cs);
154 IoInvalidateDeviceRelations(bus_pdo, BusRelations);
157 static BOOL thread_shutdown;
158 static HANDLE event_thread;
160 static int LIBUSB_CALL hotplug_cb(libusb_context *context, libusb_device *device,
161 libusb_hotplug_event event, void *user_data)
163 if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
164 add_usb_device(device);
165 else
166 remove_usb_device(device);
168 return 0;
171 static DWORD CALLBACK event_thread_proc(void *arg)
173 int ret;
175 TRACE("Starting event thread.\n");
177 while (!thread_shutdown)
179 if ((ret = libusb_handle_events(NULL)))
180 ERR("Error handling events: %s\n", libusb_strerror(ret));
183 TRACE("Shutting down event thread.\n");
184 return 0;
187 static NTSTATUS fdo_pnp(IRP *irp)
189 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
190 NTSTATUS ret;
192 TRACE("irp %p, minor function %#x.\n", irp, stack->MinorFunction);
194 switch (stack->MinorFunction)
196 case IRP_MN_QUERY_DEVICE_RELATIONS:
198 struct usb_device *device;
199 DEVICE_RELATIONS *devices;
200 unsigned int i = 0;
202 if (stack->Parameters.QueryDeviceRelations.Type != BusRelations)
204 FIXME("Unhandled device relations type %#x.\n", stack->Parameters.QueryDeviceRelations.Type);
205 break;
208 EnterCriticalSection(&wineusb_cs);
210 if (!(devices = ExAllocatePool(PagedPool,
211 offsetof(DEVICE_RELATIONS, Objects[list_count(&device_list)]))))
213 LeaveCriticalSection(&wineusb_cs);
214 irp->IoStatus.Status = STATUS_NO_MEMORY;
215 break;
218 LIST_FOR_EACH_ENTRY(device, &device_list, struct usb_device, entry)
220 devices->Objects[i++] = device->device_obj;
221 call_fastcall_func1(ObfReferenceObject, device->device_obj);
224 LeaveCriticalSection(&wineusb_cs);
226 devices->Count = i;
227 irp->IoStatus.Information = (ULONG_PTR)devices;
228 irp->IoStatus.Status = STATUS_SUCCESS;
229 break;
232 case IRP_MN_START_DEVICE:
233 if ((ret = libusb_hotplug_register_callback(NULL,
234 LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
235 LIBUSB_HOTPLUG_ENUMERATE, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
236 LIBUSB_HOTPLUG_MATCH_ANY, hotplug_cb, NULL, &hotplug_cb_handle)))
238 ERR("Failed to register callback: %s\n", libusb_strerror(ret));
239 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
240 break;
242 irp->IoStatus.Status = STATUS_SUCCESS;
243 break;
245 case IRP_MN_SURPRISE_REMOVAL:
246 irp->IoStatus.Status = STATUS_SUCCESS;
247 break;
249 case IRP_MN_REMOVE_DEVICE:
251 struct usb_device *device, *cursor;
253 libusb_hotplug_deregister_callback(NULL, hotplug_cb_handle);
254 thread_shutdown = TRUE;
255 libusb_interrupt_event_handler(NULL);
256 WaitForSingleObject(event_thread, INFINITE);
257 CloseHandle(event_thread);
259 EnterCriticalSection(&wineusb_cs);
260 LIST_FOR_EACH_ENTRY_SAFE(device, cursor, &device_list, struct usb_device, entry)
262 libusb_unref_device(device->libusb_device);
263 libusb_close(device->handle);
264 list_remove(&device->entry);
265 IoDeleteDevice(device->device_obj);
267 LeaveCriticalSection(&wineusb_cs);
269 irp->IoStatus.Status = STATUS_SUCCESS;
270 IoSkipCurrentIrpStackLocation(irp);
271 ret = IoCallDriver(bus_pdo, irp);
272 IoDetachDevice(bus_pdo);
273 IoDeleteDevice(bus_fdo);
274 return ret;
277 default:
278 FIXME("Unhandled minor function %#x.\n", stack->MinorFunction);
281 IoSkipCurrentIrpStackLocation(irp);
282 return IoCallDriver(bus_pdo, irp);
285 static void get_device_id(const struct usb_device *device, WCHAR *buffer)
287 static const WCHAR formatW[] = {'U','S','B','\\','V','I','D','_','%','0','4','X',
288 '&','P','I','D','_','%','0','4','X',0};
289 struct libusb_device_descriptor desc;
291 libusb_get_device_descriptor(device->libusb_device, &desc);
292 sprintfW(buffer, formatW, desc.idVendor, desc.idProduct);
295 static void get_hardware_ids(const struct usb_device *device, WCHAR *buffer)
297 static const WCHAR formatW[] = {'U','S','B','\\','V','I','D','_','%','0','4','X',
298 '&','P','I','D','_','%','0','4','X','&','R','E','V','_','%','0','4','X',0};
299 struct libusb_device_descriptor desc;
301 libusb_get_device_descriptor(device->libusb_device, &desc);
302 buffer += sprintfW(buffer, formatW, desc.idVendor, desc.idProduct, desc.bcdDevice) + 1;
303 get_device_id(device, buffer);
304 buffer += strlenW(buffer) + 1;
305 *buffer = 0;
308 static void get_compatible_ids(const struct usb_device *device, WCHAR *buffer)
310 static const WCHAR prot_format[] = {'U','S','B','\\','C','l','a','s','s','_','%','0','2','x',
311 '&','S','u','b','C','l','a','s','s','_','%','0','2','x',
312 '&','P','r','o','t','_','%','0','2','x',0};
313 static const WCHAR subclass_format[] = {'U','S','B','\\','C','l','a','s','s','_','%','0','2','x',
314 '&','S','u','b','C','l','a','s','s','_','%','0','2','x',0};
315 static const WCHAR class_format[] = {'U','S','B','\\','C','l','a','s','s','_','%','0','2','x',0};
317 struct libusb_device_descriptor device_desc;
319 libusb_get_device_descriptor(device->libusb_device, &device_desc);
321 buffer += sprintfW(buffer, prot_format, device_desc.bDeviceClass, device_desc.bDeviceSubClass,
322 device_desc.bDeviceProtocol) + 1;
323 buffer += sprintfW(buffer, subclass_format, device_desc.bDeviceClass, device_desc.bDeviceSubClass) + 1;
324 buffer += sprintfW(buffer, class_format, device_desc.bDeviceClass) + 1;
325 *buffer = 0;
328 static NTSTATUS query_id(const struct usb_device *device, IRP *irp, BUS_QUERY_ID_TYPE type)
330 WCHAR *id = NULL;
332 switch (type)
334 case BusQueryDeviceID:
335 if ((id = ExAllocatePool(PagedPool, 28 * sizeof(WCHAR))))
336 get_device_id(device, id);
337 break;
339 case BusQueryInstanceID:
340 if ((id = ExAllocatePool(PagedPool, 2 * sizeof(WCHAR))))
342 id[0] = '0';
343 id[1] = 0;
345 break;
347 case BusQueryHardwareIDs:
348 if ((id = ExAllocatePool(PagedPool, (28 + 37 + 1) * sizeof(WCHAR))))
349 get_hardware_ids(device, id);
350 break;
352 case BusQueryCompatibleIDs:
353 if ((id = ExAllocatePool(PagedPool, (33 + 25 + 13 + 1) * sizeof(WCHAR))))
354 get_compatible_ids(device, id);
355 break;
357 default:
358 FIXME("Unhandled ID query type %#x.\n", type);
359 return irp->IoStatus.Status;
362 irp->IoStatus.Information = (ULONG_PTR)id;
363 return STATUS_SUCCESS;
366 static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
368 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
369 struct usb_device *device = device_obj->DeviceExtension;
370 NTSTATUS ret = irp->IoStatus.Status;
372 TRACE("device_obj %p, irp %p, minor function %#x.\n", device_obj, irp, stack->MinorFunction);
374 switch (stack->MinorFunction)
376 case IRP_MN_QUERY_ID:
377 ret = query_id(device, irp, stack->Parameters.QueryId.IdType);
378 break;
380 case IRP_MN_START_DEVICE:
381 case IRP_MN_QUERY_CAPABILITIES:
382 case IRP_MN_SURPRISE_REMOVAL:
383 ret = STATUS_SUCCESS;
384 break;
386 case IRP_MN_REMOVE_DEVICE:
388 LIST_ENTRY *entry;
390 EnterCriticalSection(&wineusb_cs);
391 while ((entry = RemoveHeadList(&device->irp_list)) != &device->irp_list)
393 irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
394 irp->IoStatus.Status = STATUS_CANCELLED;
395 irp->IoStatus.Information = 0;
396 IoCompleteRequest(irp, IO_NO_INCREMENT);
398 LeaveCriticalSection(&wineusb_cs);
400 if (device->removed)
402 libusb_unref_device(device->libusb_device);
403 libusb_close(device->handle);
405 irp->IoStatus.Status = STATUS_SUCCESS;
406 IoCompleteRequest(irp, IO_NO_INCREMENT);
407 IoDeleteDevice(device->device_obj);
408 return STATUS_SUCCESS;
411 ret = STATUS_SUCCESS;
412 break;
415 default:
416 FIXME("Unhandled minor function %#x.\n", stack->MinorFunction);
419 irp->IoStatus.Status = ret;
420 IoCompleteRequest(irp, IO_NO_INCREMENT);
421 return ret;
424 static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
426 if (device == bus_fdo)
427 return fdo_pnp(irp);
428 return pdo_pnp(device, irp);
431 static NTSTATUS usbd_status_from_libusb(enum libusb_transfer_status status)
433 switch (status)
435 case LIBUSB_TRANSFER_CANCELLED:
436 return USBD_STATUS_CANCELED;
437 case LIBUSB_TRANSFER_COMPLETED:
438 return USBD_STATUS_SUCCESS;
439 case LIBUSB_TRANSFER_NO_DEVICE:
440 return USBD_STATUS_DEVICE_GONE;
441 case LIBUSB_TRANSFER_STALL:
442 return USBD_STATUS_ENDPOINT_HALTED;
443 case LIBUSB_TRANSFER_TIMED_OUT:
444 return USBD_STATUS_TIMEOUT;
445 default:
446 FIXME("Unhandled status %#x.\n", status);
447 case LIBUSB_TRANSFER_ERROR:
448 return USBD_STATUS_REQUEST_FAILED;
452 static void transfer_cb(struct libusb_transfer *transfer)
454 IRP *irp = transfer->user_data;
455 URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
457 TRACE("Completing IRP %p, status %#x.\n", irp, transfer->status);
459 urb->UrbHeader.Status = usbd_status_from_libusb(transfer->status);
461 if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
463 switch (urb->UrbHeader.Function)
465 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
466 urb->UrbBulkOrInterruptTransfer.TransferBufferLength = transfer->actual_length;
467 break;
469 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
471 struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
472 req->TransferBufferLength = transfer->actual_length;
473 memcpy(req->TransferBuffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
474 break;
477 case URB_FUNCTION_VENDOR_INTERFACE:
479 struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
480 req->TransferBufferLength = transfer->actual_length;
481 if (req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
482 memcpy(req->TransferBuffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
483 break;
486 default:
487 ERR("Unexpected function %#x.\n", urb->UrbHeader.Function);
491 EnterCriticalSection(&wineusb_cs);
492 RemoveEntryList(&irp->Tail.Overlay.ListEntry);
493 LeaveCriticalSection(&wineusb_cs);
495 irp->IoStatus.Status = STATUS_SUCCESS;
496 IoCompleteRequest(irp, IO_NO_INCREMENT);
499 static void queue_irp(struct usb_device *device, IRP *irp, struct libusb_transfer *transfer)
501 IoMarkIrpPending(irp);
502 irp->Tail.Overlay.DriverContext[0] = transfer;
503 EnterCriticalSection(&wineusb_cs);
504 InsertTailList(&device->irp_list, &irp->Tail.Overlay.ListEntry);
505 LeaveCriticalSection(&wineusb_cs);
508 struct pipe
510 unsigned char endpoint;
511 unsigned char type;
514 static HANDLE make_pipe_handle(unsigned char endpoint, USBD_PIPE_TYPE type)
516 union
518 struct pipe pipe;
519 HANDLE handle;
520 } u;
522 u.pipe.endpoint = endpoint;
523 u.pipe.type = type;
524 return u.handle;
527 static struct pipe get_pipe(HANDLE handle)
529 union
531 struct pipe pipe;
532 HANDLE handle;
533 } u;
535 u.handle = handle;
536 return u.pipe;
539 static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp)
541 URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
542 struct libusb_transfer *transfer;
543 int ret;
545 TRACE("type %#x.\n", urb->UrbHeader.Function);
547 switch (urb->UrbHeader.Function)
549 case URB_FUNCTION_ABORT_PIPE:
551 LIST_ENTRY *entry, *mark;
553 /* The documentation states that URB_FUNCTION_ABORT_PIPE may
554 * complete before outstanding requests complete, so we don't need
555 * to wait for them. */
556 EnterCriticalSection(&wineusb_cs);
557 mark = &device->irp_list;
558 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
560 IRP *queued_irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
562 if ((ret = libusb_cancel_transfer(queued_irp->Tail.Overlay.DriverContext[0])) < 0)
563 ERR("Failed to cancel transfer: %s\n", libusb_strerror(ret));
565 LeaveCriticalSection(&wineusb_cs);
567 return STATUS_SUCCESS;
570 case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL:
572 struct _URB_PIPE_REQUEST *req = &urb->UrbPipeRequest;
573 struct pipe pipe = get_pipe(req->PipeHandle);
575 if ((ret = libusb_clear_halt(device->handle, pipe.endpoint)) < 0)
576 ERR("Failed to clear halt: %s\n", libusb_strerror(ret));
578 return STATUS_SUCCESS;
581 case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
583 struct _URB_BULK_OR_INTERRUPT_TRANSFER *req = &urb->UrbBulkOrInterruptTransfer;
584 struct pipe pipe = get_pipe(req->PipeHandle);
586 if (req->TransferBufferMDL)
587 FIXME("Unhandled MDL output buffer.\n");
589 if (!(transfer = libusb_alloc_transfer(0)))
590 return STATUS_NO_MEMORY;
592 if (pipe.type == UsbdPipeTypeBulk)
594 libusb_fill_bulk_transfer(transfer, device->handle, pipe.endpoint,
595 req->TransferBuffer, req->TransferBufferLength, transfer_cb, irp, 0);
597 else if (pipe.type == UsbdPipeTypeInterrupt)
599 libusb_fill_interrupt_transfer(transfer, device->handle, pipe.endpoint,
600 req->TransferBuffer, req->TransferBufferLength, transfer_cb, irp, 0);
602 else
604 WARN("Invalid pipe type %#x.\n", pipe.type);
605 libusb_free_transfer(transfer);
606 return USBD_STATUS_INVALID_PIPE_HANDLE;
609 queue_irp(device, irp, transfer);
610 transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER;
611 ret = libusb_submit_transfer(transfer);
612 if (ret < 0)
613 ERR("Failed to submit bulk transfer: %s\n", libusb_strerror(ret));
615 return STATUS_PENDING;
618 case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
620 struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
621 unsigned char *buffer;
623 if (req->TransferBufferMDL)
624 FIXME("Unhandled MDL output buffer.\n");
626 if (!(transfer = libusb_alloc_transfer(0)))
627 return STATUS_NO_MEMORY;
629 if (!(buffer = malloc(sizeof(struct libusb_control_setup) + req->TransferBufferLength)))
631 libusb_free_transfer(transfer);
632 return STATUS_NO_MEMORY;
635 queue_irp(device, irp, transfer);
636 libusb_fill_control_setup(buffer,
637 LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
638 LIBUSB_REQUEST_GET_DESCRIPTOR, (req->DescriptorType << 8) | req->Index,
639 req->LanguageId, req->TransferBufferLength);
640 libusb_fill_control_transfer(transfer, device->handle, buffer, transfer_cb, irp, 0);
641 transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
642 ret = libusb_submit_transfer(transfer);
643 if (ret < 0)
644 ERR("Failed to submit GET_DESCRIPTOR transfer: %s\n", libusb_strerror(ret));
646 return STATUS_PENDING;
649 case URB_FUNCTION_SELECT_CONFIGURATION:
651 struct _URB_SELECT_CONFIGURATION *req = &urb->UrbSelectConfiguration;
652 ULONG i;
654 /* FIXME: In theory, we'd call libusb_set_configuration() here, but
655 * the CASIO FX-9750GII (which has only one configuration) goes into
656 * an error state if it receives a SET_CONFIGURATION request. Maybe
657 * we should skip setting that if and only if the configuration is
658 * already active? */
660 for (i = 0; i < req->Interface.NumberOfPipes; ++i)
662 USBD_PIPE_INFORMATION *pipe = &req->Interface.Pipes[i];
663 pipe->PipeHandle = make_pipe_handle(pipe->EndpointAddress, pipe->PipeType);
666 return STATUS_SUCCESS;
669 case URB_FUNCTION_VENDOR_INTERFACE:
671 struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
672 uint8_t req_type = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE;
673 unsigned char *buffer;
675 if (req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
676 req_type |= LIBUSB_ENDPOINT_IN;
677 if (req->TransferFlags & ~USBD_TRANSFER_DIRECTION_IN)
678 FIXME("Unhandled flags %#x.\n", req->TransferFlags);
680 if (req->TransferBufferMDL)
681 FIXME("Unhandled MDL output buffer.\n");
683 if (!(transfer = libusb_alloc_transfer(0)))
684 return STATUS_NO_MEMORY;
686 if (!(buffer = malloc(sizeof(struct libusb_control_setup) + req->TransferBufferLength)))
688 libusb_free_transfer(transfer);
689 return STATUS_NO_MEMORY;
692 queue_irp(device, irp, transfer);
693 libusb_fill_control_setup(buffer, req_type, req->Request,
694 req->Value, req->Index, req->TransferBufferLength);
695 if (!(req->TransferFlags & USBD_TRANSFER_DIRECTION_IN))
696 memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, req->TransferBuffer, req->TransferBufferLength);
697 libusb_fill_control_transfer(transfer, device->handle, buffer, transfer_cb, irp, 0);
698 transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
699 ret = libusb_submit_transfer(transfer);
700 if (ret < 0)
701 ERR("Failed to submit vendor-specific interface transfer: %s\n", libusb_strerror(ret));
703 return STATUS_PENDING;
706 default:
707 FIXME("Unhandled function %#x.\n", urb->UrbHeader.Function);
710 return STATUS_NOT_IMPLEMENTED;
713 static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device_obj, IRP *irp)
715 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
716 ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
717 struct usb_device *device = device_obj->DeviceExtension;
718 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
720 TRACE("device_obj %p, irp %p, code %#x.\n", device_obj, irp, code);
722 switch (code)
724 case IOCTL_INTERNAL_USB_SUBMIT_URB:
725 status = usb_submit_urb(device, irp);
726 break;
728 default:
729 FIXME("Unhandled ioctl %#x (device %#x, access %#x, function %#x, method %#x).\n",
730 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
733 if (status != STATUS_PENDING)
735 irp->IoStatus.Status = status;
736 IoCompleteRequest(irp, IO_NO_INCREMENT);
738 return status;
741 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
743 NTSTATUS ret;
745 TRACE("driver %p, pdo %p.\n", driver, pdo);
747 if ((ret = IoCreateDevice(driver, 0, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &bus_fdo)))
749 ERR("Failed to create FDO, status %#x.\n", ret);
750 return ret;
753 IoAttachDeviceToDeviceStack(bus_fdo, pdo);
754 bus_pdo = pdo;
755 bus_fdo->Flags &= ~DO_DEVICE_INITIALIZING;
757 return STATUS_SUCCESS;
760 static void WINAPI driver_unload(DRIVER_OBJECT *driver)
762 libusb_exit(NULL);
765 NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
767 int err;
769 TRACE("driver %p, path %s.\n", driver, debugstr_w(path->Buffer));
771 driver_obj = driver;
773 if ((err = libusb_init(NULL)))
775 ERR("Failed to initialize libusb: %s\n", libusb_strerror(err));
776 return STATUS_UNSUCCESSFUL;
779 event_thread = CreateThread(NULL, 0, event_thread_proc, NULL, 0, NULL);
781 driver->DriverExtension->AddDevice = driver_add_device;
782 driver->DriverUnload = driver_unload;
783 driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
784 driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl;
786 return STATUS_SUCCESS;