[USBSTOR_NEW] Create usbstor_new based on usbstor in order to contain Vadim Galyant...
authorAmine Khaldi <amine.khaldi@reactos.org>
Sun, 21 Jan 2018 12:51:07 +0000 (13:51 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sun, 21 Jan 2018 12:51:07 +0000 (13:51 +0100)
14 files changed:
drivers/usb/CMakeLists.txt
drivers/usb/usbstor_new/CMakeLists.txt [new file with mode: 0644]
drivers/usb/usbstor_new/descriptor.c [new file with mode: 0644]
drivers/usb/usbstor_new/disk.c [new file with mode: 0644]
drivers/usb/usbstor_new/error.c [new file with mode: 0644]
drivers/usb/usbstor_new/fdo.c [new file with mode: 0644]
drivers/usb/usbstor_new/guid.c [new file with mode: 0644]
drivers/usb/usbstor_new/misc.c [new file with mode: 0644]
drivers/usb/usbstor_new/pdo.c [new file with mode: 0644]
drivers/usb/usbstor_new/queue.c [new file with mode: 0644]
drivers/usb/usbstor_new/scsi.c [new file with mode: 0644]
drivers/usb/usbstor_new/usbstor.c [new file with mode: 0644]
drivers/usb/usbstor_new/usbstor.h [new file with mode: 0644]
drivers/usb/usbstor_new/usbstor.rc [new file with mode: 0644]

index 05817b0..17fc45d 100644 (file)
@@ -6,5 +6,6 @@ add_subdirectory(usbhub)
 add_subdirectory(usbohci)
 #add_subdirectory(usbohci_new)
 add_subdirectory(usbport)
+#add_subdirectory(usbport_new)
 add_subdirectory(usbstor)
 add_subdirectory(usbuhci)
diff --git a/drivers/usb/usbstor_new/CMakeLists.txt b/drivers/usb/usbstor_new/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3bb2eed
--- /dev/null
@@ -0,0 +1,25 @@
+
+add_definitions(-DDEBUG_MODE)
+include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
+
+list(APPEND SOURCE
+    descriptor.c
+    disk.c
+    fdo.c
+    misc.c
+    pdo.c
+    queue.c
+    error.c
+    scsi.c
+    usbstor.c
+    usbstor.h)
+
+add_library(usbstor SHARED
+    ${SOURCE}
+    guid.c
+    usbstor.rc)
+
+set_module_type(usbstor kernelmodedriver)
+add_importlibs(usbstor ntoskrnl hal usbd)
+add_pch(usbstor usbstor.h SOURCE)
+add_cd_file(TARGET usbstor DESTINATION reactos/system32/drivers NO_CAB FOR all)
diff --git a/drivers/usb/usbstor_new/descriptor.c b/drivers/usb/usbstor_new/descriptor.c
new file mode 100644 (file)
index 0000000..3df36a6
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/descriptor.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+NTAPI
+USBSTOR_GetDescriptor(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR DescriptorType,
+    IN ULONG DescriptorLength,
+    IN UCHAR DescriptorIndex,
+    IN LANGID LanguageId,
+    OUT PVOID *OutDescriptor)
+{
+    PURB Urb;
+    NTSTATUS Status;
+    PVOID Descriptor;
+
+    //
+    // sanity checks
+    //
+    ASSERT(DeviceObject);
+    ASSERT(OutDescriptor);
+    ASSERT(DescriptorLength);
+
+    //
+    // first allocate descriptor buffer
+    //
+    Descriptor = AllocateItem(NonPagedPool, DescriptorLength);
+    if (!Descriptor)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // allocate urb
+    //
+    Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB));
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        FreeItem(Descriptor);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize urb
+    //
+    UsbBuildGetDescriptorRequest(Urb,
+                                 sizeof(Urb->UrbControlDescriptorRequest),
+                                 DescriptorType,
+                                 DescriptorIndex,
+                                 LanguageId,
+                                 Descriptor,
+                                 NULL,
+                                 DescriptorLength,
+                                 NULL);
+
+    //
+    // submit urb
+    //
+    Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
+
+    //
+    // free urb
+    //
+    FreeItem(Urb);
+
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // store result
+        //
+        *OutDescriptor = Descriptor;
+    }
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+NTSTATUS
+USBSTOR_GetDescriptors(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    NTSTATUS Status;
+    PFDO_DEVICE_EXTENSION DeviceExtension;
+    USHORT DescriptorLength;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+     //
+     // first get device descriptor
+     //
+     Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
+     if (!NT_SUCCESS(Status))
+     {
+         //
+         // failed to get device descriptor
+         //
+         DeviceExtension->DeviceDescriptor = NULL;
+         return Status;
+     }
+
+     //
+     // now get basic configuration descriptor
+     //
+     Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
+     if (!NT_SUCCESS(Status))
+     {
+         //
+         // failed to get configuration descriptor
+         //
+         FreeItem(DeviceExtension->DeviceDescriptor);
+         DeviceExtension->DeviceDescriptor = NULL;
+         return Status;
+     }
+
+     //
+     // backup length
+     //
+     DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;
+
+     //
+     // release basic descriptor
+     //
+     FreeItem(DeviceExtension->ConfigurationDescriptor);
+     DeviceExtension->ConfigurationDescriptor = NULL;
+
+     //
+     // allocate full descriptor
+     //
+     Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
+     if (!NT_SUCCESS(Status))
+     {
+         //
+         // failed to get configuration descriptor
+         //
+         FreeItem(DeviceExtension->DeviceDescriptor);
+         DeviceExtension->DeviceDescriptor = NULL;
+         return Status;
+     }
+
+     //
+     // check if there is a serial number provided
+     //
+     if (DeviceExtension->DeviceDescriptor->iSerialNumber)
+     {
+         //
+         // get serial number
+         //
+         Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber);
+         if (!NT_SUCCESS(Status))
+         {
+             //
+             // failed to get serial number descriptor, free device descriptor
+             //
+             FreeItem(DeviceExtension->DeviceDescriptor);
+             DeviceExtension->DeviceDescriptor = NULL;
+
+             //
+             // free configuration descriptor
+             //
+             FreeItem(DeviceExtension->ConfigurationDescriptor);
+             DeviceExtension->ConfigurationDescriptor = NULL;
+
+             //
+             // set serial number to zero
+             //
+             DeviceExtension->SerialNumber = NULL;
+             return Status;
+          }
+     }
+
+     return Status;
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_ScanConfigurationDescriptor(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+    OUT PUSB_INTERFACE_DESCRIPTOR * OutInterfaceDescriptor,
+    OUT PUSB_ENDPOINT_DESCRIPTOR  * InEndpointDescriptor,
+    OUT PUSB_ENDPOINT_DESCRIPTOR  * OutEndpointDescriptor)
+{
+    PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor;
+    PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+
+    //
+    // sanity checks
+    //
+    ASSERT(ConfigurationDescriptor);
+    ASSERT(OutInterfaceDescriptor);
+    ASSERT(InEndpointDescriptor);
+    ASSERT(OutEndpointDescriptor);
+
+    //
+    // nullify pointers
+    //
+    *OutInterfaceDescriptor = NULL;
+    *InEndpointDescriptor = NULL;
+    *OutEndpointDescriptor = NULL;
+
+    //
+    // start scanning
+    //
+    CurrentDescriptor = ConfigurationDescriptor;
+
+    do
+    {
+        //
+        // check current descriptor type
+        //
+        if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
+        {
+            //
+            // found interface descriptor
+            //
+            if (*OutInterfaceDescriptor)
+            {
+                //
+                // we only process the first interface descriptor as ms does -> see documentation
+                //
+                break;
+            }
+
+            //
+            // store interface descriptor
+            //
+            *OutInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)CurrentDescriptor;
+        }
+        else if (CurrentDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
+        {
+            //
+            // convert to endpoint descriptor
+            //
+            EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CurrentDescriptor;
+
+            //
+            // sanity check
+            //
+            ASSERT(*OutInterfaceDescriptor);
+
+            //
+            // get endpoint type
+            //
+            if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)
+            {
+                 //
+                 // bulk endpoint type
+                 //
+                 if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress))
+                 {
+                     //
+                     // bulk in
+                     //
+                     *InEndpointDescriptor = EndpointDescriptor;
+                 }
+                 else
+                 {
+                     //
+                     // bulk out
+                     //
+                     *OutEndpointDescriptor = EndpointDescriptor;
+                 }
+            }
+            else if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT)
+            {
+                 //
+                 // interrupt endpoint type
+                 //
+                 UNIMPLEMENTED;
+            }
+        }
+
+        //
+        // move to next descriptor
+        //
+        CurrentDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)CurrentDescriptor + CurrentDescriptor->bLength);
+
+        //
+        // was it the last descriptor
+        //
+        if ((ULONG_PTR)CurrentDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
+        {
+            //
+            // reached last descriptor
+            //
+            break;
+        }
+
+    }while(TRUE);
+
+    //
+    // check if everything has been found
+    //
+    if (*OutInterfaceDescriptor == NULL || *InEndpointDescriptor == NULL || *OutEndpointDescriptor == NULL)
+    {
+        //
+        // failed to find interface / endpoint descriptor
+        //
+        DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor, *InEndpointDescriptor, *OutEndpointDescriptor);
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    //
+    // completed successfully
+    //
+    return STATUS_SUCCESS;
+}
+
+VOID
+DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
+{
+    DPRINT1("Dumping ConfigurationDescriptor %p\n", ConfigurationDescriptor);
+    DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
+    DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
+    DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
+    DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
+    DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
+    DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
+    DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
+    DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
+}
+
+NTSTATUS
+USBSTOR_SelectConfigurationAndInterface(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension)
+{
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+    PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor, OutEndpointDescriptor;
+    NTSTATUS Status;
+    PURB Urb;
+    PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
+
+    //
+    // now scan configuration descriptors
+    //
+    Status = USBSTOR_ScanConfigurationDescriptor(DeviceExtension->ConfigurationDescriptor, &InterfaceDescriptor, &InEndpointDescriptor, &OutEndpointDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to scan
+        //
+        return Status;
+    }
+
+    //
+    // now allocate one interface entry and terminating null entry
+    //
+    InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)AllocateItem(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * 2);
+    if (!InterfaceList)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize interface list entry
+    //
+    InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor;
+
+    //
+    // now allocate the urb
+    //
+    Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, InterfaceList);
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        FreeItem(InterfaceList);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // sanity check
+    //
+    ASSERT(InterfaceList[0].Interface);
+
+    //
+    // submit urb
+    //
+    Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to set configuration
+        //
+        DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status);
+        FreeItem(InterfaceList);
+        ExFreePoolWithTag(Urb, 0);
+        return Status;
+    }
+
+    //
+    // backup interface information
+    //
+    DeviceExtension->InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)AllocateItem(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
+    if (!DeviceExtension->InterfaceInformation)
+    {
+        //
+        // failed to allocate interface information structure
+        //
+        FreeItem(InterfaceList);
+        ExFreePoolWithTag(Urb, 0);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // copy interface information
+    //
+    RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
+
+    //
+    // store pipe handle
+    //
+    DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
+
+    //
+    // now prepare interface urb
+    //
+    UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
+
+    //
+    // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ
+    //
+    RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInformation, DeviceExtension->InterfaceInformation->Length);
+
+    //
+    // now select the interface
+    //
+    Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
+
+    //
+    // did it succeed
+    //
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // update configuration info
+        //
+        ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInformation->Length);
+        RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
+    }
+
+    //
+    // free interface list & urb
+    //
+    FreeItem(InterfaceList);
+    ExFreePoolWithTag(Urb, 0);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+USBSTOR_GetPipeHandles(
+    IN PFDO_DEVICE_EXTENSION DeviceExtension)
+{
+    ULONG Index;
+    BOOLEAN BulkInFound = FALSE, BulkOutFound = FALSE;
+
+    //
+    // no enumerate all pipes and extract bulk-in / bulk-out pipe handle
+    //
+    for(Index = 0; Index < DeviceExtension->InterfaceInformation->NumberOfPipes; Index++)
+    {
+        //
+        // check pipe type
+        //
+        if (DeviceExtension->InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeBulk)
+        {
+            //
+            // check direction
+            //
+            if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension->InterfaceInformation->Pipes[Index].EndpointAddress))
+            {
+                //
+                // bulk in pipe
+                //
+                DeviceExtension->BulkInPipeIndex = Index;
+
+                //
+                // there should not be another bulk in pipe
+                //
+                ASSERT(BulkInFound == FALSE);
+                BulkInFound = TRUE;
+            }
+            else
+            {
+                //
+                // bulk out pipe
+                //
+                DeviceExtension->BulkOutPipeIndex = Index;
+
+                //
+                // there should not be another bulk out pipe
+                //
+                ASSERT(BulkOutFound == FALSE);
+                BulkOutFound = TRUE;
+            }
+        }
+    }
+
+    //
+    // check if both bulk pipes have been found
+    //
+    if (!BulkInFound || !BulkOutFound)
+    {
+        //
+        // WTF? usb port driver does not give us bulk pipe access
+        //
+        DPRINT1("USBSTOR_GetPipeHandles> BulkInFound %c BulkOutFound %c missing!!!\n", BulkInFound, BulkOutFound);
+        return STATUS_DEVICE_CONFIGURATION_ERROR;
+    }
+
+    //
+    // device is configured
+    //
+    return STATUS_SUCCESS;
+}
diff --git a/drivers/usb/usbstor_new/disk.c b/drivers/usb/usbstor_new/disk.c
new file mode 100644 (file)
index 0000000..604f621
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/disk.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+USBSTOR_HandleInternalDeviceControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    NTSTATUS Status;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // sanity check
+    //
+    ASSERT(Request);
+
+    //
+    // get device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+    switch(Request->Function)
+    {
+        case SRB_FUNCTION_EXECUTE_SCSI:
+        {
+            DPRINT("SRB_FUNCTION_EXECUTE_SCSI\n");
+
+            //
+            // check if request is valid
+            //
+            if (Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT))
+            {
+                //
+                // data is transferred with this irp
+                //
+                if ((Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) ||
+                    Request->DataTransferLength == 0 ||
+                    Irp->MdlAddress == NULL)
+                {
+                    //
+                    // invalid parameter
+                    //
+                    Status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+            }
+            else
+            {
+                //
+                // sense buffer request
+                //
+                if (Request->DataTransferLength ||
+                    Request->DataBuffer ||
+                    Irp->MdlAddress)
+                {
+                    //
+                    // invalid parameter
+                    //
+                    Status = STATUS_INVALID_PARAMETER;
+                    break;
+                }
+            }
+
+            //
+            // add the request
+            //
+            if (!USBSTOR_QueueAddIrp(PDODeviceExtension->LowerDeviceObject, Irp))
+            {
+                //
+                // irp was not added to the queue
+                //
+                IoStartPacket(PDODeviceExtension->LowerDeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
+            }
+
+            //
+            // irp pending
+            //
+            return STATUS_PENDING;
+        }
+        case SRB_FUNCTION_RELEASE_DEVICE:
+        {
+            DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n");
+            //
+            // sanity check
+            //
+            ASSERT(PDODeviceExtension->Claimed == TRUE);
+
+            //
+            // release claim
+            //
+            PDODeviceExtension->Claimed = FALSE;
+            Status = STATUS_SUCCESS;
+            break;
+        }
+        case SRB_FUNCTION_CLAIM_DEVICE:
+        {
+            DPRINT1("SRB_FUNCTION_CLAIM_DEVICE\n");
+            //
+            // check if the device has been claimed
+            //
+            if (PDODeviceExtension->Claimed)
+            {
+                //
+                // device has already been claimed
+                //
+                Status = STATUS_DEVICE_BUSY;
+                Request->SrbStatus = SRB_STATUS_BUSY;
+                break;
+            }
+
+            //
+            // claim device
+            //
+            PDODeviceExtension->Claimed = TRUE;
+
+            //
+            // output device object
+            //
+            Request->DataBuffer = DeviceObject;
+
+            //
+            // completed successfully
+            //
+            Status = STATUS_SUCCESS;
+            break;
+        }
+        case SRB_FUNCTION_RELEASE_QUEUE:
+        {
+            DPRINT1("SRB_FUNCTION_RELEASE_QUEUE\n");
+
+            //
+            // release queue
+            //
+            USBSTOR_QueueRelease(PDODeviceExtension->LowerDeviceObject);
+
+            //
+            // set status success
+            //
+            Request->SrbStatus = SRB_STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
+            break;
+        }
+
+        case SRB_FUNCTION_SHUTDOWN:
+        case SRB_FUNCTION_FLUSH:
+        case SRB_FUNCTION_FLUSH_QUEUE:
+        {
+            DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE / SRB_FUNCTION_SHUTDOWN\n");
+
+            // HACK: don't flush pending requests
+#if 0       // we really need a proper storage stack
+            //
+            // wait for pending requests to finish
+            //
+            USBSTOR_QueueWaitForPendingRequests(PDODeviceExtension->LowerDeviceObject);
+#endif
+            //
+            // set status success
+            //
+            Request->SrbStatus = SRB_STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
+            break;
+        }
+        default:
+        {
+            //
+            // not supported
+            //
+            Status = STATUS_NOT_SUPPORTED;
+            Request->SrbStatus = SRB_STATUS_ERROR;
+        }
+    }
+
+    //
+    // complete request
+    //
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return Status;
+}
+
+ULONG
+USBSTOR_GetFieldLength(
+    IN PUCHAR Name,
+    IN ULONG MaxLength)
+{
+    ULONG Index;
+    ULONG LastCharacterPosition = 0;
+
+    //
+    // scan the field and return last position which contains a valid character
+    //
+    for(Index = 0; Index < MaxLength; Index++)
+    {
+        if (Name[Index] != ' ')
+        {
+            //
+            // trim white spaces from field
+            //
+            LastCharacterPosition = Index;
+        }
+    }
+
+    //
+    // convert from zero based index to length
+    //
+    return LastCharacterPosition + 1;
+}
+
+NTSTATUS
+USBSTOR_HandleQueryProperty(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+    PSTORAGE_PROPERTY_QUERY PropertyQuery;
+    PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader;
+    PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor;
+    ULONG FieldLengthVendor, FieldLengthProduct, FieldLengthRevision, TotalLength, FieldLengthSerialNumber;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PUFI_INQUIRY_RESPONSE InquiryData;
+    PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor;
+    PUCHAR Buffer;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    UNICODE_STRING SerialNumber;
+    ANSI_STRING AnsiString;
+    NTSTATUS Status;
+
+    DPRINT("USBSTOR_HandleQueryProperty\n");
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // sanity check
+    //
+    ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY));
+    ASSERT(Irp->AssociatedIrp.SystemBuffer);
+
+    //
+    // get property query
+    //
+    PropertyQuery = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
+
+    //
+    // check property type
+    //
+    if (PropertyQuery->PropertyId != StorageDeviceProperty &&
+        PropertyQuery->PropertyId != StorageAdapterProperty)
+    {
+        //
+        // only device property / adapter property are supported
+        //
+        return STATUS_INVALID_PARAMETER_1;
+    }
+
+    //
+    // check query type
+    //
+    if (PropertyQuery->QueryType == PropertyExistsQuery)
+    {
+        //
+        // device property / adapter property is supported
+        //
+        return STATUS_SUCCESS;
+    }
+
+    if (PropertyQuery->QueryType != PropertyStandardQuery)
+    {
+        //
+        // only standard query and exists query are supported
+        //
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    //
+    // check if it is a device property
+    //
+    if (PropertyQuery->PropertyId == StorageDeviceProperty)
+    {
+        DPRINT("USBSTOR_HandleQueryProperty StorageDeviceProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+
+        //
+        // get device extension
+        //
+        PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+        ASSERT(PDODeviceExtension);
+        ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+        //
+        // get device extension
+        //
+        FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+        ASSERT(FDODeviceExtension);
+        ASSERT(FDODeviceExtension->Common.IsFDO);
+
+        //
+        // get inquiry data
+        //
+        InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
+        ASSERT(InquiryData);
+
+        //
+        // compute extra parameters length
+        //
+        FieldLengthVendor = USBSTOR_GetFieldLength(InquiryData->Vendor, 8);
+        FieldLengthProduct = USBSTOR_GetFieldLength(InquiryData->Product, 16);
+        FieldLengthRevision = USBSTOR_GetFieldLength(InquiryData->Revision, 4);
+
+        //
+        // is there a serial number
+        //
+        if (FDODeviceExtension->SerialNumber)
+        {
+            //
+            // get length
+            //
+            FieldLengthSerialNumber = wcslen(FDODeviceExtension->SerialNumber->bString);
+        }
+        else
+        {
+            //
+            // no serial number
+            //
+            FieldLengthSerialNumber = 0;
+        }
+
+        //
+        // total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1
+        // -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
+        //
+        TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3;
+
+        //
+        // check if output buffer is long enough
+        //
+        if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < TotalLength)
+        {
+            //
+            // buffer too small
+            //
+            DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
+            ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER));
+
+            //
+            // return required size
+            //
+            DescriptorHeader->Version = TotalLength;
+            DescriptorHeader->Size = TotalLength;
+
+            Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
+            return STATUS_SUCCESS;
+        }
+
+        //
+        // get device descriptor
+        //
+        DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
+
+        //
+        // initialize device descriptor
+        //
+        DeviceDescriptor->Version = TotalLength;
+        DeviceDescriptor->Size = TotalLength;
+        DeviceDescriptor->DeviceType = InquiryData->DeviceType;
+        DeviceDescriptor->DeviceTypeModifier = (InquiryData->RMB & 0x7F);
+        DeviceDescriptor->RemovableMedia = (InquiryData->RMB & 0x80) ? TRUE : FALSE;
+        DeviceDescriptor->CommandQueueing = FALSE;
+        DeviceDescriptor->BusType = BusTypeUsb;
+        DeviceDescriptor->VendorIdOffset = sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR);
+        DeviceDescriptor->ProductIdOffset = DeviceDescriptor->VendorIdOffset + FieldLengthVendor + 1;
+        DeviceDescriptor->ProductRevisionOffset = DeviceDescriptor->ProductIdOffset + FieldLengthProduct + 1;
+        DeviceDescriptor->SerialNumberOffset = (FieldLengthSerialNumber > 0 ? DeviceDescriptor->ProductRevisionOffset + FieldLengthRevision + 1 : 0);
+        DeviceDescriptor->RawPropertiesLength = FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3 + (FieldLengthSerialNumber > 0 ? + 1 : 0);
+
+        //
+        // copy descriptors
+        //
+        Buffer = (PUCHAR)((ULONG_PTR)DeviceDescriptor + sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR));
+
+        //
+        // copy vendor
+        //
+        RtlCopyMemory(Buffer, InquiryData->Vendor, FieldLengthVendor);
+        Buffer[FieldLengthVendor] = '\0';
+        Buffer += FieldLengthVendor + 1;
+
+        //
+        // copy product
+        //
+        RtlCopyMemory(Buffer, InquiryData->Product, FieldLengthProduct);
+        Buffer[FieldLengthProduct] = '\0';
+        Buffer += FieldLengthProduct + 1;
+
+        //
+        // copy revision
+        //
+        RtlCopyMemory(Buffer, InquiryData->Revision, FieldLengthRevision);
+        Buffer[FieldLengthRevision] = '\0';
+        Buffer += FieldLengthRevision + 1;
+
+        //
+        // copy serial number
+        //
+        if (FieldLengthSerialNumber)
+        {
+            //
+            // init unicode string
+            //
+            RtlInitUnicodeString(&SerialNumber, FDODeviceExtension->SerialNumber->bString);
+
+            //
+            // init ansi string
+            //
+            AnsiString.Buffer = (PCHAR)Buffer;
+            AnsiString.Length = 0;
+            AnsiString.MaximumLength = FieldLengthSerialNumber * sizeof(WCHAR);
+
+            //
+            // convert to ansi code
+            //
+            Status = RtlUnicodeStringToAnsiString(&AnsiString, &SerialNumber, FALSE);
+            ASSERT(Status == STATUS_SUCCESS);
+        }
+
+
+        DPRINT("Vendor %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->VendorIdOffset));
+        DPRINT("Product %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductIdOffset));
+        DPRINT("Revision %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductRevisionOffset));
+        DPRINT("Serial %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->SerialNumberOffset));
+
+        //
+        // done
+        //
+        Irp->IoStatus.Information = TotalLength;
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        //
+        // adapter property query request
+        //
+        DPRINT("USBSTOR_HandleQueryProperty StorageAdapterProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
+
+        if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR))
+        {
+            //
+            // buffer too small
+            //
+            DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
+            ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER));
+
+            //
+            // return required size
+            //
+            DescriptorHeader->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
+            DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
+
+            Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
+            return STATUS_SUCCESS;
+        }
+
+        //
+        // get adapter descriptor, information is returned in the same buffer
+        //
+        AdapterDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
+
+        //
+        // fill out descriptor
+        //
+        AdapterDescriptor->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
+        AdapterDescriptor->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
+        AdapterDescriptor->MaximumTransferLength = MAXULONG; //FIXME compute some sane value
+        AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value
+        AdapterDescriptor->AlignmentMask = 0;
+        AdapterDescriptor->AdapterUsesPio = FALSE;
+        AdapterDescriptor->AdapterScansDown = FALSE;
+        AdapterDescriptor->CommandQueueing = FALSE;
+        AdapterDescriptor->AcceleratedTransfer = FALSE;
+        AdapterDescriptor->BusType = BusTypeUsb;
+        AdapterDescriptor->BusMajorVersion = 0x2; //FIXME verify
+        AdapterDescriptor->BusMinorVersion = 0x00; //FIXME
+
+        //
+        // store returned length
+        //
+        Irp->IoStatus.Information = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
+
+        //
+        // done
+        //
+        return STATUS_SUCCESS;
+    }
+}
+
+NTSTATUS
+USBSTOR_HandleDeviceControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+    NTSTATUS Status;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PSCSI_ADAPTER_BUS_INFO BusInfo;
+    PSCSI_INQUIRY_DATA InquiryData;
+    PINQUIRYDATA ScsiInquiryData;
+    PUFI_INQUIRY_RESPONSE UFIInquiryResponse;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY)
+    {
+        //
+        // query property
+        //
+        Status = USBSTOR_HandleQueryProperty(DeviceObject, Irp);
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH)
+    {
+        //
+        // query scsi pass through
+        //
+        DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n");
+        Status = STATUS_NOT_SUPPORTED;
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
+    {
+        //
+        // query scsi pass through direct
+        //
+        DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n");
+        Status = STATUS_NOT_SUPPORTED;
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
+    {
+        //
+        // query serial number
+        //
+        DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n");
+        Status = STATUS_NOT_SUPPORTED;
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_CAPABILITIES)
+    {
+        PIO_SCSI_CAPABILITIES Capabilities;
+
+        /* Legacy port capability query */
+        if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
+        {
+            Capabilities = *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = ExAllocatePoolWithTag(NonPagedPool,
+                                                                                               sizeof(IO_SCSI_CAPABILITIES),
+                                                                                               USB_STOR_TAG);
+            Irp->IoStatus.Information = sizeof(PVOID);
+        }
+        else
+        {
+            Capabilities = Irp->AssociatedIrp.SystemBuffer;
+            Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
+        }
+
+        if (Capabilities)
+        {
+            Capabilities->MaximumTransferLength = MAXULONG;
+            Capabilities->MaximumPhysicalPages = 25;
+            Capabilities->SupportedAsynchronousEvents = 0;
+            Capabilities->AlignmentMask = 0;
+            Capabilities->TaggedQueuing = FALSE;
+            Capabilities->AdapterScansDown = FALSE;
+            Capabilities->AdapterUsesPio = FALSE;
+            Status = STATUS_SUCCESS;
+        }
+        else
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+        }
+    } 
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_INQUIRY_DATA)
+    {
+        //
+        // get device extension
+        //
+        PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+        ASSERT(PDODeviceExtension);
+        ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+        //
+        // get parameters
+        //
+        BusInfo = Irp->AssociatedIrp.SystemBuffer;
+        InquiryData = (PSCSI_INQUIRY_DATA)(BusInfo + 1);
+        ScsiInquiryData = (PINQUIRYDATA)InquiryData->InquiryData;
+        
+
+        //
+        // get inquiry data
+        //
+        UFIInquiryResponse = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
+        ASSERT(UFIInquiryResponse);
+
+
+        BusInfo->NumberOfBuses = 1;
+        BusInfo->BusData[0].NumberOfLogicalUnits = 1; //FIXME
+        BusInfo->BusData[0].InitiatorBusId = 0;
+        BusInfo->BusData[0].InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO);
+
+        InquiryData->PathId = 0;
+        InquiryData->TargetId = 0;
+        InquiryData->Lun = PDODeviceExtension->LUN & MAX_LUN;
+        InquiryData->DeviceClaimed = PDODeviceExtension->Claimed;
+        InquiryData->InquiryDataLength = sizeof(INQUIRYDATA);
+        InquiryData->NextInquiryDataOffset = 0;
+
+        RtlZeroMemory(ScsiInquiryData, sizeof(INQUIRYDATA));
+        ScsiInquiryData->DeviceType = UFIInquiryResponse->DeviceType;
+        ScsiInquiryData->DeviceTypeQualifier = (UFIInquiryResponse->RMB & 0x7F);
+
+        /* Hack for IoReadPartitionTable call in disk.sys */
+        ScsiInquiryData->RemovableMedia = ((ScsiInquiryData->DeviceType != DIRECT_ACCESS_DEVICE) ? ((UFIInquiryResponse->RMB & 0x80) ? 1 : 0) : 0);
+
+        ScsiInquiryData->Versions = 0x04;
+        ScsiInquiryData->ResponseDataFormat = 0x02;
+        ScsiInquiryData->AdditionalLength = 31;
+        ScsiInquiryData->SoftReset = 0;
+        ScsiInquiryData->CommandQueue = 0;
+        ScsiInquiryData->LinkedCommands = 0;
+        ScsiInquiryData->RelativeAddressing = 0;
+
+        RtlCopyMemory(&ScsiInquiryData->VendorId, UFIInquiryResponse->Vendor, USBSTOR_GetFieldLength(UFIInquiryResponse->Vendor, 8));
+        RtlCopyMemory(&ScsiInquiryData->ProductId, UFIInquiryResponse->Product, USBSTOR_GetFieldLength(UFIInquiryResponse->Product, 16));
+
+        Irp->IoStatus.Information = sizeof(SCSI_ADAPTER_BUS_INFO) + sizeof(SCSI_INQUIRY_DATA) + sizeof(INQUIRYDATA) - 1;
+        Status = STATUS_SUCCESS;
+    }
+    else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS)
+    {
+        PSCSI_ADDRESS Address = Irp->AssociatedIrp.SystemBuffer;
+
+        Address->Length = sizeof(SCSI_ADDRESS);
+        Address->PortNumber = 0;
+        Address->PathId = 0;
+        Address->TargetId = 0;
+        Address->Lun = (((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LUN & MAX_LUN);
+        Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
+
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        //
+        // unsupported
+        //
+        DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
+        Status = STATUS_NOT_SUPPORTED;
+    }
+
+    return Status;
+}
diff --git a/drivers/usb/usbstor_new/error.c b/drivers/usb/usbstor_new/error.c
new file mode 100644 (file)
index 0000000..e920d35
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/error.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+USBSTOR_GetEndpointStatus(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR bEndpointAddress,
+    OUT PUSHORT Value)
+{
+    PURB Urb;
+    NTSTATUS Status;
+
+    //
+    // allocate urb
+    //
+    DPRINT("Allocating URB\n");
+    Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+    if (!Urb)
+    {
+        //
+        // out of memory
+        //
+        DPRINT1("OutofMemory!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // build status
+    //
+   UsbBuildGetStatusRequest(Urb, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, bEndpointAddress & 0x0F, Value, NULL, NULL);
+
+    //
+    // send the request
+    //
+    DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb);
+    Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
+
+    //
+    // free urb
+    //
+    FreeItem(Urb);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+
+NTSTATUS
+USBSTOR_ResetPipeWithHandle(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN USBD_PIPE_HANDLE PipeHandle)
+{
+    PURB Urb;
+    NTSTATUS Status;
+
+    //
+    // allocate urb
+    //
+    DPRINT("Allocating URB\n");
+    Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST));
+    if (!Urb)
+    {
+        //
+        // out of memory
+        //
+        DPRINT1("OutofMemory!\n");
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize the urb
+    //
+    Urb->UrbPipeRequest.Hdr.Length = sizeof(struct _URB_PIPE_REQUEST);
+    Urb->UrbPipeRequest.Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL;
+    Urb->UrbPipeRequest.PipeHandle = PipeHandle;
+
+    //
+    // send the request
+    //
+    DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb);
+    Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
+
+    //
+    // free urb
+    //
+    FreeItem(Urb);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+NTSTATUS
+USBSTOR_HandleTransferError(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP_CONTEXT Context)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION Stack;
+    PSCSI_REQUEST_BLOCK Request;
+    PCDB pCDB;
+
+    //
+    // sanity checks
+    //
+    ASSERT(Context);
+    ASSERT(Context->PDODeviceExtension);
+    ASSERT(Context->PDODeviceExtension->Self);
+    ASSERT(Context->Irp);
+
+    //
+    // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
+    //
+    Status = USBSTOR_ResetDevice(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // step 2 reset bulk in pipe section 5.3.4
+        //
+        Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle);
+        if (NT_SUCCESS(Status))
+        {
+            //
+            // finally reset bulk out pipe
+            //
+            Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle);
+        }
+    }
+
+    //
+    // get next stack location
+    //
+    Stack = IoGetCurrentIrpStackLocation(Context->Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1;
+    ASSERT(Request);
+
+    //
+    // obtain request type
+    //
+    pCDB = (PCDB)Request->Cdb;
+    ASSERT(pCDB);
+
+    if (Status != STATUS_SUCCESS || Context->RetryCount >= 1)
+    {
+        //
+        // Complete the master IRP
+        //
+        Context->Irp->IoStatus.Status = Status;
+        Context->Irp->IoStatus.Information = 0;
+        USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
+        IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
+
+        //
+        // Start the next request
+        //
+        USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
+
+        //
+        // srb handling finished
+        //
+        Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE;
+
+        //
+        // clear timer srb
+        //
+        Context->FDODeviceExtension->LastTimerActiveSrb = NULL;
+    }
+    else
+    {
+        DPRINT1("Retrying Count %lu %p\n", Context->RetryCount, Context->PDODeviceExtension->Self);
+
+        //
+        // re-schedule request
+        //
+        USBSTOR_HandleExecuteSCSI(Context->PDODeviceExtension->Self, Context->Irp, Context->RetryCount + 1);
+
+        //
+        // srb error handling finished
+        //
+        Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE;
+
+        //
+        // srb error handling finished
+        //
+        Context->FDODeviceExtension->TimerWorkQueueEnabled = TRUE;
+
+        //
+        // clear timer srb
+        //
+        Context->FDODeviceExtension->LastTimerActiveSrb = NULL;
+    }
+
+    //
+    // cleanup irp context
+    //
+    FreeItem(Context->cbw);
+    FreeItem(Context);
+
+
+    DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status);
+    return Status;
+}
+
+VOID
+NTAPI
+USBSTOR_ResetHandlerWorkItemRoutine(
+    PVOID Context)
+{
+    NTSTATUS Status;
+    PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context;
+
+    //
+    // clear stall on BulkIn pipe
+    //
+    Status = USBSTOR_ResetPipeWithHandle(WorkItemData->Context->FDODeviceExtension->LowerDeviceObject, WorkItemData->Context->FDODeviceExtension->InterfaceInformation->Pipes[WorkItemData->Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle);
+    DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status);
+
+    //
+    // now resend the csw as the stall got cleared
+    //
+    USBSTOR_SendCSW(WorkItemData->Context, WorkItemData->Irp);
+}
+
+VOID
+NTAPI
+ErrorHandlerWorkItemRoutine(
+    PVOID Context)
+{
+    PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context;
+
+    if (WorkItemData->Context->ErrorIndex == 2)
+    {
+        //
+        // reset device
+        //
+        USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context);
+    }
+    else
+    {
+        //
+        // clear stall
+        //
+        USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData);
+    }
+
+    //
+    // Free Work Item Data
+    //
+    ExFreePoolWithTag(WorkItemData, USB_STOR_TAG);
+}
+
+VOID
+NTAPI
+USBSTOR_TimerWorkerRoutine(
+    IN PVOID Context)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    NTSTATUS Status;
+    PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)WorkItemData->DeviceObject->DeviceExtension;
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
+    //
+    Status = USBSTOR_ResetDevice(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension);
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // step 2 reset bulk in pipe section 5.3.4
+        //
+        Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle);
+        if (NT_SUCCESS(Status))
+        {
+            //
+            // finally reset bulk out pipe
+            //
+            Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle);
+        }
+    }
+    DPRINT1("Status %x\n", Status);
+
+    //
+    // clear timer srb
+    //
+    FDODeviceExtension->LastTimerActiveSrb = NULL;
+
+    //
+    // re-schedule request
+    //
+    //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1);
+
+
+
+    //
+    // do not retry for the same packet again
+    //
+    FDODeviceExtension->TimerWorkQueueEnabled = FALSE;
+
+    //
+    // Free Work Item Data
+    //
+    ExFreePoolWithTag(WorkItemData, USB_STOR_TAG);
+}
+
+
+VOID
+NTAPI
+USBSTOR_TimerRoutine(
+    PDEVICE_OBJECT DeviceObject,
+     PVOID Context)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    BOOLEAN ResetDevice = FALSE;
+    PERRORHANDLER_WORKITEM_DATA WorkItemData;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Context;
+    DPRINT1("[USBSTOR] TimerRoutine entered\n");
+    DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension->ActiveSrb, FDODeviceExtension->ResetInProgress, FDODeviceExtension->LastTimerActiveSrb);
+
+    //
+    // acquire spinlock
+    //
+    KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
+
+    //
+    // is there an active srb and no global reset is in progress
+    //
+    if (FDODeviceExtension->ActiveSrb && FDODeviceExtension->ResetInProgress == FALSE && FDODeviceExtension->TimerWorkQueueEnabled)
+    {
+        if (FDODeviceExtension->LastTimerActiveSrb != NULL && FDODeviceExtension->LastTimerActiveSrb == FDODeviceExtension->ActiveSrb)
+        {
+            //
+            // check if empty
+            //
+            DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension->ActiveSrb);
+            ResetDevice = TRUE;
+        }
+        else
+        {
+            //
+            // update pointer
+            //
+            FDODeviceExtension->LastTimerActiveSrb = FDODeviceExtension->ActiveSrb;
+        }
+    }
+    else
+    {
+        //
+        // reset srb
+        //
+        FDODeviceExtension->LastTimerActiveSrb = NULL;
+    }
+
+    //
+    // release lock
+    //
+    KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
+
+
+    if (ResetDevice && FDODeviceExtension->TimerWorkQueueEnabled && FDODeviceExtension->SrbErrorHandlingActive == FALSE)
+    {
+        WorkItemData = ExAllocatePoolWithTag(NonPagedPool,
+                                             sizeof(ERRORHANDLER_WORKITEM_DATA),
+                                             USB_STOR_TAG);
+        if (WorkItemData)
+        {
+           //
+           // Initialize and queue the work item to handle the error
+           //
+           ExInitializeWorkItem(&WorkItemData->WorkQueueItem,
+                                 USBSTOR_TimerWorkerRoutine,
+                                 WorkItemData);
+
+           WorkItemData->DeviceObject = FDODeviceExtension->FunctionalDeviceObject;
+
+           DPRINT1("[USBSTOR] Queing Timer WorkItem\n");
+           ExQueueWorkItem(&WorkItemData->WorkQueueItem, DelayedWorkQueue);
+        }
+     }
+}
diff --git a/drivers/usb/usbstor_new/fdo.c b/drivers/usb/usbstor_new/fdo.c
new file mode 100644 (file)
index 0000000..e370704
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/fdo.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+VOID
+USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
+{
+    DPRINT1("Dumping Device Descriptor %p\n", DeviceDescriptor);
+    DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
+    DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
+    DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
+    DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
+    DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
+    DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
+    DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
+    DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
+    DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
+    DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
+    DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
+    DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
+    DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
+    DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
+}
+
+NTSTATUS
+USBSTOR_FdoHandleDeviceRelations(
+    IN PFDO_DEVICE_EXTENSION DeviceExtension,
+    IN OUT PIRP Irp)
+{
+    ULONG DeviceCount = 0;
+    LONG Index;
+    PDEVICE_RELATIONS DeviceRelations;
+    PIO_STACK_LOCATION IoStack;
+
+    //
+    // get current irp stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // check if relation type is BusRelations
+    //
+    if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
+    {
+        //
+        // FDO always only handles bus relations
+        //
+        return USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
+    }
+
+    //
+    // go through array and count device objects
+    //
+    for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
+    {
+        if (DeviceExtension->ChildPDO[Index])
+        {
+            //
+            // child pdo
+            //
+            DeviceCount++;
+        }
+    }
+
+    //
+    // allocate device relations
+    //
+    DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
+    if (!DeviceRelations)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // add device objects
+    //
+    for(Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
+    {
+        if (DeviceExtension->ChildPDO[Index])
+        {
+            //
+            // store child pdo
+            //
+            DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
+
+            //
+            // add reference
+            //
+            ObReferenceObject(DeviceExtension->ChildPDO[Index]);
+
+            //
+            // increment count
+            //
+            DeviceRelations->Count++;
+        }
+    }
+
+    //
+    // store result
+    //
+    Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
+
+    //
+    // request completed successfully
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBSTOR_FdoHandleRemoveDevice(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension,
+    IN OUT PIRP Irp)
+{
+    NTSTATUS Status;
+    ULONG Index;
+
+    DPRINT("Handling FDO removal %p\n", DeviceObject);
+
+    /* FIXME: wait for devices finished processing */
+    for(Index = 0; Index < 16; Index++)
+    {
+        if (DeviceExtension->ChildPDO[Index] != NULL)
+        {
+            DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
+            IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
+        }
+    }
+
+    /* Send the IRP down the stack */
+    IoSkipCurrentIrpStackLocation(Irp);
+    Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+
+    /* Detach from the device stack */
+    IoDetachDevice(DeviceExtension->LowerDeviceObject);
+
+    /* Delete the device object */
+    IoDeleteDevice(DeviceObject);
+
+    return Status;
+}
+
+NTSTATUS
+USBSTOR_FdoHandleStartDevice(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension,
+    IN OUT PIRP Irp)
+{
+    PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
+    NTSTATUS Status;
+    UCHAR Index = 0;
+
+    //
+    // forward irp to lower device
+    //
+    Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to start
+        //
+        DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
+        return Status;
+    }
+
+    //
+    // initialize irp queue
+    //
+    USBSTOR_QueueInitialize(DeviceExtension);
+
+    //
+    // first get device & configuration & string descriptor
+    //
+    Status = USBSTOR_GetDescriptors(DeviceObject);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to get device descriptor
+        //
+        DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
+        return Status;
+    }
+
+    //
+    // dump device descriptor
+    //
+    USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
+
+    //
+    // Check that this device uses bulk transfers and is SCSI
+    //
+    InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
+
+    //
+    // sanity check
+    //
+    ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
+    ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
+
+    DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
+    if (InterfaceDesc->bInterfaceProtocol != 0x50)
+    {
+        DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    if (InterfaceDesc->bInterfaceSubClass != 0x06)
+    {
+        //
+        // FIXME: need to pad CDBs to 12 byte
+        // mode select commands must be translated from 1AH / 15h to 5AH / 55h
+        //
+        DPRINT1("[USBSTOR] Error: need to pad CDBs\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    //
+    // now select an interface
+    //
+    Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to get device descriptor
+        //
+        DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
+        return Status;
+    }
+
+    //
+    // check if we got a bulk in + bulk out endpoint
+    //
+    Status = USBSTOR_GetPipeHandles(DeviceExtension);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to get pipe handles descriptor
+        //
+        DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
+        return Status;
+    }
+
+    //
+    // get num of lun which are supported
+    //
+    Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to get max LUN
+        //
+        DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
+        return Status;
+    }
+
+    //
+    // now create for each LUN a device object, 1 minimum
+    //
+    do
+    {
+        //
+        // create pdo
+        //
+        Status = USBSTOR_CreatePDO(DeviceObject, Index);
+
+        //
+        // check for failure
+        //
+        if (!NT_SUCCESS(Status))
+        {
+            //
+            // failed to create child pdo
+            //
+            DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
+            return Status;
+        }
+
+        //
+        // increment pdo index
+        //
+        Index++;
+        DeviceExtension->InstanceCount++;
+
+    }while(Index < DeviceExtension->MaxLUN);
+
+#if 0
+    //
+    // finally get usb device interface
+    //
+    Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to device interface
+        //
+        DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
+        return Status;
+    }
+#endif
+
+
+    //
+    // start the timer
+    //
+    //IoStartTimer(DeviceObject);
+
+
+    //
+    // fdo is now initialized
+    //
+    DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBSTOR_FdoHandlePnp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+    PFDO_DEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(DeviceExtension->Common.IsFDO);
+
+    switch(IoStack->MinorFunction)
+    {
+       case IRP_MN_SURPRISE_REMOVAL:
+       {
+           DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
+           Irp->IoStatus.Status = STATUS_SUCCESS;
+
+            //
+            // forward irp to next device object
+            //
+            IoSkipCurrentIrpStackLocation(Irp);
+            return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+       }
+       case IRP_MN_QUERY_DEVICE_RELATIONS:
+       {
+           DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p\n", DeviceObject);
+           Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
+           break;
+       }
+       case IRP_MN_STOP_DEVICE:
+       {
+           DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
+           IoStopTimer(DeviceObject);
+           Irp->IoStatus.Status = STATUS_SUCCESS;
+
+            //
+            // forward irp to next device object
+            //
+            IoSkipCurrentIrpStackLocation(Irp);
+            return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+       }
+       case IRP_MN_REMOVE_DEVICE:
+       {
+           DPRINT("IRP_MN_REMOVE_DEVICE\n");
+
+           return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
+       }
+       case IRP_MN_QUERY_CAPABILITIES:
+       {
+           //
+           // FIXME: set custom capabilities
+           //
+           IoSkipCurrentIrpStackLocation(Irp);
+           return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+       }
+       case IRP_MN_QUERY_STOP_DEVICE:
+       case IRP_MN_QUERY_REMOVE_DEVICE:
+       {
+#if 0
+           //
+           // we can if nothing is pending
+           //
+           if (DeviceExtension->IrpPendingCount != 0 ||
+               DeviceExtension->ActiveSrb != NULL)
+#else
+           if (TRUE)
+#endif
+           {
+               /* We have pending requests */
+               DPRINT1("Failing removal/stop request due to pending requests present\n");
+               Status = STATUS_UNSUCCESSFUL;
+           }
+           else
+           {
+               /* We're all clear */
+               Irp->IoStatus.Status = STATUS_SUCCESS;
+
+               IoSkipCurrentIrpStackLocation(Irp);
+               return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+           }
+           break;
+       }
+       case IRP_MN_START_DEVICE:
+       {
+           Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
+           break;
+       }
+       default:
+        {
+            //
+            // forward irp to next device object
+            //
+            IoSkipCurrentIrpStackLocation(Irp);
+            return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+        }
+    }
+
+    //
+    // complete request
+    //
+    if (Status != STATUS_PENDING)
+    {
+        //
+        // store result
+        //
+        Irp->IoStatus.Status = Status;
+
+        //
+        // complete request
+        //
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    //
+    // done processing
+    //
+    return Status;
+}
diff --git a/drivers/usb/usbstor_new/guid.c b/drivers/usb/usbstor_new/guid.c
new file mode 100644 (file)
index 0000000..2fd41c6
--- /dev/null
@@ -0,0 +1,9 @@
+/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
+
+#include <ntdef.h>
+#include <miniport.h>
+#include <usb.h>
+#include <initguid.h>
+#include <usbbusif.h>
+
+/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */
diff --git a/drivers/usb/usbstor_new/misc.c b/drivers/usb/usbstor_new/misc.c
new file mode 100644 (file)
index 0000000..6b60cf8
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/misc.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine;
+
+NTSTATUS
+NTAPI
+USBSTOR_SyncForwardIrpCompletionRoutine(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Context)
+{
+    if (Irp->PendingReturned)
+    {
+        KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
+    }
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+    KEVENT Event;
+    NTSTATUS Status;
+
+    //
+    // initialize event
+    //
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    //
+    // copy irp stack location
+    //
+    IoCopyCurrentIrpStackLocationToNext(Irp);
+
+    //
+    // set completion routine
+    //
+    IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
+
+
+    //
+    // call driver
+    //
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    //
+    // check if pending
+    //
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for the request to finish
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+        //
+        // copy status code
+        //
+        Status = Irp->IoStatus.Status;
+    }
+
+    //
+    // done
+    //
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_GetBusInterface(
+    IN PDEVICE_OBJECT DeviceObject,
+    OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface)
+{
+    KEVENT Event;
+    NTSTATUS Status;
+    PIRP Irp;
+    IO_STATUS_BLOCK IoStatus;
+    PIO_STACK_LOCATION Stack;
+
+    //
+    // sanity checks
+    //
+    ASSERT(DeviceObject);
+    ASSERT(BusInterface);
+
+
+    //
+    // initialize event
+    //
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+
+    //
+    // create irp
+    //
+    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
+                                       DeviceObject,
+                                       NULL,
+                                       0,
+                                       NULL,
+                                       &Event,
+                                       &IoStatus);
+
+    //
+    // was irp built
+    //
+    if (Irp == NULL)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize request
+    //
+    Stack=IoGetNextIrpStackLocation(Irp);
+    Stack->MajorFunction = IRP_MJ_PNP;
+    Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
+    Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
+    Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBDI_GUID;
+    Stack->Parameters.QueryInterface.Version = 2;
+    Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
+    Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+
+    //
+    // call driver
+    //
+    Status= IoCallDriver(DeviceObject, Irp);
+
+    //
+    // did operation complete
+    //
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for completion
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+        //
+        // collect status
+        //
+        Status=IoStatus.Status;
+    }
+
+    return Status;
+}
+
+NTSTATUS
+USBSTOR_SyncUrbRequest(
+    IN PDEVICE_OBJECT DeviceObject,
+    OUT PURB UrbRequest)
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    KEVENT Event;
+    NTSTATUS Status;
+
+    //
+    // allocate irp
+    //
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+    if (!Irp)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize event
+    //
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+
+    //
+    // get next stack location
+    //
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    //
+    // initialize stack location
+    //
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+    IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
+    IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+
+    //
+    // setup completion routine
+    //
+    IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
+
+    //
+    // call driver
+    //
+    Status = IoCallDriver(DeviceObject, Irp);
+
+    //
+    // check if request is pending
+    //
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for completion
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+
+        //
+        // update status
+        //
+        Status = Irp->IoStatus.Status;
+    }
+
+    //
+    // free irp
+    //
+    IoFreeIrp(Irp);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+PVOID
+AllocateItem(
+    IN POOL_TYPE PoolType,
+    IN ULONG ItemSize)
+{
+    //
+    // allocate item
+    //
+    PVOID Item = ExAllocatePoolWithTag(PoolType, ItemSize, USB_STOR_TAG);
+
+    if (Item)
+    {
+        //
+        // zero item
+        //
+        RtlZeroMemory(Item, ItemSize);
+    }
+
+    //
+    // return element
+    //
+    return Item;
+}
+
+VOID
+FreeItem(
+    IN PVOID Item)
+{
+    //
+    // free item
+    //
+    ExFreePoolWithTag(Item, USB_STOR_TAG);
+}
+
+NTSTATUS
+USBSTOR_ClassRequest(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension,
+    IN UCHAR RequestType,
+    IN USHORT Index,
+    IN ULONG TransferFlags,
+    IN ULONG TransferBufferLength,
+    IN PVOID TransferBuffer)
+
+{
+    PURB Urb;
+    NTSTATUS Status;
+
+    //
+    // first allocate urb
+    //
+    Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+    if (!Urb)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize vendor request
+    //
+    Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+    Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE;
+    Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags;
+    Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength;
+    Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer;
+    Urb->UrbControlVendorClassRequest.Request = RequestType;
+    Urb->UrbControlVendorClassRequest.Index = Index;
+
+    //
+    // submit request
+    //
+    Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
+
+    //
+    // free urb
+    //
+    FreeItem(Urb);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+NTSTATUS
+USBSTOR_GetMaxLUN(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension)
+{
+    PUCHAR Buffer;
+    NTSTATUS Status;
+
+    //
+    // allocate 1-byte buffer
+    //
+    Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR));
+    if (!Buffer)
+    {
+        //
+        // no memory
+        //
+        FreeItem(Buffer);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // execute request
+    //
+    Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer);
+
+    DPRINT("MaxLUN: %x\n", *Buffer);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (*Buffer > 0xF)
+        {
+            //
+            // invalid response documented in usb mass storage specification
+            //
+            Status = STATUS_DEVICE_DATA_ERROR;
+        }
+        else
+        {
+            //
+            // store maxlun
+            //
+            DeviceExtension->MaxLUN = *Buffer;
+        }
+    }
+    else
+    {
+        //
+        // "USB Mass Storage Class. Bulk-Only Transport. Revision 1.0"
+        // 3.2  Get Max LUN (class-specific request) :
+        // Devices that do not support multiple LUNs may STALL this command.
+        //
+        USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension);
+
+        DeviceExtension->MaxLUN = 0;
+        Status = STATUS_SUCCESS;
+    }
+
+    //
+    // free buffer
+    //
+    FreeItem(Buffer);
+
+    //
+    // done
+    //
+    return Status;
+
+}
+
+NTSTATUS
+USBSTOR_ResetDevice(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension)
+{
+    NTSTATUS Status;
+
+    //
+    // execute request
+    //
+    Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL);
+
+    //
+    // done
+    //
+    return Status;
+
+}
+
+BOOLEAN
+USBSTOR_IsFloppy(
+    IN PUCHAR Buffer,
+    IN ULONG BufferLength,
+    OUT PUCHAR MediumTypeCode)
+{
+    PUFI_CAPACITY_FORMAT_HEADER FormatHeader;
+    PUFI_CAPACITY_DESCRIPTOR Descriptor;
+    ULONG Length, Index, BlockCount, BlockLength;
+
+    //
+    // get format header
+    //
+    FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer;
+
+    //
+    // sanity checks
+    //
+    ASSERT(FormatHeader->Reserved1 == 0x00);
+    ASSERT(FormatHeader->Reserved2 == 0x00);
+    ASSERT(FormatHeader->Reserved3 == 0x00);
+
+    //
+    // is there capacity data
+    //
+    if (!FormatHeader->CapacityLength)
+    {
+        //
+        // no data provided
+        //
+        DPRINT1("[USBSTOR] No capacity length\n");
+        return FALSE;
+    }
+
+    //
+    // the format header are always 8 bytes in length
+    //
+    ASSERT((FormatHeader->CapacityLength & 0x7) == 0);
+    DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength);
+
+    //
+    // grab length and locate first descriptor
+    //
+    Length = FormatHeader->CapacityLength;
+    Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1);
+    for(Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++)
+    {
+        //
+        // blocks are little endian format
+        //
+        BlockCount = NTOHL(Descriptor->BlockCount);
+
+        //
+        // get block length
+        //
+        BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8));
+
+        DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code);
+
+        if (BlockLength == 512 && BlockCount == 1440)
+        {
+            //
+            // 720 KB DD
+            //
+            *MediumTypeCode = 0x1E;
+            return TRUE;
+        }
+        else if (BlockLength == 1024 && BlockCount == 1232)
+        {
+            //
+            // 1,25 MB
+            //
+            *MediumTypeCode = 0x93;
+            return TRUE;
+        }
+        else if (BlockLength == 512 && BlockCount == 2880)
+        {
+            //
+            // 1,44MB KB DD
+            //
+            *MediumTypeCode = 0x94;
+            return TRUE;
+        }
+
+        //
+        // move to next descriptor
+        //
+        Descriptor = (Descriptor + 1);
+    }
+
+    //
+    // no floppy detected
+    //
+    return FALSE;
+}
diff --git a/drivers/usb/usbstor_new/pdo.c b/drivers/usb/usbstor_new/pdo.c
new file mode 100644 (file)
index 0000000..6ce5d8f
--- /dev/null
@@ -0,0 +1,1376 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/pdo.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+LPCSTR
+USBSTOR_GetDeviceType(
+    IN PUFI_INQUIRY_RESPONSE InquiryData,
+    IN UCHAR IsFloppy)
+{
+    //
+    // check if device type is zero
+    //
+    if (InquiryData->DeviceType == 0)
+    {
+        if (IsFloppy)
+        {
+            //
+            // floppy device
+            //
+            return "SFloppy";
+        }
+
+        //
+        // direct access device
+        //
+        return "Disk";
+    }
+
+    //
+    // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
+    //
+    switch (InquiryData->DeviceType)
+    {
+        case 1:
+        {
+            //
+            // sequential device, i.e magnetic tape
+            //
+            return "Sequential";
+        }
+        case 4:
+        {
+            //
+            // write once device
+            //
+            return "Worm";
+        }
+        case 5:
+        {
+            //
+            // CDROM device
+            //
+            return "CdRom";
+        }
+        case 7:
+        {
+            //
+            // optical memory device
+            //
+            return "Optical";
+        }
+        case 8:
+        {
+            //
+            // medium change device
+            //
+            return "Changer";
+        }
+        default:
+        {
+            //
+            // other device
+            //
+            return "Other";
+        }
+    }
+}
+
+LPCSTR
+USBSTOR_GetGenericType(
+    IN PUFI_INQUIRY_RESPONSE InquiryData,
+    IN UCHAR IsFloppy)
+{
+    //
+    // check if device type is zero
+    //
+    if (InquiryData->DeviceType == 0)
+    {
+        if (IsFloppy)
+        {
+            //
+            // floppy device
+            //
+            return "GenSFloppy";
+        }
+
+        //
+        // direct access device
+        //
+        return "GenDisk";
+    }
+
+    //
+    // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
+    //
+    switch (InquiryData->DeviceType)
+    {
+        case 1:
+        {
+            //
+            // sequential device, i.e magnetic tape
+            //
+            return "GenSequential";
+        }
+        case 4:
+        {
+            //
+            // write once device
+            //
+            return "GenWorm";
+        }
+        case 5:
+        {
+            //
+            // CDROM device
+            //
+            return "GenCdRom";
+        }
+        case 7:
+        {
+            //
+            // optical memory device
+            //
+            return "GenOptical";
+        }
+        case 8:
+        {
+            //
+            // medium change device
+            //
+            return "GenChanger";
+        }
+        default:
+        {
+            //
+            // other device
+            //
+            return "UsbstorOther";
+        }
+    }
+}
+
+
+ULONG
+CopyField(
+    IN PUCHAR Name,
+    IN PCHAR Buffer,
+    IN ULONG MaxLength)
+{
+    ULONG Index;
+
+    for(Index = 0; Index < MaxLength; Index++)
+    {
+        if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ ||  Name[Index] == ',')
+        {
+            //
+            // convert to underscore
+            //
+            Buffer[Index] = '_';
+        }
+        else
+        {
+            //
+            // just copy character
+            //
+            Buffer[Index] = Name[Index];
+        }
+    }
+
+    return MaxLength;
+}
+
+NTSTATUS
+USBSTOR_PdoHandleQueryDeviceText(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    //PPDO_DEVICE_EXTENSION DeviceExtension;
+    PIO_STACK_LOCATION IoStack;
+    LPWSTR Buffer;
+    static WCHAR DeviceText[] = L"USB Mass Storage Device";
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
+    {
+        DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n");
+
+        //
+        // allocate item
+        //
+        Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
+        if (!Buffer)
+        {
+            //
+            // no memory
+            //
+            Irp->IoStatus.Information = 0;
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        //
+        // copy buffer
+        //
+        wcscpy(Buffer, DeviceText);
+
+        //
+        // save result
+        //
+        Irp->IoStatus.Information = (ULONG_PTR)Buffer;
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
+
+        //
+        // allocate item
+        //
+        Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
+        if (!Buffer)
+        {
+            //
+            // no memory
+            //
+            Irp->IoStatus.Information = 0;
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        //
+        // copy buffer
+        //
+        wcscpy(Buffer, DeviceText);
+
+        //
+        // save result
+        //
+        Irp->IoStatus.Information = (ULONG_PTR)Buffer;
+        return STATUS_SUCCESS;
+    }
+
+}
+
+
+NTSTATUS
+USBSTOR_PdoHandleQueryDeviceId(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PPDO_DEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+    CHAR Buffer[100];
+    LPCSTR DeviceType;
+    ULONG Offset = 0;
+    PUFI_INQUIRY_RESPONSE InquiryData;
+    ANSI_STRING AnsiString;
+    UNICODE_STRING DeviceId;
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(DeviceExtension->InquiryData);
+
+    //
+    // get inquiry data
+    //
+    InquiryData = (PUFI_INQUIRY_RESPONSE)DeviceExtension->InquiryData;
+
+    //
+    // get device type
+    //
+    DeviceType = USBSTOR_GetDeviceType(InquiryData, DeviceExtension->IsFloppy);
+
+    //
+    // zero buffer
+    //
+    RtlZeroMemory(Buffer, sizeof(Buffer));
+
+    //
+    // lets create device string
+    //
+    Offset = sprintf(&Buffer[Offset], "USBSTOR\\");
+    Offset += sprintf(&Buffer[Offset], DeviceType);
+    Offset += sprintf(&Buffer[Offset], "&Ven_");
+    Offset += CopyField(InquiryData->Vendor, &Buffer[Offset], 8);
+    Offset += sprintf(&Buffer[Offset], "&Prod_");
+    Offset += CopyField(InquiryData->Product, &Buffer[Offset], 16);
+    Offset += sprintf(&Buffer[Offset], "&Rev_");
+    Offset += CopyField(InquiryData->Revision, &Buffer[Offset], 4);
+
+    //
+    // now initialize ansi string
+    //
+    RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
+
+    //
+    // allocate DeviceId string
+    //
+    DeviceId.Length = 0;
+    DeviceId.MaximumLength = (strlen((PCHAR)Buffer) + 1) * sizeof(WCHAR);
+    DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength);
+    if (!DeviceId.Buffer)
+    {
+        //
+        // no memory
+        //
+        Irp->IoStatus.Information = 0;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+
+    //
+    // convert to unicode
+    //
+    Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE);
+
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // store result
+        //
+        Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
+    }
+
+    DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+VOID
+USBSTOR_ConvertToUnicodeString(
+    IN CHAR * Buffer,
+    IN ULONG ResultBufferLength,
+    IN ULONG ResultBufferOffset,
+    OUT LPWSTR ResultBuffer,
+    OUT PULONG NewResultBufferOffset)
+{
+    UNICODE_STRING DeviceString;
+    ANSI_STRING AnsiString;
+    NTSTATUS Status;
+
+    ASSERT(ResultBufferLength);
+    ASSERT(ResultBufferLength > ResultBufferOffset);
+
+    DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
+
+    //
+    // construct destination string
+    //
+    DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
+    DeviceString.Length = 0;
+    DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
+
+    //
+    // initialize source string
+    //
+    RtlInitAnsiString(&AnsiString, Buffer);
+
+    //
+    // convert to unicode
+    //
+    Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
+    ASSERT(Status == STATUS_SUCCESS);
+
+    //
+    // subtract consumed bytes
+    //
+    ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
+    ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
+
+    //
+    // store new offset
+    //
+    *NewResultBufferOffset = ResultBufferOffset;
+}
+
+
+
+NTSTATUS
+USBSTOR_PdoHandleQueryHardwareId(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp)
+{
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    LPCSTR GenericType, DeviceType;
+    LPWSTR Buffer;
+    CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50];
+    ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length,Id6Length;
+    ULONG Offset, TotalLength, Length;
+    PUFI_INQUIRY_RESPONSE InquiryData;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->DeviceDescriptor);
+
+    //
+    // get inquiry data
+    //
+    InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
+
+
+    //
+    // get device type and generic type
+    //
+    DeviceType = USBSTOR_GetDeviceType(InquiryData, PDODeviceExtension->IsFloppy);
+    GenericType = USBSTOR_GetGenericType(InquiryData, PDODeviceExtension->IsFloppy);
+
+    ASSERT(GenericType);
+
+    //
+    // generate id 1
+    // USBSTOR\SCSIType_Vendor(8)_Product(16)_Revision(4)
+    //
+    RtlZeroMemory(Id1, sizeof(Id1));
+    Offset = 0;
+    Offset = sprintf(&Id1[Offset], "USBSTOR\\");
+    Offset += sprintf(&Id1[Offset], DeviceType);
+    Offset += CopyField(InquiryData->Vendor, &Id1[Offset], 8);
+    Offset += CopyField(InquiryData->Product, &Id1[Offset], 16);
+    Offset += CopyField(InquiryData->Revision, &Id1[Offset], 4);
+    Id1Length = strlen(Id1) + 1;
+    DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
+
+    //
+    // generate id 2
+    // USBSTOR\SCSIType_VENDOR(8)_Product(16)
+    //
+    RtlZeroMemory(Id2, sizeof(Id2));
+    Offset = 0;
+    Offset = sprintf(&Id2[Offset], "USBSTOR\\");
+    Offset += sprintf(&Id2[Offset], DeviceType);
+    Offset += CopyField(InquiryData->Vendor, &Id2[Offset], 8);
+    Offset += CopyField(InquiryData->Product, &Id2[Offset], 16);
+    Id2Length = strlen(Id2) + 1;
+    DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
+
+    //
+    // generate id 3
+    // USBSTOR\SCSIType_VENDOR(8)
+    //
+    RtlZeroMemory(Id3, sizeof(Id3));
+    Offset = 0;
+    Offset = sprintf(&Id3[Offset], "USBSTOR\\");
+    Offset += sprintf(&Id3[Offset], DeviceType);
+    Offset += CopyField(InquiryData->Vendor, &Id3[Offset], 8);
+    Id3Length = strlen(Id3) + 1;
+    DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
+
+    //
+    // generate id 4
+    // USBSTOR\SCSIType_VENDOR(8)_Product(16)_Revision(1)
+    //
+    RtlZeroMemory(Id4, sizeof(Id4));
+    Offset = 0;
+    Offset = sprintf(&Id4[Offset], "USBSTOR\\");
+    Offset += sprintf(&Id4[Offset], DeviceType);
+    Offset += CopyField(InquiryData->Vendor, &Id4[Offset], 8);
+    Offset += CopyField(InquiryData->Product, &Id4[Offset], 16);
+    Offset += CopyField(InquiryData->Revision, &Id4[Offset], 1);
+    Id4Length = strlen(Id4) + 1;
+    DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
+
+    //
+    // generate id 5
+    // USBSTOR\SCSIType
+    //
+    RtlZeroMemory(Id5, sizeof(Id5));
+    Offset = 0;
+    Offset = sprintf(&Id5[Offset], "USBSTOR\\");
+    Offset += sprintf(&Id5[Offset], GenericType);
+    Id5Length = strlen(Id5) + 1;
+    DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
+
+    //
+    // generate id 6
+    // SCSIType
+    //
+    RtlZeroMemory(Id6, sizeof(Id6));
+    Offset = 0;
+    Offset = sprintf(&Id6[Offset], GenericType);
+    Id6Length = strlen(Id6) + 1;
+    DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
+
+    //
+    // compute total length
+    //
+    TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1;
+
+    //
+    // allocate buffer
+    //
+    Buffer = (LPWSTR)AllocateItem(PagedPool, TotalLength * sizeof(WCHAR));
+    if (!Buffer)
+    {
+        //
+        // no memory
+        //
+        Irp->IoStatus.Information = 0;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // reset offset
+    //
+    Offset = 0;
+    Length = TotalLength;
+
+    USBSTOR_ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
+    USBSTOR_ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
+    USBSTOR_ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
+    USBSTOR_ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
+    USBSTOR_ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
+    USBSTOR_ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
+
+    //
+    // sanity check
+    //
+    ASSERT(Offset + 1 == Length);
+
+    //
+    // store result
+    //
+    Irp->IoStatus.Information = (ULONG_PTR)Buffer;
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBSTOR_PdoHandleQueryCompatibleId(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp)
+{
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    CHAR Buffer[100];
+    ULONG Length, Offset;
+    LPWSTR InstanceId;
+    LPCSTR DeviceType;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->DeviceDescriptor);
+
+    //
+    // get target device type
+    //
+    DeviceType = USBSTOR_GetDeviceType((PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy);
+
+    //
+    // zero memory
+    //
+    RtlZeroMemory(Buffer, sizeof(Buffer));
+
+    //
+    // format instance id
+    //
+    Length = sprintf(Buffer, "USBSTOR\\%s", DeviceType) + 1;
+    Length += sprintf(&Buffer[Length], "USBSTOR\\%s", "RAW") + 2;
+
+    //
+    // allocate instance id
+    //
+    InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
+    if (!InstanceId)
+    {
+        //
+        // no memory
+        //
+        Irp->IoStatus.Information = 0;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    USBSTOR_ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
+    USBSTOR_ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
+
+    DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId);
+
+    //
+    // store result
+    //
+    Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
+
+    //
+    // completed successfully
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBSTOR_PdoHandleQueryInstanceId(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp)
+{
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    WCHAR Buffer[100];
+    ULONG Length;
+    LPWSTR InstanceId;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+
+    //
+    // format instance id
+    //
+    if (FDODeviceExtension->SerialNumber)
+    {
+        //
+        // using serial number from device
+        //
+        swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
+    }
+    else
+    {
+        //
+        // use instance count and LUN
+        //
+        swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN);
+    }
+
+    //
+    // calculate length
+    //
+    Length = wcslen(Buffer) + 1;
+
+    //
+    // allocate instance id
+    //
+    InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
+    if (!InstanceId)
+    {
+        //
+        // no memory
+        //
+        Irp->IoStatus.Information = 0;
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // copy instance id
+    //
+    wcscpy(InstanceId, Buffer);
+
+    DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId);
+
+    //
+    // store result
+    //
+    Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
+
+    //
+    // completed successfully
+    //
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBSTOR_PdoHandleDeviceRelations(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp)
+{
+    PDEVICE_RELATIONS DeviceRelations;
+    PIO_STACK_LOCATION IoStack;
+
+    DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
+
+    //
+    // get current irp stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // check if relation type is BusRelations
+    //
+    if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
+    {
+        //
+        // PDO handles only target device relation
+        //
+        return Irp->IoStatus.Status;
+    }
+
+    //
+    // allocate device relations
+    //
+    DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
+    if (!DeviceRelations)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize device relations
+    //
+    DeviceRelations->Count = 1;
+    DeviceRelations->Objects[0] = DeviceObject;
+    ObReferenceObject(DeviceObject);
+
+    //
+    // store result
+    //
+    Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
+
+    //
+    // completed successfully
+    //
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+USBSTOR_PdoHandlePnp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+    PPDO_DEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+    PDEVICE_CAPABILITIES Caps;
+    ULONG bDelete;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(DeviceExtension->Common.IsFDO == FALSE);
+
+    switch(IoStack->MinorFunction)
+    {
+       case IRP_MN_QUERY_DEVICE_RELATIONS:
+       {
+           Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp);
+           break;
+       }
+       case IRP_MN_QUERY_DEVICE_TEXT:
+       {
+           Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp);
+           break;
+       }
+       case IRP_MN_QUERY_ID:
+       {
+           if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
+           {
+               //
+               // handle query device id
+               //
+               Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
+               break;
+           }
+           else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
+           {
+               //
+               // handle instance id
+               //
+               Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp);
+               break;
+           }
+           else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
+           {
+               //
+               // handle instance id
+               //
+               Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp);
+               break;
+           }
+           else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
+           {
+               //
+               // handle instance id
+               //
+               Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp);
+               break;
+           }
+
+           DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
+           Status = STATUS_NOT_SUPPORTED;
+           Irp->IoStatus.Information = 0;
+           break;
+       }
+       case IRP_MN_REMOVE_DEVICE:
+       {
+           DPRINT("IRP_MN_REMOVE_DEVICE\n");
+
+           if(*DeviceExtension->PDODeviceObject != NULL)
+           {
+               //
+               // clear entry in FDO pdo list
+               //
+               *DeviceExtension->PDODeviceObject = NULL;
+               bDelete = TRUE;
+           }
+           else
+           {
+               //
+               // device object already marked for deletion
+               //
+               bDelete = FALSE;
+           }
+
+           /* Complete the IRP */
+           Irp->IoStatus.Status = STATUS_SUCCESS;
+           IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+           if (bDelete)
+           {
+               /* Delete the device object */
+               IoDeleteDevice(DeviceObject);
+           }
+           return STATUS_SUCCESS;
+       }
+       case IRP_MN_QUERY_CAPABILITIES:
+       {
+           //
+           // just forward irp to lower device
+           //
+           Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
+           ASSERT(Status == STATUS_SUCCESS);
+
+           if (NT_SUCCESS(Status))
+           {
+               //
+               // check if no unique id
+               //
+               Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
+               Caps->UniqueID = FALSE; // no unique id is supported
+               Caps->Removable = TRUE; //FIXME
+           }
+           break;
+       }
+       case IRP_MN_QUERY_REMOVE_DEVICE:
+       case IRP_MN_QUERY_STOP_DEVICE:
+       {
+#if 0
+           //
+           // if we're not claimed it's ok
+           //
+           if (DeviceExtension->Claimed)
+#else
+           if (TRUE)
+#endif
+           {
+               Status = STATUS_UNSUCCESSFUL;
+               DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction);
+           }
+           else
+               Status = STATUS_SUCCESS;
+           break;
+       }
+       case IRP_MN_START_DEVICE:
+       {
+           //
+           // no-op for PDO
+           //
+           Status = STATUS_SUCCESS;
+           break;
+       }
+       case IRP_MN_SURPRISE_REMOVAL:
+       {
+           Status = STATUS_SUCCESS;
+           break;
+       }
+       default:
+        {
+            //
+            // do nothing
+            //
+            Status = Irp->IoStatus.Status;
+        }
+    }
+
+    //
+    // complete request
+    //
+    if (Status != STATUS_PENDING)
+    {
+        //
+        // store result
+        //
+        Irp->IoStatus.Status = Status;
+
+        //
+        // complete request
+        //
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    //
+    // done processing
+    //
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_CompletionRoutine(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN PVOID Ctx)
+{
+    PKEVENT Event = (PKEVENT)Ctx;
+
+    //
+    // signal event
+    //
+    KeSetEvent(Event, 0, FALSE);
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS
+USBSTOR_AllocateIrp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN ULONG DataTransferLength,
+    IN UCHAR OpCode,
+    IN PKEVENT Event,
+    OUT PSCSI_REQUEST_BLOCK *OutRequest,
+    OUT PIRP *OutIrp)
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+    PCDB pCDB;
+
+    //
+    // allocate irp
+    //
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+    if (!Irp)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // get next stack location
+    //
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    //
+    // create scsi block
+    //
+    Request = ExAllocatePoolWithTag(NonPagedPool,
+                                    sizeof(SCSI_REQUEST_BLOCK),
+                                    USB_STOR_TAG);
+    if (!Request)
+    {
+        //
+        // no memory
+        //
+        IoFreeIrp(Irp);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // init request
+    //
+    RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK));
+
+    //
+    // allocate data transfer block
+    //
+    Request->DataBuffer = ExAllocatePoolWithTag(NonPagedPool,
+                                                DataTransferLength,
+                                                USB_STOR_TAG);
+    if (!Request->DataBuffer)
+    {
+        //
+        // no memory
+        //
+        IoFreeIrp(Irp);
+        ExFreePoolWithTag(Request, USB_STOR_TAG);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // allocate MDL
+    //
+    Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL);
+    if (!Irp->MdlAddress)
+    {
+        //
+        // no memory
+        //
+        IoFreeIrp(Irp);
+        ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
+        ExFreePoolWithTag(Request, USB_STOR_TAG);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // non paged pool
+    //
+    MmBuildMdlForNonPagedPool(Irp->MdlAddress);
+
+    //
+    // init scsi block
+    //
+    Request->DataTransferLength = DataTransferLength;
+    Request->Function = SRB_FUNCTION_EXECUTE_SCSI;
+    Request->SrbFlags = SRB_FLAGS_DATA_IN;
+
+    RtlZeroMemory(Request->DataBuffer, DataTransferLength);
+
+
+    //
+    // get SCSI command data block
+    //
+    pCDB = (PCDB)Request->Cdb;
+
+    //
+    // set op code
+    //
+    pCDB->AsByte[0] = OpCode;
+
+    //
+    // store result
+    //
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.Others.Argument1 = Request;
+    IoStack->DeviceObject = DeviceObject;
+
+    //
+    // init event
+    //
+    KeInitializeEvent(Event, NotificationEvent, FALSE);
+
+    //
+    // lets setup a completion routine
+    //
+    IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE);
+
+    //
+    // output result
+    //
+    *OutIrp = Irp;
+    *OutRequest = Request;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBSTOR_SendIrp(
+    IN PDEVICE_OBJECT PDODeviceObject,
+    IN ULONG DataTransferLength,
+    IN UCHAR OpCode,
+    OUT PVOID *OutData)
+{
+    NTSTATUS Status;
+    PIRP Irp;
+    KEVENT Event;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // let's allocate an irp
+    //
+    Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed
+        //
+        DPRINT1("[USBSTOR] Failed to build irp\n");
+        return Status;
+    }
+
+    //
+    // get device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
+
+    //
+    // send irp
+    //
+    ASSERT(Irp);
+    ASSERT(PDODeviceExtension->LowerDeviceObject);
+    Status = IoCallDriver(PDODeviceExtension->Self, Irp);
+
+    if (Status == STATUS_PENDING)
+    {
+        //
+        // wait for completion
+        //
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = Irp->IoStatus.Status;
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        //
+        // store result
+        //
+        *OutData = Request->DataBuffer;
+    }
+    else
+    {
+        //
+        // free the data
+        //
+        ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
+        *OutData = NULL;
+    }
+
+    //
+    // free resources
+    //
+    ExFreePoolWithTag(Request, USB_STOR_TAG);
+    IoFreeMdl(Irp->MdlAddress);
+    IoFreeIrp(Irp);
+    return Status;
+}
+
+NTSTATUS
+USBSTOR_SendInquiryIrp(
+    IN PDEVICE_OBJECT PDODeviceObject)
+{
+    NTSTATUS Status;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PUFI_INQUIRY_RESPONSE Response;
+
+    //
+    // get device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
+
+    //
+    // send request
+    //
+    Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // command failed
+        //
+        DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status);
+        return Status;
+    }
+
+    DPRINT1("Response %p\n", Response);
+    DPRINT1("DeviceType %x\n", Response->DeviceType);
+    DPRINT1("RMB %x\n", Response->RMB);
+    DPRINT1("Version %x\n", Response->Version);
+    DPRINT1("Format %x\n", Response->Format);
+    DPRINT1("Length %x\n", Response->Length);
+    DPRINT1("Reserved %p\n", Response->Reserved);
+    DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]);
+    DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3],
+                                                          Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
+                                                          Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
+                                                          Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
+
+    DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
+
+    //
+    // store result
+    //
+    PDODeviceExtension->InquiryData = (PVOID)Response;
+    return Status;
+}
+
+NTSTATUS
+USBSTOR_SendFormatCapacityIrp(
+    IN PDEVICE_OBJECT PDODeviceObject)
+{
+    NTSTATUS Status;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PUCHAR Response;
+
+    //
+    // get device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
+
+    //
+    // send request
+    //
+    Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // command failed
+        //
+        return Status;
+    }
+
+    //
+    // check if its a floppy
+    //
+    PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode);
+
+    //
+    // free response
+    //
+    ExFreePoolWithTag(Response, USB_STOR_TAG);
+    return Status;
+}
+
+
+
+NTSTATUS
+USBSTOR_CreatePDO(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR LUN)
+{
+    PDEVICE_OBJECT PDO;
+    NTSTATUS Status;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PUFI_INQUIRY_RESPONSE Response;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+
+    //
+    // get device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+
+    //
+    // create child device object
+    //
+    Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to create device
+        //
+        return Status;
+    }
+
+    //
+    // patch the stack size
+    //
+    PDO->StackSize = DeviceObject->StackSize;
+
+    //
+    // get device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
+
+    //
+    // initialize device extension
+    //
+    RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
+    PDODeviceExtension->Common.IsFDO = FALSE;
+    PDODeviceExtension->LowerDeviceObject = DeviceObject;
+    PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
+    PDODeviceExtension->Self = PDO;
+    PDODeviceExtension->LUN = LUN;
+
+    //
+    // set device flags
+    //
+    PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
+
+    //
+    // device is initialized
+    //
+    PDO->Flags &= ~DO_DEVICE_INITIALIZING;
+
+    //
+    // output device object
+    //
+    FDODeviceExtension->ChildPDO[LUN] = PDO;
+
+    //
+    // send inquiry command by irp
+    //
+    Status = USBSTOR_SendInquiryIrp(PDO);
+    ASSERT(Status == STATUS_SUCCESS);
+
+    //
+    // check response data
+    //
+    Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
+    ASSERT(Response);
+
+    if (Response->DeviceType == 0)
+    {
+        //
+        // check if it is a floppy
+        //
+        Status = USBSTOR_SendFormatCapacityIrp(PDO);
+
+        //
+        // display result
+        //
+        DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode);
+
+        //
+        // failing command is non critical
+        //
+        Status = STATUS_SUCCESS;
+    }
+
+    //
+    // done
+    //
+    return Status;
+}
diff --git a/drivers/usb/usbstor_new/queue.c b/drivers/usb/usbstor_new/queue.c
new file mode 100644 (file)
index 0000000..a945ab9
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/queue.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+VOID
+USBSTOR_QueueInitialize(
+    PFDO_DEVICE_EXTENSION FDODeviceExtension)
+{
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // initialize queue lock
+    //
+    KeInitializeSpinLock(&FDODeviceExtension->IrpListLock);
+
+    //
+    // initialize irp list head
+    //
+    InitializeListHead(&FDODeviceExtension->IrpListHead);
+
+    //
+    // initialize event
+    //
+    KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE);
+}
+
+VOID
+NTAPI
+USBSTOR_CancelIo(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  PIRP Irp)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // this IRP isn't in our list here
+    //  
+
+    //
+    // now release the cancel lock
+    //
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    //
+    // set cancel status
+    //
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+
+    //
+    // now cancel the irp
+    //
+    USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    //
+    // start the next one
+    //
+    USBSTOR_QueueNextRequest(DeviceObject);
+}
+
+VOID
+NTAPI
+USBSTOR_Cancel(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  PIRP Irp)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // acquire irp list lock
+    //
+    KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
+
+    //
+    // remove the irp from the list
+    //
+    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+
+    //
+    // release irp list lock
+    //
+    KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);    
+
+    //
+    // now release the cancel lock
+    //
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    //
+    // set cancel status
+    //
+    Irp->IoStatus.Status = STATUS_CANCELLED;
+
+    //
+    // now cancel the irp
+    //
+    USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    //
+    // start the next one
+    //
+    USBSTOR_QueueNextRequest(DeviceObject);
+}
+
+BOOLEAN
+USBSTOR_QueueAddIrp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PDRIVER_CANCEL OldDriverCancel;
+    KIRQL OldLevel;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    BOOLEAN IrpListFreeze;
+    BOOLEAN SrbProcessing;
+    PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
+    PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // mark irp pending
+    //
+    IoMarkIrpPending(Irp);
+
+    //
+    // acquire lock
+    //
+    KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
+
+    //
+    // check if there are irp pending
+    //
+    SrbProcessing = FDODeviceExtension->IrpPendingCount != 0;
+
+    if (SrbProcessing)
+    {
+        //
+        // add irp to queue
+        //
+        InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry);
+    }
+
+    //
+    // increment pending count
+    //
+    FDODeviceExtension->IrpPendingCount++;
+
+
+    //
+    // clear the no requests pending event
+    //
+    KeClearEvent(&FDODeviceExtension->NoPendingRequests);
+
+    //
+    // check if queue is freezed
+    //
+    IrpListFreeze = FDODeviceExtension->IrpListFreeze;
+
+    //
+    // release list lock
+    //
+    KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
+
+    //
+    // synchronize with cancellations by holding the cancel lock
+    //
+    IoAcquireCancelSpinLock(&Irp->CancelIrql);
+
+    //
+    // now set the driver cancel routine
+    //
+    if (SrbProcessing)
+    {
+        ASSERT(FDODeviceExtension->ActiveSrb != NULL);
+
+        OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel);
+    }
+    else
+    {
+        ASSERT(FDODeviceExtension->ActiveSrb == NULL);
+
+        FDODeviceExtension->ActiveSrb = Request;
+        OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo);
+    }
+
+    //
+    // check if the irp has already been cancelled
+    //
+    if (Irp->Cancel && OldDriverCancel == NULL)
+    {
+        //
+        // cancel irp
+        //
+        Irp->CancelRoutine(DeviceObject, Irp);
+
+        //
+        // irp was cancelled
+        //
+        return FALSE;
+    }
+
+    //
+    // release the cancel lock
+    //
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    //
+    // if list is freezed, dont start this packet
+    //
+    DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount);
+
+    return (IrpListFreeze || SrbProcessing);
+}
+
+PIRP
+USBSTOR_RemoveIrp(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    KIRQL OldLevel;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PLIST_ENTRY Entry;
+    PIRP Irp = NULL;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // acquire lock
+    //
+    KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
+
+    //
+    // check if list is empty
+    //
+    if (!IsListEmpty(&FDODeviceExtension->IrpListHead))
+    {
+        //
+        // remove entry
+        //
+        Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead);
+
+        //
+        // get offset to start of irp
+        //
+        Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
+    }
+
+    //
+    // release list lock
+    //
+    KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
+
+    //
+    // return result
+    //
+    return Irp;
+}
+
+VOID
+USBSTOR_QueueWaitForPendingRequests(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // perform the wait
+    //
+    KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+}
+
+VOID
+USBSTOR_QueueTerminateRequest(
+    IN PDEVICE_OBJECT FDODeviceObject,
+    IN PIRP Irp)
+{
+    KIRQL OldLevel;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
+    PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // acquire lock
+    //
+    KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
+
+    //
+    // decrement pending irp count
+    //
+    FDODeviceExtension->IrpPendingCount--;
+
+    //
+    // check if this was our current active SRB
+    //
+    if (FDODeviceExtension->ActiveSrb == Request)
+    {
+        //
+        // indicate processing is completed
+        //
+        FDODeviceExtension->ActiveSrb = NULL;
+    }
+
+    //
+    // Set the event if nothing else is pending
+    //
+    if (FDODeviceExtension->IrpPendingCount == 0 &&
+        FDODeviceExtension->ActiveSrb == NULL)
+    {
+        KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE);
+    }
+
+    //
+    // release lock
+    //
+    KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
+
+}
+
+VOID
+USBSTOR_QueueNextRequest(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PIRP Irp;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get pdo device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // check first if there's already a request pending or the queue is frozen
+    //
+    if (FDODeviceExtension->ActiveSrb != NULL ||
+        FDODeviceExtension->IrpListFreeze)
+    {
+        //
+        // no work to do yet
+        //
+        return;
+    }
+
+    //
+    // remove first irp from list
+    //
+    Irp = USBSTOR_RemoveIrp(DeviceObject);
+
+    //
+    // is there an irp pending
+    //
+    if (!Irp)
+    {
+        //
+        // no work to do
+        //
+        IoStartNextPacket(DeviceObject, TRUE);
+        return;
+    }
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get srb
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // sanity check
+    //
+    ASSERT(Request);
+
+    //
+    // set the active SRB
+    //
+    FDODeviceExtension->ActiveSrb = Request;
+
+    //
+    // start next packet
+    //
+    IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
+
+    //
+    // start next request
+    //
+    IoStartNextPacket(DeviceObject, TRUE);
+}
+
+VOID
+USBSTOR_QueueRelease(
+    IN PDEVICE_OBJECT DeviceObject)
+{
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PIRP Irp;
+    KIRQL OldLevel;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // acquire lock
+    //
+    KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
+
+    //
+    // clear freezed status
+    //
+    FDODeviceExtension->IrpListFreeze = FALSE;
+
+    //
+    // release irp list lock
+    //
+    KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
+
+    //
+    // grab newest irp
+    //
+    Irp = USBSTOR_RemoveIrp(DeviceObject);
+
+    //
+    // is there an irp
+    //
+    if (!Irp)
+    {
+        //
+        // no irp
+        //
+        return;
+    }
+
+    //
+    // get current irp stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get srb
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // start new packet
+    //
+    IoStartPacket(DeviceObject,
+                  Irp,
+                  &Request->QueueSortKey, 
+                  USBSTOR_CancelIo);
+}
+
+
+VOID
+NTAPI
+USBSTOR_StartIo(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    KIRQL OldLevel;
+    BOOLEAN ResetInProgress;
+
+    DPRINT("USBSTOR_StartIo\n");
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(FDODeviceExtension->Common.IsFDO);
+
+    //
+    // acquire cancel spinlock
+    //
+    IoAcquireCancelSpinLock(&OldLevel);
+
+    //
+    // set cancel routine to zero
+    //
+    IoSetCancelRoutine(Irp, NULL);
+
+    //
+    // check if the irp has been cancelled
+    //
+    if (Irp->Cancel)
+    {
+        //
+        // irp has been cancelled, release cancel spinlock
+        //
+        IoReleaseCancelSpinLock(OldLevel);
+
+        //
+        // irp is cancelled
+        //
+        Irp->IoStatus.Status = STATUS_CANCELLED;
+        Irp->IoStatus.Information = 0;
+
+        //
+        // terminate request
+        //
+        USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
+
+        //
+        // complete request
+        //
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        //
+        // queue next request
+        //
+        USBSTOR_QueueNextRequest(DeviceObject);
+
+        //
+        // done
+        //
+        return;
+    }
+
+    //
+    // release cancel spinlock
+    //
+    IoReleaseCancelSpinLock(OldLevel);
+
+    //
+    // acquire lock
+    //
+    KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
+
+    //
+    // check reset is in progress
+    //
+    ResetInProgress = FDODeviceExtension->ResetInProgress;
+    ASSERT(ResetInProgress == FALSE);
+
+    //
+    // release lock
+    //
+    KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
+
+    //
+    // get current irp stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get pdo device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+    //
+    // is a reset in progress
+    //
+    if (ResetInProgress)
+    {
+        //
+        // hard reset is in progress
+        //
+        Irp->IoStatus.Information = 0;
+        Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
+        USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return;
+    }
+
+    //
+    // execute scsi
+    //
+    USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp, 0);
+
+    //
+    // FIXME: handle error
+    //
+}
diff --git a/drivers/usb/usbstor_new/scsi.c b/drivers/usb/usbstor_new/scsi.c
new file mode 100644 (file)
index 0000000..ee5bfba
--- /dev/null
@@ -0,0 +1,1429 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/pdo.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+ *              Michael Martin (michael.martin@reactos.org)
+ *              Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+NTSTATUS
+USBSTOR_BuildCBW(
+    IN ULONG Tag,
+    IN ULONG DataTransferLength,
+    IN UCHAR LUN,
+    IN UCHAR CommandBlockLength,
+    IN PUCHAR CommandBlock,
+    IN OUT PCBW Control)
+{
+    //
+    // sanity check
+    //
+    ASSERT(CommandBlockLength <= 16);
+
+    //
+    // now initialize CBW
+    //
+    Control->Signature = CBW_SIGNATURE;
+    Control->Tag = Tag;
+    Control->DataTransferLength = DataTransferLength;
+    Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00;
+    Control->LUN = (LUN & MAX_LUN);
+    Control->CommandBlockLength = CommandBlockLength;
+
+    //
+    // copy command block
+    //
+    RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+PIRP_CONTEXT
+USBSTOR_AllocateIrpContext()
+{
+    PIRP_CONTEXT Context;
+
+    //
+    // allocate irp context
+    //
+    Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT));
+    if (!Context)
+    {
+        //
+        // no memory
+        //
+        return NULL;
+    }
+
+    //
+    // allocate cbw block
+    //
+    Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512);
+    if (!Context->cbw)
+    {
+        //
+        // no memory
+        //
+        FreeItem(Context);
+        return NULL;
+    }
+
+    //
+    // done
+    //
+    return Context;
+
+}
+
+BOOLEAN
+USBSTOR_IsCSWValid(
+    PIRP_CONTEXT Context)
+{
+    //
+    // sanity checks
+    //
+    if (Context->csw->Signature != CSW_SIGNATURE)
+    {
+        DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature);
+        return FALSE;
+    }
+
+    if (Context->csw->Tag != (ULONG)Context->csw)
+    {
+        DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag);
+        return FALSE;
+    }
+
+    if (Context->csw->Status != 0x00)
+    {
+        DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status);
+        return FALSE;
+    }
+
+    //
+    // CSW is valid
+    //
+    return TRUE;
+
+}
+
+NTSTATUS
+USBSTOR_QueueWorkItem(
+    PIRP_CONTEXT Context,
+    PIRP Irp)
+{
+    PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData;
+
+    //
+    // Allocate Work Item Data
+    //
+    ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG);
+    if (!ErrorHandlerWorkItemData)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // error handling started
+    //
+    Context->FDODeviceExtension->SrbErrorHandlingActive = TRUE;
+
+    //
+    // srb error handling finished
+    //
+    Context->FDODeviceExtension->TimerWorkQueueEnabled = FALSE;
+
+    //
+    // Initialize and queue the work item to handle the error
+    //
+    ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem,
+                         ErrorHandlerWorkItemRoutine,
+                         ErrorHandlerWorkItemData);
+
+    ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
+    ErrorHandlerWorkItemData->Context = Context;
+    ErrorHandlerWorkItemData->Irp = Irp;
+    ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
+
+    DPRINT1("Queuing WorkItemROutine\n");
+    ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue);
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
+
+NTSTATUS
+NTAPI
+USBSTOR_CSWCompletionRoutine(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Ctx)
+{
+    PIRP_CONTEXT Context;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+    PCDB pCDB;
+    PREAD_CAPACITY_DATA_EX CapacityDataEx;
+    PREAD_CAPACITY_DATA CapacityData;
+    PUFI_CAPACITY_RESPONSE Response;
+    NTSTATUS Status;
+
+    //
+    // access context
+    //
+    Context = (PIRP_CONTEXT)Ctx;
+
+    //
+    // is there a mdl
+    //
+    if (Context->TransferBufferMDL)
+    {
+        //
+        // is there an irp associated
+        //
+        if (Context->Irp)
+        {
+            //
+            // did we allocate the mdl
+            //
+            if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
+            {
+                //
+                // free mdl
+                //
+                IoFreeMdl(Context->TransferBufferMDL);
+            }
+        }
+        else
+        {
+            //
+            // free mdl
+            //
+            IoFreeMdl(Context->TransferBufferMDL);
+        }
+    }
+
+    DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);
+
+    if (!NT_SUCCESS(Irp->IoStatus.Information))
+    {
+        if (Context->ErrorIndex == 0)
+        {
+            //
+            // increment error index
+            //
+            Context->ErrorIndex = 1;
+
+            //
+            // clear stall and resend cbw
+            //
+            Status = USBSTOR_QueueWorkItem(Context, Irp);
+            ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+            return STATUS_MORE_PROCESSING_REQUIRED;
+        }
+
+        //
+        // perform reset recovery
+        //
+        Context->ErrorIndex = 2;
+        IoFreeIrp(Irp);
+        Status = USBSTOR_QueueWorkItem(Context, NULL);
+        ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
+
+    if (!USBSTOR_IsCSWValid(Context))
+    {
+        //
+        // perform reset recovery
+        //
+        Context->ErrorIndex = 2;
+        IoFreeIrp(Irp);
+        Status = USBSTOR_QueueWorkItem(Context, NULL);
+        ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
+
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+    ASSERT(Request);
+
+    Status = Irp->IoStatus.Status;
+
+    //
+    // get SCSI command data block
+    //
+    pCDB = (PCDB)Request->Cdb;
+    Request->SrbStatus = SRB_STATUS_SUCCESS;
+
+    //
+    // read capacity needs special work
+    //
+    if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+    {
+        //
+        // get output buffer
+        //
+        Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
+
+        //
+        // store in pdo
+        //
+        Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
+        Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
+
+        if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
+        {
+            //
+            // get input buffer
+            //
+            CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;
+
+            //
+            // set result
+            //
+            CapacityDataEx->BytesPerBlock = Response->BlockLength;
+            CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
+            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
+       }
+       else
+       {
+            //
+            // get input buffer
+            //
+            CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;
+
+            //
+            // set result
+            //
+            CapacityData->BytesPerBlock = Response->BlockLength;
+            CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
+            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
+       }
+
+       //
+       // free response
+       //
+       FreeItem(Context->TransferData);
+    }
+
+    //
+    // free cbw
+    //
+    FreeItem(Context->cbw);
+
+    //
+    // FIXME: check status
+    //
+    Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
+    Context->Irp->IoStatus.Information = Context->TransferDataLength;
+
+    //
+    // terminate current request
+    //
+    USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
+
+    //
+    // complete request
+    //
+    IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
+
+    //
+    // start next request
+    //
+    USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
+
+    //
+    // free our allocated irp
+    //
+    IoFreeIrp(Irp);
+
+    //
+    // free context
+    //
+    FreeItem(Context);
+
+    //
+    // done
+    //
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+VOID
+USBSTOR_SendCSW(
+    PIRP_CONTEXT Context,
+    PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+
+    //
+    // get next irp stack location
+    //
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    //
+    // now initialize the urb for sending the csw
+    //
+    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+                                           Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
+                                           Context->csw,
+                                           NULL,
+                                           512, //FIXME
+                                           USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+                                           NULL);
+
+    //
+    // initialize stack location
+    //
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
+    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+
+
+    //
+    // setup completion routine
+    //
+    IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+
+    //
+    // call driver
+    //
+    IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
+}
+
+
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
+
+NTSTATUS
+NTAPI
+USBSTOR_DataCompletionRoutine(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Ctx)
+{
+    PIRP_CONTEXT Context;
+    NTSTATUS Status;
+
+
+    DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
+
+    //
+    // access context
+    //
+    Context = (PIRP_CONTEXT)Ctx;
+
+    if (!NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        //
+        // clear stall and resend cbw
+        //
+        Context->ErrorIndex = 1;
+        Status = USBSTOR_QueueWorkItem(Context, Irp);
+        ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
+
+    //
+    // send csw
+    //
+    USBSTOR_SendCSW(Context, Irp);
+
+    //
+    // cancel completion
+    //
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+//
+// driver verifier
+//
+IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
+
+NTSTATUS
+NTAPI
+USBSTOR_CBWCompletionRoutine(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Ctx)
+{
+    PIRP_CONTEXT Context;
+    PIO_STACK_LOCATION IoStack;
+    UCHAR Code;
+    USBD_PIPE_HANDLE PipeHandle;
+
+    DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
+
+    //
+    // access context
+    //
+    Context = (PIRP_CONTEXT)Ctx;
+
+    //
+    // get next stack location
+    //
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    //
+    // is there data to be submitted
+    //
+    if (Context->TransferDataLength)
+    {
+        //
+        // get command code
+        //
+        Code = Context->cbw->CommandBlock[0];
+
+        if (Code == SCSIOP_WRITE)
+        {
+            //
+            // write request use bulk out pipe
+            //
+            PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
+        }
+        else
+        {
+            //
+            // default bulk in pipe
+            //
+            PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
+        }
+
+        //
+        // now initialize the urb for sending data
+        //
+        UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+                                               sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+                                               PipeHandle,
+                                               NULL,
+                                               Context->TransferBufferMDL,
+                                               Context->TransferDataLength,
+                                               ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
+                                               NULL);
+
+        //
+        // setup completion routine
+        //
+        IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
+    }
+    else
+    {
+        //
+        // now initialize the urb for sending the csw
+        //
+
+        UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+                                               sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+                                               Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
+                                               Context->csw,
+                                               NULL,
+                                               512, //FIXME
+                                               USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
+                                               NULL);
+
+        //
+        // setup completion routine
+        //
+        IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+    }
+
+    //
+    // initialize stack location
+    //
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
+    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+
+    //
+    // call driver
+    //
+    IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
+
+    return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+VOID
+DumpCBW(
+    PUCHAR Block)
+{
+    DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+        Block[0] & 0xFF, Block[1] & 0xFF, Block[2] & 0xFF, Block[3] & 0xFF, Block[4] & 0xFF, Block[5] & 0xFF, Block[6] & 0xFF, Block[7] & 0xFF, Block[8] & 0xFF, Block[9] & 0xFF,
+        Block[10] & 0xFF, Block[11] & 0xFF, Block[12] & 0xFF, Block[13] & 0xFF, Block[14] & 0xFF, Block[15] & 0xFF, Block[16] & 0xFF, Block[17] & 0xFF, Block[18] & 0xFF, Block[19] & 0xFF,
+        Block[20] & 0xFF, Block[21] & 0xFF, Block[22] & 0xFF, Block[23] & 0xFF, Block[24] & 0xFF, Block[25] & 0xFF, Block[26] & 0xFF, Block[27] & 0xFF, Block[28] & 0xFF, Block[29] & 0xFF,
+        Block[30] & 0xFF);
+
+}
+
+NTSTATUS
+USBSTOR_SendCBW(
+    PIRP_CONTEXT Context,
+    PIRP Irp)
+{
+    PIO_STACK_LOCATION IoStack;
+
+    //
+    // get next stack location
+    //
+    IoStack = IoGetNextIrpStackLocation(Irp);
+
+    //
+    // initialize stack location
+    //
+    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
+    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+
+    //
+    // setup completion routine
+    //
+    IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+
+    //
+    // call driver
+    //
+    return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
+}
+
+NTSTATUS
+USBSTOR_SendRequest(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP OriginalRequest,
+    IN UCHAR CommandLength,
+    IN PUCHAR Command,
+    IN ULONG TransferDataLength,
+    IN PUCHAR TransferData,
+    IN ULONG RetryCount)
+{
+    PIRP_CONTEXT Context;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PIRP Irp;
+    PUCHAR MdlVirtualAddress;
+
+    //
+    // first allocate irp context
+    //
+    Context = USBSTOR_AllocateIrpContext();
+    if (!Context)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // get FDO device extension
+    //
+    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
+
+    //
+    // now build the cbw
+    //
+    USBSTOR_BuildCBW((ULONG)Context->cbw,
+                     TransferDataLength,
+                     PDODeviceExtension->LUN,
+                     CommandLength,
+                     Command,
+                     Context->cbw);
+
+    DPRINT("CBW %p\n", Context->cbw);
+    DumpCBW((PUCHAR)Context->cbw);
+
+    //
+    // now initialize the urb
+    //
+    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
+                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
+                                           FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
+                                           Context->cbw,
+                                           NULL,
+                                           sizeof(CBW),
+                                           USBD_TRANSFER_DIRECTION_OUT,
+                                           NULL);
+
+    //
+    // initialize rest of context
+    //
+    Context->Irp = OriginalRequest;
+    Context->TransferData = TransferData;
+    Context->TransferDataLength = TransferDataLength;
+    Context->FDODeviceExtension = FDODeviceExtension;
+    Context->PDODeviceExtension = PDODeviceExtension;
+    Context->RetryCount = RetryCount;
+
+    //
+    // is there transfer data
+    //
+    if (Context->TransferDataLength)
+    {
+        //
+        // check if the original request already does have an mdl associated
+        //
+        if (OriginalRequest)
+        {
+            if ((OriginalRequest->MdlAddress != NULL) &&
+                (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
+            {
+                //
+                // Sanity check that the Mdl does describe the TransferData for read/write
+                //
+                if (CommandLength == UFI_READ_WRITE_CMD_LEN)
+                {
+                    MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
+
+                    //
+                    // is there an offset
+                    //
+                    if (MdlVirtualAddress != Context->TransferData)
+                    {
+                        //
+                        // lets build an mdl
+                        //
+                        Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
+                        if (!Context->TransferBufferMDL)
+                        {
+                            //
+                            // failed to allocate MDL
+                            //
+                            FreeItem(Context->cbw);
+                            FreeItem(Context);
+                            return STATUS_INSUFFICIENT_RESOURCES;
+                        }
+
+                        //
+                        // now build the partial mdl
+                        //
+                        IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
+                    }
+                }
+
+                if (!Context->TransferBufferMDL)
+                {
+                    //
+                    // I/O paging request
+                    //
+                    Context->TransferBufferMDL = OriginalRequest->MdlAddress;
+                }
+            }
+            else
+            {
+                //
+                // allocate mdl for buffer, buffer must be allocated from NonPagedPool
+                //
+                Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
+                if (!Context->TransferBufferMDL)
+                {
+                    //
+                    // failed to allocate MDL
+                    //
+                    FreeItem(Context->cbw);
+                    FreeItem(Context);
+                    return STATUS_INSUFFICIENT_RESOURCES;
+                }
+
+                //
+                // build mdl for nonpaged pool
+                //
+                MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
+            }
+        }
+        else
+        {
+            //
+            // allocate mdl for buffer, buffer must be allocated from NonPagedPool
+            //
+            Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
+            if (!Context->TransferBufferMDL)
+            {
+                //
+                // failed to allocate MDL
+                //
+                FreeItem(Context->cbw);
+                FreeItem(Context);
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            //
+            // build mdl for nonpaged pool
+            //
+            MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
+        }
+    }
+
+    //
+    // now allocate the request
+    //
+    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
+    if (!Irp)
+    {
+        FreeItem(Context->cbw);
+        FreeItem(Context);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (OriginalRequest)
+    {
+        //
+        // mark orignal irp as pending
+        //
+        IoMarkIrpPending(OriginalRequest);
+    }
+
+    //
+    // send request
+    //
+    USBSTOR_SendCBW(Context, Irp);
+
+    //
+    // done
+    //
+    return STATUS_PENDING;
+}
+
+NTSTATUS
+USBSTOR_SendFormatCapacity(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount)
+{
+    UFI_READ_FORMAT_CAPACITY Cmd;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // initialize inquiry cmd
+    //
+    RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY));
+    Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY;
+    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+    Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8;
+    Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF;
+
+    //
+    // now send the request
+    //
+    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
+}
+
+NTSTATUS
+USBSTOR_SendInquiry(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount)
+{
+    UFI_INQUIRY_CMD Cmd;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // initialize inquiry cmd
+    //
+    RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
+    Cmd.Code = SCSIOP_INQUIRY;
+    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+    Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
+
+    //
+    // sanity check
+    //
+    ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE));
+
+    //
+    // now send the request
+    //
+    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
+}
+
+NTSTATUS
+USBSTOR_SendCapacity(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount)
+{
+    UFI_CAPACITY_CMD Cmd;
+    PUFI_CAPACITY_RESPONSE Response;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // allocate capacity response
+    //
+    Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE);
+    if (!Response)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // initialize capacity cmd
+    //
+    RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
+    Cmd.Code = SCSIOP_READ_CAPACITY;
+    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+
+    //
+    // send request, response will be freed in completion routine
+    //
+    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount);
+}
+
+NTSTATUS
+USBSTOR_SendModeSense(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount)
+{
+#if 0
+    UFI_SENSE_CMD Cmd;
+    NTSTATUS Status;
+    PVOID Response;
+    PCBW OutControl;
+    PCDB pCDB;
+    PUFI_MODE_PARAMETER_HEADER Header;
+#endif
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
+    Request->SrbStatus = SRB_STATUS_SUCCESS;
+    Irp->IoStatus.Information = Request->DataTransferLength;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    //
+    // start next request
+    //
+    USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+
+    return STATUS_SUCCESS;
+
+#if 0
+    //
+    // get SCSI command data block
+    //
+    pCDB = (PCDB)Request->Cdb;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // allocate sense response from non paged pool
+    //
+    Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
+    if (!Response)
+    {
+        //
+        // no memory
+        //
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    //
+    // sanity check
+    //
+
+
+    // Supported pages
+    // MODE_PAGE_ERROR_RECOVERY
+    // MODE_PAGE_FLEXIBILE
+    // MODE_PAGE_LUN_MAPPING
+    // MODE_PAGE_FAULT_REPORTING
+    // MODE_SENSE_RETURN_ALL
+
+    //
+    // initialize mode sense cmd
+    //
+    RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
+    Cmd.Code = SCSIOP_MODE_SENSE;
+    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+    Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
+    Cmd.PC = pCDB->MODE_SENSE.Pc;
+    Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
+
+    DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
+    DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
+
+    //
+    // now send mode sense cmd
+    //
+    Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to send CBW
+        //
+        DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
+        FreeItem(Response);
+        ASSERT(FALSE);
+        return Status;
+    }
+
+    //
+    // now send data block response
+    //
+    Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
+    if (!NT_SUCCESS(Status))
+    {
+        //
+        // failed to send CBW
+        //
+        DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
+        FreeItem(Response);
+        ASSERT(FALSE);
+        return Status;
+    }
+
+    Header = (PUFI_MODE_PARAMETER_HEADER)Response;
+
+    //
+    // TODO: build layout
+    //
+    // first struct is the header
+    // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
+    //
+    // followed by
+    // MODE_PARAMETER_BLOCK
+    //
+    //
+    UNIMPLEMENTED;
+
+    //
+    // send csw
+    //
+    Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
+
+    DPRINT1("------------------------\n");
+    DPRINT1("CSW %p\n", &CSW);
+    DPRINT1("Signature %x\n", CSW.Signature);
+    DPRINT1("Tag %x\n", CSW.Tag);
+    DPRINT1("DataResidue %x\n", CSW.DataResidue);
+    DPRINT1("Status %x\n", CSW.Status);
+
+    //
+    // FIXME: handle error
+    //
+    ASSERT(CSW.Status == 0);
+    ASSERT(CSW.DataResidue == 0);
+
+    //
+    // calculate transfer length
+    //
+    *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
+
+    //
+    // copy buffer
+    //
+    RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
+
+    //
+    // free item
+    //
+    FreeItem(OutControl);
+
+    //
+    // free response
+    //
+    FreeItem(Response);
+
+    //
+    // done
+    //
+    return Status;
+#endif
+}
+
+NTSTATUS
+USBSTOR_SendReadWrite(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount)
+{
+    UFI_READ_WRITE_CMD Cmd;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PCDB pCDB;
+    ULONG BlockCount, Temp;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // get SCSI command data block
+    //
+    pCDB = (PCDB)Request->Cdb;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // informal debug print
+    //
+    DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->BlockLength);
+
+    //
+    // block count
+    //
+    BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
+
+    //
+    // initialize read cmd
+    //
+    RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
+    Cmd.Code = pCDB->AsByte[0];
+    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+    Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
+    Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
+    Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
+    Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
+    Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
+    Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
+
+    //
+    // sanity check
+    //
+    Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1);
+    ASSERT(Temp == BlockCount);
+
+    DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
+
+    //
+    // send request
+    //
+    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
+}
+
+NTSTATUS
+USBSTOR_SendTestUnit(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp,
+    IN ULONG RetryCount)
+{
+    UFI_TEST_UNIT_CMD Cmd;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // no transfer length
+    //
+    ASSERT(Request->DataTransferLength == 0);
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // initialize test unit cmd
+    //
+    RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
+    Cmd.Code = SCSIOP_TEST_UNIT_READY;
+    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
+
+    //
+    // send the request
+    //
+    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount);
+}
+
+NTSTATUS
+USBSTOR_SendUnknownRequest(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp,
+    IN ULONG RetryCount)
+{
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+    UFI_UNKNOWN_CMD Cmd;
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = IoStack->Parameters.Others.Argument1;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // check that we're sending to the right LUN
+    //
+    ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN));
+
+    //
+    // sanity check
+    //
+    ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD));
+
+    //
+    // initialize test unit cmd
+    //
+    RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength);
+
+    //
+    // send the request
+    //
+    return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount);
+}
+
+NTSTATUS
+USBSTOR_HandleExecuteSCSI(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount)
+{
+    PCDB pCDB;
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+    //
+    // get current stack location
+    //
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+    //
+    // get request block
+    //
+    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+
+    //
+    // get SCSI command data block
+    //
+    pCDB = (PCDB)Request->Cdb;
+
+    DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
+
+    if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+    {
+        //
+        // sanity checks
+        //
+        ASSERT(Request->DataBuffer);
+
+        DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength);
+        Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount);
+    }
+    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
+    {
+        DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
+        ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
+        ASSERT(Request->DataBuffer);
+
+        //
+        // send mode sense command
+        //
+        Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount);
+    }
+    else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY)
+    {
+        DPRINT("SCSIOP_READ_FORMATTED_CAPACITY DataTransferLength %lu\n", Request->DataTransferLength);
+
+        //
+        // send read format capacity
+        //
+        Status = USBSTOR_SendFormatCapacity(DeviceObject, Irp, RetryCount);
+    }
+    else if (pCDB->AsByte[0] == SCSIOP_INQUIRY)
+    {
+        DPRINT("SCSIOP_INQUIRY DataTransferLength %lu\n", Request->DataTransferLength);
+
+        //
+        // send read format capacity
+        //
+        Status = USBSTOR_SendInquiry(DeviceObject, Irp, RetryCount);
+    }
+    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ ||  pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
+    {
+        DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
+
+        //
+        // send read / write command
+        //
+        Status = USBSTOR_SendReadWrite(DeviceObject, Irp, RetryCount);
+    }
+    else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
+    {
+        DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
+
+        //
+        // just complete the request
+        //
+        Request->SrbStatus = SRB_STATUS_SUCCESS;
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = Request->DataTransferLength;
+        USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        //
+        // start next request
+        //
+        USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+
+        return STATUS_SUCCESS;
+    }
+    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
+    {
+        DPRINT("SCSIOP_TEST_UNIT_READY\n");
+
+        //
+        // send test unit command
+        //
+        Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount);
+    }
+    else
+    {
+        // Unknown request. Simply forward
+        DPRINT1("Forwarding unknown Operation Code %x\n", pCDB->AsByte[0]);
+        Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount);
+    }
+
+    return Status;
+}
diff --git a/drivers/usb/usbstor_new/usbstor.c b/drivers/usb/usbstor_new/usbstor.c
new file mode 100644 (file)
index 0000000..b13969e
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        drivers/usb/usbstor/usbstor.c
+ * PURPOSE:     USB block storage device driver.
+ * PROGRAMMERS:
+ *              James Tabor
+                Johannes Anderwald
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "usbstor.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* PUBLIC AND PRIVATE FUNCTIONS **********************************************/
+
+NTSTATUS
+NTAPI
+USBSTOR_AddDevice(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDEVICE_OBJECT PhysicalDeviceObject)
+{
+    NTSTATUS Status;
+    PDEVICE_OBJECT DeviceObject;
+    PFDO_DEVICE_EXTENSION DeviceExtension;
+
+    //
+    // lets create the device
+    //
+    Status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_EXTENSION), 0, FILE_DEVICE_BUS_EXTENDER, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject);
+
+    //
+    // check for success
+    //
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("USBSTOR_AddDevice: Failed to create FDO Status %x\n", Status);
+        return Status;
+    }
+
+    //
+    // get device extension
+    //
+    DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(DeviceExtension);
+
+    //
+    // zero device extension
+    //
+    RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
+
+    //
+    // initialize device extension
+    //
+    DeviceExtension->Common.IsFDO = TRUE;
+    DeviceExtension->FunctionalDeviceObject = DeviceObject;
+    DeviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
+    DeviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
+
+    //
+    // init timer
+    //
+    IoInitializeTimer(DeviceObject, USBSTOR_TimerRoutine, (PVOID)DeviceExtension);
+
+    //
+    // did attaching fail
+    //
+    if (!DeviceExtension->LowerDeviceObject)
+    {
+        //
+        // device removed
+        //
+        IoDeleteDevice(DeviceObject);
+
+        return STATUS_DEVICE_REMOVED;
+    }
+
+    //
+    // set device flags
+    //
+    DeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
+
+    //
+    // device is initialized
+    //
+    DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+
+    //
+    // done
+    //
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+USBSTOR_Unload(
+    PDRIVER_OBJECT DriverObject)
+{
+    //
+    // no-op
+    //
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_DispatchClose(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    //
+    // function always succeeds ;)
+    //
+    DPRINT("USBSTOR_DispatchClose\n");
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+NTAPI
+USBSTOR_DispatchDeviceControl(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    NTSTATUS Status;
+
+    //
+    // handle requests
+    //
+    Status = USBSTOR_HandleDeviceControl(DeviceObject, Irp);
+
+    //
+    // complete request
+    //
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    //
+    // done
+    //
+    return Status;
+}
+
+
+NTSTATUS
+NTAPI
+USBSTOR_DispatchScsi(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    //
+    // handle requests
+    //
+    return USBSTOR_HandleInternalDeviceControl(DeviceObject, Irp);
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_DispatchReadWrite(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    //
+    // read write ioctl is not supported
+    //
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_INVALID_PARAMETER;
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_DispatchPnp(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    PUSBSTOR_COMMON_DEVICE_EXTENSION DeviceExtension;
+
+    //
+    // get common device extension
+    //
+    DeviceExtension = (PUSBSTOR_COMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // is it for the FDO
+    //
+    if (DeviceExtension->IsFDO)
+    {
+        //
+        // dispatch pnp request to fdo pnp handler
+        //
+        return USBSTOR_FdoHandlePnp(DeviceObject, Irp);
+    }
+    else
+    {
+        //
+        // dispatch request to pdo pnp handler
+        //
+        return USBSTOR_PdoHandlePnp(DeviceObject, Irp);
+    }
+}
+
+NTSTATUS
+NTAPI
+USBSTOR_DispatchPower(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    PFDO_DEVICE_EXTENSION DeviceExtension;
+
+    // get common device extension
+    DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    if (DeviceExtension->Common.IsFDO)
+    {
+        PoStartNextPowerIrp(Irp);
+        IoSkipCurrentIrpStackLocation(Irp);
+        return PoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
+    }
+    else
+    {
+        PoStartNextPowerIrp(Irp);
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_SUCCESS;
+    }
+}
+
+
+
+NTSTATUS
+NTAPI
+DriverEntry(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PUNICODE_STRING RegPath)
+{
+
+    DPRINT("********* USB Storage *********\n");
+
+    //
+    // driver unload routine
+    //
+    DriverObject->DriverUnload = USBSTOR_Unload;
+
+    //
+    // add device function
+    //
+    DriverObject->DriverExtension->AddDevice = USBSTOR_AddDevice;
+
+    //
+    // driver start i/o routine
+    //
+    DriverObject->DriverStartIo = USBSTOR_StartIo;
+
+    //
+    // create / close
+    //
+    DriverObject->MajorFunction[IRP_MJ_CREATE] = USBSTOR_DispatchClose;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE] = USBSTOR_DispatchClose;
+
+    //
+    // scsi pass through requests
+    //
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = USBSTOR_DispatchDeviceControl;
+
+    //
+    // irp dispatch read / write
+    //
+    DriverObject->MajorFunction[IRP_MJ_READ] = USBSTOR_DispatchReadWrite;
+    DriverObject->MajorFunction[IRP_MJ_WRITE] = USBSTOR_DispatchReadWrite;
+
+    //
+    // scsi queue ioctl
+    //
+    DriverObject->MajorFunction[IRP_MJ_SCSI] = USBSTOR_DispatchScsi;
+
+    //
+    // pnp processing
+    //
+    DriverObject->MajorFunction[IRP_MJ_PNP] = USBSTOR_DispatchPnp;
+
+    //
+    // power processing
+    //
+    DriverObject->MajorFunction[IRP_MJ_POWER] = USBSTOR_DispatchPower;
+
+    return STATUS_SUCCESS;
+}
diff --git a/drivers/usb/usbstor_new/usbstor.h b/drivers/usb/usbstor_new/usbstor.h
new file mode 100644 (file)
index 0000000..f477e9a
--- /dev/null
@@ -0,0 +1,550 @@
+#ifndef _USBSTOR_H_
+#define _USBSTOR_H_
+
+#include <wdm.h>
+#include <usbdi.h>
+#include <usbbusif.h>
+#include <usbdlib.h>
+#include <classpnp.h>
+
+#define USB_STOR_TAG 'sbsu'
+#define USB_MAXCHILDREN              (16)
+
+#define HTONS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
+#define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8))
+
+#define HTONL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \
+                  ((((unsigned long)(n) & 0xFF00)) << 8) | \
+                  ((((unsigned long)(n) & 0xFF0000)) >> 8) | \
+                  ((((unsigned long)(n) & 0xFF000000)) >> 24))
+
+
+#define NTOHL(n) (((((unsigned long)(n) & 0xFF)) << 24) | \
+                  ((((unsigned long)(n) & 0xFF00)) << 8) | \
+                  ((((unsigned long)(n) & 0xFF0000)) >> 8) | \
+                  ((((unsigned long)(n) & 0xFF000000)) >> 24))
+
+#define USB_RECOVERABLE_ERRORS (USBD_STATUS_STALL_PID | USBD_STATUS_DEV_NOT_RESPONDING \
+       | USBD_STATUS_ENDPOINT_HALTED | USBD_STATUS_NO_BANDWIDTH)
+
+typedef struct __COMMON_DEVICE_EXTENSION__
+{
+    BOOLEAN IsFDO;
+
+}USBSTOR_COMMON_DEVICE_EXTENSION, *PUSBSTOR_COMMON_DEVICE_EXTENSION;
+
+typedef struct
+{
+    USBSTOR_COMMON_DEVICE_EXTENSION Common;                                                      // common device extension
+
+    PDEVICE_OBJECT FunctionalDeviceObject;                                               // functional device object
+    PDEVICE_OBJECT PhysicalDeviceObject;                                                 // physical device object
+    PDEVICE_OBJECT LowerDeviceObject;                                                    // lower device object
+    USB_BUS_INTERFACE_USBDI_V2 BusInterface;                                             // bus interface of device
+    PUSB_DEVICE_DESCRIPTOR DeviceDescriptor;                                             // usb device descriptor
+    PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;                               // usb configuration descriptor
+    PUSB_STRING_DESCRIPTOR SerialNumber;                                                 // usb serial number
+    PUSBD_INTERFACE_INFORMATION InterfaceInformation;                                    // usb interface information
+    USBD_CONFIGURATION_HANDLE ConfigurationHandle;                                       // usb configuration handle
+    UCHAR BulkInPipeIndex;                                                               // bulk in pipe index
+    UCHAR BulkOutPipeIndex;                                                              // bulk out pipe index
+    UCHAR MaxLUN;                                                                        // max lun for device
+    PDEVICE_OBJECT ChildPDO[16];                                                         // max 16 child pdo devices
+    KSPIN_LOCK IrpListLock;                                                              // irp list lock
+    LIST_ENTRY IrpListHead;                                                              // irp list head
+    BOOLEAN IrpListFreeze;                                                               // if true the irp list is freezed
+    BOOLEAN ResetInProgress;                                                             // if hard reset is in progress
+    ULONG IrpPendingCount;                                                               // count of irp pending
+    PSCSI_REQUEST_BLOCK ActiveSrb;                                                       // stores the current active SRB
+    KEVENT NoPendingRequests;                                                            // set if no pending or in progress requests
+    PSCSI_REQUEST_BLOCK LastTimerActiveSrb;                                              // last timer tick active srb
+    ULONG SrbErrorHandlingActive;                                                        // error handling of srb is activated
+    ULONG TimerWorkQueueEnabled;                                                         // timer work queue enabled
+    ULONG InstanceCount;                                                                 // pdo instance count
+}FDO_DEVICE_EXTENSION, *PFDO_DEVICE_EXTENSION;
+
+typedef struct
+{
+    USBSTOR_COMMON_DEVICE_EXTENSION Common;
+    PDEVICE_OBJECT LowerDeviceObject;                                                    // points to FDO
+    UCHAR LUN;                                                                           // lun id
+    PVOID InquiryData;                                                                   // USB SCSI inquiry data
+    PUCHAR FormatData;                                                                   // USB SCSI Read Format Capacity Data
+    UCHAR Claimed;                                                                       // indicating if it has been claimed by upper driver
+    ULONG BlockLength;                                                                   // length of block
+    ULONG LastLogicBlockAddress;                                                         // last block address
+    PDEVICE_OBJECT *PDODeviceObject;                                                     // entry in pdo list
+    PDEVICE_OBJECT Self;                                                                 // self
+    UCHAR MediumTypeCode;                                                                // floppy medium type code
+    UCHAR IsFloppy;                                                                      // is device floppy
+}PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
+
+//
+// max lun command identifier
+//
+#define USB_BULK_GET_MAX_LUN             0xFE
+#define USB_BULK_RESET_DEVICE             0xFF
+
+#include <pshpack1.h>
+typedef struct
+{
+    ULONG Signature;                                                 // CBW signature
+    ULONG Tag;                                                       // CBW Tag of operation
+    ULONG DataTransferLength;                                        // data transfer length
+    UCHAR Flags;                                                     // CBW Flags endpoint direction
+    UCHAR LUN;                                                       // lun unit
+    UCHAR CommandBlockLength;                                        // Command block length
+    UCHAR CommandBlock[16];
+}CBW, *PCBW;
+
+C_ASSERT(sizeof(CBW) == 31);
+
+
+#define CBW_SIGNATURE 0x43425355
+#define CSW_SIGNATURE 0x53425355
+
+#define MAX_LUN 0xF
+
+typedef struct
+{
+    ULONG Signature;                                                 // CSW signature
+    ULONG Tag;                                                       // CSW tag
+    ULONG DataResidue;                                               // CSW data transfer diff
+    UCHAR Status;                                                    // CSW status
+}CSW, *PCSW;
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+//
+// UFI INQUIRY command
+//
+typedef struct
+{
+    UCHAR Code;                                                      // operation code 0x12
+    UCHAR LUN;                                                       // lun address
+    UCHAR PageCode;                                                  // product data information, always 0x00
+    UCHAR Reserved;                                                  // reserved 0x00
+    UCHAR AllocationLength;                                          // length of inquiry data to be returned, default 36 bytes
+    UCHAR Reserved1[7];                                              //reserved bytes 0x00
+}UFI_INQUIRY_CMD, *PUFI_INQUIRY_CMD;
+
+C_ASSERT(sizeof(UFI_INQUIRY_CMD) == 12);
+
+#define UFI_INQUIRY_CMD_LEN 0x6
+
+//
+// UFI INQUIRY command response
+//
+typedef struct
+{
+    UCHAR DeviceType;                                                // device type
+    UCHAR RMB;                                                       // removable media bit
+    UCHAR Version;                                                   // contains version 0x00
+    UCHAR Format;                                                    // response format
+    UCHAR Length;                                                    // additional length
+    UCHAR Reserved[3];                                               // reserved
+    UCHAR Vendor[8];                                                 // vendor identification string
+    UCHAR Product[16];                                               // product identification string
+    UCHAR Revision[4];                                               // product revision code
+}UFI_INQUIRY_RESPONSE, *PUFI_INQUIRY_RESPONSE;
+
+C_ASSERT(sizeof(UFI_INQUIRY_RESPONSE) == 36);
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+//
+// UFI read cmd
+//
+typedef struct
+{
+    UCHAR Code;                                                      // operation code
+    UCHAR LUN;                                                       // lun
+    UCHAR LogicalBlockByte0;                                         // lba byte 0
+    UCHAR LogicalBlockByte1;                                         // lba byte 1
+    UCHAR LogicalBlockByte2;                                         // lba byte 2
+    UCHAR LogicalBlockByte3;                                         // lba byte 3
+    UCHAR Reserved;                                                  // reserved 0x00
+    UCHAR ContiguousLogicBlocksByte0;                                // msb contiguous logic blocks byte
+    UCHAR ContiguousLogicBlocksByte1;                                // msb contiguous logic blocks
+    UCHAR Reserved1[3];                                              // reserved 0x00
+}UFI_READ_WRITE_CMD;
+
+C_ASSERT(sizeof(UFI_READ_WRITE_CMD) == 12);
+
+#define UFI_READ_WRITE_CMD_LEN (0xA)
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+//
+// UFI read capacity cmd
+//
+typedef struct
+{
+    UCHAR Code;                                                      // operation code 0x25
+    UCHAR LUN;                                                       // lun address
+    UCHAR LBA[4];                                                   // logical block address, should be zero
+    UCHAR Reserved1[2];                                              // reserved 0x00
+    UCHAR PMI;                                                       // PMI = 0x00
+    UCHAR Reserved2[3];                                              // reserved 0x00
+}UFI_CAPACITY_CMD, *PUFI_CAPACITY_CMD;
+
+C_ASSERT(sizeof(UFI_CAPACITY_CMD) == 12);
+
+#define UFI_CAPACITY_CMD_LEN 0xA //FIXME support length 16 too if requested
+
+//
+// UFI Read Capacity command response
+//
+typedef struct
+{
+    ULONG LastLogicalBlockAddress;                                   // last logical block address
+    ULONG BlockLength;                                               // block length in bytes
+}UFI_CAPACITY_RESPONSE, *PUFI_CAPACITY_RESPONSE;
+
+#define UFI_READ_CAPACITY_CMD_LEN 0xA
+C_ASSERT(sizeof(UFI_CAPACITY_RESPONSE) == 8);
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+//
+// UFI sense mode cmd
+//
+typedef struct
+{
+    UCHAR Code;                                                      // operation code
+    UCHAR LUN;                                                       // lun address
+    UCHAR PageCode:6;                                                // page code selector
+    UCHAR PC:2;                                                      // type of parameters to be returned
+    UCHAR Reserved[4];                                               // reserved 0x00
+    USHORT AllocationLength;                                         // parameters length
+    UCHAR Reserved1[3];
+}UFI_SENSE_CMD, *PUFI_SENSE_CMD;
+
+C_ASSERT(sizeof(UFI_SENSE_CMD) == 12);
+
+#define UFI_SENSE_CMD_LEN (6)
+
+typedef struct
+{
+    USHORT ModeDataLength;                                           // length of parameters for sense cmd
+    UCHAR MediumTypeCode;                                            // 00 for mass storage, 0x94 for floppy
+    UCHAR WP:1;                                                      // write protect bit
+    UCHAR Reserved1:2;                                                // reserved 00
+    UCHAR DPOFUA:1;                                                  // should be zero
+    UCHAR Reserved2:4;                                               // reserved
+    UCHAR Reserved[4];                                               // reserved
+}UFI_MODE_PARAMETER_HEADER, *PUFI_MODE_PARAMETER_HEADER;
+
+
+C_ASSERT(sizeof(UFI_MODE_PARAMETER_HEADER) == 8);
+
+typedef struct
+{
+    UCHAR PC;
+    UCHAR PageLength;
+    UCHAR Reserved1;
+    UCHAR ITM;
+    UCHAR Flags;
+    UCHAR Reserved[3];
+}UFI_TIMER_PROTECT_PAGE, *PUFI_TIMER_PROTECT_PAGE;
+C_ASSERT(sizeof(UFI_TIMER_PROTECT_PAGE) == 8);
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+//
+// UFI read capacity cmd
+//
+
+typedef struct
+{
+    UCHAR Code;
+    UCHAR LUN;
+    UCHAR Reserved[5];
+    UCHAR AllocationLengthMsb;
+    UCHAR AllocationLengthLsb;
+    UCHAR Reserved1[3];
+}UFI_READ_FORMAT_CAPACITY, *PUFI_READ_FORMAT_CAPACITY;
+
+C_ASSERT(sizeof(UFI_READ_FORMAT_CAPACITY) == 12);
+
+#define UFI_READ_FORMAT_CAPACITY_CMD_LEN (10)
+
+typedef struct
+{
+    UCHAR Reserved1;
+    UCHAR Reserved2;
+    UCHAR Reserved3;
+    UCHAR CapacityLength;
+}UFI_CAPACITY_FORMAT_HEADER, *PUFI_CAPACITY_FORMAT_HEADER;
+
+C_ASSERT(sizeof(UFI_CAPACITY_FORMAT_HEADER) == 4);
+
+typedef struct
+{
+    ULONG BlockCount;
+    UCHAR Code;
+    UCHAR BlockLengthByte0;
+    UCHAR BlockLengthByte1;
+    UCHAR BlockLengthByte2;
+}UFI_CAPACITY_DESCRIPTOR, *PUFI_CAPACITY_DESCRIPTOR;
+
+#define UNFORMATTED_MEDIA_CODE_DESCRIPTORY_TYPE (1)
+#define FORMAT_MEDIA_CODE_DESCRIPTOR_TYPE      (2)
+#define CARTRIDGE_MEDIA_CODE_DESCRIPTOR_TYPE   (3)
+
+
+
+
+//--------------------------------------------------------------------------------------------------------------------------------------------
+//
+// UFI test unit command
+//
+
+typedef struct
+{
+    UCHAR Code;                                                       // operation code 0x00
+    UCHAR LUN;                                                        // lun
+    UCHAR Reserved[10];                                               // reserved 0x00
+}UFI_TEST_UNIT_CMD, *PUFI_TEST_UNIT_CMD;
+
+C_ASSERT(sizeof(UFI_TEST_UNIT_CMD) == 12);
+
+#define UFI_TEST_UNIT_CMD_LEN (6)
+
+//-------------------------------------------------------------------------------------------------------------------------------------------
+typedef struct
+{
+    UCHAR Bytes[16];
+}UFI_UNKNOWN_CMD, *PUFI_UNKNOWN_CMD;
+
+typedef struct
+{
+    union
+    {
+        PCBW cbw;
+        PCSW csw;
+    };
+    URB Urb;
+    PIRP Irp;
+    ULONG TransferDataLength;
+    PUCHAR TransferData;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PMDL TransferBufferMDL;
+    ULONG ErrorIndex;
+    ULONG RetryCount;
+}IRP_CONTEXT, *PIRP_CONTEXT;
+
+typedef struct _ERRORHANDLER_WORKITEM_DATA
+{
+    PDEVICE_OBJECT DeviceObject;
+    PIRP_CONTEXT Context;
+    WORK_QUEUE_ITEM WorkQueueItem;
+    PIRP Irp;
+} ERRORHANDLER_WORKITEM_DATA, *PERRORHANDLER_WORKITEM_DATA;
+
+
+//---------------------------------------------------------------------
+//
+// fdo.c routines
+//
+NTSTATUS
+USBSTOR_FdoHandlePnp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp);
+
+//---------------------------------------------------------------------
+//
+// pdo.c routines
+//
+NTSTATUS
+USBSTOR_PdoHandlePnp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp);
+
+NTSTATUS
+USBSTOR_CreatePDO(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR LUN);
+
+//---------------------------------------------------------------------
+//
+// misc.c routines
+//
+NTSTATUS
+NTAPI
+USBSTOR_SyncForwardIrp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN OUT PIRP Irp);
+
+NTSTATUS
+NTAPI
+USBSTOR_GetBusInterface(
+    IN PDEVICE_OBJECT DeviceObject,
+    OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface);
+
+PVOID
+AllocateItem(
+    IN POOL_TYPE PoolType,
+    IN ULONG ItemSize);
+
+VOID
+FreeItem(
+    IN PVOID Item);
+
+NTSTATUS
+USBSTOR_SyncUrbRequest(
+    IN PDEVICE_OBJECT DeviceObject,
+    OUT PURB UrbRequest);
+
+NTSTATUS
+USBSTOR_GetMaxLUN(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension);
+
+NTSTATUS
+NTAPI
+USBSTOR_SyncForwardIrpCompletionRoutine(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Context);
+
+NTSTATUS
+USBSTOR_ResetDevice(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension);
+
+BOOLEAN
+USBSTOR_IsFloppy(
+    IN PUCHAR Buffer,
+    IN ULONG BufferLength,
+    OUT PUCHAR MediumTypeCode);
+
+//---------------------------------------------------------------------
+//
+// descriptor.c routines
+//
+
+NTSTATUS
+USBSTOR_GetDescriptors(
+    IN PDEVICE_OBJECT DeviceObject);
+
+NTSTATUS
+USBSTOR_SelectConfigurationAndInterface(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PFDO_DEVICE_EXTENSION DeviceExtension);
+
+NTSTATUS
+USBSTOR_GetPipeHandles(
+    IN PFDO_DEVICE_EXTENSION DeviceExtension);
+
+//---------------------------------------------------------------------
+//
+// scsi.c routines
+//
+NTSTATUS
+USBSTOR_HandleExecuteSCSI(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp,
+    IN ULONG RetryCount);
+
+NTSTATUS
+NTAPI
+USBSTOR_CSWCompletionRoutine(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp,
+    PVOID Ctx);
+
+NTSTATUS
+USBSTOR_SendCBW(
+    PIRP_CONTEXT Context,
+    PIRP Irp);
+
+VOID
+USBSTOR_SendCSW(
+    PIRP_CONTEXT Context,
+    PIRP Irp);
+
+
+//---------------------------------------------------------------------
+//
+// disk.c routines
+//
+NTSTATUS
+USBSTOR_HandleInternalDeviceControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp);
+
+NTSTATUS
+USBSTOR_HandleDeviceControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp);
+
+//---------------------------------------------------------------------
+//
+// queue.c routines
+//
+VOID
+NTAPI
+USBSTOR_StartIo(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp);
+
+VOID
+USBSTOR_QueueWaitForPendingRequests(
+    IN PDEVICE_OBJECT DeviceObject);
+
+VOID
+USBSTOR_QueueRelease(
+    IN PDEVICE_OBJECT DeviceObject);
+
+BOOLEAN
+USBSTOR_QueueAddIrp(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp);
+
+VOID
+NTAPI
+USBSTOR_CancelIo(
+    IN  PDEVICE_OBJECT DeviceObject,
+    IN  PIRP Irp);
+
+VOID
+USBSTOR_QueueInitialize(
+    PFDO_DEVICE_EXTENSION FDODeviceExtension);
+
+VOID
+NTAPI
+ErrorHandlerWorkItemRoutine(
+       PVOID Context);
+
+VOID
+NTAPI
+ResetHandlerWorkItemRoutine(
+    PVOID Context);
+
+
+
+VOID
+USBSTOR_QueueNextRequest(
+    IN PDEVICE_OBJECT DeviceObject);
+
+VOID
+USBSTOR_QueueTerminateRequest(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp);
+
+/* error.c */
+NTSTATUS
+USBSTOR_GetEndpointStatus(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR bEndpointAddress,
+    OUT PUSHORT Value);
+
+NTSTATUS
+USBSTOR_ResetPipeWithHandle(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN USBD_PIPE_HANDLE PipeHandle);
+
+VOID
+NTAPI
+USBSTOR_TimerRoutine(
+    PDEVICE_OBJECT DeviceObject,
+     PVOID Context);
+
+#endif /* _USBSTOR_H_ */
diff --git a/drivers/usb/usbstor_new/usbstor.rc b/drivers/usb/usbstor_new/usbstor.rc
new file mode 100644 (file)
index 0000000..c2bbbb1
--- /dev/null
@@ -0,0 +1,5 @@
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION  "USB Storage Device Driver"
+#define REACTOS_STR_INTERNAL_NAME     "usbstor"
+#define REACTOS_STR_ORIGINAL_FILENAME "usbstor.sys"
+#include <reactos/version.rc>