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

📄 usb2com.write.cpp

📁 这是一个关于USB转接串口的驱动程序开发
💻 CPP
📖 第 1 页 / 共 2 页
字号:

		//
		// complete it directly,this is only happened if IoCancelIrp get called when we are in StartCurrentWriteIrp routine
		//
		KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

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

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

//
// queued write irp cancel routine
//
VOID Usb2ComQueuedWriteIrpCancel(__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);

	//
	// remove the irp from write queue
	//
	RemoveEntryList(&Irp->Tail.Overlay.ListEntry);

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

	KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

	//
	// complete this irp with canceled
	//
	Irp->IoStatus.Status								= STATUS_CANCELLED;
	IoCompleteRequest(Irp,IO_NO_INCREMENT);

	//
	// release remove lock on this irp
	//
	IoReleaseRemoveLock(&DevExt->RemoveLock,Irp);
}

//
// get next write irp
//
PIRP Usb2ComGetNextWriteIrp(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
	PIRP Irp											= 0;

	while(!Irp && !IsListEmpty(&DevExt->WriteQueueListHead))
	{
		PLIST_ENTRY ListEntry							= RemoveHeadList(&DevExt->WriteQueueListHead);
		Irp												= CONTAINING_RECORD(ListEntry,IRP,Tail.Overlay.ListEntry);

		//
		// handle irp cancel
		//
		PDRIVER_CANCEL OldCancelRoutine					= IoSetCancelRoutine(Irp,0);

		//
		// IoCancelIrp could just been called on this irp,
		//
		if(OldCancelRoutine)
		{
			//
			// our cancel routine has not been called,return it
			//
			ASSERT(OldCancelRoutine == &Usb2ComQueuedWriteIrpCancel);
		}
		else
		{
			//
			// our cancel routine will be called on this irp,reinitialize list entry to make cancel routine happy
			// this irp will be completed as soon as we release the write queue spin lock
			//
			ASSERT(Irp->Cancel);
			InitializeListHead(&Irp->Tail.Overlay.ListEntry);
			Irp											= 0;
		}
	}

	return Irp;
}

//
// complete current write irp
//
NTSTATUS Usb2ComCompleteCurrentWriteIrp(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in NTSTATUS Status,__in KIRQL SavedIrql)
{
	PIRP Irp											= DevExt->CurrentWriteIrp;
	ASSERT(Irp);
	
	PDRIVER_CANCEL OldCancel							= IoSetCancelRoutine(Irp,0);
	BOOLEAN CompleteCurrentIrpHere						= TRUE;

	if(OldCancel)
	{
		//
		// our cancel routine has not been call
		//
		ASSERT(OldCancel == &Usb2ComCurrentWriteIrpCancel);
		Irp->IoStatus.Status							= Status;
		
		DevExt->PendingWriteCharsCount					-= (IoGetCurrentIrpStackLocation(Irp)->Parameters.Write.Length - Irp->IoStatus.Information);
	}
	else
	{
		//
		// our cancel routine will be called as soon as we release the write lock
		//
		CompleteCurrentIrpHere							= FALSE;
	}
	

	DevExt->WriteBufferLength							= 0;
	DevExt->WriteBufferOffset							= 0;
	DevExt->WriteBuffer									= 0;
	InterlockedIncrement(&DevExt->CurrentWriteIrpSignature);
	DevExt->CurrentWriteIrp								= Usb2ComGetNextWriteIrp(DevExt);
	ULONG EventFlags									= 0;

	if(DevExt->CurrentWriteIrp)
	{
		Usb2ComStartCurrentWriteIrp(DevExt,SavedIrql);
	}
	else
	{
		EventFlags										= SERIAL_EV_TXEMPTY;
		KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
	}

	if(CompleteCurrentIrpHere)
	{
		IoCompleteRequest(Irp,IO_NO_INCREMENT);

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

	if(EventFlags)
		Usb2ComProcessEvent(DevExt,EventFlags);

	return Status;
}

//
// bulk out urb complete routine
//
NTSTATUS Usb2ComBulkOutUrbComplete(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp,__in PVOID Context)
{
	PUSB2COM_DEVICE_EXTENSION DevExt					= static_cast<PUSB2COM_DEVICE_EXTENSION>(Context);
	NTSTATUS Status										= Irp->IoStatus.Status;
	PURB Urb											= DevExt->BulkOutUrb;
	ULONG TransferLength								= Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;

	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);

	//
	// current bulk out urb is finished
	//
	DevExt->BulkOutUrbIsRunning							= FALSE;

	//
	// check the signature
	// if the signature is not the same,it means that we have already complete the current write irp
	// then we should not touch those WriteBuffer* fields
	//
	if(DevExt->CurrentBulkOutUrbSignature == DevExt->CurrentWriteIrpSignature && DevExt->CurrentWriteIrp)
	{
		if(NT_SUCCESS(Status))
		{
			//
			// update write buffer info
			//
			DevExt->WriteBufferLength					-= TransferLength;
			DevExt->WriteBufferOffset					+= TransferLength;
			Irp											= DevExt->CurrentWriteIrp;
			Irp->IoStatus.Information					+= TransferLength;
			DevExt->PendingWriteCharsCount				-= TransferLength;

			//
			// complete current write irp
			//
			if(!DevExt->WriteBufferLength)
				Usb2ComCompleteCurrentWriteIrp(DevExt,STATUS_SUCCESS,SavedIrql);
			else
				Usb2ComStartBulkOutUrb(DevExt,TRUE,SavedIrql);
		}
		else
		{
			Usb2ComCompleteCurrentWriteIrp(DevExt,Status,SavedIrql);
		}
	}
	else
	{
		if(DevExt->CurrentWriteIrp)
			Usb2ComStartCurrentWriteIrp(DevExt,SavedIrql);
		else
			KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
	}

	return STATUS_MORE_PROCESSING_REQUIRED;
}

