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
27 #define WIN32_NO_STATUS
33 #include "ddk/usbioctl.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,
47 "xchgl (%esp),%ecx\n\t"
50 #define call_fastcall_func1(func,a) wrap_fastcall_func1(func,a)
54 #define call_fastcall_func1(func,a) func(a)
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
);
74 DEVICE_OBJECT
*device_obj
;
76 libusb_device
*libusb_device
;
77 libusb_device_handle
*handle
;
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
;
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
));
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
);
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
;
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
);
166 remove_usb_device(device
);
171 static DWORD CALLBACK
event_thread_proc(void *arg
)
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");
187 static NTSTATUS
fdo_pnp(IRP
*irp
)
189 IO_STACK_LOCATION
*stack
= IoGetCurrentIrpStackLocation(irp
);
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
;
202 if (stack
->Parameters
.QueryDeviceRelations
.Type
!= BusRelations
)
204 FIXME("Unhandled device relations type %#x.\n", stack
->Parameters
.QueryDeviceRelations
.Type
);
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
;
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
);
227 irp
->IoStatus
.Information
= (ULONG_PTR
)devices
;
228 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
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
;
242 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
245 case IRP_MN_SURPRISE_REMOVAL
:
246 irp
->IoStatus
.Status
= STATUS_SUCCESS
;
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
);
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;
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;
328 static NTSTATUS
query_id(const struct usb_device
*device
, IRP
*irp
, BUS_QUERY_ID_TYPE type
)
334 case BusQueryDeviceID
:
335 if ((id
= ExAllocatePool(PagedPool
, 28 * sizeof(WCHAR
))))
336 get_device_id(device
, id
);
339 case BusQueryInstanceID
:
340 if ((id
= ExAllocatePool(PagedPool
, 2 * sizeof(WCHAR
))))
347 case BusQueryHardwareIDs
:
348 if ((id
= ExAllocatePool(PagedPool
, (28 + 37 + 1) * sizeof(WCHAR
))))
349 get_hardware_ids(device
, id
);
352 case BusQueryCompatibleIDs
:
353 if ((id
= ExAllocatePool(PagedPool
, (33 + 25 + 13 + 1) * sizeof(WCHAR
))))
354 get_compatible_ids(device
, id
);
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
);
380 case IRP_MN_START_DEVICE
:
381 case IRP_MN_QUERY_CAPABILITIES
:
382 case IRP_MN_SURPRISE_REMOVAL
:
383 ret
= STATUS_SUCCESS
;
386 case IRP_MN_REMOVE_DEVICE
:
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
);
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
;
416 FIXME("Unhandled minor function %#x.\n", stack
->MinorFunction
);
419 irp
->IoStatus
.Status
= ret
;
420 IoCompleteRequest(irp
, IO_NO_INCREMENT
);
424 static NTSTATUS WINAPI
driver_pnp(DEVICE_OBJECT
*device
, IRP
*irp
)
426 if (device
== bus_fdo
)
428 return pdo_pnp(device
, irp
);
431 static NTSTATUS
usbd_status_from_libusb(enum libusb_transfer_status 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
;
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
;
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
);
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
);
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
);
510 unsigned char endpoint
;
514 static HANDLE
make_pipe_handle(unsigned char endpoint
, USBD_PIPE_TYPE type
)
522 u
.pipe
.endpoint
= endpoint
;
527 static struct pipe
get_pipe(HANDLE handle
)
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
;
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);
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
);
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
);
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
;
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
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
);
701 ERR("Failed to submit vendor-specific interface transfer: %s\n", libusb_strerror(ret
));
703 return STATUS_PENDING
;
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
);
724 case IOCTL_INTERNAL_USB_SUBMIT_URB
:
725 status
= usb_submit_urb(device
, irp
);
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
);
741 static NTSTATUS WINAPI
driver_add_device(DRIVER_OBJECT
*driver
, DEVICE_OBJECT
*pdo
)
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
);
753 IoAttachDeviceToDeviceStack(bus_fdo
, pdo
);
755 bus_fdo
->Flags
&= ~DO_DEVICE_INITIALIZING
;
757 return STATUS_SUCCESS
;
760 static void WINAPI
driver_unload(DRIVER_OBJECT
*driver
)
765 NTSTATUS WINAPI
DriverEntry(DRIVER_OBJECT
*driver
, UNICODE_STRING
*path
)
769 TRACE("driver %p, path %s.\n", driver
, debugstr_w(path
->Buffer
));
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
;