/*++ Copyright (C) Microsoft Corporation, 1993 - 1999 Module Name: becp.c Abstract: This module contains code for the host to utilize BoundedECP if it has been detected and successfully enabled. Author: Robbie Harris (Hewlett-Packard) 27-May-1998 Environment: Kernel mode Revision History : --*/ #include "pch.h" #include "readwrit.h" #include "hwecp.h" // The following error codes were added to reflect errors that are unique to // Bounded ECP #define VE_FRAME_NO_DATA -74 // attempt to enter FrameRev w/o nPerReq #define VE_FRAME_CANT_EXIT_REVERSE -75 // attempt to exit FrameRev w/ nPerReq //========================================================= // BECP::ExitReversePhase // // Description : Get out of BECP Reverse Phase to the common state // // Input Parameters : Controller, pPortInfoStruct // // Modifies : // // Pre-conditions : // // Post-conditions : // // Returns : // //========================================================= NTSTATUS ParBecpExitReversePhase( IN PDEVICE_EXTENSION Extension ) { // When using BECP, test nPeriphRequest prior to negotiation // from reverse phase to forward phase. Do not negotiate unless the // peripheral indicates it is finished sending. If using any other // mode, negotiate immediately. if ( Extension->ModeSafety == SAFE_MODE ) { if (Extension->CurrentPhase == PHASE_REVERSE_IDLE) { if (!CHECK_DSR( Extension->Controller, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, IEEE_MAXTIME_TL) ) { ParDump2(PARERRORS, ("ParBecpExitReversePhase: Periph Stuck. Can't Flip Bus\n")); return STATUS_IO_TIMEOUT; } } } return ParEcpHwExitReversePhase(Extension); } //============================================================================ // NAME: ECPFrame::Read() // // // LAC FRAME 12Dec97 // This function is used for two different kinds of reads: // 1) continuing read - where we don't expect to exit reverse mode afterwards // 2) non-continuing read - where we expect to exit reverse mode afterwards // The problem is that we have no way of knowing which is which. I can // either wait after each read for nPeriphRequest to drop, or I can // check to see if it has dropped when I enter and handle it then. // // The other problem is that we have no way of communicating the fact that // we have done this to the PortTuple. It uses the last_direction member // to decide whether it should even look at entering or exiting some phase. // // Lets face it, we are on our own with this. It is safer to leave it // connected and then try to straighten things out when we come back. I // know that this wastes some time, but so does waiting at the end of // every read when only half of them are going to drop the nPeriphRequest. // // This routine performs a 1284 ECP mode read into the given // buffer for no more than 'BufferSize' bytes. // // This routine runs at DISPATCH_LEVEL. // // PARAMETERS: // Controller - Supplies the base address of the parallel port. // pPortInfoStruct - Supplies port information as defined in p1284.h // Buffer - Supplies the buffer to read into. // BufferSize - Supplies the number of bytes in the buffer. // BytesTransferred - Returns the number of bytes transferred. // // RETURNS: // NTSTATUS STATUS_SUCCESS or... // The number of bytes successfully read from the port is // returned via one of the arguments passed into this method. // // NOTES: // - Called ECP_PatchReverseTransfer in the original 16 bit code. // //============================================================================ NTSTATUS ParBecpRead( IN PDEVICE_EXTENSION Extension, IN PVOID Buffer, IN ULONG BufferSize, OUT PULONG BytesTransferred ) { NTSTATUS status = STATUS_SUCCESS; ParDump2(PARENTRY,("ParBecpRead: Enter BufferSize[%d]\n", BufferSize)); status = ParEcpHwRead( Extension, Buffer, BufferSize, BytesTransferred ); if (NT_SUCCESS(status)) { PUCHAR Controller; Controller = Extension->Controller; if ( CHECK_DSR_WITH_FIFO( Controller, DONT_CARE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, ECR_FIFO_EMPTY, ECR_FIFO_SOME_DATA, DEFAULT_RECEIVE_TIMEOUT) ) { ParDump2(PARINFO,("ParBecpRead: No more data. Flipping to Fwd.\n")); // // Bounded ECP rule - no more data from periph - flip bus to forward // status = ParReverseToForward( Extension ); ParDump2(PARINFO,("ParBecpRead: We have flipped to Fwd.\n")); } else { UCHAR bDSR = READ_PORT_UCHAR( Controller + OFFSET_DSR ); // // Periph still has data, check for valid state // ParDump2(PARINFO,("ParBecpRead: Periph says there is more data. Checking for stall.\n")); // It's OK for the device to continue asserting nPeriphReq, // it may have more data to send. However, nAckReverse and // XFlag should be in a known state, so double check them. if ( ! TEST_DSR( bDSR, DONT_CARE, DONT_CARE, INACTIVE, ACTIVE, DONT_CARE ) ) { #if DVRH_BUS_RESET_ON_ERROR BusReset(Controller + OFFSET_DCR); // Pass in the dcr address #endif status = STATUS_LINK_FAILED; ParDump2(PARERRORS,("ParBecpRead: nAckReverse and XFlag are bad.\n")); } else { // // Periph has correctly acknowledged that it has data (state valid) // if ( (TRUE == Extension->P12843DL.bEventActive) ) { // // Signal transport (e.g., dot4) that data is avail // KeSetEvent(Extension->P12843DL.Event, 0, FALSE); } } } } ParDump2(PAREXIT, ("ParBecpRead: Exit[%d] BytesTransferred[%d]\r\n", NT_SUCCESS(status), *BytesTransferred)); return status; } NTSTATUS ParEnterBecpMode( IN PDEVICE_EXTENSION Extension, IN BOOLEAN DeviceIdRequest ) /*++ Routine Description: This routine performs 1284 negotiation with the peripheral to the BECP mode protocol. Arguments: Controller - Supplies the port address. DeviceIdRequest - Supplies whether or not this is a request for a device id. Return Value: STATUS_SUCCESS - Successful negotiation. otherwise - Unsuccessful negotiation. --*/ { NTSTATUS Status = STATUS_SUCCESS; if ( Extension->ModeSafety == SAFE_MODE ) { if (DeviceIdRequest) { Status = IeeeEnter1284Mode (Extension, BECP_EXTENSIBILITY | DEVICE_ID_REQ); } else { Status = IeeeEnter1284Mode (Extension, BECP_EXTENSIBILITY); } } else { Extension->Connected = TRUE; } if (NT_SUCCESS(Status)) { Status = ParEcpHwSetupPhase(Extension); Extension->bSynchWrites = TRUE; // NOTE this is a temp hack!!! dvrh if (!Extension->bShadowBuffer) { Queue_Create(&(Extension->ShadowBuffer), Extension->FifoDepth * 2); Extension->bShadowBuffer = TRUE; } Extension->IsIeeeTerminateOk = TRUE; } ParDump2(PARENTRY,("ParEnterBecpMode: End [%d]\n", NT_SUCCESS(Status))); return Status; } BOOLEAN ParIsBecpSupported( IN PDEVICE_EXTENSION Extension ) /*++ Routine Description: This routine determines whether or not ECP mode is suported in the write direction by trying to negotiate when asked. Arguments: Extension - The device extension. Return Value: BOOLEAN. --*/ { NTSTATUS Status; if (Extension->BadProtocolModes & BOUNDED_ECP) { ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: BOUNDED_ECP has been marked as BadProtocolModes\n")); return FALSE; } if (Extension->ProtocolModesSupported & BOUNDED_ECP) { ParDump2(PARINFO, ("ParIsBecpSupported: PASSED: BOUNDED_ECP has already been cheacked\n")); return TRUE; } if (!(Extension->HardwareCapabilities & PPT_ECP_PRESENT)) { ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: No HWECP\n")); return FALSE; } if (0 == Extension->FifoWidth) { ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: No FifoWidth\n")); return FALSE; } // Must use BECP Enter and Terminate for this test. // Internel state machines will fail otherwise. --dvrh Status = ParEnterBecpMode (Extension, FALSE); ParTerminateBecpMode (Extension); if (NT_SUCCESS(Status)) { Extension->ProtocolModesSupported |= BOUNDED_ECP; ParDump2(PARINFO, ("ParIsBecpSupported: PASSED:\n")); return TRUE; } ParDump2(PARINFO, ("ParIsBecpSupported: FAILED: BOUNDED_ECP didn't negotiate\n")); return FALSE; } VOID ParTerminateBecpMode( IN PDEVICE_EXTENSION Extension ) /*++ Routine Description: This routine terminates the interface back to compatibility mode. Arguments: Controller - Supplies the parallel port's controller address. Return Value: None. --*/ { ParDump2( PARENTRY, ("ParTerminateBecpMode: Entry CurrentPhase %d\r\n", Extension->CurrentPhase)); // Need to check current phase -- if its reverse, need to flip bus // If its not forward -- its an incorrect phase and termination will fail. switch (Extension->CurrentPhase) { case PHASE_FORWARD_IDLE: // Legal state to terminate { break; } case PHASE_REVERSE_IDLE: // Flip the bus so we can terminate { NTSTATUS status = ParEcpHwExitReversePhase( Extension ); if ( STATUS_SUCCESS == status ) { status = ParEcpEnterForwardPhase(Extension ); } else { ParDump2( PARERRORS, ("ParTerminateBecpMode: Couldn't flip the bus\n")); } break; } case PHASE_FORWARD_XFER: case PHASE_REVERSE_XFER: { ParDump2( PARERRORS, ("ParTerminateBecpMode: invalid wCurrentPhase (XFer in progress) \r\n")); //status = VE_BUSY; // Dunno what to do here. We probably will confuse the peripheral. break; } // LAC TERMINATED 13Jan98 // Included PHASE_TERMINATE in the switch so we won't return an // error if we are already terminated. case PHASE_TERMINATE: { // We are already terminated, nothing to do break; } default: { ParDump2( PARERRORS, ("ParTerminateBecpMode: VE_CORRUPT: invalid CurrentPhase %d\r\n", Extension->CurrentPhase)); //status = VE_CORRUPT; // Dunno what to do here. We're lost and don't have a map to figure // out where we are! break; } } ParEcpHwWaitForEmptyFIFO(Extension); ParCleanupHwEcpPort(Extension); if ( Extension->ModeSafety == SAFE_MODE ) { IeeeTerminate1284Mode (Extension); } else { ParDump2(PARINFO, ("ParTerminateBecpMode: In UNSAFE_MODE.\n")); Extension->Connected = FALSE; } return; }