[USB]
[reactos.git] / reactos / drivers / storage / class / class2 / class2.c
index 93a8a46..e6528c0 100644 (file)
 #include <include/class2.h>
 #include <stdio.h>
 
+/* Part of the drive letter hack */
+#include <ntifs.h>
+#include <ketypes.h>
+
 //#define NDEBUG
 #include <debug.h>
 
 #define START_UNIT_TIMEOUT  30
 
 /* Disk layout used by Windows NT4 and earlier versions. */
-#define DEFAULT_SECTORS_PER_TRACK    32
-#define DEFAULT_TRACKS_PER_CYLINDER  64
+//#define DEFAULT_SECTORS_PER_TRACK    32
+//#define DEFAULT_TRACKS_PER_CYLINDER  64
 
 /* Disk layout used by Windows 2000 and later versions. */
-//#define DEFAULT_SECTORS_PER_TRACK    63
-//#define DEFAULT_TRACKS_PER_CYLINDER 255
+#define DEFAULT_SECTORS_PER_TRACK    63
+#define DEFAULT_TRACKS_PER_CYLINDER 255
 
 NTSTATUS
 NTAPI
@@ -130,6 +134,272 @@ DriverEntry(
     return STATUS_SUCCESS;
 }
 
+/* The following hack to assign drive letters with a non-PnP storage stack */
+
+typedef struct _CLASS_DEVICE_INFO {
+  ULONG Partitions;
+  ULONG DeviceNumber;
+  ULONG DriveNumber;
+  PDEVICE_OBJECT LowerDevice;
+} CLASS_DEVICE_INFO, *PCLASS_DEVICE_INFO;
+
+typedef struct _CLASS_DRIVER_EXTENSION {
+  ULONG PortNumber;
+  CLASS_INIT_DATA InitializationData;
+} CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION;
+
+VOID
+NTAPI
+ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
+{
+    WCHAR Buffer1[100];
+    UNICODE_STRING DriveLetterU;
+    ULONG Index;
+
+    DriveLetterU.Buffer = Buffer1;
+    DriveLetterU.MaximumLength = sizeof(Buffer1);
+
+    /* Delete the symbolic link to PhysicalDriveX */
+    DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DeviceInfo->DriveNumber) * sizeof(WCHAR);
+    IoDeleteSymbolicLink(&DriveLetterU);
+
+    DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
+
+    for (Index = 0; Index < sizeof(ULONG) * 8; Index++)
+    {
+        if (DeviceInfo->Partitions & (1 << Index))
+        {
+            DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
+            IoDeleteSymbolicLink(&DriveLetterU);
+            DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
+        }
+    }
+}
+
+NTSTATUS
+NTAPI
+ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
+{
+    WCHAR Buffer1[100];
+    WCHAR Buffer2[100];
+    UNICODE_STRING DriveLetterU, PartitionU;
+    NTSTATUS Status;
+    ULONG Index, PartitionNumber, DeviceNumber, DriveNumber;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK Iosb;
+    HANDLE PartitionHandle;
+
+    /* We assume this device does not current have a drive letter */
+
+    Index = 0;
+    DeviceNumber = 0;
+    DriveNumber = 0;
+    PartitionNumber = 1;
+    DriveLetterU.Buffer = Buffer1;
+    DriveLetterU.MaximumLength = sizeof(Buffer1);
+    PartitionU.Buffer = Buffer2;
+    PartitionU.MaximumLength = sizeof(Buffer2);
+
+    /* Determine the correct disk number */
+    do
+    {
+        /* Check that the disk exists */
+        PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\HardDisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &PartitionU,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+        Status = ZwOpenFile(&PartitionHandle,
+                            FILE_READ_ATTRIBUTES,
+                            &ObjectAttributes,
+                            &Iosb,
+                            0,
+                            0);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Return the last one that worked */
+            DeviceNumber--;
+        }
+        else
+        {
+            ZwClose(PartitionHandle);
+            DeviceNumber++;
+        }
+    } while (Status == STATUS_SUCCESS);
+
+    /* Determine the correct drive number */
+    do
+    {
+        /* Check that the drive exists */
+        PartitionU.Length = swprintf(PartitionU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &PartitionU,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+        Status = ZwOpenFile(&PartitionHandle,
+                            FILE_READ_ATTRIBUTES,
+                            &ObjectAttributes,
+                            &Iosb,
+                            0,
+                            0);
+        if (NT_SUCCESS(Status))
+        {
+            ZwClose(PartitionHandle);
+            DriveNumber++;
+        }
+    } while (Status == STATUS_SUCCESS);
+
+    /* Create the symbolic link to PhysicalDriveX */
+    PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
+    DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
+
+    Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Failed to create symbolic link */
+        return Status;
+    }
+
+    DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU);
+
+    while (TRUE)
+    {
+        /* Check that the disk exists */
+        PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\Harddisk%d\\Partition%d", DeviceNumber, PartitionNumber) * sizeof(WCHAR);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &PartitionU,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+        Status = ZwOpenFile(&PartitionHandle,
+                            FILE_READ_ATTRIBUTES,
+                            &ObjectAttributes,
+                            &Iosb,
+                            0,
+                            0);
+        if (!NT_SUCCESS(Status))
+            break;
+        else
+        {
+            ZwClose(PartitionHandle);
+
+            /* Assign it a drive letter */
+            do
+            {
+                DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
+
+                Status = IoCreateSymbolicLink(&DriveLetterU, &PartitionU);
+
+                Index++;
+            } while (Status != STATUS_SUCCESS);
+
+            DeviceInfo->Partitions |= (1 << (Index - 1));
+
+            DbgPrint("HACK: Created symbolic link %wZ -> %wZ\n", &PartitionU, &DriveLetterU);
+            PartitionNumber++;
+        }
+    }
+
+    DeviceInfo->DeviceNumber = DeviceNumber;
+    DeviceInfo->DriveNumber = DriveNumber;
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+ScsiClassPlugPlay(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    if (IrpSp->MinorFunction == IRP_MN_START_DEVICE)
+    {
+        IoSkipCurrentIrpStackLocation(Irp);
+        return STATUS_SUCCESS;
+    }
+    else if (IrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE)
+    {
+        PCLASS_DEVICE_INFO DeviceInfo = DeviceObject->DeviceExtension;
+
+        ScsiClassRemoveDriveLetter(DeviceInfo);
+
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        IoDetachDevice(DeviceInfo->LowerDevice);
+        IoDeleteDevice(DeviceObject);
+        return STATUS_SUCCESS;
+    }
+    else
+    {
+        Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        return STATUS_NOT_SUPPORTED;
+    }
+}
+
+NTSTATUS
+NTAPI
+ScsiClassAddDevice(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDEVICE_OBJECT PhysicalDeviceObject)
+{
+    PCLASS_DRIVER_EXTENSION DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
+    PCLASS_DEVICE_INFO DeviceInfo;
+    PDEVICE_OBJECT DeviceObject;
+    NTSTATUS Status;
+
+    if (DriverExtension->InitializationData.ClassFindDevices(DriverObject, NULL, &DriverExtension->InitializationData,
+                                                             PhysicalDeviceObject, DriverExtension->PortNumber))
+    {
+        /* Create a device object */
+        Status = IoCreateDevice(DriverObject,
+                                sizeof(CLASS_DEVICE_INFO),
+                                NULL,
+                                FILE_DEVICE_DISK,
+                                0,
+                                FALSE,
+                                &DeviceObject);
+        if (!NT_SUCCESS(Status))
+        {
+            return Status;
+        }
+
+        DeviceInfo = DeviceObject->DeviceExtension;
+        RtlZeroMemory(DeviceInfo, sizeof(CLASS_DEVICE_INFO));
+
+        /* Attach it to the PDO */
+        DeviceInfo->LowerDevice = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);
+
+        /* Check that the kernel has already assigned drive letters */
+        if (KeLoaderBlock == NULL)
+        {
+            /* Assign a drive letter */
+            ScsiClassAssignDriveLetter(DeviceInfo);
+        }
+        else
+        {
+            /* The kernel will handle it */
+        }
+
+        /* Move to the next port number */
+        DriverExtension->PortNumber++;
+    }
+    else
+    {
+        /* Failed to find device */
+        DbgPrint("FAILED TO FIND DEVICE!\n");
+    }
+
+    return STATUS_SUCCESS;
+}
+/* ---- End hack ---- */
+
+
 \f
 ULONG
 NTAPI
