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

📄 utils.c

📁 NXP产品LPC23XX的开发板的源文件
💻 C
📖 第 1 页 / 共 3 页
字号:
    if (TotalTimer) {

        //
        // Try to cancel the operations total timer.  If the operation
        // returns true then the timer did have a reference to the
        // irp.  Since we've canceled this timer that reference is
        // no longer valid and we can decrement the reference count.
        //
        // If the cancel returns false then this means either of two things:
        //
        // a) The timer has already fired.
        //
        // b) There never was an total timer.
        //
        // In the case of "b" there is no need to decrement the reference
        // count since the "timer" never had a reference to it.
        //
        // In the case of "a", then the timer itself will be coming
        // along and decrement it's reference.  Note that the caller
        // of this routine might actually be the this timer, but it
        // has already decremented the reference.
        //

        if (SerialCancelTimer(TotalTimer, PDevExt)) {

            SERIAL_CLEAR_REFERENCE(
                *CurrentOpIrp,
                SERIAL_REF_TOTAL_TIMER
                );
        }

    }

}

NTSTATUS
SerialStartOrQueue(
    IN PDEVICE_EXTENSION Extension,
    IN PIRP Irp,
    IN PLIST_ENTRY QueueToExamine,
    IN PIRP *CurrentOpIrp,
    IN PSERIAL_START_ROUTINE Starter
    )

/*++

Routine Description:

    This routine is used to either start or queue any requst
    that can be queued in the driver.

Arguments:

    Extension - Points to the serial device extension.

    Irp - The irp to either queue or start.  In either
          case the irp will be marked pending.

    QueueToExamine - The queue the irp will be place on if there
                     is already an operation in progress.

    CurrentOpIrp - Pointer to a pointer to the irp the is current
                   for the queue.  The pointer pointed to will be
                   set with to Irp if what CurrentOpIrp points to
                   is NULL.

    Starter - The routine to call if the queue is empty.

Return Value:

    This routine will return STATUS_PENDING if the queue is
    not empty.  Otherwise, it will return the status returned
    from the starter routine (or cancel, if the cancel bit is
    on in the irp).


--*/

{

    KIRQL oldIrql;

    ////SERIAL_LOCKED_PAGED_CODE();

    IoAcquireCancelSpinLock(&oldIrql);

    //
    // If this is a write irp then take the amount of characters
    // to write and add it to the count of characters to write.
    //

    if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction
        == IRP_MJ_WRITE) {

        Extension->TotalCharsQueued +=
            IoGetCurrentIrpStackLocation(Irp)
            ->Parameters.Write.Length;

    } else if ((IoGetCurrentIrpStackLocation(Irp)->MajorFunction
                == IRP_MJ_DEVICE_CONTROL) &&
               ((IoGetCurrentIrpStackLocation(Irp)
                 ->Parameters.DeviceIoControl.IoControlCode ==
                 IOCTL_SERIAL_IMMEDIATE_CHAR) ||
                (IoGetCurrentIrpStackLocation(Irp)
                 ->Parameters.DeviceIoControl.IoControlCode ==
                 IOCTL_SERIAL_XOFF_COUNTER))) {

        Extension->TotalCharsQueued++;

    }

    if ((IsListEmpty(QueueToExamine)) &&
        !(*CurrentOpIrp)) {

        //
        // There were no current operation.  Mark this one as
        // current and start it up.
        //

        *CurrentOpIrp = Irp;

        IoReleaseCancelSpinLock(oldIrql);

        return Starter(Extension);

    } else {

        //
        // We don't know how long the irp will be in the
        // queue.  So we need to handle cancel.
        //

        if (Irp->Cancel) {
           PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);

            IoReleaseCancelSpinLock(oldIrql);

            if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
                   IOCTL_SERIAL_SET_QUEUE_SIZE) {
               //
               // We shoved the pointer to the memory into the
               // the type 3 buffer pointer which we KNOW we
               // never use.
               //

               ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);

               ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);

               irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
            }

            Irp->IoStatus.Status = STATUS_CANCELLED;

            SerialDump(
                SERIRPPATH,
                ("SERIAL: Complete Irp: %x\n",Irp)
                );
            SerialCompleteRequest(Extension, Irp, 0);

            return STATUS_CANCELLED;

        } else {


            Irp->IoStatus.Status = STATUS_PENDING;
            IoMarkIrpPending(Irp);

            InsertTailList(
                QueueToExamine,
                &Irp->Tail.Overlay.ListEntry
                );

            IoSetCancelRoutine(
                Irp,
                SerialCancelQueued
                );

            IoReleaseCancelSpinLock(oldIrql);

            return STATUS_PENDING;

        }

    }

}


VOID
SerialCancelQueued(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )

/*++

Routine Description:

    This routine is used to cancel Irps that currently reside on
    a queue.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP to be canceled.

Return Value:

    None.

--*/

