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

📄 rw.c

📁 usb to rs232 虚拟RS232串口驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	deviceExtension->OpenPipeCount++;
	PrepareWriteIntUrb(
		DeviceObject,
		&interface->Pipes[1]
	);
	deviceExtension->PipeInfo[1].fPipeOpened = TRUE;  
	deviceExtension->OpenPipeCount++;
    irpStack = IoGetCurrentIrpStackLocation (Irp);
    fileObject = irpStack->FileObject;
    if(fileObject == NULL)
    	goto done;

    // fscontext is null for device
    fileObject->FsContext = NULL;

    if ( 0 == fileObject->FileName.Length ) // this is the case if opening device as opposed to pipe
        goto done;      // nothing more to do

    ourPipeInfo = USB2COM_PipeWithName( DeviceObject, &fileObject->FileName );

    if ( !ourPipeInfo ) {

        ntStatus = STATUS_INVALID_PARAMETER;
        goto done;

    }

	// init status to bad; will set good in below loop on success
	ntStatus = STATUS_INSUFFICIENT_RESOURCES;

	for (i=0; i<interface->NumberOfPipes; i++) {

		PipeInfo =  &interface->Pipes[i]; // PUSBD_PIPE_INFORMATION  PipeInfo;

        if ( ourPipeInfo == &deviceExtension->PipeInfo[i] ) {

    		//
			// found a match
			//
			USB2COM_KdPrint( DBGLVL_DEFAULT,("open pipe %d\n", i));
			fileObject->FsContext = PipeInfo;
			ourPipeInfo->fPipeOpened = TRUE; // set flag for opened
			ntStatus = STATUS_SUCCESS;

			deviceExtension->OpenPipeCount++;

			// try to power up device if its not in D0
			actStat = USB2COM_SelfSuspendOrActivate( DeviceObject, FALSE );
			break;
		}
	}

done:
    Irp->IoStatus.Status = ntStatus;
    Irp->IoStatus.Information = 0;


    IoCompleteRequest (Irp,
                       IO_NO_INCREMENT
                       );

    USB2COM_DecrementIoCount(DeviceObject);                               

    USB2COM_KdPrint( DBGLVL_DEFAULT,("exit USB2COM_Create %x\n", ntStatus));


    return ntStatus;
}