@@ -162,7 +432,6 @@ Return Value:
 
 
     PDRIVER_OBJECT  DriverObject = Argument1;
-    ULONG           portNumber = 0;
     PDEVICE_OBJECT  portDeviceObject;
     NTSTATUS        status;
     STRING          deviceNameString;
@@ -170,6 +439,7 @@ Return Value:
     PFILE_OBJECT    fileObject;
     CCHAR           deviceNameBuffer[256];
     BOOLEAN         deviceFound = FALSE;
+    PCLASS_DRIVER_EXTENSION DriverExtension;
 
     DebugPrint((3,"\n\nSCSI Class Driver\n"));
 
@@ -200,6 +470,16 @@ Return Value:
         return (ULONG) STATUS_REVISION_MISMATCH;
     }
 
+    status = IoAllocateDriverObjectExtension(DriverObject,
+                                             DriverObject,
+                                             sizeof(CLASS_DRIVER_EXTENSION),
+                                             (PVOID *)&DriverExtension);
+    if (!NT_SUCCESS(status))
+        return status;
+
+    RtlCopyMemory(&DriverExtension->InitializationData, InitializationData, sizeof(CLASS_INIT_DATA));
+    DriverExtension->PortNumber = 0;
+
     //
     // Update driver object with entry points.
     //
