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

📄 rw.c

📁 usb to rs232 虚拟RS232串口驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	    }
	    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->ReadQueueSpinLock, oldIrql);
	DbgPrint("DequeueReadIrp Exit\n");
	return nextIrp;
}


VOID IrpCancelRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
	PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
	KIRQL oldIrql;
	
	DbgPrint("IrpCancelRoutine 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->ReadQueueSpinLock, &oldIrql);
	
	RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
	
	KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, 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("IrpCancelRoutine Exit\n");

	return;
}

VOID
InitIntUrb(
    IN PURB urb,
    IN USBD_PIPE_HANDLE  PipeHandle,
    IN PUCHAR TransferBuffer,
    IN ULONG length,
    IN BOOLEAN Read
    )
{
    USHORT siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
    if (urb) {
        RtlZeroMemory(urb, siz);

        urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
        urb->UrbBulkOrInterruptTransfer.Hdr.Function =
                    URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
        urb->UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
        urb->UrbBulkOrInterruptTransfer.TransferFlags =
            Read ? USBD_TRANSFER_DIRECTION_IN : 0;
        // short packet is not treated as an error.
        urb->UrbBulkOrInterruptTransfer.TransferFlags |= 
            USBD_SHORT_TRANSFER_OK;            
                
        //
        // not using linked urb's
        //
        urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
        urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
        urb->UrbBulkOrInterruptTransfer.TransferBuffer = TransferBuffer;
        urb->UrbBulkOrInterruptTransfer.TransferBufferLength = length;
    }
}

