Commit 6b816b89 authored by Ivo Ivanov's avatar Ivo Ivanov Committed by Alexandre Julliard

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.
parent 47f280ca
...@@ -305,14 +305,23 @@ static NTSTATUS usbd_status_from_libusb(enum libusb_transfer_status status) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment