Windows WDM 设备驱动程序开发指南光盘 保护随书的源代码

源代码在线查看: control.cpp

软件大小: 2784 K
上传用户: norwaybaby
关键词: Windows WDM 设备 开发指南
下载地址: 免注册下载 普通下载 VIP

相关代码

				// Control.cpp -- IOCTL handlers for notify driver
				// Copyright (C) 1999 by Walter Oney
				// All rights reserved
				
				#include "stddcls.h"
				#include "driver.h"
				#include "ioctls.h"
				
				NTSTATUS CacheControlRequest(PDEVICE_EXTENSION pdx, PIRP Irp, PIRP* pIrp);
				VOID OnCancelPendingIoctl(PDEVICE_OBJECT fdo, PIRP Irp);
				NTSTATUS OnCompletePendingIoctl(PDEVICE_OBJECT junk, PIRP Irp, PDEVICE_EXTENSION pdx);
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma PAGEDCODE
				
				NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp)
					{							// DispatchControl
					PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
				
					NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);
					if (!NT_SUCCESS(status))
						return CompleteRequest(Irp, status, 0);
					ULONG info = 0;
				
					PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
					ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
					ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
					ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
				
					switch (code)
						{						// process request
				
					case IOCTL_WAIT_NOTIFY:				// code == 0x800
						{						// IOCTL_WAIT_NOTIFY
						if (cbout < sizeof(ULONG))
							status = STATUS_INVALID_PARAMETER;
						else
							status = CacheControlRequest(pdx, Irp, &pdx->NotifyIrp);
						break;
						}						// IOCTL_WAIT_NOTIFY
				
					case IOCTL_GENERATE_EVENT:				// code == 0x801
						{						// IOCTL_GENERATE_EVENT
						if (cbin < sizeof(ULONG))
							{					// buffer too small
							status = STATUS_INVALID_PARAMETER;
							break;
							}					// buffer too small
				
						PIRP nfyirp = UncacheControlRequest(pdx, &pdx->NotifyIrp);
						if (nfyirp)
							{					// complete notification IRP
							*(PULONG) nfyirp->AssociatedIrp.SystemBuffer = *(PULONG) Irp->AssociatedIrp.SystemBuffer;
							CompleteRequest(nfyirp, STATUS_SUCCESS, sizeof(ULONG));
							}					// complete notification IRP
						else
							status = STATUS_UNSUCCESSFUL;
				
						break;
						}						// IOCTL_GENERATE_EVENT
				
					default:
						status = STATUS_INVALID_DEVICE_REQUEST;
						break;
				
						}						// process request
				
					IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
					return status == STATUS_PENDING ? status : CompleteRequest(Irp, status, info);
					}							// DispatchControl
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma PAGEDCODE
				
				VOID AbortPendingIoctls(PDEVICE_EXTENSION pdx, NTSTATUS status)
					{							// AbortPendingIoctls
					PAGED_CODE();
					InterlockedExchange(&pdx->IoctlAbortStatus, status);
					CleanupControlRequests(pdx, status, NULL);
					}							// AbortPendingIoctls
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma LOCKEDCODE
				
				NTSTATUS CacheControlRequest(PDEVICE_EXTENSION pdx, PIRP Irp, PIRP* pIrp)
					{							// CacheControlRequest
					ASSERT(KeGetCurrentIrql() 				
					KIRQL oldirql;
					KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql);
				
					NTSTATUS status;
				
					if (*pIrp)
						status = STATUS_UNSUCCESSFUL;	// something already cached here
					else if (pdx->IoctlAbortStatus)
						status = pdx->IoctlAbortStatus;	// rejecting new IRPs for some reason
					else
						{						// try to cache IRP
				
						// Install a cancel routine and check for this IRP having already been
						// cancelled
				
						IoSetCancelRoutine(Irp, OnCancelPendingIoctl);
						if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
							status = STATUS_CANCELLED;	// already cancelled
				
						// Put this IRP on our list of pending IOCTLs. Install a completion
						// routine to nullify the cache pointer. Note that AddDevice would have
						// failed if there were no PDO below us, so we know there's at least
						// one free stack location here.
				
						else
							{					// cache it
							IoMarkIrpPending(Irp);
							status = STATUS_PENDING;
				
							PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
							stack->Parameters.Others.Argument1 = (PVOID) pIrp;
							IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnCompletePendingIoctl, (PVOID) pdx, TRUE, TRUE, TRUE);
							IoSetNextIrpStackLocation(Irp);	// so our completion routine will get called
							PFILE_OBJECT fop = stack->FileObject;
							stack = IoGetCurrentIrpStackLocation(Irp);
							stack->DeviceObject = pdx->DeviceObject;	// so IoCancelIrp can give us right ptr
							stack->FileObject = fop;	// for cleanup
				
							*pIrp = Irp;
							InsertTailList(&pdx->PendingIoctlList, &Irp->Tail.Overlay.ListEntry);
							}					// cache it
						}						// try to cache IRP
				
					KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
					return status;
					}							// CacheControlRequest
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma PAGEDCODE
				
				VOID CleanupControlRequests(PDEVICE_EXTENSION pdx, NTSTATUS status, PFILE_OBJECT fop)
					{							// CleanupControlRequests
					LIST_ENTRY cancellist;
					InitializeListHead(&cancellist);
				
					// Create a list of IRPs that belong to the same file object
				
					KIRQL oldirql;
					KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql);
				
					PLIST_ENTRY first = &pdx->PendingIoctlList;
					PLIST_ENTRY next;
				
					for (next = first->Flink; next != first; )
						{						// for each queued IRP
						PIRP Irp = CONTAINING_RECORD(next, IRP, Tail.Overlay.ListEntry);
						PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
				
						// Follow the chain to the next IRP now (so that the next iteration of
						// the loop is properly setup whether we dequeue this IRP or not)
				
						PLIST_ENTRY current = next;
						next = next->Flink;
				
						// Skip this IRP if it's not for the same file object as the
						// current IRP_MJ_CLEANUP.
				
						if (fop && stack->FileObject != fop)
							continue;			// not for same file object
				
						// Set the CancelRoutine pointer to NULL and remove the IRP from the
						// queue.
				
						if (!IoSetCancelRoutine(Irp, NULL))
							continue;			// being cancelled right this instant
						RemoveEntryList(current);
						InsertTailList(&cancellist, current);
						}						// for each queued IRP
				
					// Release the spin lock. We're about to undertake a potentially time-consuming
					// operation that might conceivably result in a deadlock if we keep the lock.
				
					KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
				
					// Complete the selected requests.
				
					while (!IsListEmpty(&cancellist))
						{						// cancel selected requests
						next = RemoveHeadList(&cancellist);
						PIRP Irp = CONTAINING_RECORD(next, IRP, Tail.Overlay.ListEntry);
						Irp->IoStatus.Status = STATUS_CANCELLED;
						IoCompleteRequest(Irp, IO_NO_INCREMENT);
						}						// cancel selected requests
					}							// CleanupControlRequests
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma LOCKEDCODE
				
				VOID OnCancelPendingIoctl(PDEVICE_OBJECT fdo, PIRP Irp)
					{							// OnCancelPendingIoctl
					KIRQL oldirql = Irp->CancelIrql;
					IoReleaseCancelSpinLock(DISPATCH_LEVEL);
					PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
				
					// Remove the IRP from whatever queue it's on
				
					KeAcquireSpinLockAtDpcLevel(&pdx->IoctlListLock);
					RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
					KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
				
					// Complete the IRP
				
					Irp->IoStatus.Status = STATUS_CANCELLED;
					IoCompleteRequest(Irp, IO_NO_INCREMENT);
					}							// OnCancelPendingIoctl
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma LOCKEDCODE
				
				NTSTATUS OnCompletePendingIoctl(PDEVICE_OBJECT junk, PIRP Irp, PDEVICE_EXTENSION pdx)
					{							// OnCompletePendingIoctl
					KIRQL oldirql;
					KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql);
					PIRP* pIrp = (PIRP*) IoGetCurrentIrpStackLocation(Irp)->Parameters.Others.Argument1;
					if (*pIrp == Irp)
						*pIrp = NULL;
					KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
					return STATUS_SUCCESS;
					}							// OnCompletePendingIoctl
				
				///////////////////////////////////////////////////////////////////////////////
				
				#pragma LOCKEDCODE
				
				PIRP UncacheControlRequest(PDEVICE_EXTENSION pdx, PIRP* pIrp)
					{							// UncacheControlRequest
					ASSERT(KeGetCurrentIrql() 					
					KIRQL oldirql;
					KeAcquireSpinLock(&pdx->IoctlListLock, &oldirql);
				
					PIRP Irp = (PIRP) InterlockedExchangePointer(pIrp, NULL);
				
					if (Irp)
						{						// an IRP was cached
				
						// Clear the cancel pointer for this IRP. Since both we and the
						// completion routine use a spin lock, it cannot happen that this
						// IRP pointer is suddenly invalid but the cache pointer cell
						// wasn't already NULL.
				
						if (IoSetCancelRoutine(Irp, NULL))
							{
							RemoveEntryList(&Irp->Tail.Overlay.ListEntry);	// N.B.: a macro!!
							}
						else
							Irp = NULL;			// currently being cancelled
						}						// an IRP was cached
				
					KeReleaseSpinLock(&pdx->IoctlListLock, oldirql);
				
					return Irp;
					}							// UncacheControlRequest
							

相关资源