[PATCH 1/6] wineusb.sys: Implement URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE.

Zebediah Figura z.figura12 at gmail.com
Fri Apr 17 18:03:04 CDT 2020


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/wineusb.sys/wineusb.c | 147 +++++++++++++++++++++++++++++++++++++
 1 file changed, 147 insertions(+)

diff --git a/dlls/wineusb.sys/wineusb.c b/dlls/wineusb.sys/wineusb.c
index eb1b7a261f..ed82bd3a13 100644
--- a/dlls/wineusb.sys/wineusb.c
+++ b/dlls/wineusb.sys/wineusb.c
@@ -74,6 +74,8 @@ struct usb_device
 
     libusb_device *libusb_device;
     libusb_device_handle *handle;
+
+    LIST_ENTRY irp_list;
 };
 
 static DRIVER_OBJECT *driver_obj;
@@ -120,6 +122,7 @@ static void add_usb_device(libusb_device *libusb_device)
     device->device_obj = device_obj;
     device->libusb_device = libusb_ref_device(libusb_device);
     device->handle = handle;
+    InitializeListHead(&device->irp_list);
 
     EnterCriticalSection(&wineusb_cs);
     list_add_tail(&device_list, &device->entry);
@@ -394,6 +397,149 @@ static NTSTATUS WINAPI driver_pnp(DEVICE_OBJECT *device, IRP *irp)
     return pdo_pnp(device, irp);
 }
 
+static NTSTATUS usbd_status_from_libusb(enum libusb_transfer_status status)
+{
+    switch (status)
+    {
+        case LIBUSB_TRANSFER_CANCELLED:
+            return USBD_STATUS_CANCELED;
+        case LIBUSB_TRANSFER_COMPLETED:
+            return USBD_STATUS_SUCCESS;
+        case LIBUSB_TRANSFER_NO_DEVICE:
+            return USBD_STATUS_DEVICE_GONE;
+        case LIBUSB_TRANSFER_STALL:
+            return USBD_STATUS_ENDPOINT_HALTED;
+        case LIBUSB_TRANSFER_TIMED_OUT:
+            return USBD_STATUS_TIMEOUT;
+        default:
+            FIXME("Unhandled status %#x.\n", status);
+        case LIBUSB_TRANSFER_ERROR:
+            return USBD_STATUS_REQUEST_FAILED;
+    }
+}
+
+static void transfer_cb(struct libusb_transfer *transfer)
+{
+    IRP *irp = transfer->user_data;
+    URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
+
+    TRACE("Completing IRP %p, status %#x.\n", irp, transfer->status);
+
+    urb->UrbHeader.Status = usbd_status_from_libusb(transfer->status);
+
+    if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
+    {
+        switch (urb->UrbHeader.Function)
+        {
+            case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+            {
+                struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
+                req->TransferBufferLength = transfer->actual_length;
+                memcpy(req->TransferBuffer, libusb_control_transfer_get_data(transfer), transfer->actual_length);
+                break;
+            }
+
+            default:
+                ERR("Unexpected function %#x.\n", urb->UrbHeader.Function);
+        }
+    }
+
+    EnterCriticalSection(&wineusb_cs);
+    RemoveEntryList(&irp->Tail.Overlay.ListEntry);
+    LeaveCriticalSection(&wineusb_cs);
+
+    irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(irp, IO_NO_INCREMENT);
+}
+
+static void queue_irp(struct usb_device *device, IRP *irp, struct libusb_transfer *transfer)
+{
+    EnterCriticalSection(&wineusb_cs);
+    irp->Tail.Overlay.DriverContext[0] = transfer;
+    InsertTailList(&device->irp_list, &irp->Tail.Overlay.ListEntry);
+    LeaveCriticalSection(&wineusb_cs);
+}
+
+static NTSTATUS usb_submit_urb(struct usb_device *device, IRP *irp)
+{
+    URB *urb = IoGetCurrentIrpStackLocation(irp)->Parameters.Others.Argument1;
+    struct libusb_transfer *transfer;
+    int ret;
+
+    TRACE("type %#x.\n", urb->UrbHeader.Function);
+
+    switch (urb->UrbHeader.Function)
+    {
+        case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+        {
+            struct _URB_CONTROL_DESCRIPTOR_REQUEST *req = &urb->UrbControlDescriptorRequest;
+            unsigned char *buffer;
+
+            if (req->TransferBufferMDL)
+                FIXME("Unhandled MDL output buffer.\n");
+
+            if (!(transfer = libusb_alloc_transfer(0)))
+                return STATUS_NO_MEMORY;
+
+            if (!(buffer = malloc(sizeof(struct libusb_control_setup) + req->TransferBufferLength)))
+            {
+                libusb_free_transfer(transfer);
+                return STATUS_NO_MEMORY;
+            }
+
+            queue_irp(device, irp, transfer);
+            libusb_fill_control_setup(buffer,
+                    LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
+                    LIBUSB_REQUEST_GET_DESCRIPTOR, (req->DescriptorType << 8) | req->Index,
+                    req->LanguageId, req->TransferBufferLength);
+            libusb_fill_control_transfer(transfer, device->handle, buffer, transfer_cb, irp, 0);
+            transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
+            ret = libusb_submit_transfer(transfer);
+            if (ret < 0)
+                ERR("Failed to submit GET_DESRIPTOR transfer: %s\n", libusb_strerror(ret));
+
+            return STATUS_PENDING;
+        }
+
+        default:
+            FIXME("Unhandled function %#x.\n", urb->UrbHeader.Function);
+    }
+
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device_obj, IRP *irp)
+{
+    IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
+    ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
+    struct usb_device *device = device_obj->DeviceExtension;
+    NTSTATUS status = STATUS_NOT_IMPLEMENTED;
+
+    TRACE("device_obj %p, irp %p, code %#x.\n", device_obj, irp, code);
+
+    switch (code)
+    {
+        case IOCTL_INTERNAL_USB_SUBMIT_URB:
+            status = usb_submit_urb(device, irp);
+            break;
+
+        default:
+            FIXME("Unhandled ioctl %#x (device %#x, access %#x, function %#x, method %#x).\n",
+                    code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
+    }
+
+    if (status == STATUS_PENDING)
+    {
+        IoMarkIrpPending(irp);
+    }
+    else
+    {
+        irp->IoStatus.Status = status;
+        IoCompleteRequest(irp, IO_NO_INCREMENT);
+    }
+    return status;
+}
+
 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
 {
     NTSTATUS ret;
@@ -437,6 +583,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, UNICODE_STRING *path)
     driver->DriverExtension->AddDevice = driver_add_device;
     driver->DriverUnload = driver_unload;
     driver->MajorFunction[IRP_MJ_PNP] = driver_pnp;
+    driver->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = driver_internal_ioctl;
 
     return STATUS_SUCCESS;
 }
-- 
2.26.0




More information about the wine-devel mailing list