553 lines
14 KiB
C
553 lines
14 KiB
C
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1993 - 1999
|
||
|
||
Module Name:
|
||
|
||
epp.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code to perform all EPP related tasks (including
|
||
EPP Software and EPP Hardware modes.)
|
||
|
||
Author:
|
||
|
||
Timothy T. Wells (WestTek, L.L.C.) - April 16, 1997
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History :
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
|
||
BOOLEAN
|
||
ParIsEppSwWriteSupported(
|
||
IN PPDO_EXTENSION Pdx
|
||
);
|
||
|
||
BOOLEAN
|
||
ParIsEppSwReadSupported(
|
||
IN PPDO_EXTENSION Pdx
|
||
);
|
||
|
||
NTSTATUS
|
||
ParEnterEppSwMode(
|
||
IN PPDO_EXTENSION Pdx,
|
||
IN BOOLEAN DeviceIdRequest
|
||
);
|
||
|
||
VOID
|
||
ParTerminateEppSwMode(
|
||
IN PPDO_EXTENSION Pdx
|
||
);
|
||
|
||
NTSTATUS
|
||
ParEppSwWrite(
|
||
IN PPDO_EXTENSION Pdx,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferSize,
|
||
OUT PULONG BytesTransferred
|
||
);
|
||
|
||
NTSTATUS
|
||
ParEppSwRead(
|
||
IN PPDO_EXTENSION Pdx,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferSize,
|
||
OUT PULONG BytesTransferred
|
||
);
|
||
|
||
|
||
BOOLEAN
|
||
ParIsEppSwWriteSupported(
|
||
IN PPDO_EXTENSION Pdx
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine determines whether or not EPP mode is suported
|
||
in the write direction by trying negotiate when asked.
|
||
|
||
Arguments:
|
||
|
||
Pdx - The device extension.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwWriteSupported: Entering\n");
|
||
|
||
if (!(Pdx->HardwareCapabilities & PPT_ECP_PRESENT) &&
|
||
!(Pdx->HardwareCapabilities & PPT_BYTE_PRESENT)) {
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwWriteSupported: Hardware Not Supported Leaving\n");
|
||
// Only use EPP Software in the reverse direction if an ECR is
|
||
// present or we know that we can put the data register into Byte mode.
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
if (Pdx->BadProtocolModes & EPP_SW) {
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwWriteSupported: Not Supported Leaving\n");
|
||
return FALSE;
|
||
}
|
||
|
||
if (Pdx->ProtocolModesSupported & EPP_SW) {
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwWriteSupported: Supported Leaving\n");
|
||
return TRUE;
|
||
}
|
||
|
||
// Must use SWEPP Enter and Terminate for this test.
|
||
// Internel state machines will fail otherwise. --dvrh
|
||
Status = ParEnterEppSwMode (Pdx, FALSE);
|
||
ParTerminateEppSwMode (Pdx);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwWriteSupported: Negotiated Supported Leaving\n");
|
||
Pdx->ProtocolModesSupported |= EPP_SW;
|
||
return TRUE;
|
||
}
|
||
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwWriteSupported: Not Negotiated Not Supported Leaving\n");
|
||
return FALSE;
|
||
}
|
||
|
||
BOOLEAN
|
||
ParIsEppSwReadSupported(
|
||
IN PPDO_EXTENSION Pdx
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine determines whether or not EPP mode is suported
|
||
in the read direction (need to be able to float the data register
|
||
drivers in order to do byte wide reads) by trying negotiate when asked.
|
||
|
||
Arguments:
|
||
|
||
Pdx - The device extension.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
|
||
if (!(Pdx->HardwareCapabilities & PPT_ECP_PRESENT) &&
|
||
!(Pdx->HardwareCapabilities & PPT_BYTE_PRESENT)) {
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwReadSupported: Hardware Not Supported Leaving\n");
|
||
// Only use EPP Software in the reverse direction if an ECR is
|
||
// present or we know that we can put the data register into Byte mode.
|
||
return FALSE;
|
||
}
|
||
|
||
if (Pdx->BadProtocolModes & EPP_SW)
|
||
return FALSE;
|
||
|
||
if (Pdx->ProtocolModesSupported & EPP_SW)
|
||
return TRUE;
|
||
|
||
// Must use SWEPP Enter and Terminate for this test.
|
||
// Internel state machines will fail otherwise. --dvrh
|
||
Status = ParEnterEppSwMode (Pdx, FALSE);
|
||
ParTerminateEppSwMode (Pdx);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwReadSupported: Negotiated Supported Leaving\n");
|
||
Pdx->ProtocolModesSupported |= EPP_SW;
|
||
return TRUE;
|
||
}
|
||
|
||
DD((PCE)Pdx,DDT,"ParIsEppSwReadSupported: Not Negotiated Not Supported Leaving\n");
|
||
return FALSE;
|
||
}
|
||
|
||
NTSTATUS
|
||
ParEnterEppSwMode(
|
||
IN PPDO_EXTENSION Pdx,
|
||
IN BOOLEAN DeviceIdRequest
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs 1284 negotiation with the peripheral to the
|
||
EPP 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;
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: Entering\n");
|
||
|
||
// Parport Set Chip mode will put the Chip into Byte Mode if Capable
|
||
// We need it for Epp Sw Mode
|
||
Status = Pdx->TrySetChipMode( Pdx->PortContext, ECR_BYTE_PIO_MODE );
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
if ( Pdx->ModeSafety == SAFE_MODE ) {
|
||
if (DeviceIdRequest) {
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: Calling IeeeEnter1284Mode with DEVICE_ID_REQUEST\n");
|
||
Status = IeeeEnter1284Mode (Pdx, EPP_EXTENSIBILITY | DEVICE_ID_REQ);
|
||
} else {
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: Calling IeeeEnter1284Mode\n");
|
||
Status = IeeeEnter1284Mode (Pdx, EPP_EXTENSIBILITY);
|
||
}
|
||
} else {
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: In UNSAFE_MODE.\n");
|
||
Pdx->Connected = TRUE;
|
||
}
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: IeeeEnter1284Mode returned success\n");
|
||
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
|
||
Pdx->IsIeeeTerminateOk = TRUE;
|
||
|
||
} else {
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: IeeeEnter1284Mode returned unsuccessful\n");
|
||
P5SetPhase( Pdx, PHASE_UNKNOWN );
|
||
Pdx->IsIeeeTerminateOk = FALSE;
|
||
}
|
||
|
||
DD((PCE)Pdx,DDT,"ParEnterEppSwMode: Leaving with Status : %x \n", Status);
|
||
|
||
return Status;
|
||
}
|
||
|
||
VOID
|
||
ParTerminateEppSwMode(
|
||
IN PPDO_EXTENSION Pdx
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine terminates the interface back to compatibility mode.
|
||
|
||
Arguments:
|
||
|
||
Pdx - The Device Extension which has the parallel port's controller address.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParTerminateEppMode: Entering\n");
|
||
if ( Pdx->ModeSafety == SAFE_MODE ) {
|
||
IeeeTerminate1284Mode (Pdx);
|
||
} else {
|
||
DD((PCE)Pdx,DDT,"ParTerminateEppMode: In UNSAFE_MODE.\n");
|
||
Pdx->Connected = FALSE;
|
||
}
|
||
Pdx->ClearChipMode( Pdx->PortContext, ECR_BYTE_PIO_MODE );
|
||
DD((PCE)Pdx,DDT,"ParTerminateEppMode: Leaving\n");
|
||
return;
|
||
}
|
||
|
||
NTSTATUS
|
||
ParEppSwWrite(
|
||
IN PPDO_EXTENSION Pdx,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferSize,
|
||
OUT PULONG BytesTransferred
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Writes data to the peripheral using the EPP protocol under software
|
||
control.
|
||
|
||
Arguments:
|
||
|
||
Pdx - Supplies the device extension.
|
||
|
||
Buffer - Supplies the buffer to write from.
|
||
|
||
BufferSize - Supplies the number of bytes in the buffer.
|
||
|
||
BytesTransferred - Returns the number of bytes transferred.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PUCHAR Controller;
|
||
PUCHAR pBuffer = (PUCHAR)Buffer;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG i, j;
|
||
UCHAR HDReady, HDAck, HDFinished;
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEppSwWrite: Entering\n");
|
||
|
||
Controller = Pdx->Controller;
|
||
|
||
P5SetPhase( Pdx, PHASE_FORWARD_XFER );
|
||
|
||
// BIT5 of DCR needs to be low to be in BYTE forward mode
|
||
HDReady = SET_DCR( INACTIVE, INACTIVE, ACTIVE, ACTIVE, INACTIVE, INACTIVE );
|
||
HDAck = SET_DCR( INACTIVE, INACTIVE, ACTIVE, ACTIVE, ACTIVE, INACTIVE );
|
||
HDFinished = SET_DCR( INACTIVE, INACTIVE, ACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
||
|
||
for (i = 0; i < BufferSize; i++) {
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEppSwWrite: Writing Byte to port\n");
|
||
|
||
P5WritePortBufferUchar( Controller, pBuffer++, (ULONG)0x01 );
|
||
|
||
//
|
||
// Event 62
|
||
//
|
||
StoreControl (Controller, HDReady);
|
||
|
||
// =============== Periph State 58 ===============
|
||
// Should wait up to 10 micro Seconds but waiting up
|
||
// to 15 micro just in case
|
||
for ( j = 16; j > 0; j-- ) {
|
||
if( !(GetStatus(Controller) & DSR_NOT_BUSY) )
|
||
break;
|
||
KeStallExecutionProcessor(1);
|
||
}
|
||
|
||
// see if we timed out on state 58
|
||
if ( !j ) {
|
||
// Time out.
|
||
// Bad things happened - timed out on this state,
|
||
// Mark Status as bad and let our mgr kill current mode.
|
||
Status = STATUS_IO_DEVICE_ERROR;
|
||
|
||
DD((PCE)Pdx,DDE,"ParEppSwModeWrite:Failed State 58: Controller %x\n", Controller);
|
||
P5SetPhase( Pdx, PHASE_UNKNOWN );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Event 63
|
||
//
|
||
StoreControl (Controller, HDAck);
|
||
|
||
// =============== Periph State 60 ===============
|
||
// Should wait up to 125 nano Seconds but waiting up
|
||
// to 5 micro seconds just in case
|
||
for ( j = 6; j > 0; j-- ) {
|
||
if( GetStatus(Controller) & DSR_NOT_BUSY )
|
||
break;
|
||
KeStallExecutionProcessor(1);
|
||
}
|
||
|
||
if( !j ) {
|
||
// Time out.
|
||
// Bad things happened - timed out on this state,
|
||
// Mark Status as bad and let our mgr kill current mode.
|
||
Status = STATUS_IO_DEVICE_ERROR;
|
||
|
||
DD((PCE)Pdx,DDE,"ParEppSwModeWrite:Failed State 60: Controller %x\n", Controller);
|
||
P5SetPhase( Pdx, PHASE_UNKNOWN );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Event 61
|
||
//
|
||
StoreControl (Controller, HDFinished);
|
||
|
||
// Stall a little bit between data bytes
|
||
KeStallExecutionProcessor(1);
|
||
|
||
}
|
||
|
||
*BytesTransferred = i;
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEppSwWrite: Leaving with %i Bytes Transferred\n", i);
|
||
|
||
if ( Status == STATUS_SUCCESS )
|
||
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ParEppSwRead(
|
||
IN PPDO_EXTENSION Pdx,
|
||
IN PVOID Buffer,
|
||
IN ULONG BufferSize,
|
||
OUT PULONG BytesTransferred
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs a 1284 EPP mode read under software control
|
||
into the given buffer for no more than 'BufferSize' bytes.
|
||
|
||
Arguments:
|
||
|
||
Pdx - Supplies the device extension.
|
||
|
||
Buffer - Supplies the buffer to read into.
|
||
|
||
BufferSize - Supplies the number of bytes in the buffer.
|
||
|
||
BytesTransferred - Returns the number of bytes transferred.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR Controller;
|
||
PUCHAR pBuffer = (PUCHAR)Buffer;
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG i, j;
|
||
UCHAR dcr;
|
||
UCHAR HDReady, HDAck;
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEppSwRead: Entering\n");
|
||
|
||
Controller = Pdx->Controller;
|
||
|
||
P5SetPhase( Pdx, PHASE_REVERSE_XFER );
|
||
|
||
// Save off Control
|
||
dcr = GetControl (Controller);
|
||
|
||
// BIT5 of DCR needs to be high to be in BYTE reverse mode
|
||
HDReady = SET_DCR( ACTIVE, INACTIVE, ACTIVE, ACTIVE, INACTIVE, ACTIVE );
|
||
HDAck = SET_DCR( ACTIVE, INACTIVE, ACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
||
|
||
// First time to get into reverse mode quickly
|
||
StoreControl (Controller, HDReady);
|
||
|
||
for (i = 0; i < BufferSize; i++) {
|
||
|
||
//
|
||
// Event 67
|
||
//
|
||
StoreControl (Controller, HDReady);
|
||
|
||
// =============== Periph State 58 ===============
|
||
// Should wait up to 10 micro Seconds but waiting up
|
||
// to 15 micro just in case
|
||
for ( j = 16; j > 0; j-- ) {
|
||
if( !(GetStatus(Controller) & DSR_NOT_BUSY) )
|
||
break;
|
||
KeStallExecutionProcessor(1);
|
||
}
|
||
|
||
// see if we timed out on state 58
|
||
if ( !j ) {
|
||
// Time out.
|
||
// Bad things happened - timed out on this state,
|
||
// Mark Status as bad and let our mgr kill current mode.
|
||
Status = STATUS_IO_DEVICE_ERROR;
|
||
|
||
DD((PCE)Pdx,DDE,"ParEppSwRead:Failed State 58: Controller %x\n", Controller);
|
||
P5SetPhase( Pdx, PHASE_UNKNOWN );
|
||
break;
|
||
}
|
||
|
||
// Read the Byte
|
||
P5ReadPortBufferUchar( Controller,
|
||
pBuffer++,
|
||
(ULONG)0x01 );
|
||
|
||
//
|
||
// Event 63
|
||
//
|
||
StoreControl (Controller, HDAck);
|
||
|
||
// =============== Periph State 60 ===============
|
||
// Should wait up to 125 nano Seconds but waiting up
|
||
// to 5 micro seconds just in case
|
||
for ( j = 6; j > 0; j-- ) {
|
||
if( GetStatus(Controller) & DSR_NOT_BUSY )
|
||
break;
|
||
KeStallExecutionProcessor(1);
|
||
}
|
||
|
||
if( !j ) {
|
||
// Time out.
|
||
// Bad things happened - timed out on this state,
|
||
// Mark Status as bad and let our mgr kill current mode.
|
||
Status = STATUS_IO_DEVICE_ERROR;
|
||
|
||
DD((PCE)Pdx,DDE,"ParEppSwRead:Failed State 60: Controller %x\n", Controller);
|
||
P5SetPhase( Pdx, PHASE_UNKNOWN );
|
||
break;
|
||
}
|
||
|
||
// Stall a little bit between data bytes
|
||
KeStallExecutionProcessor(1);
|
||
}
|
||
|
||
dcr &= ~DCR_DIRECTION;
|
||
StoreControl (Controller, dcr);
|
||
|
||
*BytesTransferred = i;
|
||
|
||
// dvdr
|
||
DD((PCE)Pdx,DDT,"ParEppSwRead: Leaving with %x Bytes Transferred\n", i);
|
||
|
||
if ( Status == STATUS_SUCCESS )
|
||
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
|
||
|
||
return Status;
|
||
|
||
}
|