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

📄 usb2com.write.cpp

📁 这是一个关于USB转接串口的驱动程序开发
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//********************************************************************
//	created:	11:7:2008   21:30
//	file:		usb2com.write.cpp
//	author:		tiamo
//	purpose:	write
//********************************************************************

#include "stdafx.h"

//
// write dispatch routine
//
NTSTATUS Usb2ComWrite(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp)
{
	PUSB2COM_DEVICE_EXTENSION DevExt					= static_cast<PUSB2COM_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);
	PIO_STACK_LOCATION IrpSp							= IoGetCurrentIrpStackLocation(Irp);
	NTSTATUS Status										= STATUS_SUCCESS;

	//
	// check zero-length write
	//
	if(!IrpSp->Parameters.Write.Length)
	{
		Irp->IoStatus.Status							= Status = STATUS_SUCCESS;
		Irp->IoStatus.Information						= 0;
		IoCompleteRequest(Irp,IO_NO_INCREMENT);

		return Status;
	}
	
	//
	// acquire remove lock
	//
	Status												= IoAcquireRemoveLock(&DevExt->RemoveLock,Irp);
	if(!NT_SUCCESS(Status))
	{
		//
		// we are removing
		//
		Irp->IoStatus.Status							= Status;
		Irp->IoStatus.Information						= 0;
		IoCompleteRequest(Irp,IO_NO_INCREMENT);

		return Status;
	}

	//
	// set information with zero
	//
	Irp->IoStatus.Information							= 0;

	//
	// protected by write lock
	//
	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);

	//
	// if there is a pending write irp,just queue this irp
	//
	if(DevExt->CurrentWriteIrp)
	{
		PDRIVER_CANCEL OldCancel						= IoSetCancelRoutine(Irp,&Usb2ComQueuedWriteIrpCancel);
		ASSERT(!OldCancel);

		//
		// IoCancelIrp called
		//
		if(Irp->Cancel)
		{
			OldCancel									= IoSetCancelRoutine(Irp,0);

			if(OldCancel)
			{
				//
				// our cancel routine has not been called,complete it here
				//
				ASSERT(OldCancel == &Usb2ComQueuedWriteIrpCancel);

				KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

				Irp->IoStatus.Status					= STATUS_CANCELLED;
				
				IoCompleteRequest(Irp,IO_NO_INCREMENT);

				IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);

				Status									= STATUS_CANCELLED;
			}
			else
			{
				//
				// our cancel routine will be called as soon as we release the write lock
				//
				IoMarkIrpPending(Irp);

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

				DevExt->PendingWriteCharsCount			+= IrpSp->Parameters.Write.Length;

				KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

				Status									= STATUS_PENDING;
			}
		}
		else
		{
			//
			// mark it pending and queue it
			//
			IoMarkIrpPending(Irp);

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

			DevExt->PendingWriteCharsCount				+= IrpSp->Parameters.Write.Length;

			KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

			Status										= STATUS_PENDING;
		}
	}
	else
	{
		//
		// set as the current write irp,and start it
		//
		DevExt->CurrentWriteIrp							= Irp;

		DevExt->PendingWriteCharsCount					+= IrpSp->Parameters.Write.Length;

		Status											= Usb2ComStartCurrentWriteIrp(DevExt,SavedIrql);
	}

	return Status;
}

//
// cancel all write irps
//
VOID Usb2ComCancelAllWriteIrps(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);

	LIST_ENTRY CompleteIrpListHead;
	InitializeListHead(&CompleteIrpListHead);

	PIRP Irp											= Usb2ComGetNextWriteIrp(DevExt);
	while(Irp)
	{
		InsertTailList(&CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);

		Irp												= Usb2ComGetNextWriteIrp(DevExt);
	}

	Irp													= DevExt->CurrentWriteIrp;
	if(Irp)
	{
		PDRIVER_CANCEL OldCancel						= IoSetCancelRoutine(Irp,0);
		if(OldCancel)
			InsertTailList(&CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);

		DevExt->CurrentWriteIrp							= 0;
	}

	DevExt->PendingWriteCharsCount						= 0;
	DevExt->WriteBuffer									= 0;
	DevExt->WriteBufferLength							= 0;
	DevExt->WriteBufferOffset							= 0;
	InterlockedIncrement(&DevExt->CurrentWriteIrpSignature);

	KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

	while(!IsListEmpty(&CompleteIrpListHead))
	{
		PLIST_ENTRY ListEntry							= RemoveHeadList(&CompleteIrpListHead);
		PIRP Irp										= CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);
		Irp->IoStatus.Status							= STATUS_CANCELLED;

		IoCompleteRequest(Irp,IO_NO_INCREMENT);

		IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
	}
}