{

    PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);

    //SERIAL_LOCKED_PAGED_CODE();

    Irp->IoStatus.Status = STATUS_CANCELLED;
    Irp->IoStatus.Information = 0;

    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);

    //
    // If this is a write irp then take the amount of characters
    // to write and subtract it from the count of characters to write.
    //

    if (irpSp->MajorFunction == IRP_MJ_WRITE) {

        extension->TotalCharsQueued -= irpSp->Parameters.Write.Length;

    } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

        //
        // If it's an immediate then we need to decrement the
        // count of chars queued.  If it's a resize then we
        // need to deallocate the pool that we're passing on
        // to the "resizing" routine.
        //

        if ((irpSp->Parameters.DeviceIoControl.IoControlCode ==
             IOCTL_SERIAL_IMMEDIATE_CHAR) ||
            (irpSp->Parameters.DeviceIoControl.IoControlCode ==
             IOCTL_SERIAL_XOFF_COUNTER)) {

            extension->TotalCharsQueued--;

        } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
                   IOCTL_SERIAL_SET_QUEUE_SIZE) {

            //
            // We shoved the pointer to the memory into the
            // the type 3 buffer pointer which we KNOW we
            // never use.
            //

            ASSERT(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);

            ExFreePool(irpSp->Parameters.DeviceIoControl.Type3InputBuffer);

            irpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;

        }

    }

    IoReleaseCancelSpinLock(Irp->CancelIrql);

    SerialDump(
        SERIRPPATH,
        ("SERIAL: Complete Irp: %x\n",Irp)
        );
    SerialCompleteRequest(extension, Irp, IO_SERIAL_INCREMENT);
}

NTSTATUS
SerialCompleteIfError(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp
    )

/*++

Routine Description:

    If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and
    there is an error and the application requested abort on errors,
    then cancel the irp.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP to test.

Return Value:

    STATUS_SUCCESS or STATUS_CANCELLED.

--*/

{

    PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;

    NTSTATUS status = STATUS_SUCCESS;

    //SERIAL_LOCKED_PAGED_CODE();

    if ((extension->HandFlow.ControlHandShake &
         SERIAL_ERROR_ABORT) && extension->ErrorWord) {

        PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);

        //
        // There is a current error in the driver.  No requests should
        // come through except for the GET_COMMSTATUS.
        //

        if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
            (irpSp->Parameters.DeviceIoControl.IoControlCode !=
             IOCTL_SERIAL_GET_COMMSTATUS)) {

            status = STATUS_CANCELLED;
            Irp->IoStatus.Status = STATUS_CANCELLED;
            Irp->IoStatus.Information = 0;

            SerialDump(
                SERIRPPATH,
                ("SERIAL: Complete Irp: %x\n",Irp)
                );
            SerialCompleteRequest(extension, Irp, 0);
        }

    }

    return status;

}

VOID
SerialFilterCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++

Routine Description:

    This routine will be used cancel irps on the stalled queue.

Arguments:

    PDevObj - Pointer to the device object.

    PIrp - Pointer to the Irp to cancel

Return Value:

    None.

--*/
{
   PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
   PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);

   PIrp->IoStatus.Status = STATUS_CANCELLED;
   PIrp->IoStatus.Information = 0;

   RemoveEntryList(&PIrp->Tail.Overlay.ListEntry);

   IoReleaseCancelSpinLock(PIrp->CancelIrql);
}

VOID
SerialKillAllStalled(IN PDEVICE_OBJECT PDevObj)
{
   KIRQL cancelIrql;
   PDRIVER_CANCEL cancelRoutine;
   PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;

   IoAcquireCancelSpinLock(&cancelIrql);

   while (!IsListEmpty(&pDevExt->StalledIrpQueue)) {

      PIRP currentLastIrp = CONTAINING_RECORD(pDevExt->StalledIrpQueue.Blink,
                                              IRP, Tail.Overlay.ListEntry);

      RemoveEntryList(pDevExt->StalledIrpQueue.Blink);

      cancelRoutine = currentLastIrp->CancelRoutine;
      currentLastIrp->CancelIrql = cancelIrql;
      currentLastIrp->CancelRoutine = NULL;
      currentLastIrp->Cancel = TRUE;

      cancelRoutine(PDevObj, currentLastIrp);

      IoAcquireCancelSpinLock(&cancelIrql);
   }

   IoReleaseCancelSpinLock(cancelIrql);
}


