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

📄 rw.c

📁 usb to rs232 虚拟RS232串口驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	NTSTATUS		ntStatus = STATUS_SUCCESS;
	PDEVICE_EXTENSION 	deviceExtension;
	PIO_STACK_LOCATION      nextStack;
    	UCHAR			length;
	KIRQL  			oldIrql;
	PIRP 			CurrentOpIrp;

    	
    	DbgPrint("StartWriteIntUrb Enter.\n");
	deviceExtension = DeviceObject->DeviceExtension;
    	
    	//deviceExtension->CurrentWriteIrpDataPtr = (UCHAR *)MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority );
	//deviceExtension->CurrentWriteIrpDataLen = MmGetMdlByteCount(Irp->MdlAddress);
    	
	deviceExtension->WriteIntUrb.Idle = FALSE;
	if(deviceExtension->CurrentWriteIrpDataLen > 7)
	{
		//deviceExtension->CurrentWriteIrpDataLen -= 7;
		length = 7;
	}else{
		length = (UCHAR)deviceExtension->CurrentWriteIrpDataLen;
		//deviceExtension->CurrentWriteIrpDataLen = 0;
	}
	deviceExtension->WriteIntUrb.TransferBuffer[0] = length;
	RtlCopyMemory(	
			&deviceExtension->WriteIntUrb.TransferBuffer[1],
			deviceExtension->CurrentWriteIrpDataPtr,
			length
			);
	//deviceExtension->CurrentWriteIrpDataPtr += length;	
	InitIntUrb(
		deviceExtension->WriteIntUrb.Urb,
	    	deviceExtension->WriteIntUrb.PipeInfo->PipeHandle,
	    	deviceExtension->WriteIntUrb.TransferBuffer,
	    	length+1,
	    	TRUE);
//	IoReuseIrp(deviceExtension->WriteIntUrb.Irp,STATUS_SUCCESS);
	nextStack = IoGetNextIrpStackLocation(deviceExtension->WriteIntUrb.Irp);
	USB2COM_ASSERT(nextStack != NULL);
	USB2COM_ASSERT(DeviceObject->StackSize>1);
			
	nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
	nextStack->Parameters.Others.Argument1 = deviceExtension->WriteIntUrb.Urb;
	nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
	IoSetCompletionRoutine(deviceExtension->WriteIntUrb.Irp,
	                    WriteIntUrbComplete,
	                    &deviceExtension->WriteIntUrb, 	// pass the context array element to completion routine
	                    TRUE,    // invoke on success
	                    TRUE,    // invoke on error
	                    TRUE);   // invoke on cancellation of the Irp
	USB2COM_IncrementIoCount(DeviceObject);
	ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, deviceExtension->WriteIntUrb.Irp );
	//ASSERT( ntStatus == STATUS_PENDING);

	DbgPrint("StartWriteIntUrb Exit\n");
	return ntStatus;
}


NTSTATUS
StopWriteIntUrb(
	IN PDEVICE_EXTENSION deviceExtension
	)
{
	KIRQL  			oldIrql;

	DbgPrint("StopWriteIntUrb Enter\n");
	//KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
	if(deviceExtension->WriteIntUrb.Irp
	   && !deviceExtension->WriteIntUrb.Idle)
	{
		//KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
		DbgPrint("Cancel WriteIntUrb.Irp\n");
		IoCancelIrp(deviceExtension->WriteIntUrb.Irp);
	}else{
	//	KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
	}
	DbgPrint("StopWriteIntUrb Exit\n");
	return STATUS_SUCCESS;
}

void
FreeWriteIntUrb(
	IN PDEVICE_EXTENSION deviceExtension
	)
{
	KIRQL	oldIrql;
	DbgPrint("FreeWriteIntUrb enter\n");
	KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
	if(deviceExtension->WriteIntUrb.Irp)
	{
		IoFreeIrp(deviceExtension->WriteIntUrb.Irp);
		deviceExtension->WriteIntUrb.Irp = NULL;
	}
	if(deviceExtension->WriteIntUrb.Urb)
	{
		USB2COM_ExFreePool(deviceExtension->WriteIntUrb.Urb);
		deviceExtension->WriteIntUrb.Urb = NULL;
	}
	DbgPrint("FreeWriteIntUrb exit\n");
	KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
}
	
