mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 08:54:05 +00:00
wineusb.sys: Add support for TransferBufferMDL.
Allow drivers such as NaturalPoint's npusbio_x64.sys to communicate with the lower level USB bus driver. Makes NaturalPoint's TrackIR5 head tracking system fully functional in Wine.
This commit is contained in:
parent
47f280cae6
commit
6b816b8969
|
@ -305,14 +305,23 @@ static NTSTATUS usbd_status_from_libusb(enum libusb_transfer_status status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct transfer_ctx
|
||||||
|
{
|
||||||
|
IRP *irp;
|
||||||
|
void *transfer_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
static void LIBUSB_CALL transfer_cb(struct libusb_transfer *transfer)
|
static void LIBUSB_CALL transfer_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
IRP *irp = transfer->user_data;
|
struct transfer_ctx *transfer_ctx = transfer->user_data;
|
||||||
|
IRP *irp = transfer_ctx->irp;
|
||||||
URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
|
URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
|
||||||
|
unsigned char *transfer_buffer = transfer_ctx->transfer_buffer;
|
||||||
struct usb_event event;
|
struct usb_event event;
|
||||||
|
|
||||||
TRACE("Completing IRP %p, status %#x.\n", irp, transfer->status);
|
TRACE("Completing IRP %p, status %#x.\n", irp, transfer->status);
|
||||||
|
|
||||||
|
free(transfer_ctx);
|
||||||
urb->UrbHeader.Status = usbd_status_from_libusb(transfer->status);
|
urb->UrbHeader.Status = usbd_status_from_libusb(transfer->status);
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||||||
|
@ -327,7 +336,7 @@ static void LIBUSB_CALL transfer_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
|
struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
|
||||||
req->TransferBufferLength = transfer->actual_length;
|
req->TransferBufferLength = transfer->actual_length;
|
||||||
memcpy(req->TransferBuffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
|
memcpy(transfer_buffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +345,7 @@ static void LIBUSB_CALL transfer_cb(struct libusb_transfer *transfer)
|
||||||
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
|
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
|
||||||
req->TransferBufferLength = transfer->actual_length;
|
req->TransferBufferLength = transfer->actual_length;
|
||||||
if (req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
|
if (req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
|
||||||
memcpy(req->TransferBuffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
|
memcpy(transfer_buffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,9 +419,12 @@ static NTSTATUS usb_submit_urb(void *args)
|
||||||
{
|
{
|
||||||
struct _URB_BULK_OR_INTERRUPT_TRANSFER *req = &urb->UrbBulkOrInterruptTransfer;
|
struct _URB_BULK_OR_INTERRUPT_TRANSFER *req = &urb->UrbBulkOrInterruptTransfer;
|
||||||
struct pipe pipe = get_pipe(req->PipeHandle);
|
struct pipe pipe = get_pipe(req->PipeHandle);
|
||||||
|
struct transfer_ctx *transfer_ctx;
|
||||||
|
|
||||||
if (req->TransferBufferMDL)
|
if (!(transfer_ctx = calloc(1, sizeof(*transfer_ctx))))
|
||||||
FIXME("Unhandled MDL output buffer.\n");
|
return STATUS_NO_MEMORY;
|
||||||
|
transfer_ctx->irp = irp;
|
||||||
|
transfer_ctx->transfer_buffer = params->transfer_buffer;
|
||||||
|
|
||||||
if (!(transfer = libusb_alloc_transfer(0)))
|
if (!(transfer = libusb_alloc_transfer(0)))
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
|
@ -421,12 +433,12 @@ static NTSTATUS usb_submit_urb(void *args)
|
||||||
if (pipe.type == UsbdPipeTypeBulk)
|
if (pipe.type == UsbdPipeTypeBulk)
|
||||||
{
|
{
|
||||||
libusb_fill_bulk_transfer(transfer, handle, pipe.endpoint,
|
libusb_fill_bulk_transfer(transfer, handle, pipe.endpoint,
|
||||||
req->TransferBuffer, req->TransferBufferLength, transfer_cb, irp, 0);
|
params->transfer_buffer, req->TransferBufferLength, transfer_cb, transfer_ctx, 0);
|
||||||
}
|
}
|
||||||
else if (pipe.type == UsbdPipeTypeInterrupt)
|
else if (pipe.type == UsbdPipeTypeInterrupt)
|
||||||
{
|
{
|
||||||
libusb_fill_interrupt_transfer(transfer, handle, pipe.endpoint,
|
libusb_fill_interrupt_transfer(transfer, handle, pipe.endpoint,
|
||||||
req->TransferBuffer, req->TransferBufferLength, transfer_cb, irp, 0);
|
params->transfer_buffer, req->TransferBufferLength, transfer_cb, transfer_ctx, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -446,10 +458,13 @@ static NTSTATUS usb_submit_urb(void *args)
|
||||||
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
||||||
{
|
{
|
||||||
struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
|
struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
|
||||||
|
struct transfer_ctx *transfer_ctx;
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
|
|
||||||
if (req->TransferBufferMDL)
|
if (!(transfer_ctx = calloc(1, sizeof(*transfer_ctx))))
|
||||||
FIXME("Unhandled MDL output buffer.\n");
|
return STATUS_NO_MEMORY;
|
||||||
|
transfer_ctx->irp = irp;
|
||||||
|
transfer_ctx->transfer_buffer = params->transfer_buffer;
|
||||||
|
|
||||||
if (!(transfer = libusb_alloc_transfer(0)))
|
if (!(transfer = libusb_alloc_transfer(0)))
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
|
@ -465,7 +480,7 @@ static NTSTATUS usb_submit_urb(void *args)
|
||||||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
|
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
|
||||||
LIBUSB_REQUEST_GET_DESCRIPTOR, (req->DescriptorType << 8) | req->Index,
|
LIBUSB_REQUEST_GET_DESCRIPTOR, (req->DescriptorType << 8) | req->Index,
|
||||||
req->LanguageId, req->TransferBufferLength);
|
req->LanguageId, req->TransferBufferLength);
|
||||||
libusb_fill_control_transfer(transfer, handle, buffer, transfer_cb, irp, 0);
|
libusb_fill_control_transfer(transfer, handle, buffer, transfer_cb, transfer_ctx, 0);
|
||||||
transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
|
transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
ret = libusb_submit_transfer(transfer);
|
ret = libusb_submit_transfer(transfer);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -498,16 +513,19 @@ static NTSTATUS usb_submit_urb(void *args)
|
||||||
{
|
{
|
||||||
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
|
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
|
||||||
uint8_t req_type = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE;
|
uint8_t req_type = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_INTERFACE;
|
||||||
|
struct transfer_ctx *transfer_ctx;
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
|
|
||||||
|
if (!(transfer_ctx = calloc(1, sizeof(*transfer_ctx))))
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
transfer_ctx->irp = irp;
|
||||||
|
transfer_ctx->transfer_buffer = params->transfer_buffer;
|
||||||
|
|
||||||
if (req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
|
if (req->TransferFlags & USBD_TRANSFER_DIRECTION_IN)
|
||||||
req_type |= LIBUSB_ENDPOINT_IN;
|
req_type |= LIBUSB_ENDPOINT_IN;
|
||||||
if (req->TransferFlags & ~USBD_TRANSFER_DIRECTION_IN)
|
if (req->TransferFlags & ~USBD_TRANSFER_DIRECTION_IN)
|
||||||
FIXME("Unhandled flags %#x.\n", (int)req->TransferFlags);
|
FIXME("Unhandled flags %#x.\n", (int)req->TransferFlags);
|
||||||
|
|
||||||
if (req->TransferBufferMDL)
|
|
||||||
FIXME("Unhandled MDL output buffer.\n");
|
|
||||||
|
|
||||||
if (!(transfer = libusb_alloc_transfer(0)))
|
if (!(transfer = libusb_alloc_transfer(0)))
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_NO_MEMORY;
|
||||||
irp->Tail.Overlay.DriverContext[0] = transfer;
|
irp->Tail.Overlay.DriverContext[0] = transfer;
|
||||||
|
@ -521,8 +539,8 @@ static NTSTATUS usb_submit_urb(void *args)
|
||||||
libusb_fill_control_setup(buffer, req_type, req->Request,
|
libusb_fill_control_setup(buffer, req_type, req->Request,
|
||||||
req->Value, req->Index, req->TransferBufferLength);
|
req->Value, req->Index, req->TransferBufferLength);
|
||||||
if (!(req->TransferFlags & USBD_TRANSFER_DIRECTION_IN))
|
if (!(req->TransferFlags & USBD_TRANSFER_DIRECTION_IN))
|
||||||
memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, req->TransferBuffer, req->TransferBufferLength);
|
memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, params->transfer_buffer, req->TransferBufferLength);
|
||||||
libusb_fill_control_transfer(transfer, handle, buffer, transfer_cb, irp, 0);
|
libusb_fill_control_transfer(transfer, handle, buffer, transfer_cb, transfer_ctx, 0);
|
||||||
transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
|
transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
ret = libusb_submit_transfer(transfer);
|
ret = libusb_submit_transfer(transfer);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -61,6 +61,7 @@ struct usb_submit_urb_params
|
||||||
{
|
{
|
||||||
struct unix_device *device;
|
struct unix_device *device;
|
||||||
IRP *irp;
|
IRP *irp;
|
||||||
|
void *transfer_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct usb_cancel_transfer_params
|
struct usb_cancel_transfer_params
|
||||||
|
|
|
@ -542,6 +542,39 @@ static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp)
|
||||||
.irp = irp,
|
.irp = irp,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
switch (urb->UrbHeader.Function)
|
||||||
|
{
|
||||||
|
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
|
||||||
|
{
|
||||||
|
struct _URB_BULK_OR_INTERRUPT_TRANSFER *req = &urb->UrbBulkOrInterruptTransfer;
|
||||||
|
if (req->TransferBufferMDL)
|
||||||
|
params.transfer_buffer = MmGetSystemAddressForMdlSafe(req->TransferBufferMDL, NormalPagePriority);
|
||||||
|
else
|
||||||
|
params.transfer_buffer = req->TransferBuffer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
||||||
|
{
|
||||||
|
struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
|
||||||
|
if (req->TransferBufferMDL)
|
||||||
|
params.transfer_buffer = MmGetSystemAddressForMdlSafe(req->TransferBufferMDL, NormalPagePriority);
|
||||||
|
else
|
||||||
|
params.transfer_buffer = req->TransferBuffer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case URB_FUNCTION_VENDOR_INTERFACE:
|
||||||
|
{
|
||||||
|
struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *req = &urb->UrbControlVendorClassRequest;
|
||||||
|
if (req->TransferBufferMDL)
|
||||||
|
params.transfer_buffer = MmGetSystemAddressForMdlSafe(req->TransferBufferMDL, NormalPagePriority);
|
||||||
|
else
|
||||||
|
params.transfer_buffer = req->TransferBuffer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Hold the wineusb lock while submitting and queuing, and
|
/* Hold the wineusb lock while submitting and queuing, and
|
||||||
* similarly hold it in complete_irp(). That way, if libusb reports
|
* similarly hold it in complete_irp(). That way, if libusb reports
|
||||||
* completion between submitting and queuing, we won't try to
|
* completion between submitting and queuing, we won't try to
|
||||||
|
|
Loading…
Reference in a new issue