Skip to content

Commit

Permalink
add_device: open new interface presented in newer windows versions
Browse files Browse the repository at this point in the history
add_device: use new interface to get device speed
transfer: use the device speed to set max transfer size according to MS rules
  • Loading branch information
dontech committed Feb 9, 2024
1 parent 358ef37 commit 65f9a19
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 37 deletions.
130 changes: 93 additions & 37 deletions libusb/src/driver/libusb_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,10 +386,53 @@ NTSTATUS DDKAPI add_device(DRIVER_OBJECT *driver_object,
return STATUS_NO_SUCH_DEVICE;
}

if (dev->is_filter)
status = USBD_CreateHandle(device_object,
dev->next_stack_device,
USBD_CLIENT_CONTRACT_VERSION_602,
POOL_TAG,
&dev->handle);
if (!NT_SUCCESS(status))
{
USBDBG("[filter-mode] id=#%d %s\n",dev->id, dev->device_id);
USBERR("failed to create USBD handle\n");
IoDeleteSymbolicLink(&symbolic_link_name);
IoDeleteDevice(device_object);
remove_lock_release(dev); // always release acquired locks
return status;
}

/* Detect super speed */
status = USBD_QueryUsbCapability(dev->handle,
(GUID*)&GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE,
0, NULL, NULL);
if(NT_SUCCESS(status))
{
dev->speed = SuperSpeed;
}
else
{
/* Detect high speed */
status = USBD_QueryUsbCapability(dev->handle,
(GUID*)&GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE,
0, NULL, NULL);
if(NT_SUCCESS(status))
{
dev->speed = HighSpeed;
}
else
{
/* Default to full speed. At this point we really do not know if it is
* really full speed or low speed
* Todo: detect low speed
*/
dev->speed = FullSpeed;
status = STATUS_SUCCESS;
}
}

USBDBG("[%s] id=#%d %s, speed=%d\n", dev->is_filter ? "filter_mode" : "normal-mode", dev->id, dev->device_id, dev->speed);

if (dev->is_filter)
{
/* send all USB requests to the PDO in filter driver mode */
dev->target_device = dev->physical_device_object;

Expand All @@ -405,8 +448,6 @@ NTSTATUS DDKAPI add_device(DRIVER_OBJECT *driver_object,
}
else
{
USBDBG("[normal-mode] id=#%d %s\n",dev->id, dev->device_id);

/* send all USB requests to the lower object in device driver mode */
dev->target_device = dev->next_stack_device;
device_object->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
Expand Down Expand Up @@ -690,47 +731,62 @@ bool_t update_pipe_info(libusb_device_t *dev,
maxPacketSize = interface_info->Pipes[i].MaximumPacketSize;
maxTransferSize = interface_info->Pipes[i].MaximumTransferSize;

USBMSG("EP%02Xh maximum-packet-size=%d maximum-transfer-size=%d\n",
interface_info->Pipes[i].EndpointAddress,
maxPacketSize,
maxTransferSize);

dev->config.interfaces[number].endpoints[i].handle = interface_info->Pipes[i].PipeHandle;
dev->config.interfaces[number].endpoints[i].address = interface_info->Pipes[i].EndpointAddress;
dev->config.interfaces[number].endpoints[i].maximum_packet_size = maxPacketSize;
dev->config.interfaces[number].endpoints[i].interval = interface_info->Pipes[i].Interval;
dev->config.interfaces[number].endpoints[i].pipe_type = interface_info->Pipes[i].PipeType;
dev->config.interfaces[number].endpoints[i].pipe_flags = interface_info->Pipes[i].PipeFlags;

if (maxPacketSize)
{
// set max the maximum transfer size default to an interval of max packet size.
maxTransferSize = maxTransferSize - (maxTransferSize % maxPacketSize);
if (maxTransferSize < maxPacketSize)
{
maxTransferSize = LIBUSB_MAX_READ_WRITE;
}
else if (maxTransferSize > LIBUSB_MAX_READ_WRITE)
{
maxTransferSize = LIBUSB_MAX_READ_WRITE - (LIBUSB_MAX_READ_WRITE % maxPacketSize);
}
/* These are Windows new rules for max transfer sizes
* Currently we take the speed into account but not the controller type
*
* https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-bandwidth-allocation
*
*/
switch (interface_info->Pipes[i].PipeType)
{
case UsbdPipeTypeControl:
switch(dev->speed)
{
case SuperSpeed:
maxTransferSize = 64 * 1024;
break;
default:
maxTransferSize = 4 * 1024;
break;
}
break;

case UsbdPipeTypeInterrupt:
maxTransferSize = 4 * 1024 * 1024;
break;

case UsbdPipeTypeBulk:
switch (dev->speed)
{
case SuperSpeed:
maxTransferSize = 32 * 1024 * 1024;
break;
case HighSpeed:
maxTransferSize = 4 * 1024 * 1024;
break;
default:
maxTransferSize = 256 * 1024;
break;
}
break;
}

if (maxTransferSize != interface_info->Pipes[i].MaximumTransferSize)
{
USBWRN("overriding EP%02Xh maximum-transfer-size=%d\n",
dev->config.interfaces[number].endpoints[i].address,
maxTransferSize);
}
}
else
{
if (!maxTransferSize)
{
// use the libusb-win32 default
maxTransferSize = LIBUSB_MAX_READ_WRITE;
}
}
dev->config.interfaces[number].endpoints[i].maximum_transfer_size = maxTransferSize;
// set max the maximum transfer size default to an interval of max packet size.
maxTransferSize = maxTransferSize - (maxTransferSize % maxPacketSize);

USBMSG("EP%02Xh maximum-packet-size=%d maximum-transfer-size=%d\n",
interface_info->Pipes[i].EndpointAddress,
maxPacketSize,
maxTransferSize);

dev->config.interfaces[number].endpoints[i].maximum_transfer_size = maxTransferSize;
}
}
return TRUE;
Expand Down
3 changes: 3 additions & 0 deletions libusb/src/driver/libusb_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ typedef int bool_t;
#define LowSpeed 0x01
#define FullSpeed 0x02
#define HighSpeed 0x03
#define SuperSpeed 0x04

#endif

Expand Down Expand Up @@ -183,6 +184,7 @@ typedef struct
DEVICE_OBJECT *physical_device_object;
DEVICE_OBJECT *next_stack_device;
DEVICE_OBJECT *target_device;
USBD_HANDLE handle;
libusb_remove_lock_t remove_lock;
bool_t is_filter;
bool_t is_started;
Expand All @@ -209,6 +211,7 @@ typedef struct
UNICODE_STRING device_interface_name;
int control_read_timeout;
int control_write_timeout;
int speed;
} libusb_device_t, DEVICE_EXTENSION, *PDEVICE_EXTENSION;


Expand Down
3 changes: 3 additions & 0 deletions libusb/src/driver/pnp.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp)
/* wait until all outstanding requests are finished */
remove_lock_release_and_wait(dev);

/* Close handle to USBD */
USBD_CloseHandle(dev->handle);

status = pass_irp_down(dev, irp, NULL, NULL);

USBMSG("deleting device #%d %s\n", dev->id, dev->device_id);
Expand Down

0 comments on commit 65f9a19

Please sign in to comment.