NTSTATUS
WriteIntUrbComplete(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN PVOID Context
    )
{
	PDEVICE_OBJECT 		deviceObject;
	NTSTATUS                ntStatus;
	USBD_STATUS 		usbdStatus;
	PDEVICE_EXTENSION       deviceExtension;
	PIO_STACK_LOCATION      nextStack;
	PINT_URBS		pIntUrbs;
	PIRP        		irp;
	PURB        		urb;
	KIRQL  			oldIrql;
	
	DbgPrint("WriteIntUrbComplete Enter: DeviceObject=%p, Irp=%p, Context=%p\n",
			DeviceObject,
			Irp,
			Context);
	pIntUrbs = (PINT_URBS)Context;
    	irp = pIntUrbs->Irp;
    	urb = pIntUrbs->Urb;
    	deviceObject = pIntUrbs->deviceObject;
	deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
    	DbgPrint("irp = %p, urb = %p, deviceObject = %p\n",irp,urb,deviceObject);
    	ASSERT(irp == Irp);
    	ASSERT(pIntUrbs->TransferBuffer == urb->UrbBulkOrInterruptTransfer.TransferBuffer);
    	ntStatus = irp->IoStatus.Status;
	usbdStatus = urb->UrbHeader.Status;
	DbgPrint("ntStatus=%x,usbdStatus=%x\n",ntStatus,usbdStatus);
	if((ntStatus == STATUS_CANCELLED)
	   || (ntStatus == STATUS_DEVICE_NOT_CONNECTED)
       	   || (usbdStatus == STATUS_DEVICE_NOT_CONNECTED))
       	{
       		PIRP CurrentOpIrp;
		pIntUrbs->Idle = TRUE;
       		KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
       	        //IoFreeIrp(Irp);
	        //pIntUrbs->Irp = NULL;
	        //USB2COM_ExFreePool(pIntUrbs->Urb);
	        //pIntUrbs->Urb = NULL;
	        //DbgBreakPoint();
	        CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentWriteIrp, NULL);
    		if(CurrentOpIrp) {
	        	CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
	        	CurrentOpIrp->IoStatus.Information = 0;
	        	IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
    		}
		KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
    		//DbgBreakPoint();
	        USB2COM_DecrementIoCount(deviceObject);
	        return STATUS_MORE_PROCESSING_REQUIRED;
    	}
    	if(USBD_SUCCESS(usbdStatus))
    	{
    		ULONG length = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    		DbgPrint("WriteIntUrbComplete: length = %d\n",length);
    		length -= 1;
		KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
		deviceExtension->CurrentWriteIrpDataLen -= length;
		deviceExtension->CurrentWriteIrpDataPtr += length;
		deviceExtension->TotalCharsQueued -= length;
		//check whether we can complete the current Write Irp;
		if(deviceExtension->CurrentWriteIrpDataLen <= 0)
		{
			DbgPrint("Complete CurrentWriteIrp %d\n",
					deviceExtension->CurrentWriteIrpRequestLen);
			if(deviceExtension->CurrentWriteIrp)
			{
				deviceExtension->CurrentWriteIrp->IoStatus.Information = 
					deviceExtension->CurrentWriteIrpRequestLen;
				deviceExtension->CurrentWriteIrp->IoStatus.Status = ntStatus; 
				IoCompleteRequest(deviceExtension->CurrentWriteIrp,IO_NO_INCREMENT);
			}
			KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
			deviceExtension->CurrentWriteIrp = DequeueWriteIrp(deviceExtension);
			KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
			if(deviceExtension->CurrentWriteIrp)
			{	
				deviceExtension->CurrentWriteIrpDataPtr = 
					(UCHAR *)MmGetSystemAddressForMdlSafe(
						deviceExtension->CurrentWriteIrp->MdlAddress,
						NormalPagePriority );
				deviceExtension->CurrentWriteIrpRequestLen =
				deviceExtension->CurrentWriteIrpDataLen = 
						MmGetMdlByteCount(
							deviceExtension->CurrentWriteIrp->MdlAddress
							);
			}
			KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
		}else
			KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
    	}
	USB2COM_DecrementIoCount(deviceObject);
	KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
	pIntUrbs->Idle = TRUE;
    	if(deviceExtension->CurrentWriteIrp)
    	{
		//
		//circulate the irps.
		//
		DbgPrint("Circulate the irp\n");
		StartWriteIntUrb(deviceObject);
		KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
	}else{
		ASSERT(deviceExtension->TotalCharsQueued == 0);
		deviceExtension->HistoryMask |= SERIAL_EV_TXEMPTY;
		if(deviceExtension->CurrentWaitIrp && 
			(deviceExtension->HistoryMask & deviceExtension->WaitMask))
		{
			KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
			SerialCompleteCurrentWait(
				deviceExtension->CurrentWaitIrp,
				deviceExtension->HistoryMask & deviceExtension->WaitMask);
		}else
			KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
	}
    	return STATUS_MORE_PROCESSING_REQUIRED;		
}

