reactos/drivers/storage/floppy/fdc/fdo.c

542 lines
18 KiB
C

/*
* PROJECT: ReactOS Floppy Disk Controller Driver
* LICENSE: GNU GPLv2 only as published by the Free Software Foundation
* FILE: drivers/storage/fdc/fdc/fdo.c
* PURPOSE: Functional Device Object routines
* PROGRAMMERS: Eric Kohl
*/
/* INCLUDES *******************************************************************/
#include "fdc.h"
#include <stdio.h>
#define NDEBUG
#include <debug.h>
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
ForwardIrpAndForget(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_OBJECT LowerDevice = ((PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LowerDevice;
ASSERT(LowerDevice);
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(LowerDevice, Irp);
}
static
NTSTATUS
FdcFdoStartDevice(
IN PDEVICE_OBJECT DeviceObject,
IN PCM_RESOURCE_LIST ResourceList,
IN PCM_RESOURCE_LIST ResourceListTranslated)
{
PFDO_DEVICE_EXTENSION DeviceExtension;
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
// PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptorTranslated;
ULONG i;
DPRINT("FdcFdoStartDevice called\n");
DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(DeviceExtension);
if (ResourceList == NULL ||
ResourceListTranslated == NULL)
{
DPRINT1("No allocated resources sent to driver\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if (ResourceList->Count != 1)
{
DPRINT1("Wrong number of allocated resources sent to driver\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if (ResourceList->List[0].PartialResourceList.Version != 1 ||
ResourceList->List[0].PartialResourceList.Revision != 1 ||
ResourceListTranslated->List[0].PartialResourceList.Version != 1 ||
ResourceListTranslated->List[0].PartialResourceList.Revision != 1)
{
DPRINT1("Revision mismatch: %u.%u != 1.1 or %u.%u != 1.1\n",
ResourceList->List[0].PartialResourceList.Version,
ResourceList->List[0].PartialResourceList.Revision,
ResourceListTranslated->List[0].PartialResourceList.Version,
ResourceListTranslated->List[0].PartialResourceList.Revision);
return STATUS_REVISION_MISMATCH;
}
for (i = 0; i < ResourceList->List[0].PartialResourceList.Count; i++)
{
PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
// PartialDescriptorTranslated = &ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[i];
switch (PartialDescriptor->Type)
{
case CmResourceTypePort:
DPRINT("Port: 0x%lx (%lu)\n",
PartialDescriptor->u.Port.Start.u.LowPart,
PartialDescriptor->u.Port.Length);
if (PartialDescriptor->u.Port.Length >= 6)
DeviceExtension->ControllerInfo.BaseAddress = (PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart;
break;
case CmResourceTypeInterrupt:
DPRINT("Interrupt: Level %lu Vector %lu\n",
PartialDescriptor->u.Interrupt.Level,
PartialDescriptor->u.Interrupt.Vector);
/*
Dirql = (KIRQL)PartialDescriptorTranslated->u.Interrupt.Level;
Vector = PartialDescriptorTranslated->u.Interrupt.Vector;
Affinity = PartialDescriptorTranslated->u.Interrupt.Affinity;
if (PartialDescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
InterruptMode = Latched;
else
InterruptMode = LevelSensitive;
ShareInterrupt = (PartialDescriptorTranslated->ShareDisposition == CmResourceShareShared);
*/
break;
case CmResourceTypeDma:
DPRINT("Dma: Channel %lu\n",
PartialDescriptor->u.Dma.Channel);
break;
}
}
return STATUS_SUCCESS;
}
static
NTSTATUS
NTAPI
FdcFdoConfigCallback(
PVOID Context,
PUNICODE_STRING PathName,
INTERFACE_TYPE BusType,
ULONG BusNumber,
PKEY_VALUE_FULL_INFORMATION *BusInformation,
CONFIGURATION_TYPE ControllerType,
ULONG ControllerNumber,
PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
CONFIGURATION_TYPE PeripheralType,
ULONG PeripheralNumber,
PKEY_VALUE_FULL_INFORMATION *PeripheralInformation)
{
PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor;
PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor;
PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor;
PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor;
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
PCM_FLOPPY_DEVICE_DATA FloppyDeviceData;
PFDO_DEVICE_EXTENSION DeviceExtension;
PDRIVE_INFO DriveInfo;
BOOLEAN ControllerFound = FALSE;
ULONG i;
DPRINT("FdcFdoConfigCallback() called\n");
DeviceExtension = (PFDO_DEVICE_EXTENSION)Context;
/* Get the controller resources */
ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData];
ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor +
ControllerFullDescriptor->DataOffset);
for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++)
{
PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i];
if (PartialDescriptor->Type == CmResourceTypePort)
{
if ((PUCHAR)(ULONG_PTR)PartialDescriptor->u.Port.Start.QuadPart == DeviceExtension->ControllerInfo.BaseAddress)
ControllerFound = TRUE;
}
}
/* Leave, if the enumerated controller is not the one represented by the FDO */
if (ControllerFound == FALSE)
return STATUS_SUCCESS;
/* Get the peripheral resources */
PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData];
PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor +
PeripheralFullDescriptor->DataOffset);
/* learn about drives attached to controller */
for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++)
{
PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i];
if (PartialDescriptor->Type != CmResourceTypeDeviceSpecific)
continue;
FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1);
DriveInfo = &DeviceExtension->ControllerInfo.DriveInfo[DeviceExtension->ControllerInfo.NumberOfDrives];
DriveInfo->ControllerInfo = &DeviceExtension->ControllerInfo;
DriveInfo->UnitNumber = DeviceExtension->ControllerInfo.NumberOfDrives;
DriveInfo->PeripheralNumber = PeripheralNumber;
DriveInfo->FloppyDeviceData.MaxDensity = FloppyDeviceData->MaxDensity;
DriveInfo->FloppyDeviceData.MountDensity = FloppyDeviceData->MountDensity;
DriveInfo->FloppyDeviceData.StepRateHeadUnloadTime = FloppyDeviceData->StepRateHeadUnloadTime;
DriveInfo->FloppyDeviceData.HeadLoadTime = FloppyDeviceData->HeadLoadTime;
DriveInfo->FloppyDeviceData.MotorOffTime = FloppyDeviceData->MotorOffTime;
DriveInfo->FloppyDeviceData.SectorLengthCode = FloppyDeviceData->SectorLengthCode;
DriveInfo->FloppyDeviceData.SectorPerTrack = FloppyDeviceData->SectorPerTrack;
DriveInfo->FloppyDeviceData.ReadWriteGapLength = FloppyDeviceData->ReadWriteGapLength;
DriveInfo->FloppyDeviceData.FormatGapLength = FloppyDeviceData->FormatGapLength;
DriveInfo->FloppyDeviceData.FormatFillCharacter = FloppyDeviceData->FormatFillCharacter;
DriveInfo->FloppyDeviceData.HeadSettleTime = FloppyDeviceData->HeadSettleTime;
DriveInfo->FloppyDeviceData.MotorSettleTime = FloppyDeviceData->MotorSettleTime;
DriveInfo->FloppyDeviceData.MaximumTrackValue = FloppyDeviceData->MaximumTrackValue;
DriveInfo->FloppyDeviceData.DataTransferLength = FloppyDeviceData->DataTransferLength;
/* Once it's all set up, acknowledge its existence in the controller info object */
DeviceExtension->ControllerInfo.NumberOfDrives++;
}
DeviceExtension->ControllerInfo.Populated = TRUE;
DPRINT("Detected %lu floppy drives!\n",
DeviceExtension->ControllerInfo.NumberOfDrives);
return STATUS_SUCCESS;
}
static
NTSTATUS
PciCreateHardwareIDsString(PUNICODE_STRING HardwareIDs)
{
WCHAR Buffer[256];
UNICODE_STRING BufferU;
ULONG Index;
Index = 0;
Index += swprintf(&Buffer[Index],
L"FDC\\GENERIC_FLOPPY_DRIVE");
Index++;
Buffer[Index] = UNICODE_NULL;
BufferU.Length = BufferU.MaximumLength = (USHORT) Index * sizeof(WCHAR);
BufferU.Buffer = Buffer;
return DuplicateUnicodeString(0, &BufferU, HardwareIDs);
}
static
NTSTATUS
PciCreateCompatibleIDsString(PUNICODE_STRING CompatibleIDs)
{
WCHAR Buffer[256];
UNICODE_STRING BufferU;
ULONG Index;
Index = 0;
Index += swprintf(&Buffer[Index],
L"GenFloppyDisk");
Index++;
Buffer[Index] = UNICODE_NULL;
BufferU.Length = BufferU.MaximumLength = (USHORT)Index * sizeof(WCHAR);
BufferU.Buffer = Buffer;
return DuplicateUnicodeString(0, &BufferU, CompatibleIDs);
}
static
NTSTATUS
PciCreateInstanceIDString(PUNICODE_STRING InstanceID,
ULONG PeripheralNumber)
{
WCHAR Buffer[3];
swprintf(Buffer, L"%02X", PeripheralNumber & 0xff);
return RtlCreateUnicodeString(InstanceID, Buffer) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
}
static
NTSTATUS
FdcFdoQueryBusRelations(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_RELATIONS *DeviceRelations)
{
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
INTERFACE_TYPE InterfaceType = Isa;
CONFIGURATION_TYPE ControllerType = DiskController;
CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral;
PDEVICE_RELATIONS Relations;
PDRIVE_INFO DriveInfo;
PDEVICE_OBJECT Pdo;
WCHAR DeviceNameBuffer[80];
UNICODE_STRING DeviceName;
ULONG DeviceNumber = 0;
ULONG Size;
ULONG i;
NTSTATUS Status;
DPRINT("FdcFdoQueryBusRelations() called\n");
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
Status = IoQueryDeviceDescription(&InterfaceType,
NULL,
&ControllerType,
NULL,
&PeripheralType,
NULL,
FdcFdoConfigCallback,
FdoDeviceExtension);
if (!NT_SUCCESS(Status) && (Status != STATUS_NO_MORE_ENTRIES))
return Status;
Size = sizeof(DEVICE_RELATIONS) +
sizeof(Relations->Objects) * (FdoDeviceExtension->ControllerInfo.NumberOfDrives - 1);
Relations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, Size);
if (Relations == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
Relations->Count = FdoDeviceExtension->ControllerInfo.NumberOfDrives;
for (i = 0; i < FdoDeviceExtension->ControllerInfo.NumberOfDrives; i++)
{
DriveInfo = &FdoDeviceExtension->ControllerInfo.DriveInfo[i];
if (DriveInfo->DeviceObject == NULL)
{
do
{
swprintf(DeviceNameBuffer, L"\\Device\\FloppyPDO%lu", DeviceNumber++);
RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
DPRINT("Device name: %S\n", DeviceNameBuffer);
/* Create physical device object */
Status = IoCreateDevice(FdoDeviceExtension->Common.DeviceObject->DriverObject,
sizeof(PDO_DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_MASS_STORAGE,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&Pdo);
}
while (Status == STATUS_OBJECT_NAME_COLLISION);
if (!NT_SUCCESS(Status))
{
DPRINT1("PDO creation failed (Status 0x%08lx)\n", Status);
goto done;
}
DPRINT("PDO created: %S\n", DeviceNameBuffer);
DriveInfo->DeviceObject = Pdo;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
PdoDeviceExtension->Common.IsFDO = FALSE;
PdoDeviceExtension->Common.DeviceObject = Pdo;
PdoDeviceExtension->Fdo = FdoDeviceExtension->Common.DeviceObject;
PdoDeviceExtension->DriveInfo = DriveInfo;
Pdo->Flags |= DO_DIRECT_IO;
Pdo->Flags |= DO_POWER_PAGABLE;
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
/* Add Device ID string */
RtlCreateUnicodeString(&PdoDeviceExtension->DeviceId,
L"FDC\\GENERIC_FLOPPY_DRIVE");
DPRINT("DeviceID: %S\n", PdoDeviceExtension->DeviceId.Buffer);
/* Add Hardware IDs string */
Status = PciCreateHardwareIDsString(&PdoDeviceExtension->HardwareIds);
if (!NT_SUCCESS(Status))
{
// ErrorStatus = Status;
// ErrorOccurred = TRUE;
break;
}
/* Add Compatible IDs string */
Status = PciCreateCompatibleIDsString(&PdoDeviceExtension->CompatibleIds);
if (!NT_SUCCESS(Status))
{
// ErrorStatus = Status;
// ErrorOccurred = TRUE;
break;
}
/* Add Instance ID string */
Status = PciCreateInstanceIDString(&PdoDeviceExtension->InstanceId,
DriveInfo->PeripheralNumber);
if (!NT_SUCCESS(Status))
{
// ErrorStatus = Status;
// ErrorOccurred = TRUE;
break;
}
#if 0
/* Add device description string */
Status = PciCreateDeviceDescriptionString(&PdoDeviceExtension->DeviceDescription, Device);
if (!NT_SUCCESS(Status))
{
// ErrorStatus = Status;
// ErrorOccurred = TRUE;
break;
}
/* Add device location string */
Status = PciCreateDeviceLocationString(&PdoDeviceExtension->DeviceLocation, Device);
if (!NT_SUCCESS(Status))
{
// ErrorStatus = Status;
// ErrorOccurred = TRUE;
break;
}
#endif
}
ObReferenceObject(DriveInfo->DeviceObject);
Relations->Objects[i] = DriveInfo->DeviceObject;
}
done:
if (NT_SUCCESS(Status))
{
*DeviceRelations = Relations;
}
else
{
if (Relations != NULL)
ExFreePool(Relations);
}
return Status;
}
NTSTATUS
NTAPI
FdcFdoPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PFDO_DEVICE_EXTENSION FdoExtension;
PIO_STACK_LOCATION IrpSp;
PDEVICE_RELATIONS DeviceRelations = NULL;
ULONG_PTR Information = 0;
NTSTATUS Status = STATUS_NOT_SUPPORTED;
DPRINT("FdcFdoPnp()\n");
IrpSp = IoGetCurrentIrpStackLocation(Irp);
switch (IrpSp->MinorFunction)
{
case IRP_MN_START_DEVICE:
DPRINT(" IRP_MN_START_DEVICE received\n");
/* Call lower driver */
Status = STATUS_UNSUCCESSFUL;
FdoExtension = DeviceObject->DeviceExtension;
if (IoForwardIrpSynchronously(FdoExtension->LowerDevice, Irp))
{
Status = Irp->IoStatus.Status;
if (NT_SUCCESS(Status))
{
Status = FdcFdoStartDevice(DeviceObject,
IrpSp->Parameters.StartDevice.AllocatedResources,
IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated);
}
}
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
DPRINT(" IRP_MN_QUERY_REMOVE_DEVICE\n");
break;
case IRP_MN_REMOVE_DEVICE:
DPRINT(" IRP_MN_REMOVE_DEVICE received\n");
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
DPRINT(" IRP_MN_CANCEL_REMOVE_DEVICE\n");
break;
case IRP_MN_STOP_DEVICE:
DPRINT(" IRP_MN_STOP_DEVICE received\n");
break;
case IRP_MN_QUERY_STOP_DEVICE:
DPRINT(" IRP_MN_QUERY_STOP_DEVICE received\n");
break;
case IRP_MN_CANCEL_STOP_DEVICE:
DPRINT(" IRP_MN_CANCEL_STOP_DEVICE\n");
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
DPRINT(" IRP_MN_QUERY_DEVICE_RELATIONS\n");
switch (IrpSp->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
Status = FdcFdoQueryBusRelations(DeviceObject, &DeviceRelations);
Information = (ULONG_PTR)DeviceRelations;
break;
case RemovalRelations:
DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
default:
DPRINT(" IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
IrpSp->Parameters.QueryDeviceRelations.Type);
return ForwardIrpAndForget(DeviceObject, Irp);
}
break;
case IRP_MN_SURPRISE_REMOVAL:
DPRINT(" IRP_MN_SURPRISE_REMOVAL received\n");
break;
default:
DPRINT(" Unknown IOCTL 0x%lx\n", IrpSp->MinorFunction);
return ForwardIrpAndForget(DeviceObject, Irp);
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
/* EOF */