NTSTATUS
StartReadIntUrb(
	IN PDEVICE_OBJECT DeviceObject,
	IN PUSBD_PIPE_INFORMATION PipeInfo
	)
{
	NTSTATUS		ntStatus = STATUS_SUCCESS;
	PDEVICE_EXTENSION 	deviceExtension = DeviceObject->DeviceExtension;
	PIO_STACK_LOCATION      nextStack;
	PURB 			urb;
    	PIRP 			irp;
    	CHAR 			stackSize;
    	int 			i;
    	KIRQL			oldIrql;
    	
    	DbgPrint("StartReadIntUrb Enter.\n");
    	for(i=0; i<MAX_READ_INT_URBS; i++)
	{   
		if ( !USB2COM_CanAcceptIoRequests( DeviceObject ) ) {
			// got sudden remove! ( i.e. plug was yanked )
			PIRP CurrentOpIrp;
			KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
			CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentReadIrp, NULL);
    			if(CurrentOpIrp) {
	        		CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
	        		CurrentOpIrp->IoStatus.Information = 0;
	        		IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
    			}
			KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
			return STATUS_DELETE_PENDING;
		}
	 	
		stackSize = (CCHAR) (deviceExtension->TopOfStackDeviceObject->StackSize + 1);
	
		irp = IoAllocateIrp(stackSize, FALSE);
		if(irp == NULL) {
	        	return STATUS_INSUFFICIENT_RESOURCES;
	    	}
    		urb = USB2COM_ExAllocatePool(NonPagedPool, 
    					sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
	    	if(urb == NULL)
	    	{
	    		IoFreeIrp(irp);
			return STATUS_INSUFFICIENT_RESOURCES;
	    	}
	    	deviceExtension->ReadIntUrbs[i].Irp = irp;
	    	deviceExtension->ReadIntUrbs[i].Urb = urb;
	    	deviceExtension->ReadIntUrbs[i].deviceObject = DeviceObject;
	    	deviceExtension->ReadIntUrbs[i].PipeInfo = PipeInfo;
		InitIntUrb(urb,
		    	PipeInfo->PipeHandle,
		    	deviceExtension->ReadIntUrbs[i].TransferBuffer,
		    	sizeof(deviceExtension->ReadIntUrbs[i].TransferBuffer),
		    	TRUE);
	    	nextStack = IoGetNextIrpStackLocation(irp);
		USB2COM_ASSERT(nextStack != NULL);
		USB2COM_ASSERT(DeviceObject->StackSize>1);
	
		nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
		nextStack->Parameters.Others.Argument1 = urb;
		nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
		IoSetCompletionRoutine(irp,
	                    ReadIntUrbComplete,
	                    &deviceExtension->ReadIntUrbs[i], 	// 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, irp );
		//ASSERT( ntStatus == STATUS_PENDING);
	}
	DbgPrint("StartReadIntUrb Exit\n");
	return ntStatus;
}

NTSTATUS
StopReadIntUrb(
	IN PDEVICE_EXTENSION deviceExtension
	)
{
	KIRQL 	oldIrql;
	int 	i;
	
	DbgPrint("StopReadIntUrb Enter\n");
	KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
	for(i=0; i<MAX_READ_INT_URBS; i++)
	{
		if(deviceExtension->ReadIntUrbs[i].Irp)
		{
            		IoCancelIrp(deviceExtension->ReadIntUrbs[i].Irp);
        	}
	}
	KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
	DbgPrint("StopReadIntUrb Exit\n");
	return STATUS_SUCCESS;
}

NTSTATUS
ReadIntUrbComplete(
    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;
	ULONG       		ioLength;
	PUCHAR			ioBuffer;
	KIRQL  			oldIrql;
	PIRP 			CurrentOpIrp;

	
	DbgPrint("ReadIntUrbComplete 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))
       	{
		KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
       	        IoFreeIrp(Irp);
	        pIntUrbs->Irp = NULL;
	        USB2COM_ExFreePool(pIntUrbs->Urb);
	        pIntUrbs->Urb = NULL;
	        CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentReadIrp, NULL);
    		if(CurrentOpIrp) {
	        	CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
	        	CurrentOpIrp->IoStatus.Information = 0;
	        	IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
    		}
		KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
	        USB2COM_DecrementIoCount(deviceObject);
	        return STATUS_MORE_PROCESSING_REQUIRED;
    	}
    	if(USBD_SUCCESS(usbdStatus))
    	{
    		DbgPrint("ReadIntUrbComplete: length = %d\n",urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
    		if(urb->UrbBulkOrInterruptTransfer.TransferBufferLength > 1)
    		{
			KeAcquireSpinLock(&deviceExtension->InputBufferLock, &oldIrql);
			PushCircularBufferEntry(
				&deviceExtension->InputBuffer,
				&pIntUrbs->TransferBuffer[1],
				pIntUrbs->TransferBuffer[0]);
			KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
			IoAcquireCancelSpinLock(&oldIrql);
			deviceExtension->HistoryMask |= SERIAL_EV_RXCHAR;
			if(deviceExtension->CurrentWaitIrp && 
			   (deviceExtension->HistoryMask & deviceExtension->WaitMask))
			{
				IoReleaseCancelSpinLock(oldIrql);
				SerialCompleteCurrentWait(
					deviceExtension->CurrentWaitIrp,
					deviceExtension->HistoryMask & deviceExtension->WaitMask);
			}else
				IoReleaseCancelSpinLock(oldIrql);
    		}
    	}
    	//check whether we can complete the current Read Irp;
    	if(deviceExtension->CurrentReadIrp == NULL)
    		deviceExtension->CurrentReadIrp = DequeueReadIrp(deviceExtension);
    	if(deviceExtension->CurrentReadIrp)
    	{
    		ULONG 		haveLen;
    		BOOLEAN		returnWhatsPresent = FALSE;
    		
    		if(deviceExtension->SerialTimeOuts.ReadIntervalTimeout &&
    			( deviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0) &&
    			( deviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0)
    		){
    			returnWhatsPresent = TRUE;
    		}
		ioBuffer = MmGetSystemAddressForMdlSafe(deviceExtension->CurrentReadIrp->MdlAddress,NormalPagePriority );
		ioLength = MmGetMdlByteCount(deviceExtension->CurrentReadIrp->MdlAddress);
		KeAcquireSpinLock(&deviceExtension->InputBufferLock, &oldIrql);
		haveLen = CircularBufferDataLen(&deviceExtension->InputBuffer);
	    	if( (ioLength <= haveLen) || (returnWhatsPresent && (haveLen > 0)))
	    	{
	    		ioLength = (ioLength < haveLen) ? ioLength : haveLen;
	    		DbgPrint("Complete CurrentReadIrp ioLength = %d\n",ioLength);
			ntStatus = PopCircularBufferEntry(&deviceExtension->InputBuffer,ioBuffer,ioLength);
			KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
			deviceExtension->CurrentReadIrp->IoStatus.Information = ioLength;
			deviceExtension->CurrentReadIrp->IoStatus.Status = ntStatus; 
			IoCompleteRequest(deviceExtension->CurrentReadIrp,IO_NO_INCREMENT);
			deviceExtension->CurrentReadIrp = DequeueReadIrp(deviceExtension);
	    	}else
			KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
	}
	if ( !USB2COM_CanAcceptIoRequests( deviceObject )
	 	|| (deviceExtension->PipeInfo[0].fPipeOpened == FALSE)
	)
	{
		// got sudden remove! ( i.e. plug was yanked )
		DbgPrint("fPipeOpened %d\n",deviceExtension->PipeInfo[0].fPipeOpened);
		KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
	        pIntUrbs->Irp = NULL;
	        IoFreeIrp(Irp);
		USB2COM_ExFreePool(pIntUrbs->Urb);
	        pIntUrbs->Urb = NULL;
	        CurrentOpIrp = InterlockedExchangePointer(&deviceExtension->CurrentReadIrp, NULL);
    		if(CurrentOpIrp) {
	        	CurrentOpIrp->IoStatus.Status = STATUS_DELETE_PENDING;
	        	CurrentOpIrp->IoStatus.Information = 0;
	        	IoCompleteRequest( CurrentOpIrp, IO_NO_INCREMENT );
    		}
		KeReleaseSpinLock(&deviceExtension->ReadQueueSpinLock, oldIrql);
		USB2COM_DecrementIoCount(deviceObject);
	        return STATUS_MORE_PROCESSING_REQUIRED;
	}
	USB2COM_DecrementIoCount(deviceObject);
	//
	//circulate the irps.
	//
	DbgPrint("Circulate the irp\n");
//	IoReuseIrp(Irp,STATUS_SUCCESS);
	InitIntUrb(urb,
		    	pIntUrbs->PipeInfo->PipeHandle,
		    	pIntUrbs->TransferBuffer,
		    	sizeof(pIntUrbs->TransferBuffer),
		    	TRUE);
	nextStack = IoGetNextIrpStackLocation(Irp);
	USB2COM_ASSERT(nextStack != NULL);
	USB2COM_ASSERT(deviceObject->StackSize>1);
	
	nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
	nextStack->Parameters.Others.Argument1 = urb;
	nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
	IoSetCompletionRoutine(Irp,
			ReadIntUrbComplete,
			pIntUrbs, 	// 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, Irp );
	ASSERT( ntStatus == STATUS_PENDING);
	DbgPrint("ReadIntUrbComplete Exit\n");
    	return STATUS_MORE_PROCESSING_REQUIRED;		
}


NTSTATUS
PrepareWriteIntUrb(
	IN PDEVICE_OBJECT DeviceObject,
	IN PUSBD_PIPE_INFORMATION PipeInfo
	)
{
	NTSTATUS		ntStatus = STATUS_SUCCESS;
	PDEVICE_EXTENSION 	deviceExtension = DeviceObject->DeviceExtension;
	CHAR 			stackSize;

    	
    	DbgPrint("PrepareWriteIntUrb Enter.\n");
    	if(deviceExtension->WriteIntUrb.Irp == NULL)
    	{
		stackSize = (CCHAR) (deviceExtension->TopOfStackDeviceObject->StackSize + 1);
		deviceExtension->WriteIntUrb.Irp = IoAllocateIrp(stackSize, FALSE);
		if(deviceExtension->WriteIntUrb.Irp == NULL) {
			return STATUS_INSUFFICIENT_RESOURCES;
		}
	}
	if(deviceExtension->WriteIntUrb.Urb == NULL)
	{
		deviceExtension->WriteIntUrb.Urb = USB2COM_ExAllocatePool(NonPagedPool, 
    				sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
		if(deviceExtension->WriteIntUrb.Urb == NULL)
		{
			IoFreeIrp(deviceExtension->WriteIntUrb.Irp);
			return STATUS_INSUFFICIENT_RESOURCES;
		}
	}
	deviceExtension->WriteIntUrb.Idle = TRUE;
	deviceExtension->WriteIntUrb.deviceObject = DeviceObject;
	deviceExtension->WriteIntUrb.PipeInfo = PipeInfo;
	DbgPrint("PrepareWriteIntUrb Exit\n");
	return ntStatus;    		
}

NTSTATUS
StartWriteIntUrb(
	PDEVICE_OBJECT	DeviceObject
	)
{

⌨️ 快捷键说明

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