//
// start current write irp
//
NTSTATUS Usb2ComStartCurrentWriteIrp(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in KIRQL SavedIrql)
{
	PIRP Irp											= DevExt->CurrentWriteIrp;
	NTSTATUS Status										= STATUS_PENDING;
	BOOLEAN TheFirstIrp									= TRUE;

	LIST_ENTRY CancelIrpListHead;

	//
	// we put canceled irps into this list
	//
	InitializeListHead(&CancelIrpListHead);

	do
	{
		//
		// setup a cancel routine
		//
		PDRIVER_CANCEL OldCancelRoutine					= IoSetCancelRoutine(Irp,&Usb2ComCurrentWriteIrpCancel);
		ASSERT(!OldCancelRoutine);

		//
		// IoCancelIrp is called on this irp
		//
		if(Irp->Cancel)
		{
			OldCancelRoutine							= IoSetCancelRoutine(Irp,0);

			if(OldCancelRoutine)
			{
				//
				// our cancel routine has not been called
				//
				Irp->IoStatus.Status					= STATUS_CANCELLED;

				//
				// put it into canceled irp list
				//
				InsertHeadList(&CancelIrpListHead,&Irp->Tail.Overlay.ListEntry);

				DevExt->PendingWriteCharsCount			-= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);

				if(TheFirstIrp)
				{
					Status								= STATUS_CANCELLED;
					TheFirstIrp							= FALSE;
				}
			}
			else
			{
				//
				// our cancel routine will be called as soon as we release the write lock
				//
				TheFirstIrp								= FALSE;
				IoMarkIrpPending(Irp);
			}
		}
		else
		{
			//
			// mark this irp pending
			//
			IoMarkIrpPending(Irp);

			//
			// setup buffer info
			//
			PIO_STACK_LOCATION IrpSp					= IoGetCurrentIrpStackLocation(Irp);
			DevExt->WriteBufferLength					= IrpSp->Parameters.Write.Length;
			DevExt->WriteBufferOffset					= 0;
			DevExt->WriteBuffer							= static_cast<PUCHAR>(Irp->AssociatedIrp.SystemBuffer);
			InterlockedIncrement(&DevExt->CurrentWriteIrpSignature);

			//
			// start bulk out urb
			//
			Usb2ComStartBulkOutUrb(DevExt,TRUE,SavedIrql);

			break;
		}

		DevExt->CurrentWriteIrp							= Usb2ComGetNextWriteIrp(DevExt);
		Irp												= DevExt->CurrentWriteIrp;
	}while(Irp);

	//
	// if irp is NULL,it means that we did not start any bulk urb,so we need release write lock first
	//
	if(!Irp)
		KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

	//
	// complete canceled irps
	//
	while(!IsListEmpty(&CancelIrpListHead))
	{
		PLIST_ENTRY ListEntry							= RemoveHeadList(&CancelIrpListHead);
		Irp												= CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);

		IoCompleteRequest(Irp,IO_NO_INCREMENT);

		IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
	}

	return Status;
}

//
// current write irp cancel routine
//
VOID Usb2ComCurrentWriteIrpCancel(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp)
{
	PUSB2COM_DEVICE_EXTENSION DevExt					= static_cast<PUSB2COM_DEVICE_EXTENSION>(DeviceObject->DeviceExtension);

	//
	// release global spin lock
	//
	IoReleaseCancelSpinLock(Irp->CancelIrql);

	//
	// acquire our write queue lock
	//
	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);

	//
	// if it is the current write irp,complete it and start the next one
	//
	if(Irp == DevExt->CurrentWriteIrp)
	{
		Usb2ComCompleteCurrentWriteIrp(DevExt,STATUS_CANCELLED,SavedIrql);
	}
	else
	{
		DevExt->PendingWriteCharsCount			-= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);

⌨️ 快捷键说明

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