VOID WriteIrpCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	PDEVICE_EXTENSION 	deviceExtension = DeviceObject->DeviceExtension;
	KIRQL 			oldIrql;
	
	DbgPrint("WriteIrpCancelRoutine Enter\n");
	//  Release the global cancel spin lock.  
	//  Do this while not holding any other spin locks so that we exit at the right IRQL.
	IoReleaseCancelSpinLock(Irp->CancelIrql);
	
	//
	//  Dequeue and complete the IRP.  
	//  The enqueue and dequeue functions synchronize properly so that if this cancel routine is called, 
	//  the dequeue is safe and only the cancel routine will complete the IRP. Hold the spin lock for the IRP
	//  queue while we do this.
	//
	
	KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
	RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
	
	KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
	
	//  Complete the IRP.  This is a call outside the driver, so all spin locks must be released by this point.
	Irp->IoStatus.Status = STATUS_CANCELLED;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	DbgPrint("WriteIrpCancelRoutine Exit\n");

	return;
}

NTSTATUS QueueOrStartWriteIrp(PDEVICE_EXTENSION deviceExtension, PIRP Irp)
{
	PDRIVER_CANCEL  oldCancelRoutine;
	KIRQL  		oldIrql;
	NTSTATUS 	status = STATUS_PENDING;
	PIRP		CurrentOpIrp;
	PUCHAR		ioBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority );
	ULONG 		ioLength = MmGetMdlByteCount(Irp->MdlAddress);
	
	DbgPrint("QueueOrStartWriteIrp Enter\n");
	if((ioLength <= 0) || (ioBuffer == NULL))
	{
		DbgPrint("CurrentWriteIrpDataLen %d\n",
		deviceExtension->CurrentWriteIrpDataLen);
		//DbgBreakPoint();
		Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
		Irp->IoStatus.Information = 0;
		IoCompleteRequest( Irp, IO_NO_INCREMENT );
		//DbgBreakPoint();
		return STATUS_INVALID_PARAMETER;
	}
    	
	if ( !USB2COM_CanAcceptIoRequests( deviceExtension->DeviceObject )
		|| (deviceExtension->WriteIntUrb.Irp == NULL)
	 	|| (deviceExtension->WriteIntUrb.Urb == NULL)  )
	{
		// got sudden remove! ( i.e. plug was yanked )
		//DbgBreakPoint();
	       	Irp->IoStatus.Status = STATUS_DELETE_PENDING;
		Irp->IoStatus.Information = 0;
		IoCompleteRequest( Irp, IO_NO_INCREMENT );
	    	//DbgBreakPoint();
		return STATUS_DELETE_PENDING;
	} 
	KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
	deviceExtension->TotalCharsQueued += ioLength;
	if(IsListEmpty(&deviceExtension ->WriteQueue) && !deviceExtension->CurrentWriteIrp)
	{
		DbgPrint("WriteQueue is Empty, StartWriteIrp immediately\n");
		deviceExtension->CurrentWriteIrp = Irp;
		deviceExtension->CurrentWriteIrpDataPtr = ioBuffer;
		deviceExtension->CurrentWriteIrpRequestLen = 
		deviceExtension->CurrentWriteIrpDataLen = ioLength;
		IoMarkIrpPending(Irp);
		status = StartWriteIntUrb(deviceExtension->DeviceObject);
	}else{
		
		//  Queue the IRP and call IoMarkIrpPending
		//  to indicate that the IRP may complete on a different thread.
		//  N.B. It's okay to call these inside the spin lock because they're macros, not functions.
		IoMarkIrpPending(Irp);
		InsertTailList(&deviceExtension->WriteQueue, &Irp->Tail.Overlay.ListEntry);
		
		//  Must set a Cancel routine before checking the Cancel flag.
		oldCancelRoutine = IoSetCancelRoutine(Irp, WriteIrpCancelRoutine);
		ASSERT(!oldCancelRoutine);
		
		if (Irp->Cancel){
		    //  The IRP was canceled.  Check whether our cancel routine was called.
		    oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
		    if (oldCancelRoutine){
		        //  The cancel routine was NOT called.  
		        //  So dequeue the IRP now and complete it after releasing the spin lock.
		        RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
		        status = Irp->IoStatus.Status = STATUS_CANCELLED; 
		    } //endif
		    else {
		        //  The cancel routine WAS called.  
		        //  As soon as we drop our spin lock it will dequeue and complete the IRP.
		        //  So leave the IRP in the queue and otherwise don't touch it.
		        //  Return pending since we're not completing the IRP here.
		    }  //end else
		} // endif
	}
	KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
	
	// Normally you shouldn't call IoMarkIrpPending 
	// and return a status other than STATUS_PENDING.
	// But you can break this rule if you complete the IRP.
	if (status == STATUS_CANCELLED){
	    IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}
	DbgPrint("QueueOrStartWriteIrp Exit\n");

	return status;
}

