mirror of
https://github.com/reactos/reactos.git
synced 2025-01-11 16:51:06 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
276 lines
8.6 KiB
C
276 lines
8.6 KiB
C
/*
|
||
* 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 <ntddk.h>
|
||
#include <debug.h>
|
||
|
||
#include "floppy.h"
|
||
#include "hardware.h"
|
||
#include "csqrtns.h"
|
||
#include "ioctl.h"
|
||
|
||
|
||
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: Handlees 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 && !(DriveInfo->DeviceObject->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;
|
||
}
|
||
|