floppy.c
来自「一个类似windows」· C语言 代码 · 共 1,185 行 · 第 1/3 页
C
1,185 行
continue;
if(gControllerInfo[i].DriveInfo[j].DeviceObject)
{
UNICODE_STRING Link;
RtlInitUnicodeString(&Link, gControllerInfo[i].DriveInfo[j].SymLinkBuffer);
IoDeleteSymbolicLink(&Link);
RtlInitUnicodeString(&Link, gControllerInfo[i].DriveInfo[j].ArcPathBuffer);
IoDeassignArcName(&Link);
IoDeleteDevice(gControllerInfo[i].DriveInfo[j].DeviceObject);
}
}
IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
/* Power down the controller */
if(HwPowerOff(&gControllerInfo[i]) != STATUS_SUCCESS)
{
DPRINT("floppy: unload: warning: HwPowerOff failed\n");
}
}
}
static NTSTATUS NTAPI ConfigCallback(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)
/*
* FUNCTION: Callback to IoQueryDeviceDescription, which tells us about our controllers
* ARGUMENTS:
* Context: Unused
* PathName: Unused
* BusType: Type of the bus that our controller is on
* BusNumber: Number of the bus that our controller is on
* BusInformation: Unused
* ControllerType: Unused
* ControllerNumber: Number of the controller that we're adding
* ControllerInformation: Full configuration information for our controller
* PeripheralType: Unused
* PeripheralNumber: Unused
* PeripheralInformation: Full configuration information for each drive on our controller
* RETURNS:
* STATUS_SUCCESS in all cases
* NOTES:
* - The only documentation I've found about the contents of these structures is
* from the various Microsoft floppy samples and from the DDK headers. They're
* very vague, though, so I'm only mostly sure that this stuff is correct, as
* the MS samples do things completely differently than I have done them. Seems
* to work in my VMWare, though.
* - Basically, the function gets all of the information (port, dma, irq) about the
* controller, and then loops through all of the drives presented in PeripheralInformation.
* - Each controller has a CONTROLLER_INFO created for it, and each drive has a DRIVE_INFO.
* - Device objects are created for each drive (not controller), as that's the targeted
* device in the eyes of the rest of the OS. Each DRIVE_INFO points to a single CONTROLLER_INFO.
* - We only support up to four controllers in the whole system, each of which supports up to four
* drives.
*/
{
PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData];
PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor +
ControllerFullDescriptor->DataOffset);
PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData];
PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor +
PeripheralFullDescriptor->DataOffset);
PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
PCM_FLOPPY_DEVICE_DATA FloppyDeviceData;
UCHAR i;
PAGED_CODE();
UNREFERENCED_PARAMETER(PeripheralType);
UNREFERENCED_PARAMETER(PeripheralNumber);
UNREFERENCED_PARAMETER(BusInformation);
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(ControllerType);
UNREFERENCED_PARAMETER(PathName);
DPRINT("floppy: ConfigCallback called with ControllerNumber %d\n", ControllerNumber);
gControllerInfo[gNumberOfControllers].ControllerNumber = ControllerNumber;
gControllerInfo[gNumberOfControllers].InterfaceType = BusType;
gControllerInfo[gNumberOfControllers].BusNumber = BusNumber;
/* Get controller interrupt level/vector, dma channel, and port base */
for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++)
{
KeInitializeEvent(&gControllerInfo[gNumberOfControllers].SynchEvent, NotificationEvent, FALSE);
PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i];
if(PartialDescriptor->Type == CmResourceTypeInterrupt)
{
gControllerInfo[gNumberOfControllers].Level = PartialDescriptor->u.Interrupt.Level;
gControllerInfo[gNumberOfControllers].Vector = PartialDescriptor->u.Interrupt.Vector;
if(PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
gControllerInfo[gNumberOfControllers].InterruptMode = Latched;
else
gControllerInfo[gNumberOfControllers].InterruptMode = LevelSensitive;
}
else if(PartialDescriptor->Type == CmResourceTypePort)
{
PHYSICAL_ADDRESS TranslatedAddress;
ULONG AddressSpace = 0x1; /* I/O Port Range */
if(!HalTranslateBusAddress(BusType, BusNumber, PartialDescriptor->u.Port.Start, &AddressSpace, &TranslatedAddress))
{
DPRINT("floppy: HalTranslateBusAddress failed; returning\n");
return STATUS_IO_DEVICE_ERROR;
}
if(AddressSpace == 0)
gControllerInfo[gNumberOfControllers].BaseAddress = MmMapIoSpace(TranslatedAddress, FDC_PORT_BYTES, MmNonCached);
else
gControllerInfo[gNumberOfControllers].BaseAddress = (PUCHAR)TranslatedAddress.u.LowPart;
}
else if(PartialDescriptor->Type == CmResourceTypeDma)
gControllerInfo[gNumberOfControllers].Dma = PartialDescriptor->u.Dma.Channel;
}
/* Start with 0 drives, then go looking */
gControllerInfo[gNumberOfControllers].NumberOfDrives = 0;
/* learn about drives attached to controller */
for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++)
{
PDRIVE_INFO DriveInfo = &gControllerInfo[gNumberOfControllers].DriveInfo[i];
PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i];
if(PartialDescriptor->Type != CmResourceTypeDeviceSpecific)
continue;
FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1);
DriveInfo->ControllerInfo = &gControllerInfo[gNumberOfControllers];
DriveInfo->UnitNumber = i;
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 existance in the controller info object */
gControllerInfo[gNumberOfControllers].NumberOfDrives++;
}
gControllerInfo[gNumberOfControllers].Populated = TRUE;
gNumberOfControllers++;
return STATUS_SUCCESS;
}
static BOOLEAN NTAPI Isr(PKINTERRUPT Interrupt,
PVOID ServiceContext)
/*
* FUNCTION: Interrupt service routine for the controllers
* ARGUMENTS:
* Interrupt: Interrupt object representing the interrupt that occured
* ServiceContext: Pointer to the ControllerInfo object that caused the interrupt
* RETURNS:
* TRUE in all cases (see notes)
* NOTES:
* - We should always be the target of the interrupt, being an edge-triggered ISA interrupt, but
* this won't be the case with a level-sensitive system like PCI
* - Note that it probably doesn't matter if the interrupt isn't dismissed, as it's edge-triggered.
* It probably won't keep re-interrupting.
* - There are two different ways to dismiss a floppy interrupt. If the command has a result phase
* (see intel datasheet), you dismiss the interrupt by reading the first data byte. If it does
* not, you dismiss the interrupt by doing a Sense Interrupt command. Again, because it's edge-
* triggered, this is safe to not do here, as we can just wait for the DPC.
* - Either way, we don't want to do this here. The controller shouldn't interrupt again, so we'll
* schedule a DPC to take care of it.
* - This driver really cannot shrare interrupts, as I don't know how to conclusively say
* whether it was our controller that interrupted or not. I just have to assume that any time
* my ISR gets called, it was my board that called it. Dumb design, yes, but it goes back to
* the semantics of ISA buses. That, and I don't know much about ISA drivers. :-)
* UPDATE: The high bit of Status Register A seems to work on non-AT controllers.
* - Called at DIRQL
*/
{
PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO)ServiceContext;
UNREFERENCED_PARAMETER(Interrupt);
ASSERT(ControllerInfo);
DPRINT("floppy: ISR called\n");
/*
* Due to the stupidity of the drive/controller relationship on the floppy drive, only one device object
* can have an active interrupt pending. Due to the nature of these IRPs, though, there will only ever
* be one thread expecting an interrupt at a time, and furthermore, Interrupts (outside of spurious ones)
* won't ever happen unless a thread is expecting them. Therefore, all we have to do is signal an event
* and we're done. Queue a DPC and leave.
*/
KeInsertQueueDpc(&ControllerInfo->Dpc, NULL, NULL);
return TRUE;
}
VOID NTAPI DpcForIsr(PKDPC UnusedDpc,
PVOID Context,
PVOID SystemArgument1,
PVOID SystemArgument2)
/*
* FUNCTION: This DPC gets queued by every ISR. Does the real per-interrupt work.
* ARGUMENTS:
* UnusedDpc: Pointer to the DPC object that represents our function
* DeviceObject: Device that this DPC is running for
* Irp: Unused
* Context: Pointer to our ControllerInfo struct
* NOTES:
* - This function just kicks off whatever the SynchEvent is and returns. We depend on
* the thing that caused the drive to interrupt to handle the work of clearing the interrupt.
* This enables us to get back to PASSIVE_LEVEL and not hog system time on a really stupid,
* slow, screwed-up piece of hardare.
* - If nothing is waiting for us to set the event, the interrupt is effectively lost and will
* never be dismissed. I wonder if this will become a problem.
* - Called at DISPATCH_LEVEL
*/
{
PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO)Context;
UNREFERENCED_PARAMETER(UnusedDpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
ASSERT(ControllerInfo);
DPRINT("floppy: DpcForIsr called\n");
KeSetEvent(&ControllerInfo->SynchEvent, EVENT_INCREMENT, FALSE);
}
static NTSTATUS NTAPI InitController(PCONTROLLER_INFO ControllerInfo)
/*
* FUNCTION: Initialize a newly-found controller
* ARGUMENTS:
* ControllerInfo: pointer to the controller to be initialized
* RETURNS:
* STATUS_SUCCESS if the controller is successfully initialized
* STATUS_IO_DEVICE_ERROR otherwise
*/
{
int i;
UCHAR HeadLoadTime;
UCHAR HeadUnloadTime;
UCHAR StepRateTime;
PAGED_CODE();
ASSERT(ControllerInfo);
DPRINT("floppy: InitController called with Controller 0x%x\n", ControllerInfo);
KeClearEvent(&ControllerInfo->SynchEvent);
DPRINT("floppy: InitController: resetting the controller\n");
/* Reset the controller */
if(HwReset(ControllerInfo) != STATUS_SUCCESS)
{
DPRINT("floppy: InitController: unable to reset controller\n");
return STATUS_IO_DEVICE_ERROR;
}
DPRINT("floppy: InitController: setting data rate\n");
/* Set data rate */
if(HwSetDataRate(ControllerInfo, DRSR_DSEL_500KBPS) != STATUS_SUCCESS)
{
DPRINT("floppy: InitController: unable to set data rate\n");
return STATUS_IO_DEVICE_ERROR;
}
DPRINT("floppy: InitController: waiting for initial interrupt\n");
/* Wait for an interrupt */
WaitForControllerInterrupt(ControllerInfo);
/* Reset means you have to clear each of the four interrupts (one per drive) */
for(i = 0; i < MAX_DRIVES_PER_CONTROLLER; i++)
{
DPRINT("floppy: InitController: Sensing interrupt %d\n", i);
if(HwSenseInterruptStatus(ControllerInfo) != STATUS_SUCCESS)
{
DPRINT("floppy: InitController: Unable to clear interrupt 0x%x\n", i);
return STATUS_IO_DEVICE_ERROR;
}
}
DPRINT("floppy: InitController: done sensing interrupts\n");
/* Next, see if we have the right version to do implied seek */
if(HwGetVersion(ControllerInfo) == VERSION_ENHANCED)
{
/* If so, set that up -- all defaults below except first TRUE for EIS */
if(HwConfigure(ControllerInfo, TRUE, TRUE, FALSE, 0, 0) != STATUS_SUCCESS)
{
DPRINT("floppy: InitController: unable to set up implied seek\n");
ControllerInfo->ImpliedSeeks = FALSE;
}
else
{
DPRINT("floppy: InitController: implied seeks set!\n");
ControllerInfo->ImpliedSeeks = TRUE;
}
/*
* FIXME: Figure out the answer to the below
*
* I must admit that I'm really confused about the Model 30 issue. At least one
* important bit (the disk change bit in the DIR) is flipped if this is a Model 30
* controller. However, at least one other floppy driver believes that there are only
* two computers that are guaranteed to have a Model 30 controller:
* - IBM Thinkpad 750
* - IBM PS2e
*
* ...and another driver only lists a config option for "thinkpad", that flips
* the change line. A third driver doesn't mention the Model 30 issue at all.
*
* What I can't tell is whether or not the average, run-of-the-mill computer now has
* a Model 30 controller. For the time being, I'm going to wire this to FALSE,
* and just not support the computers mentioned above, while I try to figure out
* how ubiquitous these newfangled 30 thingies are.
*/
//ControllerInfo->Model30 = TRUE;
ControllerInfo->Model30 = FALSE;
}
else
{
DPRINT("floppy: InitController: enhanced version not supported; disabling implied seeks\n");
ControllerInfo->ImpliedSeeks = FALSE;
ControllerInfo->Model30 = FALSE;
}
/* Specify */
DPRINT("FLOPPY: FIXME: Figure out speed\n");
HeadLoadTime = SPECIFY_HLT_500K;
HeadUnloadTime = SPECIFY_HUT_500K;
StepRateTime = SPECIFY_SRT_500K;
DPRINT("floppy: InitController: issuing specify command to controller\n");
/* Don't disable DMA --> enable dma (dumb & confusing) */
if(HwSpecify(ControllerInfo, HeadLoadTime, HeadUnloadTime, StepRateTime, FALSE) != STATUS_SUCCESS)
{
DPRINT("floppy: InitController: unable to specify options\n");
return STATUS_IO_DEVICE_ERROR;
}
/* Init the stop stuff */
KeInitializeDpc(&ControllerInfo->MotorStopDpc, MotorStopDpcFunc, ControllerInfo);
KeInitializeTimer(&ControllerInfo->MotorTimer);
KeInitializeEvent(&ControllerInfo->MotorStoppedEvent, NotificationEvent, FALSE);
ControllerInfo->StopDpcQueued = FALSE;
/*
* Recalibrate each drive on the controller (depends on StartMotor, which depends on the timer stuff above)
* We don't even know if there is a disk in the drive, so this may not work, but that's OK.
*/
for(i = 0; i < ControllerInfo->NumberOfDrives; i++)
{
DPRINT("floppy: InitController: recalibrating drive 0x%x on controller 0x%x\n", i, ControllerInfo);
Recalibrate(&ControllerInfo->DriveInfo[i]);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?