📄 ide.c
字号:
//
// Hmmm. Nothing to do here but plow ahead...
//
#if DBG
DbgPrint("***Controller NOT READY on WRITE!\n");
#endif
}
//
// Get the controller status after the Wait
//
controllerStatus =
READ_PORT_UCHAR(devExt->ControllerData->ControllerAddress +
STATUS_REGISTER);
//
// As a sanity check, get it 1 more time, just in case
//
if (!(controllerStatus & DATA_REQUEST_STATUS)) {
controllerStatus =
READ_PORT_UCHAR(devExt->ControllerData->ControllerAddress +
STATUS_REGISTER);
}
//
// If the controller's ready, start slamming data to it
//
if (controllerStatus & DATA_REQUEST_STATUS) {
PVOID buffer;
buffer = devExt->CurrentAddress;
//
// Update the address and lengths now because the
// numbers mean "the number of bytes left to go".
// Thus, when the interrupt occurs to signal the end
// of this write, the bytes have "already gone". This
// is necessary to keep the arithmetic straight.
//
devExt->CurrentAddress += devExt->BytesPerInterrupt;
devExt->RemainingTransferLength -= devExt->BytesPerInterrupt;
//
// Write the first buffer (which will cause an interrupt
// when the write has been compelted and it's time for us
// to send it another sector)
//
WRITE_PORT_BUFFER_USHORT(
(PUSHORT)(controllerData->ControllerAddress + DATA_REGISTER),
buffer,
devExt->BytesPerInterrupt/2);
}
break;
default:
//
// We should never get here; READ or WRITE or VERIFY (via the
// ioctl interface) should be the only possibilities.
//
#if DBG
DbgPrint("IdeStartThisRequestOnDevice: Invalid operation type %x\n",
devExt->OperationType);
#endif
break;
}
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
//
// IdeISR
//
// This routine is the Interrupt Service Routine (ISR)
//
// INPUTS:
//
// Interrupt - pointer to the interrupt object
// Context - the controller data structure
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// TRUE if it is our interrupt, otherwise FALSE
//
// IRQL:
//
// DIRQL
//
// NOTES:
//
// All read and write I/O is done in this ISR as oppoosed to the DPC.
// The DPC is really used to do cleanup activity and error recovery.
// Note that sucessful I/O transfer is indicated by a zero for the
// devExt->RemainingTransferLength.
//
///////////////////////////////////////////////////////////////////////////////
BOOLEAN
IdeISR(IN PKINTERRUPT Interrupt,
IN OUT PVOID Context)
{
PDEVICE_OBJECT deviceObject;
PCONTROLLER_DATA controllerData = (PCONTROLLER_DATA)Context;
PIDE_DEV_EXT devExt;
PIO_STACK_LOCATION ioStack;
UCHAR controllerStatus;
//
// Get the controller status. Note that this will STOP all interrupts
// on the controller.
//
controllerStatus =
READ_PORT_UCHAR(controllerData->ControllerAddress + STATUS_REGISTER);
//
// Check if this is an interrupt that we should service.
//
// We should service this interrupt if the IDE controller is not busy (i.e.
// he's waiting for US to do something) and the driver has had a chance to
// fully initialize (i.e. the controller data structure is set up)
//
if ( (controllerStatus & BUSY_STATUS) || (!controllerData->DeviceObject) ) {
return(FALSE);
}
//
// Get pointer to our device object and device extension
//
deviceObject = controllerData->DeviceObject;
devExt = deviceObject->DeviceExtension;
//
// If the controller is not indicating an error, check to see if
// there's anything to do...
//
if (!(controllerStatus & ERROR_STATUS)) {
//
// If there's data remaining to move, do it right here.
//
if (devExt->RemainingTransferLength) {
//
// if we're not ready, do 1 ping and try again
//
if (!(controllerStatus & DATA_REQUEST_STATUS)) {
controllerStatus = READ_PORT_UCHAR(
controllerData->ControllerAddress + STATUS_REGISTER);
}
//
// Check to be sure the device is ready
//
if (controllerStatus & DATA_REQUEST_STATUS) {
PVOID buffer;
//
// Update the controller with the next chunk of data
//
//
// Save the requestor's buffer address
//
buffer = devExt->CurrentAddress;
//
// adjust the address and counts in expectation
// that this I/O will complete
//
devExt->RemainingTransferLength -= devExt->BytesPerInterrupt;
devExt->CurrentAddress += devExt->BytesPerInterrupt;
//
// If this is not the last transfer, don't
// request a DPC yet.
//
if ( (devExt->RemainingTransferLength) > 0) {
controllerData->InterruptRequiresDpc = FALSE;
} else {
controllerData->InterruptRequiresDpc = TRUE;
}
//
// Move the data
//
if (devExt->OperationType == IRP_MJ_READ) {
//
// Move the data from the controller to the Requestor's
// data buffer
//
READ_PORT_BUFFER_USHORT(
(PUSHORT)(controllerData->ControllerAddress + DATA_REGISTER),
buffer,
devExt->BytesPerInterrupt/2);
#if DBG
DbgPrint("IdeISR: READ performed ISR at addr %x for %x\n",
buffer,devExt->BytesPerInterrupt);
#endif
} else {
//
// It's a WRITE
// Move the data from the requestor's data buffer to
// the controller
//
WRITE_PORT_BUFFER_USHORT(
(PUSHORT)(controllerData->ControllerAddress + DATA_REGISTER),
buffer,
devExt->BytesPerInterrupt/2);
#if DBG
DbgPrint("IdeISR: WRITe performed ISR at addr %x for %x\n",
buffer,
devExt->BytesPerInterrupt);
#endif
}
} else {
#if DBG
DbgPrint("IdeISR: Unable to complete operation %x controllerStatus %x irp %x\n",
devExt->OperationType,
controllerStatus,deviceObject->CurrentIrp);
#endif
}
}
}
//
// Request the DpcForIsr
//
if (controllerData->InterruptRequiresDpc) {
controllerData->InterruptRequiresDpc = FALSE;
IoRequestDpc(deviceObject,
deviceObject->CurrentIrp,
(PVOID)controllerStatus);
}
return(TRUE);
}
///////////////////////////////////////////////////////////////////////////////
//
// IdeDPC
//
// This routine is the Deferred Procedure Call (DPC), invoked indirectly
// by the ISR (IdeISR) via IoRequestDpc()
//
// INPUTS:
//
// Dpc - pointer to the DPC object
// DeferredContext - device object
// SystemArgument1 - current IRP - UNUSED
// SystemArgument2 - controller status (as setup in IdeISR)
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS
//
// IRQL:
//
// IRQL_DISPATCH_LEVEL
//
// NOTES:
//
// When this is invoked for a read or write operation, the operation
// should have been completed by the ISR. The DPC's job is to cleanup
// and do any error recovery (if possible) and then tell the IO
// Manager that:
//
// a) it's time to start the next packet (via IoStartNextPacketByKey)
// b) this IRP is complete (via IoCompleteRequest).
//
// Note that both a) and b) are actually done in the routine FinishIrp()
//
// Since we are at IRQL_DISPATCH_LEVEL < DIRQL, we shouldn't access
// the HW registers. However, since we are doing system queuing, the
// requests are searailized. Therefore, when the ISR is done, we know
// that either the request has completed, sucessfully or not. In either
// case, there should be no other interrupts pending on the device.
// Thus, we are able to read the controllerStatus on the device to check
// if the device is ready for the next operation. Also, note that we
// take advantage of the fact that the device is not busy if we get into
// the situation where we have to reset the disk (and we have to touch
// the HW registers again).
//
///////////////////////////////////////////////////////////////////////////////
VOID
IdeDPC(IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
PDEVICE_OBJECT deviceObject;
PIDE_DEV_EXT devExt;
PCONTROLLER_DATA controllerData;
PIRP irp;
PIO_STACK_LOCATION ioStack;
NTSTATUS returnStatus;
ULONG controllerStatus;
UCHAR codeValue;
UCHAR errorReg, driveHead, cylHigh, cylLow, sectorNumber, sectorCount;
NTSTATUS ntStatus;
//
// setup locals
//
deviceObject = (PDEVICE_OBJECT)DeferredContext;
devExt = deviceObject->DeviceExtension;
controllerData = devExt->ControllerData;
//
// Default to completing the IRP with success
//
returnStatus = STATUS_SUCCESS;
//
// Get the controller status. Note that since this device only has
// one operation in progress at a time, passing back the controller
// status this way from the ISR presents no problem.
//
controllerStatus = (ULONG)SystemArgument2;
//
// If there is some kind of error (or correctable error) then capture the
// register state of the controller
//
if (controllerStatus & ERROR_STATUS) {
errorReg = READ_PORT_UCHAR(controllerData->ControllerAddress + ERROR_REGISTER);
driveHead = READ_PORT_UCHAR(controllerData->ControllerAddress + DRIVE_HEAD_REGISTER);
cylHigh = READ_PORT_UCHAR(controllerData->ControllerAddress + CYLINDER_HIGH_REGISTER);
cylLow = READ_PORT_UCHAR(controllerData->ControllerAddress + CYLINDER_LOW_REGISTER),
sectorNumber = READ_PORT_UCHAR(controllerData->ControllerAddress + SECTOR_NUMBER_REGISTER);
sectorCount = READ_PORT_UCHAR(controllerData->ControllerAddress + SECTOR_COUNT_REGISTER);
#if DBG
DbgPrint(
"IdeDPC: Transaction error - ErrorReg %x cylinder High %x Low %x Sector Number %x sector Count %x driveHead %x controllerStatus %x\n",
errorReg,cylHigh, cylLow,sectorNumber, sectorCount,
controllerStatus);
#endif
}
//
// get some IRP context
//
irp = deviceObject->CurrentIrp;
ASSERT(irp);
ioStack = IoGetCurrentIrpStackLocation(irp);
//
// Before doing anything else, service a controller reset that may
// have been in progress.
//
// Note that if there was no reset pending, the state will be set to
// "RESET_NOT_RESTTING"
//
// If we ARE resetting, then we complete the operation and return
// right within the following switch statement.
//
switch (controllerData->ResettingController) {
//
// No reset presently in progress, thank you.
//
case RESET_NOT_RESETTING:
break;
//
// Drive has been reset.
//
case RESET_DRIVE_SET:
#if DBG
DbgPrint("IdeDPC: Reset the drive\n");
#endif
//
// Nothing should have failed at this point but it
// doesn't hurt to check.
//
if (controllerStatus & ERROR_STATUS) {
#if DBG
DbgPrint("IdeDPC: Error on RESET_DRIVE - status %x\n",controllerStatus);
#endif
goto RetryIrp;
}
//
// stall out to give the disk some time to catch up
//
KeStallExecutionProcessor(25);
//
// Request a recalibration of the drive
//
controllerData->ResettingController = RESET_DRIVE_RECALIBRATED;
controllerData->InterruptRequiresDpc = TRUE;
controllerData->DeviceObject = devExt->DeviceObject;
#if DBG
DbgPrint("IdeDPC: About to recalibrate controller for ext: %x\n"
" with a device unit of: %x\n",
devExt, devExt->DeviceUnit);
#endif
//
// make sure we're ready -- LOOOOONG delay possible here
//
(VOID)IdeWaitControllerReady(controllerData, 20, 150000);
//
// issue the reset (and generate a new interrupt)
//
WRITE_PORT_UCHAR(controllerData->ControllerAddress + DRIVE_HEAD_REGISTER,
devExt->DeviceUnit);
WRITE_PORT_UCHAR(controllerData->ControllerAddress + COMMAND_REGISTER,
RECALIBRATE_COMMAND);
//
// We're done with the reset... NEXT, we do a drive RECAL (below).
// RETURN for now
//
return;
//
// Drive being recalibrated
//
case RESET_DRIVE_RECALIBRATED:
#if DBG
DbgPrint("IdeDPC: Recalibrated drive\n");
#endif
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -