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

📄 power.c

📁 串口Windows驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
//depot/Lab01_N/Drivers/serial/serial/power.c#4 - edit change 11732 (text)
/*++

Copyright (c) 1997 Microsoft Corporation

Module Name:

    power.c

Abstract:

    This module contains the code that handles the power IRPs for the serial
    driver.


Environment:

    Kernel mode

Revision History :


--*/

#include "precomp.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGESRP0, SerialGotoPowerState)
#pragma alloc_text(PAGESRP0, SerialPowerDispatch)
#pragma alloc_text(PAGESRP0, SerialSetPowerD0)
#pragma alloc_text(PAGESRP0, SerialSetPowerD3)
#pragma alloc_text(PAGESRP0, SerialSaveDeviceState)
#pragma alloc_text(PAGESRP0, SerialRestoreDeviceState)
#pragma alloc_text(PAGESRP0, SerialSendWaitWake)
#endif // ALLOC_PRAGMA


VOID
SerialSystemPowerCompletion(IN PDEVICE_OBJECT PDevObj, UCHAR MinorFunction,
                            IN POWER_STATE PowerState, IN PVOID Context,
                            PIO_STATUS_BLOCK IoStatus)
/*++

Routine Description:

    This routine is the completion routine for PoRequestPowerIrp calls
    in this module.

Arguments:

    PDevObj - Pointer to the device object the irp is completing for

    MinorFunction - IRP_MN_XXXX value requested

    PowerState - Power state request was made of

    Context - Event to set or NULL if no setting required

    IoStatus - Status block from request

Return Value:

    VOID


--*/
{
   if (Context != NULL) {
      KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, 0);
   }

   return;
}



VOID
SerialSaveDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt)
/*++

Routine Description:

    This routine saves the device state of the UART

Arguments:

    PDevExt - Pointer to the device extension for the devobj to save the state
              for.

Return Value:

    VOID


--*/
{
   PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState;

   PAGED_CODE();

   SerialDbgPrintEx(SERTRACECALLS, "Entering SerialSaveDeviceState\n");

   //
   // Read necessary registers direct
   //

   pDevState->IER = READ_INTERRUPT_ENABLE(PDevExt->Controller);
   pDevState->MCR = READ_MODEM_CONTROL(PDevExt->Controller);
   pDevState->LCR = READ_LINE_CONTROL(PDevExt->Controller);


   SerialDbgPrintEx(SERTRACECALLS, "Leaving SerialSaveDeviceState\n");
}


VOID
SerialRestoreDeviceState(IN PSERIAL_DEVICE_EXTENSION PDevExt)
/*++

Routine Description:

    This routine restores the device state of the UART

Arguments:

    PDevExt - Pointer to the device extension for the devobj to restore the
    state for.

Return Value:

    VOID


--*/
{
   PSERIAL_DEVICE_STATE pDevState = &PDevExt->DeviceState;
   SHORT divisor;
   SERIAL_IOCTL_SYNC S;
   KIRQL oldIrql;

   PAGED_CODE();

   SerialDbgPrintEx(SERTRACECALLS, "Enter SerialRestoreDeviceState\n");
   SerialDbgPrintEx(SERTRACECALLS, "PDevExt: %x\n", PDevExt);

   //
   // Disable interrupts both via OUT2 and IER
   //

   WRITE_MODEM_CONTROL(PDevExt->Controller, 0);
   DISABLE_ALL_INTERRUPTS(PDevExt->Controller);

   //
   // Set the baud rate
   //

   SerialGetDivisorFromBaud(PDevExt->ClockRate, PDevExt->CurrentBaud, &divisor);
   S.Extension = PDevExt;
   S.Data = (PVOID)divisor;
   SerialSetBaud(&S);

   //
   // Reset / Re-enable the FIFO's
   //

   if (PDevExt->FifoPresent) {
      WRITE_FIFO_CONTROL(PDevExt->Controller, (UCHAR)0);
      READ_RECEIVE_BUFFER(PDevExt->Controller);
      WRITE_FIFO_CONTROL(PDevExt->Controller,
                         (UCHAR)(SERIAL_FCR_ENABLE | PDevExt->RxFifoTrigger
                                 | SERIAL_FCR_RCVR_RESET
                                 | SERIAL_FCR_TXMT_RESET));
   } else {
      WRITE_FIFO_CONTROL(PDevExt->Controller, (UCHAR)0);
   }

   //
   // In case we are dealing with a bitmasked multiportcard,
   // that has the mask register enabled, enable the
   // interrupts.
   //

   if (PDevExt->InterruptStatus) {
      if (PDevExt->Indexed) {
            WRITE_PORT_UCHAR(PDevExt->InterruptStatus, (UCHAR)0xFF);
      } else {
         //
         // Either we are standalone or already mapped
         //

         if (PDevExt->OurIsrContext == PDevExt) {
            //
            // This is a standalone
            //

            WRITE_PORT_UCHAR(PDevExt->InterruptStatus,
                             (UCHAR)(1 << (PDevExt->PortIndex - 1)));
         } else {
            //
            // One of many
            //

            WRITE_PORT_UCHAR(PDevExt->InterruptStatus,
                             (UCHAR)((PSERIAL_MULTIPORT_DISPATCH)PDevExt->
                                     OurIsrContext)->UsablePortMask);
         }
      }
   }

   //
   // Restore a couple more registers
   //

   WRITE_INTERRUPT_ENABLE(PDevExt->Controller, pDevState->IER);
   WRITE_LINE_CONTROL(PDevExt->Controller, pDevState->LCR);

   //
   // Clear out any stale interrupts
   //

   READ_INTERRUPT_ID_REG(PDevExt->Controller);
   READ_LINE_STATUS(PDevExt->Controller);
   READ_MODEM_STATUS(PDevExt->Controller);

   if (PDevExt->DeviceState.Reopen == TRUE) {
      SerialDbgPrintEx(SERPNPPOWER, "Reopening device\n");

      SetDeviceIsOpened(PDevExt, TRUE, FALSE);

      //
      // This enables interrupts on the device!
      //

      WRITE_MODEM_CONTROL(PDevExt->Controller,
                          (UCHAR)(pDevState->MCR | SERIAL_MCR_OUT2));

      //
      // Refire the state machine
      //

      DISABLE_ALL_INTERRUPTS(PDevExt->Controller);
      ENABLE_ALL_INTERRUPTS(PDevExt->Controller);
   }
   

}


