/* * ReactOS Floppy Driver * Copyright (C) 2004, Vizzini (vizzini@plasmic.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * PROJECT: ReactOS Floppy Driver * FILE: ioctl.c * PURPOSE: IOCTL Routines * PROGRAMMER: Vizzini (vizzini@plasmic.com) * REVISIONS: * 15-Feb-2004 vizzini - Created * NOTES: * - All IOCTL documentation taken from the DDK * - This driver tries to support all of the IOCTLs that the DDK floppy * sample does * * TODO: Add support to GET_MEDIA_TYPES for non-1.44 disks * TODO: Implement format */ #include "precomp.h" #include NTSTATUS NTAPI DeviceIoctl(PDEVICE_OBJECT DeviceObject, PIRP Irp) /* * FUNCTION: Queue IOCTL IRPs * ARGUMENTS: * DeviceObject: DeviceObject that is the target of the IRP * Irp: IRP to process * RETURNS: * STATUS_SUCCESS in all cases, so far * NOTES: * - We can't just service these immediately because, even though some * are able to run at DISPATCH, they'll get out of sync with other * read/write or ioctl irps. */ { ASSERT(DeviceObject); ASSERT(Irp); Irp->Tail.Overlay.DriverContext[0] = DeviceObject; IoCsqInsertIrp(&Csq, Irp, NULL); return STATUS_PENDING; } VOID NTAPI DeviceIoctlPassive(PDRIVE_INFO DriveInfo, PIRP Irp) /* * FUNCTION: Handles IOCTL requests at PASSIVE_LEVEL * ARGUMENTS: * DriveInfo: Drive that the IOCTL is directed at * Irp: IRP with the request in it */ { PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); ULONG OutputLength = Stack->Parameters.DeviceIoControl.OutputBufferLength; PVOID OutputBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG Code = Stack->Parameters.DeviceIoControl.IoControlCode; BOOLEAN DiskChanged; TRACE_(FLOPPY, "DeviceIoctl called\n"); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; /* * First the non-change-sensitive ioctls */ if(Code == IOCTL_DISK_GET_MEDIA_TYPES) { PDISK_GEOMETRY Geometry = OutputBuffer; INFO_(FLOPPY, "IOCTL_DISK_GET_MEDIA_TYPES Called\n"); if(OutputLength < sizeof(DISK_GEOMETRY)) { INFO_(FLOPPY, "IOCTL_DISK_GET_MEDIA_TYPES: insufficient buffer; returning STATUS_INVALID_PARAMETER\n"); Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } /* * for now, this driver only supports 3.5" HD media */ Geometry->MediaType = F3_1Pt44_512; Geometry->Cylinders.QuadPart = 80; Geometry->TracksPerCylinder = 2 * 18; Geometry->SectorsPerTrack = 18; Geometry->BytesPerSector = 512; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); INFO_(FLOPPY, "Ioctl: completing with STATUS_SUCCESS\n"); IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } /* * Now, check to see if the volume needs to be verified. If so, * return STATUS_VERIFY_REQUIRED. * * NOTE: This code, which is outside of the switch and if/else blocks, * will implicity catch and correctly service IOCTL_DISK_CHECK_VERIFY. * Therefore if we see one below in the switch, we can return STATUS_SUCCESS * immediately. */ if(DriveInfo->DeviceObject->Flags & DO_VERIFY_VOLUME && !(Stack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) { INFO_(FLOPPY, "DeviceIoctl(): completing with STATUS_VERIFY_REQUIRED\n"); Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } /* * Start the drive to see if the disk has changed */ StartMotor(DriveInfo); /* * Check the change line, and if it's set, return */ if(HwDiskChanged(DriveInfo, &DiskChanged) != STATUS_SUCCESS) { WARN_(FLOPPY, "DeviceIoctl(): unable to sense disk change; completing with STATUS_UNSUCCESSFUL\n"); Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); StopMotor(DriveInfo->ControllerInfo); return; } if(DiskChanged) { INFO_(FLOPPY, "DeviceIoctl(): detected disk changed; signalling media change and completing\n"); SignalMediaChanged(DriveInfo->DeviceObject, Irp); /* * Just guessing here - I have a choice of returning NO_MEDIA or VERIFY_REQUIRED. If there's * really no disk in the drive, I'm thinking I can save time by just reporting that fact, rather * than forcing windows to ask me twice. If this doesn't work, we'll need to split this up and * handle the CHECK_VERIFY IOCTL separately. */ if(ResetChangeFlag(DriveInfo) == STATUS_NO_MEDIA_IN_DEVICE) Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE; IoCompleteRequest(Irp, IO_NO_INCREMENT); StopMotor(DriveInfo->ControllerInfo); return; } switch(Code) { case IOCTL_DISK_IS_WRITABLE: { UCHAR Status; INFO_(FLOPPY, "IOCTL_DISK_IS_WRITABLE Called\n"); /* This IRP always has 0 information */ Irp->IoStatus.Information = 0; if(HwSenseDriveStatus(DriveInfo) != STATUS_SUCCESS) { WARN_(FLOPPY, "IoctlDiskIsWritable(): unable to sense drive status\n"); Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; break; } /* Now, read the drive's status back */ if(HwSenseDriveStatusResult(DriveInfo->ControllerInfo, &Status) != STATUS_SUCCESS) { WARN_(FLOPPY, "IoctlDiskIsWritable(): unable to read drive status result\n"); Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; break; } /* Check to see if the write flag is set. */ if(Status & SR3_WRITE_PROTECT_STATUS_SIGNAL) { INFO_(FLOPPY, "IOCTL_DISK_IS_WRITABLE: disk is write protected\n"); Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED; } else Irp->IoStatus.Status = STATUS_SUCCESS; } break; case IOCTL_DISK_CHECK_VERIFY: INFO_(FLOPPY, "IOCTL_DISK_CHECK_VERIFY called\n"); if (OutputLength != 0) { if (OutputLength < sizeof(ULONG)) { Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; } else { *((PULONG)OutputBuffer) = DriveInfo->DiskChangeCount; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(ULONG); } } else { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; } break; case IOCTL_DISK_GET_DRIVE_GEOMETRY: { INFO_(FLOPPY, "IOCTL_DISK_GET_DRIVE_GEOMETRY Called\n"); if(OutputLength < sizeof(DISK_GEOMETRY)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; break; } /* This still works right even if DriveInfo->DiskGeometry->MediaType = Unknown */ memcpy(OutputBuffer, &DriveInfo->DiskGeometry, sizeof(DISK_GEOMETRY)); Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); break; } case IOCTL_DISK_FORMAT_TRACKS: case IOCTL_DISK_FORMAT_TRACKS_EX: ERR_(FLOPPY, "Format called; not supported yet\n"); Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; Irp->IoStatus.Information = 0; break; case IOCTL_DISK_GET_PARTITION_INFO: INFO_(FLOPPY, "IOCTL_DISK_GET_PARTITION_INFO Called; not supported by a floppy driver\n"); Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; break; default: ERR_(FLOPPY, "UNKNOWN IOCTL CODE: 0x%x\n", Code); Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; Irp->IoStatus.Information = 0; break; } INFO_(FLOPPY, "ioctl: completing with status 0x%x\n", Irp->IoStatus.Status); IoCompleteRequest(Irp, IO_NO_INCREMENT); StopMotor(DriveInfo->ControllerInfo); return; }