//
// start bulk out urb
//
VOID Usb2ComStartBulkOutUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in BOOLEAN AlreadyLocked,__in KIRQL SavedIrql)
{
	BOOLEAN ReleaseLock									= TRUE;

	__try
	{
		//
		// acquire write lock
		//
		if(!AlreadyLocked)
			KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);

		//
		// check write urb is running
		//
		if(!DevExt->BulkOutUrbIsRunning)
		{
			//
			// check hold condition
			//
			if(DevExt->TxHoldReason)
				try_leave(NOTHING);

			//
			// check buffer length
			//
			if(!DevExt->WriteBufferLength)
				try_leave(NOTHING);

			//
			// copy write buffer to urb buffer and set its length
			//
			ULONG Length								= DevExt->WriteBufferLength > 0x40 ? 0x40 : DevExt->WriteBufferLength;
			RtlCopyMemory(DevExt->BulkOutBuffer,DevExt->WriteBuffer + DevExt->WriteBufferOffset,Length);

			//
			// set urb signature with irp signature
			//
			DevExt->CurrentBulkOutUrbSignature			= DevExt->CurrentWriteIrpSignature;
			
			//
			// reuse write irp
			//
			IoReuseIrp(DevExt->BulkOutIrp,STATUS_SUCCESS);

			UsbBuildInterruptOrBulkTransferRequest(DevExt->BulkOutUrb,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),DevExt->UsbInterfaceInfo->Pipes[1].PipeHandle,
												   DevExt->BulkOutBuffer,0,Length,USBD_TRANSFER_DIRECTION_OUT,0);

			PIO_STACK_LOCATION NextIrpSp				= IoGetNextIrpStackLocation(DevExt->BulkOutIrp);
			NextIrpSp->MajorFunction					= IRP_MJ_INTERNAL_DEVICE_CONTROL;
			NextIrpSp->Parameters.Others.Argument1		= DevExt->BulkOutUrb;
			NextIrpSp->Parameters.Others.Argument2		= 0;
			NextIrpSp->Parameters.Others.Argument3		= reinterpret_cast<PVOID>(IOCTL_INTERNAL_USB_SUBMIT_URB);
			NextIrpSp->Parameters.Others.Argument4		= 0;
			
			IoSetCompletionRoutine(DevExt->BulkOutIrp,&Usb2ComBulkOutUrbComplete,DevExt,TRUE,TRUE,TRUE);

			if(!DevExt->ForceBulkOutUrbStop)
			{
				DevExt->BulkOutUrbIsRunning				= TRUE;

				KeResetEvent(&DevExt->BulkOutUrbStopEvent);

				KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);
				ReleaseLock								= FALSE;

				IoCallDriver(DevExt->LowerDeviceObject,DevExt->BulkOutIrp);
			}
		}
	}
	__finally
	{
		if(ReleaseLock)
		{
			BOOLEAN SetEvent							= !DevExt->BulkOutUrbIsRunning;

			KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

			if(SetEvent)
				KeSetEvent(&DevExt->BulkOutUrbStopEvent,IO_NO_INCREMENT,FALSE);
		}
	}
}

//
// stop bulk out urb
//
VOID Usb2ComStopBulkOutUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->WriteLock,&SavedIrql);

	DevExt->ForceBulkOutUrbStop						= TRUE;

	KeReleaseSpinLock(&DevExt->WriteLock,SavedIrql);

	IoCancelIrp(DevExt->BulkOutIrp);
}

//
// wait bulk out urb stop
//
VOID Usb2ComWaitBulkOutUrbStopped(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
	KeWaitForSingleObject(&DevExt->BulkOutUrbStopEvent,Executive,KernelMode,FALSE,0);
}

⌨️ 快捷键说明

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