@@ -208,10 +488,12 @@ Return Value:
     DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiClassCreateClose;
     DriverObject->MajorFunction[IRP_MJ_READ] = ScsiClassReadWrite;
     DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiClassReadWrite;
+    DriverObject->MajorFunction[IRP_MJ_PNP] = ScsiClassPlugPlay;
     DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiClassInternalIoControl;
     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiClassDeviceControlDispatch;
     DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ScsiClassShutdownFlush;
     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ScsiClassShutdownFlush;
+    DriverObject->DriverExtension->AddDevice = ScsiClassAddDevice;
 
     if (InitializationData->ClassStartIo) {
         DriverObject->DriverStartIo = InitializationData->ClassStartIo;
@@ -223,7 +505,7 @@ Return Value:
 
     do {
 
-        sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", portNumber);
+        sprintf(deviceNameBuffer, "\\Device\\ScsiPort%lu", DriverExtension->PortNumber);
 
         DebugPrint((2, "ScsiClassInitialize: Open Port %s\n", deviceNameBuffer));
 
@@ -249,7 +531,7 @@ Return Value:
             //
 
             if (InitializationData->ClassFindDevices(DriverObject, Argument2, InitializationData,
-                                                     portDeviceObject, portNumber)) {
+                                                     portDeviceObject, DriverExtension->PortNumber)) {
 
                 deviceFound = TRUE;
             }
@@ -259,11 +541,12 @@ Return Value:
         // Check next SCSI adapter.
         //
 
-        portNumber++;
+        DriverExtension->PortNumber++;
 
     } while(NT_SUCCESS(status));
 
-    return deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;
+    /* We don't want to fail init just because we don't have devices right now */
+    return STATUS_SUCCESS; /*deviceFound ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;*/
 }
 
 \f
@@ -1510,7 +1793,7 @@ Return Value:
             srb,
             irpStack->MajorFunction,
             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
-            MAXIMUM_RETRIES - ((ULONG_PTR)irpStack->Parameters.Others.Argument4),
+            MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4),
             &status);
 
         //
@@ -1662,7 +1945,7 @@ Return Value:
             srb,
             irpStack->MajorFunction,
             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
-            MAXIMUM_RETRIES - ((ULONG_PTR)irpStack->Parameters.Others.Argument4),
+            MAXIMUM_RETRIES - PtrToUlong(irpStack->Parameters.Others.Argument4),
             &status);
 
         //