PIRP DequeueWriteIrp(PDEVICE_EXTENSION deviceExtension)
{
	KIRQL oldIrql;
	PIRP nextIrp = NULL;
	
	DbgPrint("DequeueWriteIrp Enter\n");
	KeAcquireSpinLock(&deviceExtension->WriteQueueSpinLock, &oldIrql);
	
	while (!nextIrp && !IsListEmpty(&deviceExtension ->WriteQueue)){
	    PDRIVER_CANCEL oldCancelRoutine;
	    PLIST_ENTRY listEntry = RemoveHeadList(&deviceExtension ->ReadQueue);
	
	    // Get the next IRP off the queue.
	    nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
	
	    //  Clear the IRP's cancel routine
	    oldCancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
	    //  IoCancelIrp() could have just been called on this IRP.
	    //  What we're interested in is not whether IoCancelIrp() was called (nextIrp->Cancel flag set),
	    //  but whether IoCancelIrp() called (or is about to call) our cancel routine.
	    //  To check that, check the result of the test-and-set macro IoSetCancelRoutine.
	    if (oldCancelRoutine){
	        //  Cancel routine not called for this IRP.  Return this IRP.
	        ASSERT(oldCancelRoutine == IrpCancelRoutine);
	    }
	    else {
	        //  This IRP was just canceled and the cancel routine was (or will be) called.
	        //  The cancel routine will complete this IRP as soon as we drop the spin lock,
	        //  so don't do anything with the IRP.
	        //  Also, the cancel routine will try to dequeue the IRP, 
	        //  so make the IRP's listEntry point to itself.
	        ASSERT(nextIrp->Cancel);
	        InitializeListHead(&nextIrp->Tail.Overlay.ListEntry);
	        nextIrp = NULL;
	    }
	}
	
	KeReleaseSpinLock(&deviceExtension->WriteQueueSpinLock, oldIrql);
	DbgPrint("DequeueWriteIrp Exit\n");
	return nextIrp;
}

⌨️ 快捷键说明

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