📄 floppy.c
字号:
IN OUT PDISKETTE_EXTENSION DisketteExtension
)
/*++
Routine Description:
This routine queues the given irp to be serviced by the controller's
thread. If the thread is down then this routine creates the thread.
Arguments:
Irp - Supplies the IRP to queue to the controller's thread.
ControllerData - Supplies the controller data.
Return Value:
May return an error if PsCreateSystemThread fails.
Otherwise returns STATUS_PENDING and marks the IRP pending.
--*/
{
KIRQL oldIrql;
NTSTATUS status;
HANDLE threadHandle;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Verify if the system is powering down. If so we fail
// the irps.
//
ExAcquireFastMutex(&DisketteExtension->PowerDownMutex);
if (DisketteExtension->PoweringDown == TRUE) {
ExReleaseFastMutex(&DisketteExtension->PowerDownMutex);
FloppyDump( FLOPDBGP,
("Queue IRP: Bailing out since power irp is waiting.\n"));
Irp->IoStatus.Status = STATUS_POWER_STATE_INVALID;
Irp->IoStatus.Information = 0;
return STATUS_POWER_STATE_INVALID;
}
ExReleaseFastMutex(&DisketteExtension->PowerDownMutex);
FloppyDump( FLOPSHOW, ("Queue IRP: No power irp waiting.\n"));
ExAcquireFastMutex(&DisketteExtension->ThreadReferenceMutex);
if (++(DisketteExtension->ThreadReferenceCount) == 0) {
OBJECT_ATTRIBUTES ObjAttributes;
DisketteExtension->ThreadReferenceCount++;
FloppyResetDriverPaging();
//
// Create the thread.
//
ASSERT(DisketteExtension->FloppyThread == NULL);
InitializeObjectAttributes(&ObjAttributes, NULL,
OBJ_KERNEL_HANDLE,
NULL,
NULL);
status = PsCreateSystemThread(&threadHandle,
(ACCESS_MASK) 0L,
&ObjAttributes,
(HANDLE) 0L,
NULL,
FloppyThread,
DisketteExtension);
if (!NT_SUCCESS(status)) {
DisketteExtension->ThreadReferenceCount = -1;
FloppyPageEntireDriver();
ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
return status;
}
status = ObReferenceObjectByHandle( threadHandle,
SYNCHRONIZE,
NULL,
KernelMode,
&DisketteExtension->FloppyThread,
NULL );
ASSERT(NT_SUCCESS(status));
ZwClose(threadHandle);
ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
if (!NT_SUCCESS(status)) {
return status;
}
} else {
ExReleaseFastMutex(&DisketteExtension->ThreadReferenceMutex);
}
IoMarkIrpPending(Irp);
ExInterlockedInsertTailList(
&DisketteExtension->ListEntry,
&Irp->Tail.Overlay.ListEntry,
&DisketteExtension->ListSpinLock );
KeReleaseSemaphore(
&DisketteExtension->RequestSemaphore,
(KPRIORITY) 0,
1,
FALSE );
return STATUS_PENDING;
}
NTSTATUS
FloppyCreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called only rarely by the I/O system; it's mainly
for layered drivers to call. All it does is complete the IRP
successfully.
Arguments:
DeviceObject - a pointer to the object that represents the device
that I/O is to be done on.
Irp - a pointer to the I/O Request Packet for this request.
Return Value:
Always returns STATUS_SUCCESS, since this is a null operation.
--*/
{
UNREFERENCED_PARAMETER( DeviceObject );
FloppyDump(
FLOPSHOW,
("FloppyCreateClose...\n")
);
//
// Null operation. Do not give an I/O boost since
// no I/O was actually done. IoStatus.Information should be
// FILE_OPENED for an open; it's undefined for a close.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
NTSTATUS
FloppyDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is called by the I/O system to perform a device I/O
control function.
Arguments:
DeviceObject - a pointer to the object that represents the device
that I/O is to be done on.
Irp - a pointer to the I/O Request Packet for this request.
Return Value:
STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
STATUS_INVALID_DEVICE_REQUEST otherwise.
--*/
{
PIO_STACK_LOCATION irpSp;
PDISKETTE_EXTENSION disketteExtension;
PDISK_GEOMETRY outputBuffer;
NTSTATUS ntStatus;
ULONG outputBufferLength;
UCHAR i;
DRIVE_MEDIA_TYPE lowestDriveMediaType;
DRIVE_MEDIA_TYPE highestDriveMediaType;
ULONG formatExParametersSize;
PFORMAT_EX_PARAMETERS formatExParameters;
FloppyDump( FLOPSHOW, ("FloppyDeviceControl...\n") );
disketteExtension = DeviceObject->DeviceExtension;
irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// We need to check if we are currently holding requests.
//
ExAcquireFastMutex(&(disketteExtension->HoldNewReqMutex));
if ( disketteExtension->HoldNewRequests ) {
//
// Queue request only if this is not an ACPI exec method. There is
// a nasty recursion with ACPI and fdc/flpy that requires that these
// requests get through in order to avoid a deadlock.
//
if ( irpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_ACPI_ASYNC_EVAL_METHOD ) {
ntStatus = FloppyQueueRequest( disketteExtension, Irp );
ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
return ntStatus;
}
}
ExReleaseFastMutex(&(disketteExtension->HoldNewReqMutex));
//
// If the device has been removed we will just fail this request outright.
//
if ( disketteExtension->IsRemoved ) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_DELETE_PENDING;
}
//
// If the device hasn't been started we will let the IOCTL through. This
// is another hack for ACPI.
//
if (!disketteExtension->IsStarted) {
IoSkipCurrentIrpStackLocation( Irp );
return IoCallDriver( disketteExtension->TargetObject, Irp );
}
switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: {
PMOUNTDEV_NAME mountName;
FloppyDump( FLOPSHOW, ("FloppyDeviceControl: IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n") );
ASSERT(disketteExtension->DeviceName.Buffer);
if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(MOUNTDEV_NAME) ) {
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
mountName = Irp->AssociatedIrp.SystemBuffer;
mountName->NameLength = disketteExtension->DeviceName.Length;
if ( irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(USHORT) + mountName->NameLength) {
ntStatus = STATUS_BUFFER_OVERFLOW;
Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
break;
}
RtlCopyMemory( mountName->Name, disketteExtension->DeviceName.Buffer,
mountName->NameLength);
ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(USHORT) + mountName->NameLength;
break;
}
case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: {
PMOUNTDEV_UNIQUE_ID uniqueId;
FloppyDump( FLOPSHOW, ("FloppyDeviceControl: IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n") );
if ( !disketteExtension->InterfaceString.Buffer ||
irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(MOUNTDEV_UNIQUE_ID)) {
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
uniqueId = Irp->AssociatedIrp.SystemBuffer;
uniqueId->UniqueIdLength =
disketteExtension->InterfaceString.Length;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(USHORT) + uniqueId->UniqueIdLength) {
ntStatus = STATUS_BUFFER_OVERFLOW;
Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
break;
}
RtlCopyMemory( uniqueId->UniqueId,
disketteExtension->InterfaceString.Buffer,
uniqueId->UniqueIdLength );
ntStatus = STATUS_SUCCESS;
Irp->IoStatus.Information = sizeof(USHORT) +
uniqueId->UniqueIdLength;
break;
}
case IOCTL_DISK_FORMAT_TRACKS:
case IOCTL_DISK_FORMAT_TRACKS_EX:
//
// Make sure that we got all the necessary format parameters.
//
if ( irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof( FORMAT_PARAMETERS ) ) {
FloppyDump(
FLOPDBGP,
("Floppy: invalid FORMAT buffer length\n")
);
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
//
// Make sure the parameters we got are reasonable.
//
if ( !FlCheckFormatParameters(
disketteExtension,
(PFORMAT_PARAMETERS) Irp->AssociatedIrp.SystemBuffer ) ) {
FloppyDump(
FLOPDBGP,
("Floppy: invalid FORMAT parameters\n")
);
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
//
// If this is an EX request then make a couple of extra checks
//
if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_DISK_FORMAT_TRACKS_EX) {
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(FORMAT_EX_PARAMETERS)) {
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
formatExParameters = (PFORMAT_EX_PARAMETERS)
Irp->AssociatedIrp.SystemBuffer;
formatExParametersSize =
FIELD_OFFSET(FORMAT_EX_PARAMETERS, SectorNumber) +
formatExParameters->SectorsPerTrack*sizeof(USHORT);
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
formatExParametersSize ||
formatExParameters->FormatGapLength >= 0x100 ||
formatExParameters->SectorsPerTrack >= 0x100) {
ntStatus = STATUS_INVALID_PARAMETER;
break;
}
}
//
// Fall through to queue the request.
//
case IOCTL_DISK_CHECK_VERIFY:
case IOCTL_STORAGE_CHECK_VERIFY:
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
case IOCTL_DISK_IS_WRITABLE:
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -