⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide.c

📁 硬盘驱动的例子
💻 C
📖 第 1 页 / 共 4 页
字号:

                //
                // 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 + -