From e2277b1f0286bf6a5b5528bdde372ce07bd27d7f Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Sat, 15 Dec 2018 20:02:03 +0100 Subject: [PATCH] [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(-) create mode 100644 drivers/storage/floppy_new/CMakeLists.txt create mode 100644 drivers/storage/floppy_new/floppy.c create mode 100644 drivers/storage/floppy_new/floppy.rc create mode 100644 drivers/storage/floppy_new/floppy_reg.inf create mode 100644 drivers/storage/floppy_new/guid.c diff --git a/drivers/storage/floppy_new/CMakeLists.txt b/drivers/storage/floppy_new/CMakeLists.txt new file mode 100644 index 00000000000..154e553c326 --- /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 00000000000..3c9a1ebf9c0 --- /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 +#include +#ifndef __REACTOS__ +#include +#endif +#include +#include +#include +#include + +#include +#include + +#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 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; iMediaType) + { + 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 00000000000..d23ec119d46 --- /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@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 diff --git a/drivers/storage/floppy_new/floppy_reg.inf b/drivers/storage/floppy_new/floppy_reg.inf new file mode 100644 index 00000000000..ad620f4b3ee --- /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 00000000000..757901b4222 --- /dev/null +++ b/drivers/storage/floppy_new/guid.c @@ -0,0 +1,11 @@ +/* DO NOT USE THE PRECOMPILED HEADER FOR THIS FILE! */ + +#include +#include +#include +#include + +#define DEVICE_TYPE ULONG +#include + +/* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/media/doc/README.FSD b/media/doc/README.FSD index 8d9993d40fc..4f285212455 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