VOID
SerialFinishDevicePower(IN PDEVICE_OBJECT PDevObj, IN UCHAR MinorFunction,
                        IN POWER_STATE State,
                        IN PSERIAL_POWER_COMPLETION_CONTEXT PContext,
                        IN PIO_STATUS_BLOCK PIoStatus)
{
   PSERIAL_DEVICE_EXTENSION pDevExt = PContext->PDevObj->DeviceExtension;
   PIRP pSIrp = PContext->PSIrp;

   //
   // A possible cleaner approach is to not use a proprietary context
   // and pass the Irp down using our devobj rather than the PDO.
   //

   //
   // Copy status from D request to S request
   //

   pSIrp->IoStatus.Status = PIoStatus->Status;

   ExFreePool(PContext);

   //
   // Complete S request
   //

   PoStartNextPowerIrp(pSIrp);
   SerialCompleteRequest(pDevExt, pSIrp, IO_NO_INCREMENT);
}


NTSTATUS
SerialFinishSystemPower(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp,
                        IN PVOID PContext)
/*++

Routine Description:

    This is the completion routine for the system set power request.

Arguments:

    PDevObj - Pointer to the device object for this device

    PIrp - Pointer to the IRP for the system set request

    PContext - Not used

Return Value:

    The function value is the final status of the call


--*/
{
   PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
   NTSTATUS status = PIrp->IoStatus.Status;
   PSERIAL_POWER_COMPLETION_CONTEXT pContext;
   PIO_STACK_LOCATION pIrpSp;

   UNREFERENCED_PARAMETER(PContext);

   //
   // See if it failed, and if so, just return it.
   //

   if (!NT_SUCCESS(status)) {
      PoStartNextPowerIrp(PIrp);
      return status;
   }

   pContext
      = (PSERIAL_POWER_COMPLETION_CONTEXT)
        ExAllocatePool(NonPagedPool, sizeof(SERIAL_POWER_COMPLETION_CONTEXT));

   if (pContext == NULL) {
      status = STATUS_INSUFFICIENT_RESOURCES;
      goto SerialFinishSystemPowerErrOut;
   }

   pIrpSp = IoGetCurrentIrpStackLocation(PIrp);

   pContext->PDevObj = PDevObj;
   pContext->PSIrp = PIrp;

   status = PoRequestPowerIrp(pDevExt->Pdo, pIrpSp->MinorFunction,
                              pDevExt->NewDevicePowerState,
                              SerialFinishDevicePower, pContext, NULL);

SerialFinishSystemPowerErrOut:

   if (!NT_SUCCESS(status)) {
      if (pContext != NULL) {
         ExFreePool(pContext);
      }

      PoStartNextPowerIrp(PIrp);
      PIrp->IoStatus.Status = status;

      SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
   }

   return STATUS_MORE_PROCESSING_REQUIRED;
}


NTSTATUS
SerialPowerDispatch(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)

/*++

Routine Description:

    This is a dispatch routine for the IRPs that come to the driver with the
    IRP_MJ_POWER major code (power IRPs).

Arguments:

    PDevObj - Pointer to the device object for this device

    PIrp - Pointer to the IRP for the current request

Return Value:

    The function value is the final status of the call


--*/

