//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: readwrit.c // //-------------------------------------------------------------------------- // // This file contains functions associated with handling Read and Write requests // #include "pch.h" NTSTATUS ParForwardToReverse( IN PPDO_EXTENSION Pdx ) /*++ Routine Description: This routine flips the bus from Forward to Reverse direction. Arguments: Pdx - Supplies the device extension. Return Value: None. --*/ { NTSTATUS Status = STATUS_SUCCESS; // Do a quick check to see if we are where we want to be. // Happy punt if everything is ok. if( Pdx->Connected && ( Pdx->CurrentPhase == PHASE_REVERSE_IDLE || Pdx->CurrentPhase == PHASE_REVERSE_XFER) ) { DD((PCE)Pdx,DDT,"ParForwardToReverse - already in reverse mode\n"); return Status; } if (Pdx->Connected) { if (Pdx->CurrentPhase != PHASE_REVERSE_IDLE && Pdx->CurrentPhase != PHASE_REVERSE_XFER) { if (afpForward[Pdx->IdxForwardProtocol].ProtocolFamily == arpReverse[Pdx->IdxReverseProtocol].ProtocolFamily) { // Protocol Families match and we are in Fwd. Exit Fwd to cleanup the state // machine, fifo, etc. We will call EnterReverse later to // actually bus flip. Also only do this if in safe mode if ( (afpForward[Pdx->IdxForwardProtocol].fnExitForward) ) { Status = afpForward[Pdx->IdxForwardProtocol].fnExitForward(Pdx); } } else { // // Protocol Families don't match...need to terminate from the forward mode // if (afpForward[Pdx->IdxForwardProtocol].fnDisconnect) { afpForward[Pdx->IdxForwardProtocol].fnDisconnect (Pdx); } if ((Pdx->ForwardInterfaceAddress != DEFAULT_ECP_CHANNEL) && (afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress)) Pdx->SetForwardAddress = TRUE; } } } if( (!Pdx->Connected) && (arpReverse[Pdx->IdxReverseProtocol].fnConnect) ) { // // If we are still connected the protocol families match... // Status = arpReverse[Pdx->IdxReverseProtocol].fnConnect(Pdx, FALSE); // // Makes the assumption that the connected address is always 0 // if ((NT_SUCCESS(Status)) && (arpReverse[Pdx->IdxReverseProtocol].fnSetInterfaceAddress) && (Pdx->ReverseInterfaceAddress != DEFAULT_ECP_CHANNEL)) { Pdx->SetReverseAddress = TRUE; } } // // Set the channel address if we need to. // if (NT_SUCCESS(Status) && Pdx->SetReverseAddress && (arpReverse[Pdx->IdxReverseProtocol].fnSetInterfaceAddress)) { Status = arpReverse[Pdx->IdxReverseProtocol].fnSetInterfaceAddress ( Pdx, Pdx->ReverseInterfaceAddress); if (NT_SUCCESS(Status)) Pdx->SetReverseAddress = FALSE; else Pdx->SetReverseAddress = TRUE; } // // Do we need to reverse? // if ( (NT_SUCCESS(Status)) && ((Pdx->CurrentPhase != PHASE_REVERSE_IDLE) && (Pdx->CurrentPhase != PHASE_REVERSE_XFER)) ) { if ((arpReverse[Pdx->IdxReverseProtocol].fnEnterReverse)) Status = arpReverse[Pdx->IdxReverseProtocol].fnEnterReverse(Pdx); } DD((PCE)Pdx,DDT,"ParForwardToReverse - exit w/status=%x\n",Status); return Status; } BOOLEAN ParHaveReadData( IN PPDO_EXTENSION Pdx ) /*++ Routine Description: This method determines if the dot4 peripheral has any data ready to send to the host. Arguments: Pdx - Supplies the device EXTENSION. Return Value: TRUE - Either the peripheral has data FALSE - No data --*/ { NTSTATUS status; BOOLEAN justAcquiredPort = FALSE; if( Pdx->CurrentPhase != PHASE_TERMINATE && Pdx->CurrentPhase != PHASE_REVERSE_IDLE && Pdx->CurrentPhase != PHASE_REVERSE_XFER && Pdx->CurrentPhase != PHASE_FORWARD_IDLE && Pdx->CurrentPhase != PHASE_FORWARD_XFER ) { // unexpected phase - no idea what to do here - pretend that // there is no data avail and return DD((PCE)Pdx,DDE,"ParHaveReadData - unexpected CurrentPhase %x\n",Pdx->CurrentPhase); PptAssertMsg("ParHaveReadData - unexpected CurrentPhase",FALSE); return FALSE; } if( PHASE_TERMINATE == Pdx->CurrentPhase ) { // // we're not currently talking with the peripheral and we // likely don't have access to the port - try to acquire the // port and establish communication with the peripheral so // that we can check if the peripheral has data for us // // CurrentPhase indicates !Connected - do a check for consistency PptAssert( !Pdx->Connected ); DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_TERMINATE\n"); if( !Pdx->bAllocated ) { // we don't have the port - try to acquire port DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_TERMINATE - don't have port\n"); status = PptAcquirePortViaIoctl( Pdx->Fdo, NULL ); if( STATUS_SUCCESS == status ) { // we now have the port DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_TERMINATE - port acquired\n"); // note that we have just now acquired the port so // that we can release the port below if we are unable // to establish communication with the peripheral justAcquiredPort = TRUE; Pdx->bAllocated = TRUE; } else { // we couldn't get the port - bail out DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_TERMINATE - don't have port - acquire failed\n"); return FALSE; } } // endif !Pdx->bAllocated // // we now have the port - try to negotiate into a forward // mode since we believe that the check for periph data // avail is more robust in forward modes // DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_TERMINATE - we have the port - try to Connect\n"); DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - try to Connect - calling ParReverseToForward\n"); // // ParReverseToForward: // // 1) tries to negotiate the peripheral into the forward mode // specified by a combination of the device specific // Pdx->IdxForwardProtocol and the driver global afpForward // array. // // 2) sets up our internal state machine, Pdx->CurrentPhase // // 3) as a side effect - sets Pdx->SetForwardAddress if we // need to use a non-Zero ECP (or EPP) address. // status = ParReverseToForward( Pdx ); if( STATUS_SUCCESS == status ) { // // We are in communication with the peripheral // DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - connected - ParReverseToForward SUCCESS\n"); // Set the channel address if we need to - use the side effect from ParReverseToForward here if( Pdx->SetForwardAddress ) { DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - connected - try to set Forward Address\n"); if( afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress ) { status = afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress ( Pdx, Pdx->ForwardInterfaceAddress ); if( STATUS_SUCCESS == status ) { // success - set flag to indicate that we don't need to set the address again DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - connected - set Forward Address - SUCCESS\n"); Pdx->SetForwardAddress = FALSE; } else { // couldn't set address - clean up and bail out - report no peripheral data avail DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - connected - set Forward Address - FAIL\n"); Pdx->SetForwardAddress = TRUE; // Return peripheral to quiescent state // (Compatibility Mode Forward Idle) and set // our state machine accordingly ParTerminate( Pdx ); // if we just acquired the port in this function then give // up the port, otherwise keep it for now if( justAcquiredPort ) { DD((PCE)Pdx,DDE,"ParHaveReadData - set address failed - giving up port\n"); ParFreePort( Pdx ); } return FALSE; } } } else { DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - connected - no need to set Forward Address\n"); } } else { // unable to establish communication with peripheral DD((PCE)Pdx,DDE,"ParHaveReadData - we have the port - try to Connect - ParReverseToForward FAILED\n"); // if we just acquired the port in this function then give // up the port, otherwise keep it for now if( justAcquiredPort ) { DD((PCE)Pdx,DDE,"ParHaveReadData - connect failed - giving up port\n"); ParFreePort( Pdx ); } return FALSE; } // we're communicating with the peripheral - fall through to below to check for data avail } // endif PHASE_TERMINATE == CurrentPhase if( Pdx->CurrentPhase == PHASE_REVERSE_IDLE || Pdx->CurrentPhase == PHASE_REVERSE_XFER ) { DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_REVERSE_*\n"); if( arpReverse[Pdx->IdxReverseProtocol].fnHaveReadData ) { if( arpReverse[Pdx->IdxReverseProtocol].fnHaveReadData( Pdx ) ) { DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_REVERSE_* - we have data\n"); return TRUE; } } DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_REVERSE_* - no data - flip bus to forward\n"); // Don't have data. This could be a fluke. Let's flip the bus // and try again in Fwd mode since some peripherals reportedly // have broken firmware that does not properly signal that // they have data avail when in some reverse modes. ParReverseToForward( Pdx ); } if( Pdx->CurrentPhase == PHASE_FORWARD_IDLE || Pdx->CurrentPhase == PHASE_FORWARD_XFER ) { DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_FORWARD_*\n"); if( afpForward[Pdx->IdxForwardProtocol].ProtocolFamily == FAMILY_BECP || afpForward[Pdx->IdxForwardProtocol].Protocol & ECP_HW_NOIRQ || afpForward[Pdx->IdxForwardProtocol].Protocol & ECP_HW_IRQ) { if( PptEcpHwHaveReadData( Pdx ) ) { DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_FORWARD_* - ECP HW - have data\n"); return TRUE; } // Hmmm. No data. Is the chip stuck? DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_FORWARD_* - ECP HW - no data\n"); return FALSE; } else { if( afpForward[Pdx->IdxForwardProtocol].Protocol & ECP_SW ) { DD((PCE)Pdx,DDE,"ParHaveReadData - PHASE_FORWARD_* - ECP SW - checking for data\n"); return ParEcpHaveReadData( Pdx ); } } } // DVRH RMT // We got here because the protocol doesn't support peeking. // - pretend there is data avail DD((PCE)Pdx,DDE,"ParHaveReadData - exit - returning TRUE\n"); return TRUE; } NTSTATUS ParPing( IN PPDO_EXTENSION Pdx ) /*++ Routine Description: This method was intended to ping the device, but it is currently a NOOP. Arguments: Pdx - Supplies the device EXTENSION. Return Value: none --*/ { NTSTATUS NtStatus = STATUS_SUCCESS; UNREFERENCED_PARAMETER( Pdx ); return NtStatus; } NTSTATUS PptPdoReadWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the dispatch routine for READ and WRITE requests. Arguments: DeviceObject - Supplies the device object. Irp - Supplies the I/O request packet. Return Value: STATUS_PENDING - Request pending - a worker thread will carry out the request at PASSIVE_LEVEL IRQL STATUS_SUCCESS - Success - asked for a read or write of length zero. STATUS_INVALID_PARAMETER - Invalid parameter. STATUS_DELETE_PENDING - This device object is being deleted. --*/ { PIO_STACK_LOCATION IrpSp; PPDO_EXTENSION Pdx; Irp->IoStatus.Information = 0; IrpSp = IoGetCurrentIrpStackLocation(Irp); Pdx = DeviceObject->DeviceExtension; // // bail out if a delete is pending for this device object // if(Pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING) { return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information ); } // // bail out if a remove is pending for our ParPort device object // if(Pdx->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) { return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information ); } // // bail out if device has been removed // if(Pdx->DeviceStateFlags & (PPT_DEVICE_REMOVED|PPT_DEVICE_SURPRISE_REMOVED) ) { return P4CompleteRequest( Irp, STATUS_DEVICE_REMOVED, Irp->IoStatus.Information ); } // // Note that checks of the Write IRP parameters also handles Read IRPs // because the Write and Read structures are identical in the // IO_STACK_LOCATION.Parameters union // // // bail out on nonzero offset // if( (IrpSp->Parameters.Write.ByteOffset.HighPart != 0) || (IrpSp->Parameters.Write.ByteOffset.LowPart != 0) ) { return P4CompleteRequest( Irp, STATUS_INVALID_PARAMETER, Irp->IoStatus.Information ); } // // immediately succeed read or write request of length zero // if (IrpSp->Parameters.Write.Length == 0) { return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information ); } // // Request appears to be valid, queue it for our worker thread to handle at // PASSIVE_LEVEL IRQL and wake up the thread to do the work // { KIRQL OldIrql; // make sure IRP isn't cancelled out from under us IoAcquireCancelSpinLock(&OldIrql); if (Irp->Cancel) { // IRP has been cancelled, bail out IoReleaseCancelSpinLock(OldIrql); return STATUS_CANCELLED; } else { BOOLEAN needToSignalSemaphore = (IsListEmpty( &Pdx->WorkQueue ) && !KeReadStateSemaphore( &Pdx->RequestSemaphore )) ? TRUE : FALSE; #pragma warning( push ) #pragma warning( disable : 4054 4055 ) IoSetCancelRoutine(Irp, ParCancelRequest); #pragma warning( pop ) IoMarkIrpPending(Irp); InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry); IoReleaseCancelSpinLock(OldIrql); if( needToSignalSemaphore ) { KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE); } return STATUS_PENDING; } } } NTSTATUS ParRead( IN PPDO_EXTENSION Pdx, OUT PVOID Buffer, IN ULONG NumBytesToRead, OUT PULONG NumBytesRead ) { NTSTATUS Status = STATUS_SUCCESS; PUCHAR lpsBufPtr = (PUCHAR)Buffer; // Pointer to buffer cast to desired data type ULONG Bytes = 0; *NumBytesRead = Bytes; // only do this if we are in safe mode if ( Pdx->ModeSafety == SAFE_MODE ) { if (arpReverse[Pdx->IdxReverseProtocol].fnReadShadow) { Queue *pQueue; pQueue = &(Pdx->ShadowBuffer); arpReverse[Pdx->IdxReverseProtocol].fnReadShadow( pQueue, lpsBufPtr, NumBytesToRead, &Bytes ); NumBytesToRead -= Bytes; *NumBytesRead += Bytes; lpsBufPtr += Bytes; if ( 0 == NumBytesToRead ) { Status = STATUS_SUCCESS; if ((!Queue_IsEmpty(pQueue)) && (TRUE == Pdx->P12843DL.bEventActive) ) { KeSetEvent(Pdx->P12843DL.Event, 0, FALSE); } goto ParRead_ExitLabel; } } if (arpReverse[Pdx->IdxReverseProtocol].fnHaveReadData) { if (!arpReverse[Pdx->IdxReverseProtocol].fnHaveReadData(Pdx)) { DD((PCE)Pdx,DDT,"ParRead - periph doesn't have data - give cycles to someone else\n"); Status = STATUS_SUCCESS; goto ParRead_ExitLabel; } } } // Go ahead and flip the bus if need be. The proc will just make sure we're properly // connected and pointing in the right direction. Status = ParForwardToReverse( Pdx ); // // The read mode will vary depending upon the currently negotiated mode. // Default: Nibble // if (NT_SUCCESS(Status)) { if (Pdx->fnRead || arpReverse[Pdx->IdxReverseProtocol].fnRead) { // // Do the read... // if(Pdx->fnRead) { Status = ((PPROTOCOL_READ_ROUTINE)Pdx->fnRead)( Pdx, (PVOID)lpsBufPtr, NumBytesToRead, &Bytes ); } else { Status = arpReverse[Pdx->IdxReverseProtocol].fnRead( Pdx, (PVOID)lpsBufPtr, NumBytesToRead, &Bytes ); } *NumBytesRead += Bytes; NumBytesToRead -= Bytes; #if DVRH_SHOW_BYTE_LOG { ULONG i=0; DD((PCE)Pdx,DDT,"Parallel:Read: "); for (i=0; i<*NumBytesRead; ++i) { DD((PCE)Pdx,DDT," %02x",((PUCHAR)lpsBufPtr)[i]); } DD((PCE)Pdx,DDT,"\n"); } #endif } else { // If you are here, you've got a bug somewhere else DD((PCE)Pdx,DDE,"ParRead - you're hosed man - no fnRead\n"); PptAssertMsg("ParRead - don't have a fnRead! Can't Read!\n",FALSE); } } else { DD((PCE)Pdx,DDE,"ParRead - Bus Flip Forward->Reverse FAILED - can't read\n"); } ParRead_ExitLabel: return Status; } VOID ParReadIrp( IN PPDO_EXTENSION Pdx ) /*++ Routine Description: This routine implements a READ request with the extension's current irp. Arguments: Pdx - Supplies the device extension. Return Value: None. --*/ { PIRP Irp = Pdx->CurrentOpIrp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); ULONG bytesRead; NTSTATUS status; status = ParRead( Pdx, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Read.Length, &bytesRead ); Irp->IoStatus.Status = status; Irp->IoStatus.Information = bytesRead; DD((PCE)Pdx,DDT,"ParReadIrp - status = %x, bytesRead=%d\n", status, bytesRead); return; } NTSTATUS ParReverseToForward( IN PPDO_EXTENSION Pdx ) /*++ Routine Description: This routine flips the bus from Reverse to Forward direction. Arguments: Pdx - Supplies the device extension. Return Value: None. --*/ { NTSTATUS Status = STATUS_SUCCESS; // dvdr if (Pdx->Connected) { // Do a quick check to see if we are where we want to be. // Happy punt if everything is ok. if( Pdx->CurrentPhase == PHASE_FORWARD_IDLE || Pdx->CurrentPhase == PHASE_FORWARD_XFER ) { DD((PCE)Pdx,DDT,"ParReverseToForward: Already in Fwd. Exit STATUS_SUCCESS\n"); return Status; } else { if (afpForward[Pdx->IdxForwardProtocol].ProtocolFamily != arpReverse[Pdx->IdxReverseProtocol].ProtocolFamily) { // // Protocol Families don't match...need to terminate from the forward mode // if (arpReverse[Pdx->IdxReverseProtocol].fnDisconnect) { arpReverse[Pdx->IdxReverseProtocol].fnDisconnect (Pdx); } if ((Pdx->ReverseInterfaceAddress != DEFAULT_ECP_CHANNEL) && (arpReverse[Pdx->IdxReverseProtocol].fnSetInterfaceAddress)) { Pdx->SetReverseAddress = TRUE; } } else if((Pdx->CurrentPhase == PHASE_REVERSE_IDLE) || (Pdx->CurrentPhase == PHASE_REVERSE_XFER)) { if ( (arpReverse[Pdx->IdxReverseProtocol].fnExitReverse) ) { Status = arpReverse[Pdx->IdxReverseProtocol].fnExitReverse(Pdx); } } else { // We are in a screwy state. DD((PCE)Pdx,DDE,"ParReverseToForward: We're lost! Unknown state - Gonna start spewing!\n"); Status = STATUS_IO_TIMEOUT; // I picked a RetVal from thin air! } } } // Yes, we still want to check for connection since we might have // terminated in the previous code block! if (!Pdx->Connected && afpForward[Pdx->IdxForwardProtocol].fnConnect) { Status = afpForward[Pdx->IdxForwardProtocol].fnConnect( Pdx, FALSE ); // // Makes the assumption that the connected address is always 0 // if ((NT_SUCCESS(Status)) && (Pdx->ForwardInterfaceAddress != DEFAULT_ECP_CHANNEL)) { Pdx->SetForwardAddress = TRUE; } } // // Do we need to enter a forward mode? // if ( (NT_SUCCESS(Status)) && (Pdx->CurrentPhase != PHASE_FORWARD_IDLE) && (Pdx->CurrentPhase != PHASE_FORWARD_XFER) && (afpForward[Pdx->IdxForwardProtocol].fnEnterForward) ) { Status = afpForward[Pdx->IdxForwardProtocol].fnEnterForward(Pdx); } DD((PCE)Pdx,DDT,"ParReverseToForward - exit w/status= %x\n", Status); return Status; } NTSTATUS ParSetFwdAddress( IN PPDO_EXTENSION Pdx ) { NTSTATUS Status = STATUS_SUCCESS; DD((PCE)Pdx,DDT,"ParSetFwdAddress: Start: Channel [%x]\n", Pdx->ForwardInterfaceAddress); if (afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress) { Status = ParReverseToForward(Pdx); if (!NT_SUCCESS(Status)) { DD((PCE)Pdx,DDE,"ParSetFwdAddress: FAIL. Couldn't flip the bus for Set ECP/EPP Channel failed.\n"); goto ParSetFwdAddress_ExitLabel; } Status = afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress ( Pdx, Pdx->ForwardInterfaceAddress); if (NT_SUCCESS(Status)) { Pdx->SetForwardAddress = FALSE; } else { DD((PCE)Pdx,DDE,"ParSetFwdAddress: FAIL. Set ECP/EPP Channel failed.\n"); goto ParSetFwdAddress_ExitLabel; } } else { DD((PCE)Pdx,DDE,"ParSetFwdAddress: FAIL. Protocol doesn't support SetECP/EPP Channel\n"); Status = STATUS_UNSUCCESSFUL; goto ParSetFwdAddress_ExitLabel; } ParSetFwdAddress_ExitLabel: return Status; } VOID ParTerminate( IN PPDO_EXTENSION Pdx ) { if (!Pdx->Connected) { return; } if (Pdx->CurrentPhase == PHASE_REVERSE_IDLE || Pdx->CurrentPhase == PHASE_REVERSE_XFER) { if (afpForward[Pdx->IdxForwardProtocol].ProtocolFamily != arpReverse[Pdx->IdxReverseProtocol].ProtocolFamily) { if (arpReverse[Pdx->IdxReverseProtocol].fnDisconnect) { DD((PCE)Pdx,DDT,"ParTerminate: Calling arpReverse.fnDisconnect\r\n"); arpReverse[Pdx->IdxReverseProtocol].fnDisconnect (Pdx); } return; } ParReverseToForward(Pdx); } if (afpForward[Pdx->IdxForwardProtocol].fnDisconnect) { DD((PCE)Pdx,DDT,"ParTerminate: Calling afpForward.fnDisconnect\r\n"); afpForward[Pdx->IdxForwardProtocol].fnDisconnect (Pdx); } } NTSTATUS ParWrite( IN PPDO_EXTENSION Pdx, OUT PVOID Buffer, IN ULONG NumBytesToWrite, OUT PULONG NumBytesWritten ) { NTSTATUS Status = STATUS_SUCCESS; // // The routine which performs the write varies depending upon the currently // negotiated mode. Start I/O moves the IRP into the Pdx (CurrentOpIrp) // // Default mode: Centronics // // Go ahead and flip the bus if need be. The proc will just make sure we're properly // connected and pointing in the right direction. Status = ParReverseToForward( Pdx ); // only do this if we are in safe mode if ( Pdx->ModeSafety == SAFE_MODE ) { // // Set the channel address if we need to. // if (NT_SUCCESS(Status) && Pdx->SetForwardAddress && (afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress)) { Status = afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress ( Pdx, Pdx->ForwardInterfaceAddress); if (NT_SUCCESS(Status)) Pdx->SetForwardAddress = FALSE; else Pdx->SetForwardAddress = TRUE; } } if (NT_SUCCESS(Status)) { if (Pdx->fnWrite || afpForward[Pdx->IdxForwardProtocol].fnWrite) { *NumBytesWritten = 0; #if DVRH_SHOW_BYTE_LOG { ULONG i=0; DD((PCE)Pdx,DDT,"Parallel:Write: "); for (i=0; ifnWrite) { Status = ((PPROTOCOL_WRITE_ROUTINE)Pdx->fnWrite)(Pdx, Buffer, NumBytesToWrite, NumBytesWritten); } else { Status = afpForward[Pdx->IdxForwardProtocol].fnWrite(Pdx, Buffer, NumBytesToWrite, NumBytesWritten); } } } return Status; } VOID ParWriteIrp( IN PPDO_EXTENSION Pdx ) /*++ Routine Description: This routine implements a WRITE request with the extension's current irp. Arguments: Pdx - Supplies the device extension. Return Value: None. --*/ { PIRP Irp; PIO_STACK_LOCATION IrpSp; ULONG NumBytesWritten = 0; Irp = Pdx->CurrentOpIrp; IrpSp = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Status = ParWrite(Pdx, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Write.Length, &NumBytesWritten); Irp->IoStatus.Information = NumBytesWritten; }