https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e2277b1f0286bf6a5b552…
commit e2277b1f0286bf6a5b5528bdde372ce07bd27d7f
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sat Dec 15 20:02:03 2018 +0100
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Sat Dec 15 20:04:00 2018 +0100
[FLOPPY_NEW] Import the floppy driver from MS GitHub repository
Do not enable it yet, as it doesn't work in ROS for the moment :-(.
Its place in tree is not optimal (it should be with disk/class/etc.),
but I prefer keeping it close to actual driver for now.
All the work has been done so that it compiles and links with ReactOS
SDK though.
---
drivers/storage/floppy_new/CMakeLists.txt | 9 +
drivers/storage/floppy_new/floppy.c | 3574 +++++++++++++++++++++++++++++
drivers/storage/floppy_new/floppy.rc | 13 +
drivers/storage/floppy_new/floppy_reg.inf | 7 +
drivers/storage/floppy_new/guid.c | 11 +
media/doc/README.FSD | 3 +-
6 files changed, 3616 insertions(+), 1 deletion(-)
diff --git a/drivers/storage/floppy_new/CMakeLists.txt
b/drivers/storage/floppy_new/CMakeLists.txt
new file mode 100644
index 0000000000..154e553c32
--- /dev/null
+++ b/drivers/storage/floppy_new/CMakeLists.txt
@@ -0,0 +1,9 @@
+list(APPEND SOURCE
+ guid.c
+ floppy.c)
+
+add_library(floppy SHARED ${SOURCE} floppy.rc)
+set_module_type(floppy kernelmodedriver)
+add_importlibs(floppy classpnp hal ntoskrnl)
+add_cd_file(TARGET floppy DESTINATION reactos/system32/drivers NO_CAB FOR all)
+add_registry_inf(floppy_reg.inf)
diff --git a/drivers/storage/floppy_new/floppy.c b/drivers/storage/floppy_new/floppy.c
new file mode 100644
index 0000000000..3c9a1ebf9c
--- /dev/null
+++ b/drivers/storage/floppy_new/floppy.c
@@ -0,0 +1,3574 @@
+/*++
+
+Copyright (C) Microsoft Corporation, 1991 - 1999
+
+Module Name:
+
+ floppy.c
+
+Abstract:
+
+ SCSI floppy class driver
+
+Author:
+
+ Jeff Havens (jhavens)
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+Revision History:
+02/28/96 georgioc Merged this code with code developed by compaq in
+ parallel with microsoft, for 120MB floppy support.
+
+01/17/96 georgioc Made code PNP aware (uses the new \storage\classpnp/scsiport)
+
+--*/
+
+#ifdef _MSC_VER
+#pragma warning(disable:4214) // nonstandard extension used : bit field types other than
int
+#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union
+#endif
+
+#include <stddef.h>
+#include <ntddk.h>
+#ifndef __REACTOS__
+#include <winerror.h>
+#endif
+#include <scsi.h>
+#include <classpnp.h>
+#include <initguid.h>
+#include <ntddstor.h>
+
+#include <ntstrsafe.h>
+#include <intsafe.h>
+
+#define MODE_DATA_SIZE 192
+#define SCSI_FLOPPY_TIMEOUT 20
+#define SFLOPPY_SRB_LIST_SIZE 4
+//
+// Define all possible drive/media combinations, given drives listed above
+// and media types in ntdddisk.h.
+//
+// These values are used to index the DriveMediaConstants table.
+//
+
+#define NUMBER_OF_DRIVE_TYPES 7
+#define DRIVE_TYPE_120M 4 //120MB Floptical
+#define DRIVE_TYPE_NONE NUMBER_OF_DRIVE_TYPES
+
+//
+// This array describes all media types we support.
+// It should be arranged in the increasing order of density
+//
+// For a given drive, we list all the mediatypes that will
+// work with that drive. For instance, a 120MB drive will
+// take 720KB media, 1.44MB media, and 120MB media.
+//
+// Note that, DriveMediaConstants given below is grouped
+// as drive and media combination
+//
+typedef enum _DRIVE_MEDIA_TYPE {
+ Drive360Media160, // 5.25" 360k drive; 160k media
+ Drive360Media180, // 5.25" 360k drive; 180k media
+ Drive360Media320, // 5.25" 360k drive; 320k media
+ Drive360Media32X, // 5.25" 360k drive; 320k 1k secs
+ Drive360Media360, // 5.25" 360k drive; 360k media
+ Drive720Media720, // 3.5" 720k drive; 720k media
+ Drive120Media160, // 5.25" 1.2Mb drive; 160k media
+ Drive120Media180, // 5.25" 1.2Mb drive; 180k media
+ Drive120Media320, // 5.25" 1.2Mb drive; 320k media
+ Drive120Media32X, // 5.25" 1.2Mb drive; 320k 1k secs
+ Drive120Media360, // 5.25" 1.2Mb drive; 360k media
+ Drive120Media120, // 5.25" 1.2Mb drive; 1.2Mb media
+ Drive144Media720, // 3.5" 1.44Mb drive; 720k media
+ Drive144Media144, // 3.5" 1.44Mb drive; 1.44Mb media
+ Drive288Media720, // 3.5" 2.88Mb drive; 720k media
+ Drive288Media144, // 3.5" 2.88Mb drive; 1.44Mb media
+ Drive288Media288, // 3.5" 2.88Mb drive; 2.88Mb media
+ Drive2080Media720, // 3.5" 20.8Mb drive; 720k media
+ Drive2080Media144, // 3.5" 20.8Mb drive; 1.44Mb media
+ Drive2080Media2080, // 3.5" 20.8Mb drive; 20.8Mb media
+ Drive32MMedia32M, // 3.5" 32Mb drive; 32MB media
+ Drive120MMedia720, // 3.5" 120Mb drive; 720k media
+ Drive120MMedia144, // 3.5" 120Mb drive; 1.44Mb media
+ Drive120MMedia120M, // 3.5" 120Mb drive; 120Mb media
+ Drive240MMedia144M, // 3.5" 240Mb drive; 1.44Mb media
+ Drive240MMedia120M, // 3.5" 240Mb drive; 120Mb media
+ Drive240MMedia240M // 3.5" 240Mb drive; 240Mb media
+} DRIVE_MEDIA_TYPE;
+
+//
+// When we want to determine the media type in a drive, we will first
+// guess that the media with highest possible density is in the drive,
+// and keep trying lower densities until we can successfully read from
+// the drive.
+//
+// These values are used to select a DRIVE_MEDIA_TYPE value.
+//
+// The following table defines ranges that apply to the DRIVE_MEDIA_TYPE
+// enumerated values when trying media types for a particular drive type.
+// Note that for this to work, the DRIVE_MEDIA_TYPE values must be sorted
+// by ascending densities within drive types. Also, for maximum track
+// size to be determined properly, the drive types must be in ascending
+// order.
+//
+
+typedef struct _DRIVE_MEDIA_LIMITS {
+ DRIVE_MEDIA_TYPE HighestDriveMediaType;
+ DRIVE_MEDIA_TYPE LowestDriveMediaType;
+} DRIVE_MEDIA_LIMITS, *PDRIVE_MEDIA_LIMITS;
+
+#if 0
+DRIVE_MEDIA_LIMITS DriveMediaLimits[NUMBER_OF_DRIVE_TYPES] = {
+
+ { Drive360Media360, Drive360Media160 }, // DRIVE_TYPE_0360
+ { Drive120Media120, Drive120Media160 }, // DRIVE_TYPE_1200
+ { Drive720Media720, Drive720Media720 }, // DRIVE_TYPE_0720
+ { Drive144Media144, Drive144Media720 }, // DRIVE_TYPE_1440
+ { Drive288Media288, Drive288Media720 }, // DRIVE_TYPE_2880
+ { Drive2080Media2080, Drive2080Media720 }
+};
+#else
+DRIVE_MEDIA_LIMITS DriveMediaLimits[NUMBER_OF_DRIVE_TYPES] = {
+
+ { Drive720Media720, Drive720Media720 }, // DRIVE_TYPE_0720
+ { Drive144Media144, Drive144Media720}, // DRIVE_TYPE_1440
+ { Drive288Media288, Drive288Media720}, // DRIVE_TYPE_2880
+ { Drive2080Media2080, Drive2080Media720 },
+ { Drive32MMedia32M, Drive32MMedia32M }, // DRIVE_TYPE_32M
+ { Drive120MMedia120M, Drive120MMedia720 }, // DRIVE_TYPE_120M
+ { Drive240MMedia240M, Drive240MMedia144M } // DRIVE_TYPE_240M
+};
+
+#endif
+//
+// For each drive/media combination, define important constants.
+//
+
+typedef struct _DRIVE_MEDIA_CONSTANTS {
+ MEDIA_TYPE MediaType;
+ USHORT BytesPerSector;
+ UCHAR SectorsPerTrack;
+ USHORT MaximumTrack;
+ UCHAR NumberOfHeads;
+} DRIVE_MEDIA_CONSTANTS, *PDRIVE_MEDIA_CONSTANTS;
+
+//
+// Magic value to add to the SectorLengthCode to use it as a shift value
+// to determine the sector size.
+//
+
+#define SECTORLENGTHCODE_TO_BYTESHIFT 7
+
+//
+// The following values were gleaned from many different sources, which
+// often disagreed with each other. Where numbers were in conflict, I
+// chose the more conservative or most-often-selected value.
+//
+
+DRIVE_MEDIA_CONSTANTS DriveMediaConstants[] =
+ {
+
+ { F5_160_512, 0x200, 0x08, 0x27, 0x1 },
+ { F5_180_512, 0x200, 0x09, 0x27, 0x1 },
+ { F5_320_1024, 0x400, 0x04, 0x27, 0x2 },
+ { F5_320_512, 0x200, 0x08, 0x27, 0x2 },
+ { F5_360_512, 0x200, 0x09, 0x27, 0x2 },
+
+ { F3_720_512, 0x200, 0x09, 0x4f, 0x2 },
+
+ { F5_160_512, 0x200, 0x08, 0x27, 0x1 },
+ { F5_180_512, 0x200, 0x09, 0x27, 0x1 },
+ { F5_320_1024, 0x400, 0x04, 0x27, 0x2 },
+ { F5_320_512, 0x200, 0x08, 0x27, 0x2 },
+ { F5_360_512, 0x200, 0x09, 0x27, 0x2 },
+ { F5_1Pt2_512, 0x200, 0x0f, 0x4f, 0x2 },
+
+ { F3_720_512, 0x200, 0x09, 0x4f, 0x2 },
+ { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
+
+ { F3_720_512, 0x200, 0x09, 0x4f, 0x2 },
+ { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
+ { F3_2Pt88_512, 0x200, 0x24, 0x4f, 0x2 },
+
+ { F3_720_512, 0x200, 0x09, 0x4f, 0x2 },
+ { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
+ { F3_20Pt8_512, 0x200, 0x1b, 0xfa, 0x6 },
+
+ { F3_32M_512, 0x200, 0x20, 0x3ff,0x2},
+
+ { F3_720_512, 0x200, 0x09, 0x4f, 0x2 },
+ { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
+ { F3_120M_512, 0x200, 0x20, 0x3c2,0x8 },
+
+ { F3_1Pt44_512, 0x200, 0x12, 0x4f, 0x2 },
+ { F3_120M_512, 0x200, 0x20, 0x3c2,0x8 },
+ { F3_240M_512, 0x200, 0x38, 0x105,0x20}
+};
+
+
+#define NUMBER_OF_DRIVE_MEDIA_COMBINATIONS
sizeof(DriveMediaConstants)/sizeof(DRIVE_MEDIA_CONSTANTS)
+
+//
+// floppy device data
+//
+
+typedef struct _DISK_DATA {
+ ULONG DriveType;
+ BOOLEAN IsDMF;
+ // BOOLEAN EnableDMF;
+ UNICODE_STRING FloppyInterfaceString;
+} DISK_DATA, *PDISK_DATA;
+
+//
+// The FloppyCapacities and FloppyGeometries arrays are used by the
+// USBFlopGetMediaTypes() and USBFlopFormatTracks() routines.
+
+// The FloppyCapacities and FloppyGeometries arrays must be kept in 1:1 sync,
+// i.e. each FloppyGeometries[i] must correspond to each FloppyCapacities[i].
+
+// Also, the arrays must be kept in sorted ascending order so that they
+// are returned in sorted ascending order by IOCTL_DISK_GET_MEDIA_TYPES.
+//
+
+typedef struct _FORMATTED_CAPACITY
+{
+ ULONG NumberOfBlocks;
+
+ ULONG BlockLength;
+
+ BOOLEAN CanFormat; // return for IOCTL_DISK_GET_MEDIA_TYPES ?
+
+} FORMATTED_CAPACITY, *PFORMATTED_CAPACITY;
+
+
+FORMATTED_CAPACITY FloppyCapacities[] =
+{
+ // Blocks BlockLen CanFormat H T B/S S/T
+ {0x000500, 0x0200, TRUE}, // 2 80 512 8 640 KB F5_640_512
+ {0x0005A0, 0x0200, TRUE}, // 2 80 512 9 720 KB F3_720_512
+ {0x000960, 0x0200, TRUE}, // 2 80 512 15 1.20 MB F3_1Pt2_512 (Toshiba)
+ {0x0004D0, 0x0400, TRUE}, // 2 77 1024 8 1.23 MB F3_1Pt23_1024 (NEC)
+ {0x000B40, 0x0200, TRUE}, // 2 80 512 18 1.44 MB F3_1Pt44_512
+ {0x000D20, 0x0200, FALSE}, // 2 80 512 21 1.70 MB DMF
+ {0x010000, 0x0200, TRUE}, // 2 1024 512 32 32 MB F3_32M_512
+ {0x03C300, 0x0200, TRUE}, // 8 963 512 32 120 MB F3_120M_512
+ {0x0600A4, 0x0200, TRUE}, // 13 890 512 34 200 MB F3_200Mb_512 (HiFD)
+ {0x072A00, 0x0200, TRUE} // 32 262 512 56 240 MB F3_240M_512
+};
+
+DISK_GEOMETRY FloppyGeometries[] =
+{
+ // Cyl MediaType Trk/Cyl Sec/Trk Bytes/Sec
+#ifndef __REACTOS__
+ {{80,0}, F3_640_512, 2, 8, 512},
+ {{80,0}, F3_720_512, 2, 9, 512},
+ {{80,0}, F3_1Pt2_512, 2, 15, 512},
+ {{77,0}, F3_1Pt23_1024, 2, 8, 1024},
+ {{80,0}, F3_1Pt44_512, 2, 18, 512},
+ {{80,0}, F3_1Pt44_512, 2, 21, 512}, // DMF -> F3_1Pt44_512
+ {{1024,0}, F3_32M_512, 2, 32, 512},
+ {{963,0}, F3_120M_512, 8, 32, 512},
+ {{890,0}, F3_200Mb_512, 13, 34, 512},
+ {{262,0}, F3_240M_512, 32, 56, 512}
+#else
+ {{.LowPart = 80, .HighPart = 0}, F3_640_512, 2, 8, 512},
+ {{.LowPart = 80, .HighPart = 0}, F3_720_512, 2, 9, 512},
+ {{.LowPart = 80, .HighPart = 0}, F3_1Pt2_512, 2, 15, 512},
+ {{.LowPart = 77, .HighPart = 0}, F3_1Pt23_1024, 2, 8, 1024},
+ {{.LowPart = 80, .HighPart = 0}, F3_1Pt44_512, 2, 18, 512},
+ {{.LowPart = 80, .HighPart = 0}, F3_1Pt44_512, 2, 21, 512}, // DMF
-> F3_1Pt44_512
+ {{.LowPart = 1024, .HighPart = 0}, F3_32M_512, 2, 32, 512},
+ {{.LowPart = 963, .HighPart = 0}, F3_120M_512, 8, 32, 512},
+ {{.LowPart = 890, .HighPart = 0}, F3_200Mb_512, 13, 34, 512},
+ {{.LowPart = 262, .HighPart = 0}, F3_240M_512, 32, 56, 512}
+#endif
+};
+
+#define FLOPPY_CAPACITIES (sizeof(FloppyCapacities)/sizeof(FloppyCapacities[0]))
+
+C_ASSERT((sizeof(FloppyGeometries)/sizeof(FloppyGeometries[0])) == FLOPPY_CAPACITIES);
+
+//
+// The following structures are used by USBFlopFormatTracks()
+//
+
+#pragma pack (push, 1)
+
+typedef struct _CDB12FORMAT
+{
+ UCHAR OperationCode;
+ UCHAR DefectListFormat : 3;
+ UCHAR CmpList : 1;
+ UCHAR FmtData : 1;
+ UCHAR LogicalUnitNumber : 3;
+ UCHAR TrackNumber;
+ UCHAR InterleaveMsb;
+ UCHAR InterleaveLsb;
+ UCHAR Reserved1[2];
+ UCHAR ParameterListLengthMsb;
+ UCHAR ParameterListLengthLsb;
+ UCHAR Reserved2[3];
+} CDB12FORMAT, *PCDB12FORMAT;
+
+
+typedef struct _DEFECT_LIST_HEADER
+{
+ UCHAR Reserved1;
+ UCHAR Side : 1;
+ UCHAR Immediate : 1;
+ UCHAR Reserved2 : 2;
+ UCHAR SingleTrack : 1;
+ UCHAR DisableCert : 1;
+ UCHAR Reserved3 : 1;
+ UCHAR FormatOptionsValid : 1;
+ UCHAR DefectListLengthMsb;
+ UCHAR DefectListLengthLsb;
+} DEFECT_LIST_HEADER, *PDEFECT_LIST_HEADER;
+
+typedef struct _FORMAT_UNIT_PARAMETER_LIST
+{
+ DEFECT_LIST_HEADER DefectListHeader;
+ FORMATTED_CAPACITY_DESCRIPTOR FormatDescriptor;
+} FORMAT_UNIT_PARAMETER_LIST, *PFORMAT_UNIT_PARAMETER_LIST;
+
+#pragma pack (pop)
+
+DRIVER_INITIALIZE DriverEntry;
+
+DRIVER_UNLOAD ScsiFlopUnload;
+
+DRIVER_ADD_DEVICE ScsiFlopAddDevice;
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopInitDevice(
+ IN PDEVICE_OBJECT Fdo
+ );
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopStartDevice(
+ IN PDEVICE_OBJECT Fdo
+ );
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopRemoveDevice(
+ IN PDEVICE_OBJECT Fdo,
+ IN UCHAR Type
+ );
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopStopDevice(
+ IN PDEVICE_OBJECT Fdo,
+ IN UCHAR Type
+ );
+
+BOOLEAN
+FindScsiFlops(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath,
+ IN PCLASS_INIT_DATA InitializationData,
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN ULONG PortNumber
+ );
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopReadWriteVerification(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopDeviceControl(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+BOOLEAN
+IsFloppyDevice(
+ PDEVICE_OBJECT DeviceObject
+ );
+
+NTSTATUS
+CreateFlopDeviceObject(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT PortDeviceObject,
+ IN ULONG DeviceCount
+ );
+
+NTSTATUS
+DetermineMediaType(
+ PDEVICE_OBJECT DeviceObject
+ );
+
+ULONG
+DetermineDriveType(
+ PDEVICE_OBJECT DeviceObject
+ );
+
+BOOLEAN
+FlCheckFormatParameters(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PFORMAT_PARAMETERS FormatParameters
+ );
+
+NTSTATUS
+FormatMedia(
+ PDEVICE_OBJECT DeviceObject,
+ MEDIA_TYPE MediaType
+ );
+
+NTSTATUS
+FlopticalFormatMedia(
+ PDEVICE_OBJECT DeviceObject,
+ PFORMAT_PARAMETERS Format
+ );
+
+VOID
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopProcessError(
+ PDEVICE_OBJECT DeviceObject,
+ PSCSI_REQUEST_BLOCK Srb,
+ NTSTATUS *Status,
+ BOOLEAN *Retry
+ );
+
+NTSTATUS
+USBFlopGetMediaTypes(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+NTSTATUS
+USBFlopFormatTracks(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT, DriverEntry)
+
+#pragma alloc_text(PAGE, ScsiFlopUnload)
+#pragma alloc_text(PAGE, ScsiFlopAddDevice)
+#pragma alloc_text(PAGE, CreateFlopDeviceObject)
+#pragma alloc_text(PAGE, ScsiFlopStartDevice)
+#pragma alloc_text(PAGE, ScsiFlopRemoveDevice)
+#pragma alloc_text(PAGE, IsFloppyDevice)
+#pragma alloc_text(PAGE, DetermineMediaType)
+#pragma alloc_text(PAGE, DetermineDriveType)
+#pragma alloc_text(PAGE, FlCheckFormatParameters)
+#pragma alloc_text(PAGE, FormatMedia)
+#pragma alloc_text(PAGE, FlopticalFormatMedia)
+#pragma alloc_text(PAGE, USBFlopGetMediaTypes)
+#pragma alloc_text(PAGE, USBFlopFormatTracks)
+
+#endif
+
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ This is the system initialization routine for installable drivers.
+ It calls the SCSI class driver initialization routine.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by system.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ CLASS_INIT_DATA InitializationData;
+
+ //
+ // Zero InitData
+ //
+
+ RtlZeroMemory (&InitializationData, sizeof(CLASS_INIT_DATA));
+
+ //
+ // Set sizes
+ //
+
+ InitializationData.InitializationDataSize = sizeof(CLASS_INIT_DATA);
+ InitializationData.FdoData.DeviceExtensionSize =
+ sizeof(FUNCTIONAL_DEVICE_EXTENSION) + sizeof(DISK_DATA);
+
+ InitializationData.FdoData.DeviceType = FILE_DEVICE_DISK;
+ InitializationData.FdoData.DeviceCharacteristics = FILE_REMOVABLE_MEDIA |
FILE_FLOPPY_DISKETTE;
+
+ //
+ // Set entry points
+ //
+
+ InitializationData.FdoData.ClassInitDevice = ScsiFlopInitDevice;
+ InitializationData.FdoData.ClassStartDevice = ScsiFlopStartDevice;
+ InitializationData.FdoData.ClassStopDevice = ScsiFlopStopDevice;
+ InitializationData.FdoData.ClassRemoveDevice = ScsiFlopRemoveDevice;
+
+ InitializationData.FdoData.ClassReadWriteVerification =
ScsiFlopReadWriteVerification;
+ InitializationData.FdoData.ClassDeviceControl = ScsiFlopDeviceControl;
+
+ InitializationData.FdoData.ClassShutdownFlush = NULL;
+ InitializationData.FdoData.ClassCreateClose = NULL;
+ InitializationData.FdoData.ClassError = ScsiFlopProcessError;
+ InitializationData.ClassStartIo = NULL;
+
+ InitializationData.ClassAddDevice = ScsiFlopAddDevice;
+ InitializationData.ClassUnload = ScsiFlopUnload;
+ //
+ // Call the class init routine
+ //
+
+ return ClassInitialize( DriverObject, RegistryPath, &InitializationData);
+
+
+} // end DriverEntry()
+
+VOID
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(DriverObject);
+ return;
+}
+
+//
+// AddDevice operation is performed in CreateFlopDeviceObject function which
+// is called by ScsiFlopAddDevice (The AddDevice routine for sfloppy.sys).
+// DO_DEVICE_INITIALIZING flag is cleard upon successfully processing AddDevice
+// operation in CreateFlopDeviceObject. But PREFAST is currently unable to
+// detect that DO_DEVICE_INITIALIZING is indeed cleard in CreateFlopDeviceObject
+// and it raises Warning 28152 (The return from an AddDevice-like function
+// unexpectedly did not clear DO_DEVICE_INITIALIZING). Suppress that warning
+// using #pragma.
+//
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:28152)
+#endif
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopAddDevice (
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT Pdo
+ )
+/*++
+
+Routine Description:
+
+ This routine creates and initializes a new FDO for the corresponding
+ PDO. It may perform property queries on the FDO but cannot do any
+ media access operations.
+
+Arguments:
+
+ DriverObject - Scsiscan class driver object.
+
+ Pdo - the physical device object we are being added to
+
+Return Value:
+
+ status
+
+--*/
+{
+ NTSTATUS status;
+ ULONG floppyCount = IoGetConfigurationInformation()->FloppyCount;
+
+ PAGED_CODE();
+
+ //
+ // Get the number of disks already initialized.
+ //
+
+ status = CreateFlopDeviceObject(DriverObject, Pdo, floppyCount);
+
+ if (NT_SUCCESS(status)) {
+
+ //
+ // Increment system floppy device count.
+ //
+
+ IoGetConfigurationInformation()->FloppyCount++;
+ }
+
+ return status;
+}
+
+NTSTATUS
+CreateFlopDeviceObject(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT Pdo,
+ IN ULONG DeviceCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates an object for the device and then calls the
+ SCSI port driver for media capacity and sector size.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by system.
+ PortDeviceObject - to connect to SCSI port driver.
+ DeviceCount - Number of previously installed Floppys.
+ AdapterDescriptor - Pointer to structure returned by SCSI port
+ driver describing adapter capabilites (and limitations).
+ DeviceDescriptor - Pointer to configuration information for this device.
+
+Return Value:
+
+--*/
+{
+ NTSTATUS status;
+ PDEVICE_OBJECT deviceObject = NULL;
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
+ PDISK_DATA diskData;
+
+ PAGED_CODE();
+
+ DebugPrint((3,"CreateFlopDeviceObject: Enter routine\n"));
+
+ //
+ // Try to claim the device.
+ //
+
+ status = ClassClaimDevice(Pdo,FALSE);
+
+ if (!NT_SUCCESS(status)) {
+ return(status);
+ }
+
+ DeviceCount--;
+
+ do {
+ UCHAR name[256];
+
+ //
+ // Create device object for this device.
+ //
+
+ DeviceCount++;
+
+ status = RtlStringCbPrintfA((PCCHAR) name,
+ sizeof(name)/sizeof(UCHAR),
+ "\\Device\\Floppy%u",
+ DeviceCount);
+ if (NT_SUCCESS(status)) {
+
+ status = ClassCreateDeviceObject(DriverObject,
+ (PCCHAR) name,
+ Pdo,
+ TRUE,
+ &deviceObject);
+ }
+ } while ((status == STATUS_OBJECT_NAME_COLLISION) ||
+ (status == STATUS_OBJECT_NAME_EXISTS));
+
+ if (!NT_SUCCESS(status)) {
+ DebugPrint((1,"CreateFlopDeviceObjects: Can not create device\n"));
+ goto CreateFlopDeviceObjectExit;
+ }
+
+ //
+ // Indicate that IRPs should include MDLs.
+ //
+
+ deviceObject->Flags |= DO_DIRECT_IO;
+
+ fdoExtension = deviceObject->DeviceExtension;
+
+ //
+ // Back pointer to device object.
+ //
+
+ fdoExtension->CommonExtension.DeviceObject = deviceObject;
+
+ //
+ // This is the physical device.
+ //
+
+ fdoExtension->CommonExtension.PartitionZeroExtension = fdoExtension;
+
+ //
+ // Reset the drive type.
+ //
+
+ diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
+ diskData->DriveType = DRIVE_TYPE_NONE;
+ diskData->IsDMF = FALSE;
+ // diskData->EnableDMF = TRUE;
+
+ //
+ // Initialize lock count to zero. The lock count is used to
+ // disable the ejection mechanism when media is mounted.
+ //
+
+ fdoExtension->LockCount = 0;
+
+ //
+ // Save system floppy number
+ //
+
+ fdoExtension->DeviceNumber = DeviceCount;
+
+ //
+ // Set the alignment requirements for the device based on the
+ // host adapter requirements
+ //
+
+ if (Pdo->AlignmentRequirement > deviceObject->AlignmentRequirement) {
+ deviceObject->AlignmentRequirement = Pdo->AlignmentRequirement;
+ }
+
+ //
+ // Clear the SrbFlags and disable synchronous transfers
+ //
+
+ fdoExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // Finally, attach to the PDO
+ //
+
+ fdoExtension->LowerPdo = Pdo;
+
+ fdoExtension->CommonExtension.LowerDeviceObject =
+ IoAttachDeviceToDeviceStack(deviceObject, Pdo);
+
+ if(fdoExtension->CommonExtension.LowerDeviceObject == NULL) {
+
+ status = STATUS_UNSUCCESSFUL;
+ goto CreateFlopDeviceObjectExit;
+ }
+
+ deviceObject->StackSize++;
+
+ //
+ // The device is initialized properly - mark it as such.
+ //
+
+ deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ return STATUS_SUCCESS;
+
+CreateFlopDeviceObjectExit:
+
+ if (deviceObject != NULL) {
+ IoDeleteDevice(deviceObject);
+ }
+
+ return status;
+
+} // end CreateFlopDeviceObject()
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopInitDevice(
+ IN PDEVICE_OBJECT Fdo
+ )
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
+ PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
+ PDISK_DATA diskData = commonExtension->DriverData;
+
+ PVOID senseData = NULL;
+ ULONG timeOut;
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ //
+ // Allocate request sense buffer.
+ //
+
+#ifndef __REACTOS__
+ senseData = ExAllocatePool(NonPagedPoolNxCacheAligned, SENSE_BUFFER_SIZE);
+#else
+ senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
+#endif
+
+ if (senseData == NULL) {
+
+ //
+ // The buffer cannot be allocated.
+ //
+
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ return status;
+ }
+
+ //
+ // Set the sense data pointer in the device extension.
+ //
+
+ fdoExtension->SenseData = senseData;
+
+ //
+ // Build the lookaside list for srb's for this device.
+ //
+
+ ClassInitializeSrbLookasideList((PCOMMON_DEVICE_EXTENSION)fdoExtension,
+ SFLOPPY_SRB_LIST_SIZE);
+
+ //
+ // Register for media change notification
+ //
+ ClassInitializeMediaChangeDetection(fdoExtension,
+ (PUCHAR) "SFloppy");
+
+ //
+ // Set timeout value in seconds.
+ //
+
+ timeOut = ClassQueryTimeOutRegistryValue(Fdo);
+ if (timeOut) {
+ fdoExtension->TimeOutValue = timeOut;
+ } else {
+ fdoExtension->TimeOutValue = SCSI_FLOPPY_TIMEOUT;
+ }
+
+ //
+ // Floppies are not partitionable so starting offset is 0.
+ //
+
+ fdoExtension->CommonExtension.StartingOffset.QuadPart = (LONGLONG)0;
+
+#if 0
+ if (!IsFloppyDevice(Fdo) ||
+ !(Fdo->Characteristics & FILE_REMOVABLE_MEDIA) ||
+ (fdoExtension->DeviceDescriptor->DeviceType != DIRECT_ACCESS_DEVICE)) {
+
+ ExFreePool(senseData);
+ status = STATUS_NO_SUCH_DEVICE;
+ return status;
+ }
+#endif
+
+ RtlZeroMemory(&(fdoExtension->DiskGeometry),
+ sizeof(DISK_GEOMETRY));
+
+ //
+ // Determine the media type if possible. Set the current media type to
+ // Unknown so that determine media type will check the media.
+ //
+
+ fdoExtension->DiskGeometry.MediaType = Unknown;
+
+ //
+ // Register interfaces for this device.
+ //
+
+ {
+ UNICODE_STRING interfaceName;
+
+ RtlInitUnicodeString(&interfaceName, NULL);
+
+ status = IoRegisterDeviceInterface(fdoExtension->LowerPdo,
+ (LPGUID) &GUID_DEVINTERFACE_FLOPPY,
+ NULL,
+ &interfaceName);
+
+ if(NT_SUCCESS(status)) {
+ diskData->FloppyInterfaceString = interfaceName;
+ } else {
+ RtlInitUnicodeString(&(diskData->FloppyInterfaceString), NULL);
+ DebugPrint((1, "ScsiFlopStartDevice: Unable to register device "
+ "interface for fdo %p [%08lx]\n",
+ Fdo, status));
+ }
+ }
+
+ return (STATUS_SUCCESS);
+}
+
+#ifdef _MSC_VER
+#pragma warning(suppress:6262) // This function uses 1096 bytes of stack which exceed
default value of 1024 bytes used by Code Analysis for flagging as warning
+#endif
+#ifdef __REACTOS__
+NTSTATUS NTAPI ScsiFlopStartDevice(
+#else
+NTSTATUS ScsiFlopStartDevice(
+#endif
+ IN PDEVICE_OBJECT Fdo
+ )
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
+ PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
+
+ PIRP irp;
+ IO_STATUS_BLOCK ioStatus;
+
+ SCSI_ADDRESS scsiAddress;
+
+ WCHAR ntNameBuffer[256];
+ UNICODE_STRING ntUnicodeString;
+
+ WCHAR arcNameBuffer[256];
+ UNICODE_STRING arcUnicodeString;
+
+ KEVENT event;
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ KeInitializeEvent(&event,SynchronizationEvent,FALSE);
+
+ DetermineMediaType(Fdo); // ignore unsuccessful here
+
+ //
+ // Create device object for this device.
+ //
+
+ RtlStringCbPrintfW(ntNameBuffer,
+ sizeof(ntNameBuffer)/sizeof(WCHAR),
+ L"\\Device\\Floppy%u",
+ fdoExtension->DeviceNumber);
+
+ //
+ // Create local copy of unicode string
+ //
+ RtlInitUnicodeString(&ntUnicodeString,ntNameBuffer);
+
+ //
+ // Create a symbolic link from the disk name to the corresponding
+ // ARC name, to be used if we're booting off the disk. This will
+ // fail if it's not system initialization time; that's fine. The
+ // ARC name looks something like \ArcName\scsi(0)Flop(0)fdisk(0).
+ // In order to get the address, we need to send a IOCTL_SCSI_GET_ADDRESS...
+ //
+
+ irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_ADDRESS,
+ Fdo,
+ NULL,
+ 0,
+ &scsiAddress,
+ sizeof(scsiAddress),
+ FALSE,
+ &event,
+ &ioStatus);
+
+ if (irp == NULL) {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
+
+ if (status == STATUS_PENDING) {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ status = ioStatus.Status;
+ }
+
+ //
+ // IOCTL_SCSI_GET_ADDRESS might not be supported by the port driver and
+ // hence may fail. But it is not a fatal error. Do not fail PnP start
+ // if this IOCTL fails.
+ //
+ if (NT_SUCCESS(status)) {
+
+ RtlStringCbPrintfW(arcNameBuffer,
+ sizeof(arcNameBuffer)/sizeof(WCHAR),
+ L"\\ArcName\\scsi(%u)disk(%u)fdisk(%u)",
+ scsiAddress.PortNumber,
+ scsiAddress.TargetId,
+ scsiAddress.Lun);
+
+ RtlInitUnicodeString(&arcUnicodeString, arcNameBuffer);
+
+ IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
+ }
+
+ status = STATUS_SUCCESS;
+
+ //
+ // Create the multi() arc name -- Create the "fake"
+ // name of multi(0)disk(0)fdisk(#) to handle the case where the
+ // SCSI floppy is the only floppy in the system. If this fails
+ // it doesn't matter because the previous scsi() based ArcName
+ // will work. This name is necessary for installation.
+ //
+
+ RtlStringCbPrintfW(arcNameBuffer,
+ sizeof(arcNameBuffer)/sizeof(WCHAR),
+ L"\\ArcName\\multi(%u)disk(%u)fdisk(%u)",
+ 0,
+ 0,
+ fdoExtension->DeviceNumber);
+
+ RtlInitUnicodeString(&arcUnicodeString, arcNameBuffer);
+
+ IoAssignArcName(&arcUnicodeString, &ntUnicodeString);
+
+ //
+ // Set our interface state.
+ //
+
+ {
+ PDISK_DATA diskData = commonExtension->DriverData;
+
+ if(diskData->FloppyInterfaceString.Buffer != NULL) {
+
+ status = IoSetDeviceInterfaceState(
+ &(diskData->FloppyInterfaceString),
+ TRUE);
+
+ if(!NT_SUCCESS(status)) {
+ DebugPrint((1, "ScsiFlopStartDevice: Unable to set device "
+ "interface state to TRUE for fdo %p "
+ "[%08lx]\n",
+ Fdo, status));
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopReadWriteVerification(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ NT Status
+
+--*/
+
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS status = STATUS_SUCCESS;
+
+ //
+ // Make sure that the number of bytes to transfer is a multiple of the sector size
+ //
+ if ((irpSp->Parameters.Read.Length &
(fdoExtension->DiskGeometry.BytesPerSector - 1)) != 0)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ Irp->IoStatus.Status = status;
+
+ return status;
+}
+
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopDeviceControl(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ Status is returned.
+
+--*/
+
+{
+ KIRQL currentIrql;
+ PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
+ PSCSI_REQUEST_BLOCK srb;
+ PCDB cdb;
+ NTSTATUS status;
+ PDISK_GEOMETRY outputBuffer;
+ ULONG outputBufferLength;
+ ULONG i;
+ DRIVE_MEDIA_TYPE lowestDriveMediaType;
+ DRIVE_MEDIA_TYPE highestDriveMediaType;
+ PFORMAT_PARAMETERS formatParameters;
+ PMODE_PARAMETER_HEADER modeData;
+ ULONG length;
+
+ //
+ // Initialize the information field
+ //
+ Irp->IoStatus.Information = 0;
+
+#ifndef __REACTOS__
+ srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
+#else
+ srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
+#endif
+
+ if (srb == NULL) {
+
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ if (IoIsErrorUserInduced(Irp->IoStatus.Status)) {
+
+ IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
+ }
+
+ KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
+ ClassReleaseRemoveLock(DeviceObject, Irp);
+ ClassCompleteRequest(DeviceObject, Irp, 0);
+ KeLowerIrql(currentIrql);
+
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ //
+ // Write zeros to Srb.
+ //
+
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ cdb = (PCDB)srb->Cdb;
+
+ switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
+
+
+ case IOCTL_DISK_VERIFY: {
+
+ PVERIFY_INFORMATION verifyInfo = Irp->AssociatedIrp.SystemBuffer;
+ LARGE_INTEGER byteOffset;
+ ULONG sectorOffset;
+ USHORT sectorCount;
+
+ //
+ // Validate buffer length.
+ //
+
+ if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(VERIFY_INFORMATION)) {
+
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ break;
+ }
+
+ //
+ // Perform a bounds check on the sector range
+ //
+ if ((verifyInfo->StartingOffset.QuadPart >
fdoExtension->CommonExtension.PartitionLength.QuadPart) ||
+ (verifyInfo->StartingOffset.QuadPart < 0))
+ {
+ status = STATUS_NONEXISTENT_SECTOR;
+ break;
+ }
+ else
+ {
+ ULONGLONG bytesRemaining =
fdoExtension->CommonExtension.PartitionLength.QuadPart -
verifyInfo->StartingOffset.QuadPart;
+
+ if ((ULONGLONG)verifyInfo->Length > bytesRemaining)
+ {
+ status = STATUS_NONEXISTENT_SECTOR;
+ break;
+ }
+ }
+
+ //
+ // Verify sectors
+ //
+
+ srb->CdbLength = 10;
+
+ cdb->CDB10.OperationCode = SCSIOP_VERIFY;
+
+ //
+ // Add disk offset to starting sector.
+ //
+
+ byteOffset.QuadPart = fdoExtension->CommonExtension.StartingOffset.QuadPart +
+ verifyInfo->StartingOffset.QuadPart;
+
+ //
+ // Convert byte offset to sector offset.
+ //
+
+ sectorOffset = (ULONG)(byteOffset.QuadPart >>
fdoExtension->SectorShift);
+
+ //
+ // Convert ULONG byte count to USHORT sector count.
+ //
+
+ sectorCount = (USHORT)(verifyInfo->Length >>
fdoExtension->SectorShift);
+
+ //
+ // Move little endian values into CDB in big endian format.
+ //
+
+ cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)§orOffset)->Byte3;
+ cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)§orOffset)->Byte2;
+ cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)§orOffset)->Byte1;
+ cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)§orOffset)->Byte0;
+
+ cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)§orCount)->Byte1;
+ cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)§orCount)->Byte0;
+
+ //
+ // The verify command is used by the NT FORMAT utility and
+ // requests are sent down for 5% of the volume size. The
+ // request timeout value is calculated based on the number of
+ // sectors verified.
+ //
+
+ srb->TimeOutValue = ((sectorCount + 0x7F) >> 7) *
+ fdoExtension->TimeOutValue;
+
+ status = ClassSendSrbAsynchronous(DeviceObject,
+ srb,
+ Irp,
+ NULL,
+ 0,
+ FALSE);
+ return(status);
+
+ }
+
+ case IOCTL_DISK_GET_PARTITION_INFO: {
+
+ if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb) {
+
+ USBFlopGetMediaTypes(DeviceObject, NULL);
+
+ // Don't need to propagate any error if one occurs
+ //
+ status = STATUS_SUCCESS;
+
+ } else {
+
+ status = DetermineMediaType(DeviceObject);
+ }
+
+ if (!NT_SUCCESS(status)) {
+ // so will propogate error
+ NOTHING;
+ } else if (fdoExtension->DiskGeometry.MediaType == F3_120M_512) {
+ //so that the format code will not try to partition it.
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ } else {
+ //
+ // Free the Srb, since it is not needed.
+ //
+
+ ExFreePool(srb);
+
+ //
+ // Pass the request to the common device control routine.
+ //
+
+ return(ClassDeviceControl(DeviceObject, Irp));
+ }
+ break;
+ }
+
+ case IOCTL_DISK_GET_DRIVE_GEOMETRY: {
+
+ DebugPrint((3,"ScsiDeviceIoControl: Get drive geometry\n"));
+
+ if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
+ {
+ status = USBFlopGetMediaTypes(DeviceObject,
+ Irp);
+ break;
+ }
+
+ //
+ // If there's not enough room to write the
+ // data, then fail the request.
+ //
+
+ if ( irpStack->Parameters.DeviceIoControl.OutputBufferLength <
+ sizeof( DISK_GEOMETRY ) ) {
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = DetermineMediaType(DeviceObject);
+
+ if (!NT_SUCCESS(status)) {
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = status;
+
+ } else {
+
+ //
+ // Copy drive geometry information from device extension.
+ //
+
+ RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer,
+ &(fdoExtension->DiskGeometry),
+ sizeof(DISK_GEOMETRY));
+
+ Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
+ status = STATUS_SUCCESS;
+
+ }
+
+ break;
+ }
+
+ case IOCTL_DISK_GET_MEDIA_TYPES: {
+
+ if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
+ {
+ status = USBFlopGetMediaTypes(DeviceObject,
+ Irp);
+ break;
+ }
+
+ i = DetermineDriveType(DeviceObject);
+
+ if (i == DRIVE_TYPE_NONE) {
+ status = STATUS_UNRECOGNIZED_MEDIA;
+ break;
+ }
+
+ lowestDriveMediaType = DriveMediaLimits[i].LowestDriveMediaType;
+ highestDriveMediaType = DriveMediaLimits[i].HighestDriveMediaType;
+
+ outputBufferLength =
+ irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ //
+ // Make sure that the input buffer has enough room to return
+ // at least one descriptions of a supported media type.
+ //
+
+ if ( outputBufferLength < ( sizeof( DISK_GEOMETRY ) ) ) {
+
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ //
+ // Assume success, although we might modify it to a buffer
+ // overflow warning below (if the buffer isn't big enough
+ // to hold ALL of the media descriptions).
+ //
+
+ status = STATUS_SUCCESS;
+
+ if (outputBufferLength < ( sizeof( DISK_GEOMETRY ) *
+ ( highestDriveMediaType - lowestDriveMediaType + 1 ) ) ) {
+
+ //
+ // The buffer is too small for all of the descriptions;
+ // calculate what CAN fit in the buffer.
+ //
+
+ status = STATUS_BUFFER_OVERFLOW;
+
+ highestDriveMediaType = (DRIVE_MEDIA_TYPE)( ( lowestDriveMediaType - 1 ) +
+ ( outputBufferLength /
+ sizeof( DISK_GEOMETRY ) ) );
+ }
+
+ outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
+
+ for (i = (UCHAR)lowestDriveMediaType;i <= (UCHAR)highestDriveMediaType;i++ )
{
+
+ outputBuffer->MediaType = DriveMediaConstants[i].MediaType;
+ outputBuffer->Cylinders.LowPart =
+ DriveMediaConstants[i].MaximumTrack + 1;
+ outputBuffer->Cylinders.HighPart = 0;
+ outputBuffer->TracksPerCylinder =
+ DriveMediaConstants[i].NumberOfHeads;
+ outputBuffer->SectorsPerTrack =
+ DriveMediaConstants[i].SectorsPerTrack;
+ outputBuffer->BytesPerSector =
+ DriveMediaConstants[i].BytesPerSector;
+ outputBuffer++;
+
+ Irp->IoStatus.Information += sizeof( DISK_GEOMETRY );
+ }
+
+ break;
+ }
+
+ case IOCTL_DISK_FORMAT_TRACKS: {
+
+ if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb)
+ {
+ status = USBFlopFormatTracks(DeviceObject,
+ Irp);
+ break;
+ }
+
+ //
+ // Make sure that we got all the necessary format parameters.
+ //
+
+ if ( irpStack->Parameters.DeviceIoControl.InputBufferLength <sizeof(
FORMAT_PARAMETERS ) ) {
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ formatParameters = (PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Make sure the parameters we got are reasonable.
+ //
+
+ if ( !FlCheckFormatParameters(DeviceObject, formatParameters)) {
+
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // If this request is for a 20.8 MB floppy then call a special
+ // floppy format routine.
+ //
+
+ if (formatParameters->MediaType == F3_20Pt8_512) {
+ status = FlopticalFormatMedia(DeviceObject,
+ formatParameters
+ );
+
+ break;
+ }
+
+ //
+ // All the work is done in the pass. If this is not the first pass,
+ // then complete the request and return;
+ //
+
+ if (formatParameters->StartCylinderNumber != 0 ||
formatParameters->StartHeadNumber != 0) {
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ status = FormatMedia( DeviceObject, formatParameters->MediaType);
+ break;
+ }
+
+ case IOCTL_DISK_IS_WRITABLE: {
+
+ if ((fdoExtension->DiskGeometry.MediaType) == F3_32M_512) {
+
+ //
+ // 32MB media is READ ONLY. Just return
+ // STATUS_MEDIA_WRITE_PROTECTED
+ //
+
+ status = STATUS_MEDIA_WRITE_PROTECTED;
+
+ break;
+ }
+
+ //
+ // Determine if the device is writable.
+ //
+
+#ifndef __REACTOS__
+ modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
+#else
+ modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
+#endif
+
+ if (modeData == NULL) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ RtlZeroMemory(modeData, MODE_DATA_SIZE);
+
+ length = ClassModeSense(DeviceObject,
+ (PCHAR) modeData,
+ MODE_DATA_SIZE,
+ MODE_SENSE_RETURN_ALL);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ //
+ // Retry the request in case of a check condition.
+ //
+
+ length = ClassModeSense(DeviceObject,
+ (PCHAR) modeData,
+ MODE_DATA_SIZE,
+ MODE_SENSE_RETURN_ALL);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+ status = STATUS_IO_DEVICE_ERROR;
+ ExFreePool(modeData);
+ break;
+ }
+ }
+
+ if (modeData->DeviceSpecificParameter & MODE_DSP_WRITE_PROTECT) {
+ status = STATUS_MEDIA_WRITE_PROTECTED;
+ } else {
+ status = STATUS_SUCCESS;
+ }
+
+ DebugPrint((2,"IOCTL_DISK_IS_WRITABLE returns %08X\n", status));
+
+ ExFreePool(modeData);
+ break;
+ }
+
+ default: {
+
+ DebugPrint((3,"ScsiIoDeviceControl: Unsupported device IOCTL\n"));
+
+ //
+ // Free the Srb, since it is not needed.
+ //
+
+ ExFreePool(srb);
+
+ //
+ // Pass the request to the common device control routine.
+ //
+
+ return(ClassDeviceControl(DeviceObject, Irp));
+
+ break;
+ }
+
+ } // end switch( ...
+
+ //
+ // Check if SL_OVERRIDE_VERIFY_VOLUME flag is set in the IRP.
+ // If so, do not return STATUS_VERIFY_REQUIRED
+ //
+ if ((status == STATUS_VERIFY_REQUIRED) &&
+ (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME))) {
+
+ status = STATUS_IO_DEVICE_ERROR;
+
+ }
+
+ Irp->IoStatus.Status = status;
+
+ if (!NT_SUCCESS(status) && IoIsErrorUserInduced(status)) {
+
+ IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
+ }
+
+ KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql);
+ ClassReleaseRemoveLock(DeviceObject, Irp);
+ ClassCompleteRequest(DeviceObject, Irp, 0);
+ KeLowerIrql(currentIrql);
+
+ ExFreePool(srb);
+
+ return status;
+
+} // end ScsiFlopDeviceControl()
+
+#if 0
+
+BOOLEAN
+IsFloppyDevice(
+ PDEVICE_OBJECT DeviceObject
+ )
+/*++
+
+Routine Description:
+
+ The routine performs the necessary funcitons to deterime if the device is
+ really a floppy rather than a harddisk. This is done by a mode sense
+ command. First a check is made to see if the medimum type is set. Second
+ a check is made for the flexible parameters mode page.
+
+Arguments:
+
+ DeviceObject - Supplies the device object to be tested.
+
+Return Value:
+
+ Return TRUE if the indicated device is a floppy.
+
+--*/
+{
+
+ PVOID modeData;
+ PUCHAR pageData;
+ ULONG length;
+
+ modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
+
+ if (modeData == NULL) {
+ return(FALSE);
+ }
+
+ RtlZeroMemory(modeData, MODE_DATA_SIZE);
+
+ length = ClassModeSense(DeviceObject, modeData, MODE_DATA_SIZE,
MODE_SENSE_RETURN_ALL);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ //
+ // Retry the request in case of a check condition.
+ //
+
+ length = ClassModeSense(DeviceObject,
+ modeData,
+ MODE_DATA_SIZE,
+ MODE_SENSE_RETURN_ALL);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ ExFreePool(modeData);
+ return(FALSE);
+
+ }
+ }
+
+#if 0
+ //
+ // Some drives incorrectly report this. In particular the SONY RMO-S350
+ // when in disk mode.
+ //
+
+ if (((PMODE_PARAMETER_HEADER) modeData)->MediumType >= MODE_FD_SINGLE_SIDE
+ && ((PMODE_PARAMETER_HEADER) modeData)->MediumType <=
MODE_FD_MAXIMUM_TYPE) {
+
+ DebugPrint((1, "ScsiFlop: MediumType value %2x, This is a floppy.\n",
((PMODE_PARAMETER_HEADER) modeData)->MediumType));
+ ExFreePool(modeData);
+ return(TRUE);
+ }
+
+#endif
+
+ //
+ // If the length is greater than length indiated by the mode data reset
+ // the data to the mode data.
+ //
+ if (length > (ULONG)((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1) {
+ length = (ULONG)((PMODE_PARAMETER_HEADER) modeData)->ModeDataLength + 1;
+
+ }
+
+ //
+ // Look for the flexible disk mode page.
+ //
+
+ pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
+
+ if (pageData != NULL) {
+
+ DebugPrint((1, "ScsiFlop: Flexible disk page found, This is a
floppy.\n"));
+
+ //
+ // As a special case for the floptical driver do a magic mode sense to
+ // enable the drive.
+ //
+
+ ClassModeSense(DeviceObject, modeData, 0x2a, 0x2e);
+
+ ExFreePool(modeData);
+ return(TRUE);
+
+ }
+
+ ExFreePool(modeData);
+ return(FALSE);
+
+}
+#endif
+
+
+NTSTATUS
+DetermineMediaType(
+ PDEVICE_OBJECT DeviceObject
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the floppy media type based on the size of the
+ device. The geometry information is set for the device object.
+
+Arguments:
+
+ DeviceObject - Supplies the device object to be tested.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
+ PDISK_GEOMETRY geometry;
+ LONG index;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ geometry = &(fdoExtension->DiskGeometry);
+
+ //
+ // Issue ReadCapacity to update device extension
+ // with information for current media.
+ //
+
+ status = ClassReadDriveCapacity(DeviceObject);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Set the media type to unknow and zero the geometry information.
+ //
+
+ geometry->MediaType = Unknown;
+
+ return status;
+
+ }
+
+ //
+ // Look at the capcity of disk to determine its type.
+ //
+
+ for (index = NUMBER_OF_DRIVE_MEDIA_COMBINATIONS - 1; index >= 0; index--) {
+
+ //
+ // Walk the table backward untill the drive capacity holds all of the
+ // data and the bytes per setor are equal
+ //
+
+ if ((ULONG) (DriveMediaConstants[index].NumberOfHeads *
+ (DriveMediaConstants[index].MaximumTrack + 1) *
+ DriveMediaConstants[index].SectorsPerTrack *
+ DriveMediaConstants[index].BytesPerSector) <=
+ fdoExtension->CommonExtension.PartitionLength.LowPart &&
+ DriveMediaConstants[index].BytesPerSector ==
+ geometry->BytesPerSector) {
+
+ geometry->MediaType = DriveMediaConstants[index].MediaType;
+ geometry->TracksPerCylinder = DriveMediaConstants[index].NumberOfHeads;
+ geometry->SectorsPerTrack = DriveMediaConstants[index].SectorsPerTrack;
+ geometry->Cylinders.LowPart = DriveMediaConstants[index].MaximumTrack+1;
+ break;
+ }
+ }
+
+ if (index == -1) {
+
+ //
+ // Set the media type to unknow and zero the geometry information.
+ //
+
+ geometry->MediaType = Unknown;
+
+
+ } else {
+ //
+ // DMF check breaks the insight SCSI floppy, so its disabled for that case
+ //
+ PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
+
+ // if (diskData->EnableDMF == TRUE) {
+
+ //
+ //check to see if DMF
+ //
+
+ PSCSI_REQUEST_BLOCK srb;
+ PVOID readData;
+
+ //
+ // Allocate a Srb for the read command.
+ //
+
+#ifndef __REACTOS__
+ readData = ExAllocatePool(NonPagedPoolNx, geometry->BytesPerSector);
+#else
+ readData = ExAllocatePool(NonPagedPool, geometry->BytesPerSector);
+#endif
+ if (readData == NULL) {
+ return STATUS_NO_MEMORY;
+ }
+
+#ifndef __REACTOS__
+ srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
+#else
+ srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
+#endif
+
+ if (srb == NULL) {
+
+ ExFreePool(readData);
+ return STATUS_NO_MEMORY;
+ }
+
+ RtlZeroMemory(readData, geometry->BytesPerSector);
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ srb->CdbLength = 10;
+ srb->Cdb[0] = SCSIOP_READ;
+ srb->Cdb[5] = 0;
+ srb->Cdb[8] = (UCHAR) 1;
+
+ //
+ // Set timeout value.
+ //
+
+ srb->TimeOutValue = fdoExtension->TimeOutValue;
+
+ //
+ // Send the mode select data.
+ //
+
+ status = ClassSendSrbSynchronous(DeviceObject,
+ srb,
+ readData,
+ geometry->BytesPerSector,
+ FALSE
+ );
+
+ if (NT_SUCCESS(status)) {
+ char *pchar = (char *)readData;
+
+ pchar += 3; //skip 3 bytes jump code
+
+ // If the MSDMF3. signature is there then mark it as DMF diskette
+ if (RtlCompareMemory(pchar, "MSDMF3.", 7) == 7) {
+ diskData->IsDMF = TRUE;
+ }
+
+ }
+ ExFreePool(readData);
+ ExFreePool(srb);
+ // }// else
+ }
+ return status;
+}
+
+ULONG
+DetermineDriveType(
+ PDEVICE_OBJECT DeviceObject
+ )
+/*++
+
+Routine Description:
+
+ The routine determines the device type so that the supported medias can be
+ determined. It does a mode sense for the default parameters. This code
+ assumes that the returned values are for the maximum device size.
+
+Arguments:
+
+ DeviceObject - Supplies the device object to be tested.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
+ PVOID modeData;
+ PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
+ PMODE_FLEXIBLE_DISK_PAGE pageData;
+ ULONG length;
+ LONG index;
+ UCHAR numberOfHeads;
+ UCHAR sectorsPerTrack;
+ USHORT maximumTrack;
+ BOOLEAN applyFix = FALSE;
+
+ PAGED_CODE();
+
+ if (diskData->DriveType != DRIVE_TYPE_NONE) {
+ return(diskData->DriveType);
+ }
+
+#ifndef __REACTOS__
+ modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
+#else
+ modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
+#endif
+
+ if (modeData == NULL) {
+ return(DRIVE_TYPE_NONE);
+ }
+
+ RtlZeroMemory(modeData, MODE_DATA_SIZE);
+
+ length = ClassModeSense(DeviceObject,
+ modeData,
+ MODE_DATA_SIZE,
+ MODE_PAGE_FLEXIBILE);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ //
+ // Retry the request one more time
+ // in case of a check condition.
+ //
+ length = ClassModeSense(DeviceObject,
+ modeData,
+ MODE_DATA_SIZE,
+ MODE_PAGE_FLEXIBILE);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+
+ ExFreePool(modeData);
+ return(DRIVE_TYPE_NONE);
+ }
+ }
+
+ //
+ // Look for the flexible disk mode page.
+ //
+
+ pageData = ClassFindModePage( modeData,
+ length,
+ MODE_PAGE_FLEXIBILE,
+ TRUE);
+
+ //
+ // Make sure the page is returned and is large enough.
+ //
+
+ if ((pageData != NULL) &&
+ (pageData->PageLength + 2 >=
+ (UCHAR)offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) {
+
+ //
+ // Pull out the heads, cylinders, and sectors.
+ //
+
+ numberOfHeads = pageData->NumberOfHeads;
+ maximumTrack = pageData->NumberOfCylinders[1];
+ maximumTrack |= pageData->NumberOfCylinders[0] << 8;
+ sectorsPerTrack = pageData->SectorsPerTrack;
+
+
+ //
+ // Convert from number of cylinders to maximum track.
+ //
+
+ maximumTrack--;
+
+ //
+ // Search for the maximum supported media. Based on the number of heads,
+ // sectors per track and number of cylinders
+ //
+ for (index = 0; index < NUMBER_OF_DRIVE_MEDIA_COMBINATIONS; index++) {
+
+ //
+ // Walk the table forward until the drive capacity holds all of the
+ // data and the bytes per setor are equal
+ //
+
+ if (DriveMediaConstants[index].NumberOfHeads == numberOfHeads &&
+ DriveMediaConstants[index].MaximumTrack == maximumTrack &&
+ DriveMediaConstants[index].SectorsPerTrack ==sectorsPerTrack) {
+
+ ExFreePool(modeData);
+
+ //
+ // index is now a drive media combination. Compare this to
+ // the maximum drive media type in the drive media table.
+ //
+
+ for (length = 0; length < NUMBER_OF_DRIVE_TYPES; length++) {
+
+ if (DriveMediaLimits[length].HighestDriveMediaType == index) {
+ return(length);
+ }
+ }
+ return(DRIVE_TYPE_NONE);
+ }
+ }
+
+ // If the maximum track is greater than 8 bits then divide the
+ // number of tracks by 3 and multiply the number of heads by 3.
+ // This is a special case for the 20.8 MB floppy.
+ //
+
+ if (!applyFix && maximumTrack >= 0x0100) {
+ maximumTrack++;
+ maximumTrack /= 3;
+ maximumTrack--;
+ numberOfHeads *= 3;
+ } else {
+ ExFreePool(modeData);
+ return(DRIVE_TYPE_NONE);
+ }
+
+ }
+
+ ExFreePool(modeData);
+ return(DRIVE_TYPE_NONE);
+}
+
+
+BOOLEAN
+FlCheckFormatParameters(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PFORMAT_PARAMETERS FormatParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the supplied format parameters to make sure that
+ they'll work on the drive to be formatted.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object to be formated.
+
+ FormatParameters - a pointer to the caller's parameters for the FORMAT.
+
+Return Value:
+
+ TRUE if parameters are OK.
+ FALSE if the parameters are bad.
+
+--*/
+
+{
+ PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
+ DRIVE_MEDIA_TYPE driveMediaType;
+ ULONG index;
+
+ PAGED_CODE();
+
+ //
+ // Get the device type.
+ //
+
+ index = DetermineDriveType(DeviceObject);
+
+ if (index == DRIVE_TYPE_NONE) {
+
+ //
+ // If the determine device type failed then just use the media type
+ // and try the parameters.
+ //
+
+ driveMediaType = Drive360Media160;
+
+ while (( DriveMediaConstants[driveMediaType].MediaType !=
+ FormatParameters->MediaType ) &&
+ ( driveMediaType < Drive288Media288) ) {
+
+ driveMediaType++;
+ }
+
+ } else {
+
+ //
+ // Figure out which entry in the DriveMediaConstants table to use.
+ //
+
+ driveMediaType =
+ DriveMediaLimits[index].HighestDriveMediaType;
+
+ while ( ( DriveMediaConstants[driveMediaType].MediaType !=
+ FormatParameters->MediaType ) &&
+ ( driveMediaType > DriveMediaLimits[index].
+ LowestDriveMediaType ) ) {
+
+ driveMediaType--;
+ }
+
+ }
+
+
+ // driveMediaType is bounded below by DriveMediaLimits[].LowestDriveMediaType
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:33010) // 33010: Enum used as array index may be negative
+#endif
+ if ( DriveMediaConstants[driveMediaType].MediaType !=
+ FormatParameters->MediaType ) {
+ return FALSE;
+
+ } else {
+
+ driveMediaConstants = &DriveMediaConstants[driveMediaType];
+
+ if ( ( FormatParameters->StartHeadNumber >
+ (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
+ ( FormatParameters->EndHeadNumber >
+ (ULONG)( driveMediaConstants->NumberOfHeads - 1 ) ) ||
+ ( FormatParameters->StartCylinderNumber >
+ driveMediaConstants->MaximumTrack ) ||
+ ( FormatParameters->EndCylinderNumber >
+ driveMediaConstants->MaximumTrack ) ||
+ ( FormatParameters->EndCylinderNumber <
+ FormatParameters->StartCylinderNumber ) ) {
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+ }
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+}
+
+NTSTATUS
+FormatMedia(
+ PDEVICE_OBJECT DeviceObject,
+ MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine formats the floppy disk. The entire floppy is formated in
+ one shot.
+
+Arguments:
+
+ DeviceObject - Supplies the device object to be tested.
+
+ Irp - Supplies a pointer to the requesting Irp.
+
+ MediaType - Supplies the media type format the device for.
+
+Return Value:
+
+ Returns a status for the operation.
+
+--*/
+{
+ PVOID modeData;
+ PSCSI_REQUEST_BLOCK srb;
+ PMODE_FLEXIBLE_DISK_PAGE pageData;
+ DRIVE_MEDIA_TYPE driveMediaType;
+ PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
+ ULONG length;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+#ifndef __REACTOS__
+ modeData = ExAllocatePool(NonPagedPoolNxCacheAligned, MODE_DATA_SIZE);
+#else
+ modeData = ExAllocatePool(NonPagedPoolCacheAligned, MODE_DATA_SIZE);
+#endif
+
+ if (modeData == NULL) {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlZeroMemory(modeData, MODE_DATA_SIZE);
+
+ length = ClassModeSense(DeviceObject,
+ modeData,
+ MODE_DATA_SIZE,
+ MODE_PAGE_FLEXIBILE);
+
+ if (length < sizeof(MODE_PARAMETER_HEADER)) {
+ ExFreePool(modeData);
+ return(STATUS_INVALID_DEVICE_REQUEST);
+ }
+
+ //
+ // Look for the flexible disk mode page.
+ //
+
+ pageData = ClassFindModePage( modeData, length, MODE_PAGE_FLEXIBILE, TRUE);
+
+ //
+ // Make sure the page is returned and is large enough.
+ //
+
+ if ((pageData == NULL) ||
+ (pageData->PageLength + 2 <
+ (UCHAR)offsetof(MODE_FLEXIBLE_DISK_PAGE, StartWritePrecom))) {
+
+ ExFreePool(modeData);
+ return(STATUS_INVALID_DEVICE_REQUEST);
+
+ }
+
+ //
+ // Look for a drive media type which matches the requested media type.
+ //
+ //
+ //start from Drive120MMedia120M instead of Drive2080Media2080
+ //
+ for (driveMediaType = Drive120MMedia120M;
+ DriveMediaConstants[driveMediaType].MediaType != MediaType;
+ driveMediaType--) {
+ if (driveMediaType == Drive360Media160) {
+
+ ExFreePool(modeData);
+ return(STATUS_INVALID_PARAMETER);
+
+ }
+ }
+
+ driveMediaConstants = &DriveMediaConstants[driveMediaType];
+
+ if ((pageData->NumberOfHeads != driveMediaConstants->NumberOfHeads) ||
+ (pageData->SectorsPerTrack != driveMediaConstants->SectorsPerTrack) ||
+ ((pageData->NumberOfCylinders[0] !=
(UCHAR)((driveMediaConstants->MaximumTrack+1) >> 8)) &&
+ (pageData->NumberOfCylinders[1] !=
(UCHAR)driveMediaConstants->MaximumTrack+1)) ||
+ (pageData->BytesPerSector[0] != driveMediaConstants->BytesPerSector
>> 8 )) {
+
+ //
+ // Update the flexible parameters page with the new parameters.
+ //
+
+ pageData->NumberOfHeads = driveMediaConstants->NumberOfHeads;
+ pageData->SectorsPerTrack = driveMediaConstants->SectorsPerTrack;
+ pageData->NumberOfCylinders[0] =
(UCHAR)((driveMediaConstants->MaximumTrack+1) >> 8);
+ pageData->NumberOfCylinders[1] =
(UCHAR)driveMediaConstants->MaximumTrack+1;
+ pageData->BytesPerSector[0] = driveMediaConstants->BytesPerSector >>
8;
+
+ //
+ // Clear the mode parameter header.
+ //
+
+ RtlZeroMemory(modeData, sizeof(MODE_PARAMETER_HEADER));
+
+ //
+ // Set the length equal to the length returned for the flexible page.
+ //
+
+ length = pageData->PageLength + 2;
+
+ //
+ // Copy the page after the mode parameter header.
+ //
+
+ RtlMoveMemory((PCHAR) modeData + sizeof(MODE_PARAMETER_HEADER),
+ pageData,
+ length
+ );
+ length += sizeof(MODE_PARAMETER_HEADER);
+
+
+ //
+ // Allocate a Srb for the format command.
+ //
+
+#ifndef __REACTOS__
+ srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
+#else
+ srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
+#endif
+
+ if (srb == NULL) {
+
+ ExFreePool(modeData);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ srb->CdbLength = 6;
+ srb->Cdb[0] = SCSIOP_MODE_SELECT;
+ srb->Cdb[4] = (UCHAR) length;
+
+ //
+ // Set the PF bit.
+ //
+
+ srb->Cdb[1] |= 0x10;
+
+ //
+ // Set timeout value.
+ //
+
+ srb->TimeOutValue = 2;
+
+ //
+ // Send the mode select data.
+ //
+
+ status = ClassSendSrbSynchronous(DeviceObject,
+ srb,
+ modeData,
+ length,
+ TRUE
+ );
+
+ //
+ // The mode data not needed any more so free it.
+ //
+
+ ExFreePool(modeData);
+
+ if (!NT_SUCCESS(status)) {
+ ExFreePool(srb);
+ return(status);
+ }
+
+ } else {
+
+ //
+ // The mode data not needed any more so free it.
+ //
+
+ ExFreePool(modeData);
+
+ //
+ // Allocate a Srb for the format command.
+ //
+
+#ifndef __REACTOS__
+ srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
+#else
+ srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
+#endif
+
+ if (srb == NULL) {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ }
+
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ srb->CdbLength = 6;
+
+ srb->Cdb[0] = SCSIOP_FORMAT_UNIT;
+
+ //
+ // Set timeout value.
+ //
+
+ srb->TimeOutValue = 10 * 60;
+
+ status = ClassSendSrbSynchronous(DeviceObject,
+ srb,
+ NULL,
+ 0,
+ FALSE
+ );
+ ExFreePool(srb);
+
+ return(status);
+
+}
+
+VOID
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopProcessError(
+ PDEVICE_OBJECT DeviceObject,
+ PSCSI_REQUEST_BLOCK Srb,
+ NTSTATUS *Status,
+ BOOLEAN *Retry
+ )
+/*++
+
+Routine Description:
+
+ This routine checks the type of error. If the error indicate the floppy
+ controller needs to be reinitialize a command is made to do it.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the device object.
+
+ Srb - Supplies a pointer to the failing Srb.
+
+ Status - Status with which the IRP will be completed.
+
+ Retry - Indication of whether the request will be retried.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
+ PDISK_DATA diskData = (PDISK_DATA) fdoExtension->CommonExtension.DriverData;
+ PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
+ PIO_STACK_LOCATION irpStack;
+ PIRP irp;
+ PSCSI_REQUEST_BLOCK srb;
+ LARGE_INTEGER largeInt;
+ PCOMPLETION_CONTEXT context;
+ PCDB cdb;
+ ULONG_PTR alignment;
+ ULONG majorFunction;
+
+ UNREFERENCED_PARAMETER(Status);
+ UNREFERENCED_PARAMETER(Retry);
+
+ largeInt.QuadPart = 1;
+
+ //
+ // Check the status. The initialization command only needs to be sent
+ // if UNIT ATTENTION or LUN NOT READY is returned.
+ //
+
+ if (!(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) {
+
+ //
+ // The drive does not require reinitialization.
+ //
+
+ return;
+ }
+
+ //
+ // Reset the drive type.
+ //
+
+ diskData->DriveType = DRIVE_TYPE_NONE;
+ diskData->IsDMF = FALSE;
+
+ fdoExtension->DiskGeometry.MediaType = Unknown;
+
+ if (fdoExtension->AdapterDescriptor->BusType == BusTypeUsb) {
+
+ // FLPYDISK.SYS never returns a non-zero value for the ChangeCount
+ // on an IOCTL_DISK_CHECK_VERIFY. Some things seem to work better
+ // if we do the same. In particular, FatVerifyVolume() can exit between
+ // the IOCTL_DISK_CHECK_VERIFY and the IOCTL_DISK_GET_DRIVE_GEOMETRY
+ // if a non-zero ChangeCount is returned, and this appears to cause
+ // issues formatting unformatted media in some situations.
+ //
+ // This is something that should probably be revisited at some point.
+ //
+ fdoExtension->MediaChangeCount = 0;
+
+ if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION)
&&
+ (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_MEDIUM_CHANGED)) {
+
+ struct _START_STOP *startStopCdb;
+
+ DebugPrint((2,"Sending SCSIOP_START_STOP_UNIT\n"));
+
+#ifndef __REACTOS__
+ context = ExAllocatePool(NonPagedPoolNx,
+#else
+ context = ExAllocatePool(NonPagedPool,
+#endif
+ sizeof(COMPLETION_CONTEXT));
+
+ if (context == NULL) {
+
+ return;
+ }
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+ srb = &context->Srb.Srb;
+#else
+ srb = &context->Srb;
+#endif
+
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ srb->SrbFlags = SRB_FLAGS_DISABLE_AUTOSENSE;
+
+ srb->CdbLength = 6;
+
+ startStopCdb = (struct _START_STOP *)srb->Cdb;
+
+ startStopCdb->OperationCode = SCSIOP_START_STOP_UNIT;
+ startStopCdb->Start = 1;
+
+ // A Start Stop Unit request has no transfer buffer.
+ // Set the request to IRP_MJ_FLUSH_BUFFERS when calling
+ // IoBuildAsynchronousFsdRequest() so that it ignores
+ // the buffer pointer and buffer length parameters.
+ //
+ majorFunction = IRP_MJ_FLUSH_BUFFERS;
+
+ } else if ((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_MEDIUM_ERROR) {
+
+ // Return ERROR_UNRECOGNIZED_MEDIA instead of
+ // STATUS_DEVICE_DATA_ERROR to make shell happy.
+ //
+ *Status = STATUS_UNRECOGNIZED_MEDIA;
+ return;
+
+ } else {
+
+ return;
+ }
+
+#ifndef __REACTOS__
+ } else if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY) &&
+ senseBuffer->AdditionalSenseCodeQualifier ==
SCSI_SENSEQ_INIT_COMMAND_REQUIRED ||
+ (senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
+#else
+ } else if ((((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_NOT_READY)
&&
+ senseBuffer->AdditionalSenseCodeQualifier ==
SCSI_SENSEQ_INIT_COMMAND_REQUIRED) ||
+ (senseBuffer->SenseKey & 0xf) == SCSI_SENSE_UNIT_ATTENTION) {
+#endif
+
+ ULONG sizeNeeded;
+ ULONG tmpSize;
+ BOOLEAN overFlow;
+
+ DebugPrint((1, "ScsiFlopProcessError: Reinitializing the floppy.\n"));
+
+ //
+ // Send the special mode sense command to enable writes on the
+ // floptical drive.
+ //
+
+ alignment = DeviceObject->AlignmentRequirement ?
+ DeviceObject->AlignmentRequirement : 1;
+
+ sizeNeeded = 0;
+ overFlow = TRUE;
+ if (SUCCEEDED(ULongAdd(sizeof(COMPLETION_CONTEXT), 0x2a, &tmpSize))) {
+
+ if (SUCCEEDED(ULongAdd(tmpSize, (ULONG) alignment, &sizeNeeded))) {
+ overFlow = FALSE;
+ }
+ }
+
+ context = NULL;
+
+ if (!overFlow) {
+#ifndef __REACTOS__
+ context = ExAllocatePool(NonPagedPoolNx, sizeNeeded);
+#else
+ context = ExAllocatePool(NonPagedPool, sizeNeeded);
+#endif
+ }
+
+ if (context == NULL) {
+
+ //
+ // If there is not enough memory to fulfill this request,
+ // simply return. A subsequent retry will fail and another
+ // chance to start the unit.
+ //
+
+ return;
+ }
+
+#if (NTDDI_VERSION >= NTDDI_WIN8)
+ srb = &context->Srb.Srb;
+#else
+ srb = &context->Srb;
+#endif
+
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ //
+ // Set the transfer length.
+ //
+
+ srb->DataTransferLength = 0x2a;
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_AUTOSENSE |
SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+
+ //
+ // The data buffer must be aligned.
+ //
+
+ srb->DataBuffer = (PVOID) (((ULONG_PTR) (context + 1) + (alignment - 1))
&
+ ~(alignment - 1));
+
+
+ //
+ // Build the start unit CDB.
+ //
+
+ srb->CdbLength = 6;
+ cdb = (PCDB)srb->Cdb;
+ cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
+ cdb->MODE_SENSE.PageCode = 0x2e;
+ cdb->MODE_SENSE.AllocationLength = 0x2a;
+
+ majorFunction = IRP_MJ_READ;
+
+ } else {
+
+ return;
+ }
+
+ context->DeviceObject = DeviceObject;
+
+ //
+ // Write length to SRB.
+ //
+
+ srb->Length = SCSI_REQUEST_BLOCK_SIZE;
+
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+ srb->TimeOutValue = fdoExtension->TimeOutValue;
+
+ //
+ // Build the asynchronous request
+ // to be sent to the port driver.
+ //
+
+ irp = IoBuildAsynchronousFsdRequest(majorFunction,
+ DeviceObject,
+ srb->DataBuffer,
+ srb->DataTransferLength,
+ &largeInt,
+ NULL);
+
+ if(irp == NULL) {
+ ExFreePool(context);
+ return;
+ }
+
+
+ IoSetCompletionRoutine(irp,
+ (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
+ context,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ ClassAcquireRemoveLock(DeviceObject, irp);
+
+ irpStack = IoGetNextIrpStackLocation(irp);
+
+ irpStack->MajorFunction = IRP_MJ_SCSI;
+
+ srb->OriginalRequest = irp;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ irpStack->Parameters.Others.Argument1 = (PVOID)srb;
+
+ //
+ // Can't release the remove lock yet - let ClassAsynchronousCompletion
+ // take care of that for us.
+ //
+
+ (VOID)IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
+
+ return;
+}
+
+NTSTATUS
+FlopticalFormatMedia(
+ PDEVICE_OBJECT DeviceObject,
+ PFORMAT_PARAMETERS Format
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to do perform a format tracks for the 20.8 MB
+ floppy. Because the device does not support format tracks and the full
+ format takes a long time a write of zeros is done instead.
+
+Arguments:
+
+ DeviceObject - Supplies the device object to be tested.
+
+ Format - Supplies the format parameters.
+
+Return Value:
+
+ Returns a status for the operation.
+
+--*/
+{
+ IO_STATUS_BLOCK ioStatus;
+ PIRP irp;
+ KEVENT event;
+ LARGE_INTEGER offset;
+ ULONG length;
+ PVOID buffer;
+ PDRIVE_MEDIA_CONSTANTS driveMediaConstants;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ driveMediaConstants = &DriveMediaConstants[Drive2080Media2080];
+
+ //
+ // Calculate the length of the buffer.
+ //
+
+ length = ((Format->EndCylinderNumber - Format->StartCylinderNumber) *
+ driveMediaConstants->NumberOfHeads +
+ Format->EndHeadNumber - Format->StartHeadNumber + 1) *
+ driveMediaConstants->SectorsPerTrack *
+ driveMediaConstants->BytesPerSector;
+
+#ifndef __REACTOS__
+ buffer = ExAllocatePool(NonPagedPoolNxCacheAligned, length);
+#else
+ buffer = ExAllocatePool(NonPagedPoolCacheAligned, length);
+#endif
+
+ if (buffer == NULL) {
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlZeroMemory(buffer, length);
+
+ offset.QuadPart =
+ (Format->StartCylinderNumber * driveMediaConstants->NumberOfHeads +
+ Format->StartHeadNumber) * driveMediaConstants->SectorsPerTrack *
+ driveMediaConstants->BytesPerSector;
+
+ //
+ // Set the event object to the unsignaled state.
+ // It will be used to signal request completion.
+ //
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ //
+ // Build the synchronous request with data transfer.
+ //
+
+ irp = IoBuildSynchronousFsdRequest(
+ IRP_MJ_WRITE,
+ DeviceObject,
+ buffer,
+ length,
+ &offset,
+ &event,
+ &ioStatus);
+
+ if (irp != NULL) {
+ status = IoCallDriver(DeviceObject, irp);
+
+ if (status == STATUS_PENDING) {
+
+ //
+ // Wait for the request to complete if necessary.
+ //
+
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ //
+ // If the call driver suceeded then set the status to the status block.
+ //
+
+ if (NT_SUCCESS(status)) {
+ status = ioStatus.Status;
+ }
+ } else {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ExFreePool(buffer);
+
+ return(status);
+
+}
+
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopRemoveDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR Type
+ )
+/*++
+
+Routine Description:
+
+ This routine is responsible for releasing any resources in use by the
+ sfloppy driver. This routine is called
+ when all outstanding requests have been completed and the driver has
+ disappeared - no requests may be issued to the lower drivers.
+
+Arguments:
+
+ DeviceObject - the device object being removed
+
+ Type - the type of remove operation (QUERY, REMOVE or CANCEL)
+
+Return Value:
+
+ for a query - success if the device can be removed or a failure code
+ indiciating why not.
+
+ for a remove or cancel - STATUS_SUCCESS
+
+--*/
+
+{
+ PFUNCTIONAL_DEVICE_EXTENSION deviceExtension =
+ DeviceObject->DeviceExtension;
+ PDISK_DATA diskData = deviceExtension->CommonExtension.DriverData;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ if((Type == IRP_MN_QUERY_REMOVE_DEVICE) ||
+ (Type == IRP_MN_CANCEL_REMOVE_DEVICE)) {
+ return STATUS_SUCCESS;
+ }
+
+ if (Type == IRP_MN_REMOVE_DEVICE){
+ if(deviceExtension->DeviceDescriptor) {
+ ExFreePool(deviceExtension->DeviceDescriptor);
+ deviceExtension->DeviceDescriptor = NULL;
+ }
+
+ if(deviceExtension->AdapterDescriptor) {
+ ExFreePool(deviceExtension->AdapterDescriptor);
+ deviceExtension->AdapterDescriptor = NULL;
+ }
+
+ if(deviceExtension->SenseData) {
+ ExFreePool(deviceExtension->SenseData);
+ deviceExtension->SenseData = NULL;
+ }
+
+ ClassDeleteSrbLookasideList(&deviceExtension->CommonExtension);
+ }
+
+ if(diskData->FloppyInterfaceString.Buffer != NULL) {
+
+ status = IoSetDeviceInterfaceState(
+ &(diskData->FloppyInterfaceString),
+ FALSE);
+
+ if (!NT_SUCCESS(status)) {
+ // Failed to disable device interface during removal. Not a fatal error.
+ DebugPrint((1, "ScsiFlopRemoveDevice: Unable to set device "
+ "interface state to FALSE for fdo %p "
+ "[%08lx]\n",
+ DeviceObject, status));
+ }
+
+ RtlFreeUnicodeString(&(diskData->FloppyInterfaceString));
+ RtlInitUnicodeString(&(diskData->FloppyInterfaceString), NULL);
+ }
+
+ if(Type == IRP_MN_REMOVE_DEVICE) {
+ IoGetConfigurationInformation()->FloppyCount--;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+#ifdef __REACTOS__
+NTAPI
+#endif
+ScsiFlopStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN UCHAR Type
+ )
+{
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Type);
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+USBFlopGetMediaTypes(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+/*++
+
+Routine Description:
+
+ This routines determines the current or default geometry of the drive
+ for IOCTL_DISK_GET_DRIVE_GEOMETRY, or all currently supported geometries
+ of the drive (which is determined by its currently inserted media) for
+ IOCTL_DISK_GET_MEDIA_TYPES.
+
+ The returned geometries are determined by issuing a Read Format Capacities
+ request and then matching the returned {Number of Blocks, Block Length}
+ pairs in a table of known floppy geometries.
+
+Arguments:
+
+ DeviceObject - Supplies the device object.
+
+ Irp - A IOCTL_DISK_GET_DRIVE_GEOMETRY or a IOCTL_DISK_GET_MEDIA_TYPES Irp.
+ If NULL, the device geometry is updated with the current device
+ geometry.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
+ PIO_STACK_LOCATION irpStack;
+ ULONG ioControlCode;
+ PDISK_GEOMETRY outputBuffer;
+ PDISK_GEOMETRY outputBufferEnd;
+ ULONG outputBufferLength;
+ PSCSI_REQUEST_BLOCK srb;
+ PVOID dataBuffer;
+ ULONG dataTransferLength;
+ struct _READ_FORMATTED_CAPACITIES *cdb;
+ PFORMATTED_CAPACITY_LIST capList;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ fdoExtension = DeviceObject->DeviceExtension;
+
+ if (Irp != NULL) {
+
+ // Get the Irp parameters
+ //
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
+
+ Irp->IoStatus.Information = 0;
+
+ outputBuffer = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
+
+ outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (outputBufferLength < sizeof(DISK_GEOMETRY))
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // Pointer arithmetic to allow multiple DISK_GEOMETRY's to be returned.
+ // Rounds BufferEnd down to integral multiple of DISK_GEOMETRY structs.
+ //
+ outputBufferEnd = outputBuffer +
+ outputBufferLength / sizeof(DISK_GEOMETRY);
+
+ } else {
+
+ // No Irp to return the result in, just update the current geometry
+ // in the device extension.
+ //
+ ioControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY;
+
+ outputBuffer = NULL;
+
+ outputBufferEnd = NULL;
+
+ outputBufferLength = 0;
+ }
+
+ if (ioControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {
+
+ fdoExtension->DiskGeometry.MediaType = Unknown;
+
+ status = ClassReadDriveCapacity(DeviceObject);
+
+ if (!NT_SUCCESS(status))
+ {
+ // If the media is not recongized, we want to return the default
+ // geometry so that the media can be formatted. Unrecognized media
+ // causes SCSI_SENSE_MEDIUM_ERROR, which gets reported as
+ // STATUS_DEVICE_DATA_ERROR. Ignore these errors, but return other
+ // errors, such as STATUS_NO_MEDIA_IN_DEVICE.
+ //
+ if (status != STATUS_UNRECOGNIZED_MEDIA)
+ {
+ DebugPrint((2,"IOCTL_DISK_GET_DRIVE_GEOMETRY returns %08X\n",
status));
+
+ return status;
+ }
+ }
+ }
+
+ // Allocate an SRB for the SCSIOP_READ_FORMATTED_CAPACITY request
+ //
+#ifndef __REACTOS__
+ srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
+#else
+ srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
+#endif
+
+ if (srb == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Allocate a transfer buffer for the SCSIOP_READ_FORMATTED_CAPACITY request
+ // The length of the returned descriptor array is limited to a byte field
+ // in the capacity list header.
+ //
+ dataTransferLength = sizeof(FORMATTED_CAPACITY_LIST) +
+ 31 * sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
+
+ ASSERT(dataTransferLength < 0x100);
+
+#ifndef __REACTOS__
+ dataBuffer = ExAllocatePool(NonPagedPoolNx, dataTransferLength);
+#else
+ dataBuffer = ExAllocatePool(NonPagedPool, dataTransferLength);
+#endif
+
+ if (dataBuffer == NULL)
+ {
+ ExFreePool(srb);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Initialize the SRB and CDB
+ //
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ RtlZeroMemory(dataBuffer, dataTransferLength);
+
+ srb->CdbLength = sizeof(struct _READ_FORMATTED_CAPACITIES);
+
+ srb->TimeOutValue = fdoExtension->TimeOutValue;
+
+ cdb = (struct _READ_FORMATTED_CAPACITIES *)srb->Cdb;
+
+ cdb->OperationCode = SCSIOP_READ_FORMATTED_CAPACITY;
+ cdb->AllocationLength[1] = (UCHAR)dataTransferLength;
+
+ //
+ // Send down the SCSIOP_READ_FORMATTED_CAPACITY request
+ //
+ status = ClassSendSrbSynchronous(DeviceObject,
+ srb,
+ dataBuffer,
+ dataTransferLength,
+ FALSE);
+
+ capList = (PFORMATTED_CAPACITY_LIST)dataBuffer;
+
+ // If we don't get as much data as requested, it is not an error.
+ //
+ if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status) &&
+ srb->DataTransferLength >= sizeof(FORMATTED_CAPACITY_LIST) &&
+ capList->CapacityListLength &&
+ capList->CapacityListLength % sizeof(FORMATTED_CAPACITY_DESCRIPTOR) == 0)
+ {
+ ULONG NumberOfBlocks;
+ ULONG BlockLength;
+ ULONG count;
+ ULONG i, j;
+ LONG currentGeometry;
+ BOOLEAN capacityMatches[FLOPPY_CAPACITIES];
+
+ // Subtract the size of the Capacity List Header to get
+ // just the size of the Capacity List Descriptor array.
+ //
+ srb->DataTransferLength -= sizeof(FORMATTED_CAPACITY_LIST);
+
+ // Only look at the Capacity List Descriptors that were actually
+ // returned.
+ //
+ if (srb->DataTransferLength < capList->CapacityListLength)
+ {
+ count = srb->DataTransferLength /
+ sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
+ }
+ else
+ {
+ count = capList->CapacityListLength /
+ sizeof(FORMATTED_CAPACITY_DESCRIPTOR);
+ }
+
+ // Updated only if a match is found for the first Capacity List
+ // Descriptor returned by the device.
+ //
+ currentGeometry = -1;
+
+ // Initialize the array of capacities that hit a match.
+ //
+ RtlZeroMemory(capacityMatches, sizeof(capacityMatches));
+
+ // Iterate over each Capacity List Descriptor returned from the device
+ // and record matching capacities in the capacity match array.
+ //
+ for (i = 0; i < count; i++)
+ {
+ NumberOfBlocks = (capList->Descriptors[i].NumberOfBlocks[0] << 24)
+
+ (capList->Descriptors[i].NumberOfBlocks[1] << 16)
+
+ (capList->Descriptors[i].NumberOfBlocks[2] << 8)
+
+ (capList->Descriptors[i].NumberOfBlocks[3]);
+
+ BlockLength = (capList->Descriptors[i].BlockLength[0] << 16) +
+ (capList->Descriptors[i].BlockLength[1] << 8) +
+ (capList->Descriptors[i].BlockLength[2]);
+
+ // Given the {NumberOfBlocks, BlockLength} from this Capacity List
+ // Descriptor, find a matching entry in FloppyCapacities[].
+ //
+ for (j = 0; j < FLOPPY_CAPACITIES; j++)
+ {
+ if (NumberOfBlocks == FloppyCapacities[j].NumberOfBlocks &&
+ BlockLength == FloppyCapacities[j].BlockLength)
+ {
+ // A matching capacity was found, record it.
+ //
+ capacityMatches[j] = TRUE;
+
+ // A match was found for the first Capacity List
+ // Descriptor returned by the device.
+ //
+ if (i == 0)
+ {
+ currentGeometry = j;
+ }
+ } else if ((capList->Descriptors[i].Valid) &&
+ (BlockLength == FloppyCapacities[j].BlockLength)) {
+
+ ULONG inx;
+ ULONG mediaInx;
+
+ //
+ // Check if this is 32MB media type. 32MB media
+ // reports variable NumberOfBlocks. So we cannot
+ // use that to determine the drive type
+ //
+ inx = DetermineDriveType(DeviceObject);
+ if (inx != DRIVE_TYPE_NONE) {
+ mediaInx = DriveMediaLimits[inx].HighestDriveMediaType;
+ if ((DriveMediaConstants[mediaInx].MediaType)
+ == F3_32M_512) {
+ capacityMatches[j] = TRUE;
+
+ if (i == 0) {
+ currentGeometry = j;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Default status is STATUS_UNRECOGNIZED_MEDIA, unless we return
+ // either STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW.
+ //
+ status = STATUS_UNRECOGNIZED_MEDIA;
+
+ if (ioControlCode == IOCTL_DISK_GET_DRIVE_GEOMETRY) {
+
+ if (currentGeometry != -1)
+ {
+ // Update the current device geometry
+ //
+ fdoExtension->DiskGeometry = FloppyGeometries[currentGeometry];
+
+ //
+ // Calculate sector to byte shift.
+ //
+
+ WHICH_BIT(fdoExtension->DiskGeometry.BytesPerSector,
+ fdoExtension->SectorShift);
+
+ fdoExtension->CommonExtension.PartitionLength.QuadPart =
+ (LONGLONG)FloppyCapacities[currentGeometry].NumberOfBlocks *
+ FloppyCapacities[currentGeometry].BlockLength;
+
+ DebugPrint((2,"geometry is: %3d %2d %d %2d %4d %2d %08X\n",
+ fdoExtension->DiskGeometry.Cylinders.LowPart,
+ fdoExtension->DiskGeometry.MediaType,
+ fdoExtension->DiskGeometry.TracksPerCylinder,
+ fdoExtension->DiskGeometry.SectorsPerTrack,
+ fdoExtension->DiskGeometry.BytesPerSector,
+ fdoExtension->SectorShift,
+ fdoExtension->CommonExtension.PartitionLength.LowPart));
+
+ // Return the current device geometry
+ //
+ if (Irp != NULL)
+ {
+ *outputBuffer = FloppyGeometries[currentGeometry];
+
+ Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
+ }
+
+ status = STATUS_SUCCESS;
+ }
+
+ } else {
+
+ // Iterate over the capacities and return the geometry
+ // corresponding to each matching Capacity List Descriptor
+ // returned from the device.
+ //
+ // The resulting list should be in sorted ascending order,
+ // assuming that the FloppyGeometries[] array is in sorted
+ // ascending order.
+ //
+ for (i = 0; i < FLOPPY_CAPACITIES; i++)
+ {
+ if (capacityMatches[i] && FloppyCapacities[i].CanFormat)
+ {
+ if (outputBuffer < outputBufferEnd)
+ {
+ *outputBuffer++ = FloppyGeometries[i];
+
+ Irp->IoStatus.Information += sizeof(DISK_GEOMETRY);
+
+ DebugPrint((2,"geometry : %3d %2d %d %2d %4d\n",
+ FloppyGeometries[i].Cylinders.LowPart,
+ FloppyGeometries[i].MediaType,
+ FloppyGeometries[i].TracksPerCylinder,
+ FloppyGeometries[i].SectorsPerTrack,
+ FloppyGeometries[i].BytesPerSector));
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ // We ran out of output buffer room before we ran out
+ // geometries to return.
+ //
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+ }
+ }
+ }
+ }
+ else if (NT_SUCCESS(status))
+ {
+ // The SCSIOP_READ_FORMATTED_CAPACITY request was successful, but
+ // returned data does not appear valid.
+ //
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ ExFreePool(dataBuffer);
+ ExFreePool(srb);
+
+ return status;
+}
+
+
+NTSTATUS
+USBFlopFormatTracks(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+/*++
+
+Routine Description:
+
+ This routines formats the specified tracks. If multiple tracks are
+ specified, each is formatted with a separate Format Unit request.
+
+Arguments:
+
+ DeviceObject - Supplies the device object.
+
+ Irp - A IOCTL_DISK_FORMAT_TRACKS Irp.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+ PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
+ PIO_STACK_LOCATION irpStack;
+ PFORMAT_PARAMETERS formatParameters;
+ PDISK_GEOMETRY geometry;
+ PFORMATTED_CAPACITY capacity;
+ PSCSI_REQUEST_BLOCK srb;
+ PFORMAT_UNIT_PARAMETER_LIST parameterList;
+ PCDB12FORMAT cdb;
+ ULONG i;
+ ULONG cylinder, head;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ fdoExtension = DeviceObject->DeviceExtension;
+
+ // Get the Irp parameters
+ //
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
+ sizeof(FORMAT_PARAMETERS))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ formatParameters = (PFORMAT_PARAMETERS)Irp->AssociatedIrp.SystemBuffer;
+
+ // Find the geometry / capacity entries corresponding to the format
+ // parameters MediaType
+ //
+ geometry = NULL;
+ capacity = NULL;
+
+ for (i=0; i<FLOPPY_CAPACITIES; i++)
+ {
+ if (FloppyGeometries[i].MediaType == formatParameters->MediaType)
+ {
+ geometry = &FloppyGeometries[i];
+ capacity = &FloppyCapacities[i];
+
+ break;
+ }
+ }
+
+ if (geometry == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Check if the format parameters are valid
+ //
+ if ((formatParameters->StartCylinderNumber >
+ geometry->Cylinders.LowPart - 1) ||
+
+ (formatParameters->EndCylinderNumber >
+ geometry->Cylinders.LowPart - 1) ||
+
+ (formatParameters->StartHeadNumber >
+ geometry->TracksPerCylinder - 1) ||
+
+ (formatParameters->EndHeadNumber >
+ geometry->TracksPerCylinder - 1) ||
+
+ (formatParameters->StartCylinderNumber >
+ formatParameters->EndCylinderNumber) ||
+
+ (formatParameters->StartHeadNumber >
+ formatParameters->EndHeadNumber))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Don't low level format LS-120 media, Imation says it's best to not
+ // do this.
+ //
+ if ((formatParameters->MediaType == F3_120M_512) ||
+ (formatParameters->MediaType == F3_240M_512) ||
+ (formatParameters->MediaType == F3_32M_512))
+ {
+ return STATUS_SUCCESS;
+ }
+
+ // Allocate an SRB for the SCSIOP_FORMAT_UNIT request
+ //
+#ifndef __REACTOS__
+ srb = ExAllocatePool(NonPagedPoolNx, SCSI_REQUEST_BLOCK_SIZE);
+#else
+ srb = ExAllocatePool(NonPagedPool, SCSI_REQUEST_BLOCK_SIZE);
+#endif
+
+ if (srb == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Allocate a transfer buffer for the SCSIOP_FORMAT_UNIT parameter list
+ //
+#ifndef __REACTOS__
+ parameterList = ExAllocatePool(NonPagedPoolNx,
+#else
+ parameterList = ExAllocatePool(NonPagedPool,
+#endif
+ sizeof(FORMAT_UNIT_PARAMETER_LIST));
+
+ if (parameterList == NULL)
+ {
+ ExFreePool(srb);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Initialize the parameter list
+ //
+ RtlZeroMemory(parameterList, sizeof(FORMAT_UNIT_PARAMETER_LIST));
+
+ parameterList->DefectListHeader.SingleTrack = 1;
+ parameterList->DefectListHeader.DisableCert = 1; // TEAC requires this set
+ parameterList->DefectListHeader.FormatOptionsValid = 1;
+ parameterList->DefectListHeader.DefectListLengthLsb = 8;
+
+ parameterList->FormatDescriptor.NumberOfBlocks[0] =
+ (UCHAR)((capacity->NumberOfBlocks >> 24) & 0xFF);
+
+ parameterList->FormatDescriptor.NumberOfBlocks[1] =
+ (UCHAR)((capacity->NumberOfBlocks >> 16) & 0xFF);
+
+ parameterList->FormatDescriptor.NumberOfBlocks[2] =
+ (UCHAR)((capacity->NumberOfBlocks >> 8) & 0xFF);
+
+ parameterList->FormatDescriptor.NumberOfBlocks[3] =
+ (UCHAR)(capacity->NumberOfBlocks & 0xFF);
+
+ parameterList->FormatDescriptor.BlockLength[0] =
+ (UCHAR)((capacity->BlockLength >> 16) & 0xFF);
+
+ parameterList->FormatDescriptor.BlockLength[1] =
+ (UCHAR)((capacity->BlockLength >> 8) & 0xFF);
+
+ parameterList->FormatDescriptor.BlockLength[2] =
+ (UCHAR)(capacity->BlockLength & 0xFF);
+
+
+ for (cylinder = formatParameters->StartCylinderNumber;
+ cylinder <= formatParameters->EndCylinderNumber;
+ cylinder++)
+ {
+ for (head = formatParameters->StartHeadNumber;
+ head <= formatParameters->EndHeadNumber;
+ head++)
+ {
+ // Initialize the SRB and CDB
+ //
+ RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
+
+ srb->CdbLength = sizeof(CDB12FORMAT);
+
+ srb->TimeOutValue = fdoExtension->TimeOutValue;
+
+ cdb = (PCDB12FORMAT)srb->Cdb;
+
+ cdb->OperationCode = SCSIOP_FORMAT_UNIT;
+ cdb->DefectListFormat = 7;
+ cdb->FmtData = 1;
+ cdb->TrackNumber = (UCHAR)cylinder;
+ cdb->ParameterListLengthLsb = sizeof(FORMAT_UNIT_PARAMETER_LIST);
+
+ parameterList->DefectListHeader.Side = (UCHAR)head;
+
+ //
+ // Send down the SCSIOP_FORMAT_UNIT request
+ //
+ status = ClassSendSrbSynchronous(DeviceObject,
+ srb,
+ parameterList,
+ sizeof(FORMAT_UNIT_PARAMETER_LIST),
+ TRUE);
+
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+ }
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+ }
+
+ if (NT_SUCCESS(status) && formatParameters->StartCylinderNumber == 0)
+ {
+ // Update the device geometry
+ //
+
+ DebugPrint((2,"geometry was: %3d %2d %d %2d %4d %2d %08X\n",
+ fdoExtension->DiskGeometry.Cylinders.LowPart,
+ fdoExtension->DiskGeometry.MediaType,
+ fdoExtension->DiskGeometry.TracksPerCylinder,
+ fdoExtension->DiskGeometry.SectorsPerTrack,
+ fdoExtension->DiskGeometry.BytesPerSector,
+ fdoExtension->SectorShift,
+ fdoExtension->CommonExtension.PartitionLength.LowPart));
+
+ fdoExtension->DiskGeometry = *geometry;
+
+ //
+ // Calculate sector to byte shift.
+ //
+
+ WHICH_BIT(fdoExtension->DiskGeometry.BytesPerSector,
+ fdoExtension->SectorShift);
+
+ fdoExtension->CommonExtension.PartitionLength.QuadPart =
+ (LONGLONG)capacity->NumberOfBlocks *
+ capacity->BlockLength;
+
+ DebugPrint((2,"geometry is: %3d %2d %d %2d %4d %2d %08X\n",
+ fdoExtension->DiskGeometry.Cylinders.LowPart,
+ fdoExtension->DiskGeometry.MediaType,
+ fdoExtension->DiskGeometry.TracksPerCylinder,
+ fdoExtension->DiskGeometry.SectorsPerTrack,
+ fdoExtension->DiskGeometry.BytesPerSector,
+ fdoExtension->SectorShift,
+ fdoExtension->CommonExtension.PartitionLength.LowPart));
+ }
+
+ // Free everything we allocated
+ //
+ ExFreePool(parameterList);
+ ExFreePool(srb);
+
+ return status;
+}
+
diff --git a/drivers/storage/floppy_new/floppy.rc b/drivers/storage/floppy_new/floppy.rc
new file mode 100644
index 0000000000..d23ec119d4
--- /dev/null
+++ b/drivers/storage/floppy_new/floppy.rc
@@ -0,0 +1,13 @@
+/*
+ * PROJECT: ReactOS Floppy Driver
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: drivers/storage/floppy/floppy.rc
+ * PURPOSE: Resource definition file
+ * PROGRAMMERS: Vizzini (vizzini(a)plasmic.com)
+ */
+
+#define REACTOS_VERSION_DLL
+#define REACTOS_STR_FILE_DESCRIPTION "Floppy Disk Controller Driver"
+#define REACTOS_STR_INTERNAL_NAME "floppy"
+#define REACTOS_STR_ORIGINAL_FILENAME "floppy.sys"
+#include <reactos/version.rc>
diff --git a/drivers/storage/floppy_new/floppy_reg.inf
b/drivers/storage/floppy_new/floppy_reg.inf
new file mode 100644
index 0000000000..ad620f4b3e
--- /dev/null
+++ b/drivers/storage/floppy_new/floppy_reg.inf
@@ -0,0 +1,7 @@
+; Floppy driver
+[AddReg]
+HKLM,"SYSTEM\CurrentControlSet\Services\Floppy","ErrorControl",0x00010001,0x00000000
+HKLM,"SYSTEM\CurrentControlSet\Services\Floppy","Group",0x00000000,"Primary
Disk"
+HKLM,"SYSTEM\CurrentControlSet\Services\Floppy","ImagePath",0x00020000,"system32\drivers\floppy.sys"
+HKLM,"SYSTEM\CurrentControlSet\Services\Floppy","Start",0x00010001,0x00000001
+HKLM,"SYSTEM\CurrentControlSet\Services\Floppy","Type",0x00010001,0x00000001
diff --git a/drivers/storage/floppy_new/guid.c b/drivers/storage/floppy_new/guid.c
new file mode 100644
index 0000000000..757901b422
--- /dev/null
+++ b/drivers/storage/floppy_new/guid.c
@@ -0,0 +1,11 @@
+/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */
+
+#include <ntdef.h>
+#include <initguid.h>
+#include <ioevent.h>
+#include <wdmguid.h>
+
+#define DEVICE_TYPE ULONG
+#include <ntddstor.h>
+
+/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */
diff --git a/media/doc/README.FSD b/media/doc/README.FSD
index 8d9993d40f..4f28521245 100644
--- a/media/doc/README.FSD
+++ b/media/doc/README.FSD
@@ -19,7 +19,8 @@ reactos/drivers/filesystems/reiserfs # Synced to 0.26
The following FSD are shared with:
https://github.com/Microsoft/Windows-driver-samples
reactos/drivers/filesystems/fastfat_new # Synced to 2817004
-reactos/drivers/filesystems/cdfs_new # Synced to f73e552
+reactos/drivers/filesystems/cdfs # Synced to f73e552
+reactos/drivers/storage/floppy_new # Synced to 9d23d43
The following FS libs are shared with:
https://github.com/dosfstools/dosfstools
reactos/sdk/lib/fslib/vfatlib/check # Synced to 4.1