/*++ Copyright (c) 1998 Microsoft Corporation Module Name: acpiirp.c Abstract: This module contains routines for simplifying IRP handling Author: Adrian J. Oney (AdriaO) Environment: NT Kernel Model Driver only Revision History: --*/ #include "pch.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, ACPIIrpInvokeDispatchRoutine) #pragma alloc_text(PAGE, ACPIIrpSetPagableCompletionRoutineAndForward) #pragma alloc_text(PAGE, ACPIIrpCompletionRoutineWorker) #endif NTSTATUS ACPIIrpInvokeDispatchRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context, IN ACPICALLBACKROUTINE CompletionRoutine, IN BOOLEAN InvokeOnSuccess, IN BOOLEAN InvokeIfUnhandled ) { PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject); NTSTATUS status, returnStatus; PAGED_CODE(); ACPIDebugEnter( "ACPIIrpInvokeDispatchRoutine" ); // // Retrieve the status from the embedded IRP // status = Irp->IoStatus.Status; returnStatus = STATUS_NOT_SUPPORTED; // // And call the completion routine appropriately // if (NT_SUCCESS(status)) { if (InvokeOnSuccess) { returnStatus = CompletionRoutine(DeviceObject, Irp, Context, FALSE); } } else if (status == STATUS_NOT_SUPPORTED) { if (InvokeIfUnhandled) { returnStatus = CompletionRoutine(DeviceObject, Irp, Context, FALSE); } } if (deviceExtension->Flags & DEV_TYPE_PDO) { if (returnStatus != STATUS_PENDING) { if (returnStatus != STATUS_NOT_SUPPORTED) { Irp->IoStatus.Status = returnStatus; } else { returnStatus = Irp->IoStatus.Status; } IoCompleteRequest(Irp, IO_NO_INCREMENT); } } else if (returnStatus != STATUS_PENDING) { if (returnStatus != STATUS_NOT_SUPPORTED) { Irp->IoStatus.Status = returnStatus; } if (NT_SUCCESS(returnStatus) || (returnStatus == STATUS_NOT_SUPPORTED)) { returnStatus = IoCallDriver( deviceExtension->TargetDeviceObject, Irp ); } else { IoCompleteRequest(Irp, IO_NO_INCREMENT); } } return returnStatus; ACPIDebugExit( "ACPIIrpInvokeDispatchRoutine" ); } NTSTATUS ACPIIrpSetPagableCompletionRoutineAndForward( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ACPICALLBACKROUTINE CompletionRoutine, IN PVOID Context, IN BOOLEAN InvokeOnSuccess, IN BOOLEAN InvokeIfUnhandled, IN BOOLEAN InvokeOnError, IN BOOLEAN InvokeOnCancel ) /*++ Routine Description: This routine handles an ACPI Filter Irp call. Irp count referencing is automatically taken care of. Arguments: DeviceObject - Pointer to the device object we received the request for. Irp - Pointer to the request CompletionRoutine - Routine to call after completion of the Irp Return Value: NTSTATUS --*/ { PDEVICE_EXTENSION deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject); PACPI_IO_CONTEXT pIoContext ; PIO_WORKITEM pIoWorkItem ; PAGED_CODE() ; ACPIDebugEnter( "ACPIIrpSetPagableCompletionRoutineAndForward" ); pIoContext = (PACPI_IO_CONTEXT) ExAllocatePool( NonPagedPool, sizeof(ACPI_IO_CONTEXT) ); if (pIoContext == NULL) { Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES ; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_INSUFFICIENT_RESOURCES ; } pIoWorkItem = IoAllocateWorkItem(DeviceObject); if (pIoWorkItem == NULL) { ExFreePool(pIoContext); Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES ; IoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_INSUFFICIENT_RESOURCES ; } pIoContext->CompletionRoutine = CompletionRoutine ; pIoContext->DeviceObject = DeviceObject ; pIoContext->Context = Context ; pIoContext->InvokeOnSuccess = InvokeOnSuccess ; pIoContext->InvokeIfUnhandled = InvokeIfUnhandled ; pIoContext->InvokeOnError = InvokeOnError ; pIoContext->InvokeOnCancel = InvokeOnCancel ; pIoContext->Irp = Irp ; pIoContext->IoWorkItem = pIoWorkItem ; // // We have a callback routine --- so we need to make sure to // increment the ref count since we will handle it later // InterlockedIncrement( &(deviceExtension->OutstandingIrpCount) ); // // Copy the stack location... // IoCopyCurrentIrpStackLocationToNext( Irp ); // // Set the completion event to be called... // IoSetCompletionRoutine( Irp, ACPIIrpGenericFilterCompletionHandler, (PVOID) pIoContext, TRUE, TRUE, TRUE ); // // Mark the IRP pending // IoMarkIrpPending(Irp); // // Send the request along // IoCallDriver( deviceExtension->TargetDeviceObject, Irp ); // // We do this because we may change the status in the completion routine. // return STATUS_PENDING; ACPIDebugExit( "ACPIIrpSetPagableCompletionRoutineAndForward" ); } NTSTATUS ACPIIrpGenericFilterCompletionHandler( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) /*++ Routine Description: A rather generic "synchronize the IRP on this thread" completion routine. Argument: DeviceObject - Pointer to the device object we received the request for Irp - Pointer to the request Event - Pointer to structure containing the Irp handlers Return Value: NTSTATUS --*/ { PACPI_IO_CONTEXT pIoContext = (PACPI_IO_CONTEXT) Context; ACPIDebugEnter( "ACPIIrpGenericFilterCompletionHandler" ); if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } if (KeGetCurrentIrql() != PASSIVE_LEVEL) { IoQueueWorkItem( pIoContext->IoWorkItem, ACPIIrpCompletionRoutineWorker, DelayedWorkQueue, pIoContext ); } else { ACPIIrpCompletionRoutineWorker(DeviceObject, Context); } return STATUS_MORE_PROCESSING_REQUIRED; ACPIDebugExit( "ACPIIrpGenericFilterCompletionHandler" ); } VOID ACPIIrpCompletionRoutineWorker( IN PDEVICE_OBJECT DeviceObject, IN PVOID Context ) { PACPI_IO_CONTEXT pIoContext; PDEVICE_EXTENSION deviceExtension; ACPICALLBACKROUTINE completionRoutine; PIRP irp; NTSTATUS status, returnStatus; PVOID context; PAGED_CODE(); ACPIDebugEnter( "ACPIIrpCompletionRoutineWorker" ); // // Read out fields from the device object // deviceExtension = ACPIInternalGetDeviceExtension(DeviceObject); // // Cast the context and dig into it. // pIoContext = (PACPI_IO_CONTEXT) Context; completionRoutine = pIoContext->CompletionRoutine; context = pIoContext->Context; irp = pIoContext->Irp; // // Retrieve the status from the embedded IRP // status = irp->IoStatus.Status; returnStatus = STATUS_NOT_SUPPORTED; // // And call the completion routine appropriately // if (NT_SUCCESS(status)) { if (pIoContext->InvokeOnSuccess) { returnStatus = completionRoutine(DeviceObject, irp, context, TRUE); } } else if (status == STATUS_NOT_SUPPORTED) { if (pIoContext->InvokeIfUnhandled) { returnStatus = completionRoutine(DeviceObject, irp, context, TRUE); } } else { if ((pIoContext->InvokeOnError) || (irp->Cancel && pIoContext->InvokeOnCancel)) { returnStatus = completionRoutine(DeviceObject, irp, context, TRUE); } } // // Remove our reference // ACPIInternalDecrementIrpReferenceCount( deviceExtension ); IoFreeWorkItem(pIoContext->IoWorkItem); ExFreePool(pIoContext) ; if (returnStatus != STATUS_PENDING) { if (returnStatus != STATUS_NOT_SUPPORTED) { irp->IoStatus.Status = returnStatus; } IoCompleteRequest(irp, IO_NO_INCREMENT); } ACPIDebugExit( "ACPIIrpCompletionRoutineWorker" ); }