BOOLEAN
USB2COM_CancelPendingIo(
    IN PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:
	Cancels pending IO, as on a sudden IRP_MN_REMOVE_DEVICE 
	This driver maintains and array of info structs (USB2COM_RW_CONTEXT)
	on self-generated IRPS for staged read/writes; This routine traverses
	it and cancels all pending IO irps

Arguments:

    DeviceObject - pointer to the device object for this instance of the 82930
                    device.


Return Value:

    TRUE if cancelled any, else FALSE

--*/
{
	PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
       	KIRQL OldIrql;

    	USB2COM_KdPrint( DBGLVL_DEFAULT,("enter USB2COM_CancelPendingIo\n"));

	StopReadIntUrb(deviceExtension);
	StopWriteIntUrb(deviceExtension);
	//ASSERT(IsListEmpty(&deviceExtension->WriteQueue));
	//ASSERT(IsListEmpty(&deviceExtension->ReadQueue));
	USB2COM_KdPrint( DBGLVL_DEFAULT,("exit USB2COM_CancelPendingIo\n"));
	return TRUE;
}

NTSTATUS
USB2COM_AbortPipes(
    IN PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

	Called as part of sudden device removal handling.
    Cancels any pending transfers for all open pipes. 
	If any pipes are still open, call USBD with URB_FUNCTION_ABORT_PIPE
	Also marks the pipe 'closed' in our saved  configuration info.

Arguments:

    Ptrs to our FDO

Return Value:

    NT status code

--*/
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PURB urb;
    PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
	ULONG i;

    PUSBD_INTERFACE_INFORMATION interface;
    PUSB2COM_PIPEINFO  PipeInfo;
    PUCHAR  pInf = (PUCHAR ) deviceExtension->PipeInfo;

    interface = deviceExtension->UsbInterface;

    for (i=0; i<interface->NumberOfPipes; i++) {

        PipeInfo =  (PUSB2COM_PIPEINFO) pInf; // PUSB2COM_PIPEINFO  PipeInfo;

		if ( PipeInfo->fPipeOpened ) { // we set this if open, clear if closed

			USB2COM_KdPrint( DBGLVL_HIGH,("USB2COM_AbortPipes() Aborting open  Pipe %d\n", i));

			urb = USB2COM_ExAllocatePool(NonPagedPool,
								 sizeof(struct _URB_PIPE_REQUEST));

			if (urb) {

				urb->UrbHeader.Length = (USHORT) sizeof (struct _URB_PIPE_REQUEST);
				urb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
				urb->UrbPipeRequest.PipeHandle =
					interface->Pipes[i].PipeHandle;

				ntStatus = USB2COM_CallUSBD(DeviceObject, urb);

				USB2COM_ExFreePool(urb);

			} else {
				ntStatus = STATUS_INSUFFICIENT_RESOURCES;
				USB2COM_KdPrint( DBGLVL_HIGH,("USB2COM_AbortPipes() FAILED urb alloc\n" ));
				break;
			}


			if (!(NT_SUCCESS(ntStatus))) {
				// if we failed, dump out
#if DBG
				if ( gpDbg )
					gpDbg->PipeErrorCount++;
#endif
				break;
			}
			else {
				PipeInfo->fPipeOpened = FALSE; // mark the pipe 'closed'

				deviceExtension->OpenPipeCount--;
#if DBG
				if ( gpDbg )
					gpDbg->AbortPipeCount++;
#endif


			}

		} // end, if pipe open

        pInf += sizeof ( USB2COM_PIPEINFO );

	} // end, for all pipes


    return ntStatus;
}



BOOLEAN
USB2COM_CanAcceptIoRequests(
    IN PDEVICE_OBJECT DeviceObject
    )
/*++

Routine Description:

  Check device extension status flags; 

     Can't accept a new io request if device:
      1) is removed, 
      2) has never been started, 
      3) is stopped,
      4) has a remove request pending, or
      5) has a stop device pending


Arguments:

    DeviceObject - pointer to the device object for this instance of the 82930
                    device.


Return Value:

    return TRUE if can accept new io requests, else FALSE

--*/
{
    PDEVICE_EXTENSION deviceExtension;
	BOOLEAN fCan = FALSE;

    deviceExtension = DeviceObject->DeviceExtension;

	//flag set when processing IRP_MN_REMOVE_DEVICE
    if ( !deviceExtension->DeviceRemoved &&
		 // device must be started( enabled )
		 deviceExtension->DeviceStarted &&
 		 // flag set when driver has answered success to IRP_MN_QUERY_REMOVE_DEVICE
		 !deviceExtension->RemoveDeviceRequested &&
		 // flag set when driver has answered success to IRP_MN_QUERY_STOP_DEVICE
		 !deviceExtension->StopDeviceRequested ){
			fCan = TRUE;
	}

    USB2COM_KdPrintCond( DBGLVL_MAXIMUM, !fCan, ("**** FALSE return from USB2COM_CanAcceptIoRequests()!\n"));

	return fCan;
}

NTSTATUS QueueOrCompleteReadIrp(PDEVICE_EXTENSION deviceExtension, PIRP Irp)
{
	PDRIVER_CANCEL  oldCancelRoutine;
	KIRQL  		oldIrql;
	NTSTATUS 	status = STATUS_PENDING;
    	ULONG 		haveLen;
    	BOOLEAN		returnWhatsPresent = FALSE;
	PUCHAR		ioBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority );
	ULONG 		ioLength = MmGetMdlByteCount(Irp->MdlAddress);
	
	DbgPrint("QueueOrCompleteReadIrp Enter\n");
	if((ioLength <= 0) || (ioBuffer == NULL))
	{
		DbgPrint("ioBuffer %p ioLength %d\n",ioBuffer,ioLength);
		//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->ReadIntUrbs[0].Irp == NULL)
	 	|| (deviceExtension->ReadIntUrbs[0].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;
	} 

  	/*Platform SDK: Files and I/O About Communications Time-Outs
  	Interval timing forces a read operation to return when
  	there is a lull in reception. A process using interval 
  	time-outs can set a fairly short interval parameter, 
  	so it can respond quickly to small, isolated bursts of 
  	one or a few characters, yet it can still collect 
  	large buffers of characters with a single call 
  	when data is received in a steady stream.
  	*/   		
	if(deviceExtension->SerialTimeOuts.ReadIntervalTimeout &&
		( deviceExtension->SerialTimeOuts.ReadTotalTimeoutMultiplier == 0) &&
		( deviceExtension->SerialTimeOuts.ReadTotalTimeoutConstant == 0)
	){
		returnWhatsPresent = TRUE;
	}
	KeAcquireSpinLock(&deviceExtension->InputBufferLock, &oldIrql);
	haveLen = CircularBufferDataLen(&deviceExtension->InputBuffer);
    	if( (ioLength <= haveLen) || (returnWhatsPresent && (haveLen > 0)) )
	{
		ioLength = (ioLength < haveLen) ? ioLength : haveLen;
		DbgPrint("Complete ReadIrp ioLength=%d\n",ioLength);
		status = PopCircularBufferEntry(&deviceExtension->InputBuffer,ioBuffer,ioLength);
		KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
		Irp->IoStatus.Information = ioLength;
		Irp->IoStatus.Status = status; 
		IoCompleteRequest( Irp,IO_NO_INCREMENT);
		return status;
	}
	KeReleaseSpinLock(&deviceExtension->InputBufferLock, oldIrql);
	KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
	
	//  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->ReadQueue, &Irp->Tail.Overlay.ListEntry);
	
	//  Must set a Cancel routine before checking the Cancel flag.
	oldCancelRoutine = IoSetCancelRoutine(Irp, IrpCancelRoutine);
	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->ReadQueueSpinLock, 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_PENDING){
	    IoCompleteRequest(Irp, IO_NO_INCREMENT);
	}
	DbgPrint("QueueOrCompleteReadIrp Exit\n");

	return status;
}

PIRP DequeueReadIrp(PDEVICE_EXTENSION deviceExtension)
{
	KIRQL oldIrql;
	PIRP nextIrp = NULL;
	
	DbgPrint("DequeueReadIrp Enter\n");
	KeAcquireSpinLock(&deviceExtension->ReadQueueSpinLock, &oldIrql);
	
	while (!nextIrp && !IsListEmpty(&deviceExtension ->ReadQueue)){
	    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);

⌨️ 快捷键说明

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