{

   PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
   PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
   NTSTATUS status;
   PDEVICE_OBJECT pLowerDevObj = pDevExt->LowerDeviceObject;
   PDEVICE_OBJECT pPdo = pDevExt->Pdo;
   BOOLEAN acceptingIRPs;

   PAGED_CODE();

   if ((status = SerialIRPPrologue(PIrp, pDevExt)) != STATUS_SUCCESS) {
      //
      // The request may have been queued if we are stopped.  If so,
      // we just return the status.  Otherwise, it must be an error
      // so we complete the power request.
      //

      if (status != STATUS_PENDING) {
         PoStartNextPowerIrp(PIrp);
         SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
      }
      return status;
   }

   status = STATUS_SUCCESS;

   switch (pIrpStack->MinorFunction) {

   case IRP_MN_WAIT_WAKE:
      SerialDbgPrintEx(SERPNPPOWER, "Got IRP_MN_WAIT_WAKE Irp\n");
      break;


   case IRP_MN_POWER_SEQUENCE:
      SerialDbgPrintEx(SERPNPPOWER, "Got IRP_MN_POWER_SEQUENCE Irp\n");
      break;


   case IRP_MN_SET_POWER:
      SerialDbgPrintEx(SERPNPPOWER, "Got IRP_MN_SET_POWER Irp\n");

      //
      // Perform different ops if it was system or device
      //

      switch (pIrpStack->Parameters.Power.Type) {
      case SystemPowerState: {
         POWER_STATE powerState;

            //
            // They asked for a system power state change
            //

            SerialDbgPrintEx(SERPNPPOWER, "SystemPowerState\n");

            //
            // We will only service this if we are policy owner -- we
            // don't need to lock on this value since we only service
            // one power request at a time.
            //

            if (pDevExt->OwnsPowerPolicy != TRUE) {
               status = STATUS_SUCCESS;
               goto PowerExit;
            }


            switch (pIrpStack->Parameters.Power.State.SystemState) {
            case PowerSystemUnspecified:
               powerState.DeviceState = PowerDeviceUnspecified;
               break;

            case PowerSystemWorking:
               powerState.DeviceState = PowerDeviceD0;
               break;

            case PowerSystemSleeping1:
            case PowerSystemSleeping2:
            case PowerSystemSleeping3:
            case PowerSystemHibernate:
            case PowerSystemShutdown:
            case PowerSystemMaximum:
               powerState.DeviceState
                  = pDevExt->DeviceStateMap[pIrpStack->
                                            Parameters.Power.State.SystemState];
               break;

            default:
               status = STATUS_SUCCESS;
               goto PowerExit;
               break;
            }


            //
            // Send IRP to change device state if we should change
            //

            //
            // We only power up the stack if the device is open.  This is based
            // on our policy of keeping the device powered down unless it is
            // open. Additionally, we should power the stack if the RetainPowerOnClose 
            // flag is set.
            //

            if (((powerState.DeviceState < pDevExt->PowerState)
                 && (pDevExt->RetainPowerOnClose || pDevExt->OpenCount))) {
               //
               // Send the request down
               //

               //
               // Mark the IRP as pending
               //

               pDevExt->NewDevicePowerState = powerState;

               IoMarkIrpPending(PIrp);

               IoCopyCurrentIrpStackLocationToNext(PIrp);
               IoSetCompletionRoutine(PIrp, SerialFinishSystemPower, NULL,
                                      TRUE, TRUE, TRUE);

               PoCallDriver(pDevExt->LowerDeviceObject, PIrp);

               return STATUS_PENDING;
            }else {
               //
               // If powering down, we can't go past wake state
               // if wait-wake pending
               //

               if (powerState.DeviceState >= pDevExt->PowerState) {

                  //
                  // Power down -- ensure there is no wake-wait pending OR
                  // we can do down to that level and still wake the machine
                  //

                  if ((pDevExt->PendingWakeIrp == NULL && !pDevExt->SendWaitWake)
                      || powerState.DeviceState <= pDevExt->DeviceWake) {
                     //
                     // Send the request down
                     //

                     //
                     // Mark the IRP as pending
                     //

                     pDevExt->NewDevicePowerState = powerState;

                     IoMarkIrpPending(PIrp);

                     IoCopyCurrentIrpStackLocationToNext(PIrp);
                     IoSetCompletionRoutine(PIrp, SerialFinishSystemPower, NULL,
                                            TRUE, TRUE, TRUE);

                     PoCallDriver(pDevExt->LowerDeviceObject, PIrp);

                     return STATUS_PENDING;
                  } else {
                     //
                     // Fail the request
                     //

                     status = STATUS_INVALID_DEVICE_STATE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -