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

📄 usb2com.read.cpp

📁 这是一个关于USB转接串口的驱动程序开发
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			// 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;
}

//
// update read buffer
//
BOOLEAN Usb2ComUpdateReadBuffer(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in PUCHAR Buffer,__in ULONG Length)
{
	//
	// buffer is full
	//
	if(DevExt->ReadBufferCharsCount >= 0x2000)
		return FALSE;

	BOOLEAN ReceivedEventChar							= FALSE;
	ULONG WritePos										= (DevExt->FirstReadCharSlot + DevExt->ReadBufferCharsCount) % 0x2000;

	for(ULONG i = 0; i < Length && DevExt->ReadBufferCharsCount <= 0x2000; i ++,WritePos = (WritePos + 1) % 0x2000,DevExt->ReadBufferCharsCount ++)
	{
		UCHAR Char										= Buffer[i];
		DevExt->ReadBuffer[WritePos]					= Char;

		if(Char == DevExt->SerialChars.EventChar && DevExt->SerialChars.EventChar)
			ReceivedEventChar							= TRUE;
	}

	return ReceivedEventChar;
}

//
// copy from read buffer
//
VOID Usb2ComCopyFromReadBuffer(__in PUSB2COM_DEVICE_EXTENSION DevExt,__in PUCHAR Buffer,__in ULONG Length)
{
	ULONG LengthFirstTry								= 0x2000 - DevExt->FirstReadCharSlot;
	
	if(LengthFirstTry > Length)
		LengthFirstTry									= Length;

	RtlCopyMemory(Buffer,DevExt->ReadBuffer + DevExt->FirstReadCharSlot,LengthFirstTry);

	DevExt->FirstReadCharSlot							= (DevExt->FirstReadCharSlot + LengthFirstTry) % 0x2000;

	if(LengthFirstTry < Length)
	{
		ASSERT(!DevExt->FirstReadCharSlot);
		RtlCopyMemory(Buffer + LengthFirstTry,DevExt->ReadBuffer,Length - LengthFirstTry);
		DevExt->FirstReadCharSlot						= Length - LengthFirstTry;
	}

	DevExt->ReadBufferCharsCount						-= Length;
}

//
// process pending read
//
NTSTATUS Usb2ComProcessPendingReadIrps(__in PUSB2COM_DEVICE_EXTENSION DevExt,__out PLIST_ENTRY CompleteIrpListHead,__in BOOLEAN SetCancelRoutine)
{
	NTSTATUS Status										= STATUS_PENDING;
	BOOLEAN FirstIrp									= TRUE;

	while(DevExt->CurrentReadIrp)
	{
		PIRP Irp										= DevExt->CurrentReadIrp;

		//
		// set current read cancel routine
		//
		PDRIVER_CANCEL OldCancel						= 0;

		if(SetCancelRoutine)
			OldCancel									= IoSetCancelRoutine(Irp,&Usb2ComCurrentReadIrpCancel);

		ASSERT(!OldCancel);

		//
		// IoCancelIrp called
		//
		if(Irp->Cancel)
		{
			OldCancel									= IoSetCancelRoutine(Irp,0);
			if(OldCancel)
			{
				Irp->IoStatus.Status					= STATUS_CANCELLED;
				InsertTailList(CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);

				if(FirstIrp)
				{
					FirstIrp							= FALSE;
					Status								= STATUS_CANCELLED;
				}
			}
			else
			{
				IoMarkIrpPending(Irp);
				FirstIrp								= FALSE;
			}
		}
		else
		{
			PIO_STACK_LOCATION IrpSp					= IoGetCurrentIrpStackLocation(Irp);
			ULONG LengthInIrp							= IrpSp->Parameters.Read.Length;
			ULONG AlreadyReadCount						= Irp->IoStatus.Information;
			ULONG LeftCount								= LengthInIrp - AlreadyReadCount;
			PUCHAR IrpBuffer							= static_cast<PUCHAR>(Irp->AssociatedIrp.SystemBuffer);
			ULONG CopyCount								= LeftCount > DevExt->ReadBufferCharsCount ? DevExt->ReadBufferCharsCount : LeftCount;

			if(CopyCount)
			{
				//
				// copy from read buffer to user irp buffer
				//
				Usb2ComCopyFromReadBuffer(DevExt,IrpBuffer + AlreadyReadCount,CopyCount);
				
				//
				// update irp's length
				//
				Irp->IoStatus.Information				+= CopyCount;
			}

			//
			// we can complete the current irp 
			//
			if(LeftCount == CopyCount)
			{
				OldCancel								= IoSetCancelRoutine(Irp,0);
				if(OldCancel)
				{
					ASSERT(OldCancel == &Usb2ComCurrentReadIrpCancel);
					InsertTailList(CompleteIrpListHead,&Irp->Tail.Overlay.ListEntry);
					Irp->IoStatus.Status				= STATUS_SUCCESS;
				}
				else
				{
					IoMarkIrpPending(Irp);
				}

				if(FirstIrp)
				{
					FirstIrp							= FALSE;
					Status								= OldCancel ? STATUS_SUCCESS : STATUS_PENDING;
				}
			}
			else
			{
				IoMarkIrpPending(Irp);
				break;
			}
		}

		DevExt->CurrentReadIrp							= Usb2ComGetNextReadIrp(DevExt);
		SetCancelRoutine								= TRUE;
	}

	return Status;
}

//
// bulk in urb complete routine
//
NTSTATUS Usb2ComBulkInUrbComplete(__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->BulkInUrb;
	ULONG EventFlags									= 0;
	
	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->ReadLock,&SavedIrql);

	//
	// current bulk in urb is finished
	//
	DevExt->BulkInUrbIsRunning							= FALSE;

	LIST_ENTRY CompleteIrpListHead;
	InitializeListHead(&CompleteIrpListHead);

	if(NT_SUCCESS(Status))
	{
		//
		// update read buffer
		//
		if(Usb2ComUpdateReadBuffer(DevExt,static_cast<PUCHAR>(Urb->UrbBulkOrInterruptTransfer.TransferBuffer),Urb->UrbBulkOrInterruptTransfer.TransferBufferLength))
			EventFlags									|= SERIAL_EV_RXFLAG;

		//
		// process pending read
		//
		Usb2ComProcessPendingReadIrps(DevExt,&CompleteIrpListHead,FALSE);

		if(DevExt->ReadBufferCharsCount)
			EventFlags									|= SERIAL_EV_RXCHAR;

		if(DevExt->ReadBufferCharsCount > 0x2000 * 80 / 100)
			EventFlags									|= SERIAL_EV_RX80FULL;
	}

	Usb2ComStartBulkInUrb(DevExt,TRUE,SavedIrql);

	if(EventFlags & SERIAL_EV_RXFLAG)
	{
		Usb2ComProcessEvent(DevExt,SERIAL_EV_RXFLAG);
		EventFlags									&= (~SERIAL_EV_RXFLAG);
	}

	if(EventFlags)
		Usb2ComProcessEvent(DevExt,EventFlags);

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

		IoCompleteRequest(Irp,IO_NO_INCREMENT);

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

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

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

		//
		// check read urb is running
		//
		if(!DevExt->BulkInUrbIsRunning)
		{
			//
			// check hold condition
			//
			if(DevExt->RxHoldReason)
				try_leave(NOTHING);

			//
			// reuse read irp
			//
			IoReuseIrp(DevExt->BulkInIrp,STATUS_SUCCESS);

			UsbBuildInterruptOrBulkTransferRequest(DevExt->BulkInUrb,sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),DevExt->UsbInterfaceInfo->Pipes[2].PipeHandle,
												   DevExt->BulkInBuffer,0,0x40,USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,0);

			PIO_STACK_LOCATION NextIrpSp				= IoGetNextIrpStackLocation(DevExt->BulkInIrp);
			NextIrpSp->MajorFunction					= IRP_MJ_INTERNAL_DEVICE_CONTROL;
			NextIrpSp->Parameters.Others.Argument1		= DevExt->BulkInUrb;
			NextIrpSp->Parameters.Others.Argument2		= 0;
			NextIrpSp->Parameters.Others.Argument3		= reinterpret_cast<PVOID>(IOCTL_INTERNAL_USB_SUBMIT_URB);
			NextIrpSp->Parameters.Others.Argument4		= 0;

			IoSetCompletionRoutine(DevExt->BulkInIrp,&Usb2ComBulkInUrbComplete,DevExt,TRUE,TRUE,TRUE);

			if(!DevExt->ForceBulkInUrbStop)
			{
				DevExt->BulkInUrbIsRunning				= TRUE;

				KeResetEvent(&DevExt->BulkInUrbStopEvent);

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

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

			KeReleaseSpinLock(&DevExt->ReadLock,SavedIrql);

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

//
// stop bulk in urb
//
VOID Usb2ComStopBulkInUrb(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
	KIRQL SavedIrql;
	KeAcquireSpinLock(&DevExt->ReadLock,&SavedIrql);

	DevExt->ForceBulkInUrbStop						= TRUE;

	KeReleaseSpinLock(&DevExt->ReadLock,SavedIrql);

	IoCancelIrp(DevExt->BulkInIrp);
}

//
// wait bulk in urb stop
//
VOID Usb2ComWaitBulkInUrbStopped(__in PUSB2COM_DEVICE_EXTENSION DevExt)
{
	KeWaitForSingleObject(&DevExt->BulkInUrbStopEvent,Executive,KernelMode,FALSE,0);
}

⌨️ 快捷键说明

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