NTSTATUS
SerialFilterIrps(IN PIRP PIrp, IN PDEVICE_EXTENSION PDevExt)
/*++

Routine Description:

    This routine will be used to approve irps for processing.
    If an irp is approved, success will be returned.  If not,
    the irp will be queued or rejected outright.  The IoStatus struct
    and return value will appropriately reflect the actions taken.

Arguments:

    PIrp - Pointer to the Irp to cancel

    PDevExt - Pointer to the device extension

Return Value:

    None.

--*/
{
   PIO_STACK_LOCATION pIrpStack;
   KIRQL oldIrqlFlags;

   pIrpStack = IoGetCurrentIrpStackLocation(PIrp);

   KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrqlFlags);

   if ((PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK)
       && ((PDevExt->Flags & SERIAL_FLAGS_BROKENHW) == 0)) {
      KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
      return STATUS_SUCCESS;
   }

   if ((PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_REMOVING)
       || (PDevExt->Flags & SERIAL_FLAGS_BROKENHW)
       || (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {

      KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);

      //
      // Accept all PNP IRP's -- we assume PNP can synchronize itself
      //

      if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
         return STATUS_SUCCESS;
      }

      PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
      return STATUS_DELETE_PENDING;
   }

   if (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_STOPPING) {
       KIRQL oldIrql;

       KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);


      //
      // Accept all PNP IRP's -- we assume PNP can synchronize itself
      //

      if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
         return STATUS_SUCCESS;
      }

      IoAcquireCancelSpinLock(&oldIrql);

      if (PIrp->Cancel) {
         IoReleaseCancelSpinLock(oldIrql);
         PIrp->IoStatus.Status = STATUS_CANCELLED;
         return STATUS_CANCELLED;
      } else {
         //
         // Mark the Irp as pending
         //

         PIrp->IoStatus.Status = STATUS_PENDING;
         IoMarkIrpPending(PIrp);

         //
         // Queue up the IRP
         //

         InsertTailList(&PDevExt->StalledIrpQueue,
                        &PIrp->Tail.Overlay.ListEntry);

         IoSetCancelRoutine(PIrp, SerialFilterCancelQueued);
         IoReleaseCancelSpinLock(oldIrql);
         return STATUS_PENDING;
      }
   }

   KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);

   return STATUS_SUCCESS;
}


VOID
SerialUnstallIrps(IN PDEVICE_EXTENSION PDevExt)
/*++

Routine Description:

    This routine will be used to restart irps temporarily stalled on
    the stall queue due to a stop or some such nonsense.

Arguments:

    PDevExt - Pointer to the device extension

Return Value:

    None.

--*/
{
   PLIST_ENTRY pIrpLink;
   PIRP pIrp;
   PIO_STACK_LOCATION pIrpStack;
   PDEVICE_OBJECT pDevObj;
   PDRIVER_OBJECT pDrvObj;
   KIRQL oldIrql;

   SerialDump(SERTRACECALLS, ("SERIAL: Entering SerialUnstallIrps\n"));
   IoAcquireCancelSpinLock(&oldIrql);

   pIrpLink = PDevExt->StalledIrpQueue.Flink;

   while (pIrpLink != &PDevExt->StalledIrpQueue) {
      pIrp = CONTAINING_RECORD(pIrpLink, IRP, Tail.Overlay.ListEntry);
      RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);

      pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
      pDevObj = pIrpStack->DeviceObject;
      pDrvObj = pDevObj->DriverObject;
      IoSetCancelRoutine(pIrp, NULL);
      IoReleaseCancelSpinLock(oldIrql);

      SerialDump(SERPNPPOWER, ("SERIAL: Unstalling Irp 0x%x with 0x%x\n",
                               pIrp, pIrpStack->MajorFunction));

      pDrvObj->MajorFunction[pIrpStack->MajorFunction](pDevObj, pIrp);

      IoAcquireCancelSpinLock(&oldIrql);
      pIrpLink = PDevExt->StalledIrpQueue.Flink;
   }

   IoReleaseCancelSpinLock(oldIrql);

   SerialDump(SERTRACECALLS, ("SERIAL: Leaving SerialUnstallIrps\n"));
}


NTSTATUS
SerialIRPPrologue(IN PIRP PIrp, IN PDEVICE_EXTENSION PDevExt)
/*++

Routine Description:

   This function must be called at any IRP dispatch entry point.  It,
   with SerialIRPEpilogue(), keeps track of all pending IRP's for the given
   PDevObj.

Arguments:

   PDevObj - Pointer to the device object we are tracking pending IRP's for.

Return Value:

    Tentative status of the Irp.

--*/
{
   InterlockedIncrement(&PDevExt->PendingIRPCnt);

   return SerialFilterIrps(PIrp, PDevExt);
}



VOID
SerialIRPEpilogue(IN PDEVICE_EXTENSION PDevExt)
/*++

Routine Description:

   This function must be called at any IRP dispatch entry point.  It,
   with SerialIRPPrologue(), keeps track of all pending IRP's for the given
   PDevObj.

Arguments:

   PDevObj - Pointer to the device object we are tracking pending IRP's for.

Return Value:

   None.

⌨️ 快捷键说明

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