1316 lines
37 KiB
C
1316 lines
37 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (C) Microsoft Corporation, 1993 - 1999
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
parmode.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is the main module for Extended Parallel Port (ECP) and
|
|||
|
Enhanced Parallel Port (EPP) detection. This module
|
|||
|
will detect for invalid chipshets and do ECR detection
|
|||
|
for ECP and EPP hardware support if the invalid chipset
|
|||
|
is not found.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Don Redford (v-donred) 4-Mar-1998
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History :
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
#define USE_PARCHIP_ECRCONTROLLER 1
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptDetectChipFilter(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called once per DeviceObject to see if the filter driver
|
|||
|
for detecting parallel chip capabilities is there and to get the chip
|
|||
|
capabilities if there of the port in question.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if we were able detect the chip and modes possible.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_NO_SUCH_DEVICE;
|
|||
|
PIRP Irp;
|
|||
|
KEVENT Event;
|
|||
|
IO_STATUS_BLOCK IoStatus;
|
|||
|
UCHAR ecrLast;
|
|||
|
PUCHAR Controller, EcpController;
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
EcpController = Fdx->PnpInfo.EcpController;
|
|||
|
|
|||
|
// Setting variable to FALSE to make sure we do not acidentally succeed
|
|||
|
Fdx->ChipInfo.success = FALSE;
|
|||
|
|
|||
|
// Setting the Address to send to the filter driver to check the chips
|
|||
|
Fdx->ChipInfo.Controller = Controller;
|
|||
|
|
|||
|
// Setting the Address to send to the filter driver to check the chips
|
|||
|
Fdx->ChipInfo.EcrController = EcpController;
|
|||
|
|
|||
|
#ifndef USE_PARCHIP_ECRCONTROLLER
|
|||
|
// if there is not value in the ECR controller then PARCHIP and PARPORT
|
|||
|
// will conflict and PARCHIP will not work with PARPORT unless we
|
|||
|
// use the ECR controller found by PARCHIP.
|
|||
|
if ( !EcpController ) {
|
|||
|
return Status;
|
|||
|
}
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Initialize
|
|||
|
//
|
|||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
// Send a Pointer to the ChipInfo structure to and from the filter
|
|||
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_PARCHIP_CONNECT,
|
|||
|
Fdx->ParentDeviceObject,
|
|||
|
&Fdx->ChipInfo,
|
|||
|
sizeof(PARALLEL_PARCHIP_INFO),
|
|||
|
&Fdx->ChipInfo,
|
|||
|
sizeof(PARALLEL_PARCHIP_INFO),
|
|||
|
TRUE, &Event, &IoStatus);
|
|||
|
|
|||
|
if (!Irp) {
|
|||
|
// couldn't create an IRP
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Call down to our parent and see if Filter is present
|
|||
|
//
|
|||
|
Status = IoCallDriver(Fdx->ParentDeviceObject, Irp);
|
|||
|
|
|||
|
if (Status == STATUS_PENDING) {
|
|||
|
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
|||
|
Status = Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If successful then we have a filter driver and we need to get the modes supported
|
|||
|
//
|
|||
|
if ( NT_SUCCESS(Status) ) {
|
|||
|
|
|||
|
//
|
|||
|
// check to see if the filter driver was able to determine the I/O chip
|
|||
|
//
|
|||
|
if ( Fdx->ChipInfo.success ) {
|
|||
|
Fdx->PnpInfo.HardwareCapabilities = Fdx->ChipInfo.HardwareModes;
|
|||
|
#ifdef USE_PARCHIP_ECRCONTROLLER
|
|||
|
// only replace it if defined
|
|||
|
if ( Fdx->PnpInfo.EcpController != Fdx->ChipInfo.EcrController ) {
|
|||
|
Fdx->PnpInfo.EcpController = Fdx->ChipInfo.EcrController;
|
|||
|
EcpController = Fdx->PnpInfo.EcpController;
|
|||
|
}
|
|||
|
#endif
|
|||
|
// Set variable to say we have a filter driver
|
|||
|
Fdx->FilterMode = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// if there is a filter and ECP capable we need to get the Fifo Size
|
|||
|
if ( Fdx->FilterMode && Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {
|
|||
|
|
|||
|
Status = Fdx->ChipInfo.ParChipSetMode ( Fdx->ChipInfo.Context, ECR_ECP_MODE );
|
|||
|
|
|||
|
// if able to set ECP mode
|
|||
|
if ( NT_SUCCESS( Status ) ) {
|
|||
|
PUCHAR wPortECR;
|
|||
|
|
|||
|
wPortECR = EcpController + ECR_OFFSET;
|
|||
|
|
|||
|
// get value from ECR reg & save it
|
|||
|
ecrLast = P5ReadPortUchar( wPortECR );
|
|||
|
|
|||
|
// Determining Fifo Size
|
|||
|
PptDetermineFifoWidth(Fdx);
|
|||
|
PptDetermineFifoDepth(Fdx);
|
|||
|
|
|||
|
// return ecr to original
|
|||
|
P5WritePortUchar( wPortECR, ecrLast);
|
|||
|
|
|||
|
Status = Fdx->ChipInfo.ParChipClearMode ( Fdx->ChipInfo.Context, ECR_ECP_MODE );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptDetectPortType(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called once per DeviceObject to detect the type of
|
|||
|
parallel chip capabilities of the port in question.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if we were able detect the chip and modes possible.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING ParportPath;
|
|||
|
RTL_QUERY_REGISTRY_TABLE RegTable[2];
|
|||
|
ULONG IdentifierHex = 12169;
|
|||
|
ULONG zero = 0;
|
|||
|
|
|||
|
//
|
|||
|
// -- May want to get detection order from Registry.
|
|||
|
// -- May also want to store/retrieve last known good configuration in/from registry.
|
|||
|
// -- Finally we should set a registry flag during dection so that we'll know
|
|||
|
// if we crashed while attempting to detect and not try it again.
|
|||
|
//
|
|||
|
RtlInitUnicodeString(&ParportPath, (PWSTR)L"Parport");
|
|||
|
|
|||
|
// Setting up to get the Parport info
|
|||
|
RtlZeroMemory( RegTable, sizeof(RegTable) );
|
|||
|
|
|||
|
RegTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|||
|
RegTable[0].Name = (PWSTR)L"ModeCheckedStalled";
|
|||
|
RegTable[0].EntryContext = &IdentifierHex;
|
|||
|
RegTable[0].DefaultType = REG_DWORD;
|
|||
|
RegTable[0].DefaultData = &zero;
|
|||
|
RegTable[0].DefaultLength = sizeof(ULONG);
|
|||
|
|
|||
|
//
|
|||
|
// Querying the registry for Parport to see if we tried to go check mode and we crashed
|
|||
|
// the registry key would still be there
|
|||
|
//
|
|||
|
Status = RtlQueryRegistryValues(
|
|||
|
RTL_REGISTRY_SERVICES,
|
|||
|
ParportPath.Buffer,
|
|||
|
RegTable,
|
|||
|
NULL,
|
|||
|
NULL );
|
|||
|
|
|||
|
//
|
|||
|
// if registry key is there then we will just check ECP and Byte
|
|||
|
//
|
|||
|
if ( !(NT_SUCCESS( Status ) && IdentifierHex == 0) && (Status != STATUS_OBJECT_NAME_NOT_FOUND) ) {
|
|||
|
|
|||
|
// dvtw, Check for ECP anyway! We just won't turn it on
|
|||
|
|
|||
|
PptDetectEcpPort(Fdx);
|
|||
|
PptDetectBytePort(Fdx);
|
|||
|
|
|||
|
if( Fdx->PnpInfo.HardwareCapabilities & (PPT_ECP_PRESENT | PPT_BYTE_PRESENT) ) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
return STATUS_NO_SUCH_DEVICE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IdentifierHex = 12169;
|
|||
|
// Write the registry key out there just in case we crash
|
|||
|
Status = RtlWriteRegistryValue(
|
|||
|
RTL_REGISTRY_SERVICES,
|
|||
|
ParportPath.Buffer,
|
|||
|
(PWSTR)L"ModeCheckedStalled",
|
|||
|
REG_DWORD,
|
|||
|
&IdentifierHex,
|
|||
|
sizeof(ULONG) );
|
|||
|
|
|||
|
//
|
|||
|
// Now we can start detecting the parallel port chip capabilities
|
|||
|
//
|
|||
|
Status = PptDetectPortCapabilities( Fdx );
|
|||
|
|
|||
|
// Delete the registry key out there since we finished
|
|||
|
Status = RtlDeleteRegistryValue( RTL_REGISTRY_SERVICES, ParportPath.Buffer, (PWSTR)L"ModeCheckedStalled" );
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptDetectPortCapabilities(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the "default" detection code, which looks for an ECR. If the ECR
|
|||
|
is present it tries to set mode 100b in <7:5>. If it sticks we'll call it
|
|||
|
EPP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the port type was detected.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
PptDetectEcpPort( Fdx );
|
|||
|
|
|||
|
// dvdr
|
|||
|
//
|
|||
|
// if we did not detect an ECR for ECP mode and ECP mode failed
|
|||
|
// EPP mode would fail also
|
|||
|
// Also cannot have EPP mode at an address that ends with a "C"
|
|||
|
//
|
|||
|
if ( (Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT) &&
|
|||
|
(((ULONG_PTR)Fdx->PortInfo.Controller & 0x0F) != 0x0C) ) {
|
|||
|
|
|||
|
// Need to check for National chipsets before trying EPP mode
|
|||
|
// dvdr - need to add detection for old Winbond
|
|||
|
|
|||
|
Status = PptFindNatChip( Fdx );
|
|||
|
|
|||
|
if ( NT_SUCCESS( Status ) ) {
|
|||
|
if ( !Fdx->NationalChipFound ) {
|
|||
|
// National chipset was NOT found so we can see if generic EPP is supported
|
|||
|
|
|||
|
PptDetectEppPortIfDot3DevicePresent( Fdx );
|
|||
|
|
|||
|
if( !Fdx->CheckedForGenericEpp ) {
|
|||
|
// we didn't have a dot3 device to use for screening, do check anyway
|
|||
|
// if user has explicitly requested EPP detection
|
|||
|
PptDetectEppPortIfUserRequested( Fdx );
|
|||
|
}
|
|||
|
} else {
|
|||
|
// National chipset was found so can't do generic EPP
|
|||
|
Fdx->CheckedForGenericEpp = TRUE; // check is complete - generic EPP is unsafe
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
// ECP failed no check for Generic EPP
|
|||
|
Fdx->CheckedForGenericEpp = TRUE; // check is complete - generic EPP is unsafe
|
|||
|
}
|
|||
|
|
|||
|
PptDetectBytePort( Fdx );
|
|||
|
|
|||
|
if (Fdx->PnpInfo.HardwareCapabilities & (PPT_ECP_PRESENT | PPT_EPP_PRESENT | PPT_BYTE_PRESENT) ) {
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_NO_SUCH_DEVICE;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PptDetectEcpPort(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine looks for the presence of an ECR register to determine that
|
|||
|
it has ECP.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension of the device we are
|
|||
|
reporting resources for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUCHAR Controller;
|
|||
|
PUCHAR wPortDCR; // IO address of Device Control Register (DCR)
|
|||
|
PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
|
|||
|
UCHAR ecrLast, ecr, dcr;
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
wPortDCR = Controller + DCR_OFFSET;
|
|||
|
|
|||
|
if( 0 == Fdx->PnpInfo.EcpController ) {
|
|||
|
// PnP didn't give us an ECP Register set - we're done here
|
|||
|
return;
|
|||
|
}
|
|||
|
wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
|
|||
|
|
|||
|
ecrLast = ecr = P5ReadPortUchar(wPortECR);
|
|||
|
|
|||
|
// Initialize the DCR's nAutoFeed and nStrobe to a harmless combination
|
|||
|
// that could be returned by the ECR, but is not likely to be returned if
|
|||
|
// the ECR isn't present. Depending on the host's address decode logic,
|
|||
|
// reading a non-existant ECR could have one of two results: the ECR address
|
|||
|
// could decode on top of the DCR, so we'll read the value we are about to set.
|
|||
|
// Alternately, we might just read a floating bus and get a random value.
|
|||
|
dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, INACTIVE, ACTIVE );
|
|||
|
P5WritePortUchar( wPortDCR, dcr );
|
|||
|
|
|||
|
ecrLast = ecr = P5ReadPortUchar(wPortECR);
|
|||
|
|
|||
|
|
|||
|
// Attempt to read the ECR. If ECP hardware is present, the ECR register's
|
|||
|
// bit 1 and bit 0 should read a 00 (some data in the FIFO), 01 (FIFO empty),
|
|||
|
// or 10 (FIFO full). If we read a 11 (illegal combination) then we know for
|
|||
|
// sure that no ECP hardware is present. Also, a valid ECR should never return
|
|||
|
// 0xFF (but a nonexistant register probably would), so we'll test for that
|
|||
|
// specific value also.
|
|||
|
if ( ( TEST_ECR_FIFO( ecr, ECR_FIFO_MASK ) ) || ( ecrLast == 0xFF ) ) {
|
|||
|
// ECR[1:0] returned a value of 11, so this can't be hardware ECP.
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectEcpPort: illegal FIFO status\n");
|
|||
|
|
|||
|
// Restore the DCR so that all lines are inactive.
|
|||
|
dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
|||
|
P5WritePortUchar( wPortDCR, dcr );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// OK, so we got either a 00, 01, or 10 for ECR[1:0]. If it was 10, the
|
|||
|
if( TEST_ECR_FIFO( ecr, ECR_FIFO_FULL ) ) { // Looking for ECR[1:0] of 10...
|
|||
|
|
|||
|
// The ECR[1:0] returned 10. This is a legal value, but possibly the
|
|||
|
// hardware might have just decoded the DCR and we merely read back the
|
|||
|
// DCR value we set earlier. Or, we might have just read back a value
|
|||
|
// that was hanging on the bus due to bus capacitance. So, we'll change
|
|||
|
// the DCR, read the ECR again, and see if the two registers continue to
|
|||
|
// track each other. If they do track, we'll conclude that there is no
|
|||
|
// ECP hardware.
|
|||
|
|
|||
|
// Put the DCR's nAutoFeed and nStrobe register bits back to zero.
|
|||
|
dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
|||
|
P5WritePortUchar( wPortDCR, dcr );
|
|||
|
|
|||
|
// Read the ECR again
|
|||
|
ecr = P5ReadPortUchar( wPortECR );
|
|||
|
|
|||
|
if ( TEST_ECR_FIFO( ecr, ECR_FIFO_SOME_DATA ) ) {
|
|||
|
// ECR[1:0] is tracking DCR[1:0], so this can't be hardware ECP.
|
|||
|
|
|||
|
// Restore the DCR so that all lines are inactive.
|
|||
|
dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
|||
|
P5WritePortUchar( wPortDCR, dcr );
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// If we get this far, then the ECR appears to be returning something valid that
|
|||
|
// doesn't track the DCR. It is beginning to look promising. We're going
|
|||
|
// to take a chance, and write the ECR to put the chip in compatiblity
|
|||
|
// mode. Doing so will reset the FIFO, so when we read FIFO status it should
|
|||
|
// come back empty. However, if we're wrong and this isn't ECP hardware, the
|
|||
|
// value we're about to write will turn on 1284Active (nSelectIn) and this might
|
|||
|
// cause headaches for the peripheral.
|
|||
|
P5WritePortUchar( wPortECR, DEFAULT_ECR_COMPATIBILITY );
|
|||
|
|
|||
|
// Read the ECR again
|
|||
|
ecr = P5ReadPortUchar( wPortECR );
|
|||
|
|
|||
|
// Now test the ECR snapshot to see if the FIFO status is correct. The FIFO
|
|||
|
// should test empty.
|
|||
|
if (!TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) )
|
|||
|
{
|
|||
|
// Restore the DCR so that all lines are inactive.
|
|||
|
dcr = SET_DCR( DIR_WRITE, IRQEN_DISABLE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
|
|||
|
P5WritePortUchar( wPortDCR, dcr );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// OK, it looks very promising. Perform a couple of additional tests that
|
|||
|
// will give us a lot of confidence, as well as providing some information
|
|||
|
// we need about the ECP chip.
|
|||
|
|
|||
|
// return ecr to original
|
|||
|
P5WritePortUchar(wPortECR, ecrLast);
|
|||
|
|
|||
|
//
|
|||
|
// Test here for ECP capable
|
|||
|
//
|
|||
|
|
|||
|
// get value from ECR reg & save it
|
|||
|
ecrLast = P5ReadPortUchar( wPortECR );
|
|||
|
ecr = (UCHAR)(ecrLast & ECR_MODE_MASK);
|
|||
|
|
|||
|
// Put the chip into test mode; the FIFO should start out empty
|
|||
|
P5WritePortUchar(wPortECR, (UCHAR)(ecr | ECR_TEST_MODE) );
|
|||
|
|
|||
|
PptDetermineFifoWidth(Fdx);
|
|||
|
if( 0 != Fdx->PnpInfo.FifoWidth) {
|
|||
|
Fdx->PnpInfo.HardwareCapabilities |= PPT_ECP_PRESENT;
|
|||
|
|
|||
|
PptDetermineFifoDepth( Fdx );
|
|||
|
|
|||
|
if( 0 == Fdx->PnpInfo.FifoDepth ) {
|
|||
|
// Probe for FIFO depth failed - mark ECP as bad chip mode
|
|||
|
Fdx->PnpInfo.HardwareCapabilities &= ~(PPT_ECP_PRESENT);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// return ecr to original
|
|||
|
P5WritePortUchar( wPortECR, ecrLast );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PptDetectEppPortIfDot3DevicePresent(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
If a 1284.3 daisy chain device is present, use the dot3 device to screen
|
|||
|
any printer from signal leakage while doing EPP detection. Otherwise
|
|||
|
abort detection.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension of the device we are
|
|||
|
reporting resources for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PUCHAR Controller = Fdx->PortInfo.Controller;
|
|||
|
PARALLEL_1284_COMMAND Command;
|
|||
|
|
|||
|
if( 0 == Fdx->PnpInfo.Ieee1284_3DeviceCount ) {
|
|||
|
// No dot3 DC device present - aborting - unsafe for some printers if we check for EPP here
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// 1284.3 daisy chain device is present. Use device to screen printer from
|
|||
|
// possible signal leakage.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Select 1284.3 daisy chain device
|
|||
|
//
|
|||
|
Command.ID = 0;
|
|||
|
Command.Port = 0;
|
|||
|
Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
|
|||
|
status = PptTrySelectDevice( Fdx, &Command );
|
|||
|
if( !NT_SUCCESS( status ) ) {
|
|||
|
// unable to select device - something is wrong - just bail out
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// do the detection for chipset EPP capability
|
|||
|
//
|
|||
|
// DOT3 Device Present and selected
|
|||
|
PptDetectEppPort( Fdx );
|
|||
|
|
|||
|
//
|
|||
|
// Deselect 1284.3 daisy chain device
|
|||
|
//
|
|||
|
Command.ID = 0;
|
|||
|
Command.Port = 0;
|
|||
|
Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
|
|||
|
status = PptDeselectDevice( Fdx, &Command );
|
|||
|
if( !NT_SUCCESS( status ) ) {
|
|||
|
// deselect failed??? - this shouldn't happen - our daisy chain interface is likely hung
|
|||
|
DD((PCE)Fdx,DDE,"PptDetectEppPort - deselect of 1284.3 device FAILED - Controller=%x\n", Controller);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PptDetectEppPortIfUserRequested(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
If user explicitly requested Generic EPP detection then do the check.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension of the device we are
|
|||
|
reporting resources for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG RequestEppTest = 0;
|
|||
|
PptRegGetDeviceParameterDword( Fdx->PhysicalDeviceObject, (PWSTR)L"RequestEppTest", &RequestEppTest );
|
|||
|
if( RequestEppTest ) {
|
|||
|
DD((PCE)Fdx,DDT,"-- User Requested EPP detection - %x\n", RequestEppTest);
|
|||
|
PptDetectEppPort( Fdx );
|
|||
|
} else {
|
|||
|
DD((PCE)Fdx,DDT,"-- User did not request EPP detection\n");
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PptDetectEppPort(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks for EPP capable port after ECP was found.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension of the device we are
|
|||
|
reporting resources for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUCHAR Controller;
|
|||
|
UCHAR dcr, i;
|
|||
|
UCHAR Reverse = (UCHAR)(DCR_DIRECTION | DCR_NOT_INIT | DCR_AUTOFEED | DCR_DSTRB);
|
|||
|
UCHAR Forward = (UCHAR)(DCR_NOT_INIT | DCR_AUTOFEED | DCR_DSTRB);
|
|||
|
|
|||
|
ASSERTMSG(FALSE, "PptDetectEppPort shouldn't be called in current driver version");
|
|||
|
|
|||
|
DD((PCE)Fdx,DDT,"-- PptDetectEppPort - Enter\n");
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: Enter\n");
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
|
|||
|
// Get current DCR
|
|||
|
dcr = P5ReadPortUchar( Controller + DCR_OFFSET );
|
|||
|
|
|||
|
//
|
|||
|
// Temporarily set capability to true to bypass PptEcrSetMode validity
|
|||
|
// check. We'll clear the flag before we return if EPP test fails.
|
|||
|
//
|
|||
|
Fdx->PnpInfo.HardwareCapabilities |= PPT_EPP_PRESENT;
|
|||
|
|
|||
|
// Setting EPP mode
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: Setting EPP Mode\n");
|
|||
|
PptEcrSetMode( Fdx, ECR_EPP_PIO_MODE );
|
|||
|
|
|||
|
//
|
|||
|
// Testing the hardware for EPP capable
|
|||
|
//
|
|||
|
for ( i = 0x01; i <= 0x02; i++ ) {
|
|||
|
// Put it into reverse phase so it doesn't talk to a device
|
|||
|
P5WritePortUchar( Controller + DCR_OFFSET, Reverse );
|
|||
|
KeStallExecutionProcessor( 5 );
|
|||
|
P5WritePortUchar( Controller + EPP_OFFSET, (UCHAR)i );
|
|||
|
|
|||
|
// put it back into forward phase to read the byte we put out there
|
|||
|
P5WritePortUchar( Controller + DCR_OFFSET, Forward );
|
|||
|
KeStallExecutionProcessor( 5 );
|
|||
|
if ( P5ReadPortUchar( Controller ) != i ) {
|
|||
|
// failure so clear EPP flag
|
|||
|
Fdx->PnpInfo.HardwareCapabilities &= ~PPT_EPP_PRESENT;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Clearing EPP Mode
|
|||
|
PptEcrClearMode( Fdx );
|
|||
|
// Restore DCR
|
|||
|
P5WritePortUchar( Controller + DCR_OFFSET, dcr );
|
|||
|
|
|||
|
Fdx->CheckedForGenericEpp = TRUE; // check is complete
|
|||
|
|
|||
|
if( Fdx->PnpInfo.HardwareCapabilities & PPT_EPP_PRESENT ) {
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: EPP present - Controller=%x\n", Controller);
|
|||
|
DD((PCE)Fdx,DDT,"-- PptDetectEppPort - HAVE Generic EPP\n");
|
|||
|
} else {
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectEppPort: EPP NOT present - Controller=%x\n", Controller);
|
|||
|
DD((PCE)Fdx,DDT,"-- PptDetectEppPort - DON'T HAVE Generic EPP\n");
|
|||
|
}
|
|||
|
|
|||
|
DD((PCE)Fdx,DDT,"-- PptDetectEppPort - Exit\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PptDetectBytePort(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine check to see if the port is Byte capable.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension of the device we are
|
|||
|
reporting resources for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectBytePort Enter.\n" );
|
|||
|
|
|||
|
Status = PptSetByteMode( Fdx, ECR_BYTE_PIO_MODE );
|
|||
|
|
|||
|
if ( NT_SUCCESS(Status) ) {
|
|||
|
// Byte Mode found
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectBytePort: Byte Found\n");
|
|||
|
Fdx->PnpInfo.HardwareCapabilities |= PPT_BYTE_PRESENT;
|
|||
|
} else {
|
|||
|
// Byte Mode Not Found
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetectBytePort: Byte Not Found\n");
|
|||
|
}
|
|||
|
|
|||
|
(VOID)PptClearByteMode( Fdx );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID PptDetermineFifoDepth(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
{
|
|||
|
PUCHAR Controller;
|
|||
|
PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
|
|||
|
PUCHAR wPortDFIFO;
|
|||
|
UCHAR ecr, ecrLast;
|
|||
|
ULONG wFifoDepth;
|
|||
|
UCHAR writeFifoDepth; // Depth calculated while writing FIFO
|
|||
|
UCHAR readFifoDepth; // Depth calculated while reading FIFO
|
|||
|
ULONG limitCount; // Prevents infinite looping on FIFO status
|
|||
|
UCHAR testData;
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
wPortECR = Fdx->PnpInfo.EcpController+ ECR_OFFSET;
|
|||
|
wPortDFIFO = Fdx->PnpInfo.EcpController;
|
|||
|
wFifoDepth = 0;
|
|||
|
|
|||
|
ecrLast = P5ReadPortUchar(wPortECR );
|
|||
|
|
|||
|
P5WritePortUchar(wPortECR, DEFAULT_ECR_TEST );
|
|||
|
|
|||
|
ecr = P5ReadPortUchar(wPortECR );
|
|||
|
|
|||
|
if ( TEST_ECR_FIFO( ecr, ECR_FIFO_EMPTY ) ) {
|
|||
|
|
|||
|
// Write bytes into the FIFO until it indicates full.
|
|||
|
writeFifoDepth = 0;
|
|||
|
limitCount = 0;
|
|||
|
|
|||
|
while (((P5ReadPortUchar (wPortECR) & ECR_FIFO_MASK) != ECR_FIFO_FULL ) &&
|
|||
|
(limitCount <= ECP_MAX_FIFO_DEPTH)) {
|
|||
|
|
|||
|
P5WritePortUchar( wPortDFIFO, (UCHAR)(writeFifoDepth & 0xFF) );
|
|||
|
writeFifoDepth++;
|
|||
|
limitCount++;
|
|||
|
}
|
|||
|
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth:: write fifo depth = %d\r\n", writeFifoDepth);
|
|||
|
|
|||
|
// Now read the bytes back, comparing what comes back.
|
|||
|
readFifoDepth = 0;
|
|||
|
limitCount = 0;
|
|||
|
|
|||
|
while (((P5ReadPortUchar( wPortECR ) & ECR_FIFO_MASK ) != ECR_FIFO_EMPTY ) &&
|
|||
|
(limitCount <= ECP_MAX_FIFO_DEPTH)) {
|
|||
|
|
|||
|
testData = P5ReadPortUchar( wPortDFIFO );
|
|||
|
if ( testData != (readFifoDepth & (UCHAR)0xFF )) {
|
|||
|
|
|||
|
// Data mismatch indicates problems...
|
|||
|
// FIFO status didn't pan out, may not be an ECP chip after all
|
|||
|
P5WritePortUchar( wPortECR, ecrLast);
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth::: data mismatch\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
readFifoDepth++;
|
|||
|
limitCount++;
|
|||
|
}
|
|||
|
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth::: read fifo depth = %d\r\n", readFifoDepth);
|
|||
|
|
|||
|
// The write depth should match the read depth...
|
|||
|
if ( writeFifoDepth == readFifoDepth ) {
|
|||
|
|
|||
|
wFifoDepth = readFifoDepth;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
// Assume no FIFO
|
|||
|
P5WritePortUchar( wPortECR, ecrLast);
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth::: No Fifo\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
// FIFO status didn't pan out, may not be an ECP chip after all
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoDepth:: Bad Fifo\n");
|
|||
|
P5WritePortUchar(wPortECR, ecrLast);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// put chip into spp mode
|
|||
|
P5WritePortUchar( wPortECR, ecrLast );
|
|||
|
Fdx->PnpInfo.FifoDepth = wFifoDepth;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PptDetermineFifoWidth(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
{
|
|||
|
PUCHAR Controller;
|
|||
|
UCHAR bConfigA;
|
|||
|
PUCHAR wPortECR;
|
|||
|
|
|||
|
DD((PCE)Fdx,DDT,"ParMode::PptDetermineFifoWidth: Start\n");
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
|
|||
|
wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
|
|||
|
|
|||
|
// Put chip into configuration mode so we can access the ConfigA register
|
|||
|
P5WritePortUchar( wPortECR, DEFAULT_ECR_CONFIGURATION );
|
|||
|
|
|||
|
// The FIFO width is bits <6:4> of the ConfigA register.
|
|||
|
bConfigA = P5ReadPortUchar( Fdx->PnpInfo.EcpController );
|
|||
|
Fdx->PnpInfo.FifoWidth = (ULONG)(( bConfigA & CNFGA_IMPID_MASK ) >> CNFGA_IMPID_SHIFT);
|
|||
|
|
|||
|
// Put the chip back in compatibility mode.
|
|||
|
P5WritePortUchar(wPortECR, DEFAULT_ECR_COMPATIBILITY );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptSetChipMode (
|
|||
|
IN PFDO_EXTENSION Fdx,
|
|||
|
IN UCHAR ChipMode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function will put the current parallel chip into the
|
|||
|
given mode if supported. The determination of supported mode
|
|||
|
was in the PptDetectPortType function.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the port type was detected.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
UCHAR EcrMode = (UCHAR)( ChipMode & ~ECR_MODE_MASK );
|
|||
|
|
|||
|
// Also allow PptSetChipMode from PS/2 mode - we need this for HWECP
|
|||
|
// bus flip from Forward to Reverse in order to meet the required
|
|||
|
// sequence specified in the Microsoft ECP Port Spec version 1.06,
|
|||
|
// July 14, 1993, to switch directly from PS/2 mode with output
|
|||
|
// drivers disabled (direction bit set to "read") to HWECP via
|
|||
|
// the ECR. Changed 2000-02-11.
|
|||
|
if ( Fdx->PnpInfo.CurrentMode != INITIAL_MODE && Fdx->PnpInfo.CurrentMode != ECR_BYTE_MODE ) {
|
|||
|
|
|||
|
DD((PCE)Fdx,DDW,"PptSetChipMode - CurrentMode invalid\n");
|
|||
|
|
|||
|
// Current mode is not valid to put in EPP or ECP mode
|
|||
|
Status = STATUS_INVALID_DEVICE_STATE;
|
|||
|
|
|||
|
goto ExitSetChipModeNoChange;
|
|||
|
}
|
|||
|
|
|||
|
// need to find out what mode it was and try to take it out of it
|
|||
|
|
|||
|
// Check to see if we need to use the filter to set the mode
|
|||
|
if ( Fdx->FilterMode ) {
|
|||
|
Status = Fdx->ChipInfo.ParChipSetMode ( Fdx->ChipInfo.Context, ChipMode );
|
|||
|
} else {
|
|||
|
|
|||
|
// If asked for ECP check to see if we can do it
|
|||
|
if ( EcrMode == ECR_ECP_MODE ) {
|
|||
|
if ((Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT) ^ PPT_ECP_PRESENT) {
|
|||
|
// ECP Not Present
|
|||
|
return STATUS_NO_SUCH_DEVICE;
|
|||
|
}
|
|||
|
Status = PptEcrSetMode ( Fdx, ChipMode );
|
|||
|
goto ExitSetChipModeWithChanges;
|
|||
|
}
|
|||
|
|
|||
|
// If asked for EPP check to see if we can do it
|
|||
|
if ( EcrMode == ECR_EPP_MODE ) {
|
|||
|
if ((Fdx->PnpInfo.HardwareCapabilities & PPT_EPP_PRESENT) ^ PPT_EPP_PRESENT) {
|
|||
|
// EPP Not Present
|
|||
|
return STATUS_NO_SUCH_DEVICE;
|
|||
|
}
|
|||
|
Status = PptEcrSetMode ( Fdx, ChipMode );
|
|||
|
goto ExitSetChipModeWithChanges;
|
|||
|
}
|
|||
|
|
|||
|
// If asked for Byte Mode check to see if it is still enabled
|
|||
|
if ( EcrMode == ECR_BYTE_MODE ) {
|
|||
|
if ((Fdx->PnpInfo.HardwareCapabilities & PPT_BYTE_PRESENT) ^ PPT_BYTE_PRESENT) {
|
|||
|
// BYTE Not Present
|
|||
|
return STATUS_NO_SUCH_DEVICE;
|
|||
|
}
|
|||
|
Status = PptSetByteMode ( Fdx, ChipMode );
|
|||
|
goto ExitSetChipModeWithChanges;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExitSetChipModeWithChanges:
|
|||
|
|
|||
|
if ( NT_SUCCESS(Status) ) {
|
|||
|
Fdx->PnpInfo.CurrentMode = EcrMode;
|
|||
|
} else {
|
|||
|
DD((PCE)Fdx,DDW,"PptSetChipMode - failed w/status = %x\n",Status);
|
|||
|
}
|
|||
|
|
|||
|
ExitSetChipModeNoChange:
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptClearChipMode (
|
|||
|
IN PFDO_EXTENSION Fdx,
|
|||
|
IN UCHAR ChipMode
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine Clears the Given chip mode.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
ChipMode - The given mode to clear from the Chip
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the port type was detected.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|||
|
ULONG EcrMode = ChipMode & ~ECR_MODE_MASK;
|
|||
|
|
|||
|
// make sure we have a mode to clear
|
|||
|
if ( EcrMode != Fdx->PnpInfo.CurrentMode ) {
|
|||
|
|
|||
|
DD((PCE)Fdx,DDW,"ParMode::PptClearChipMode: Mode to Clear != CurrentModen");
|
|||
|
|
|||
|
// Current mode is not the same as requested to take it out of
|
|||
|
Status = STATUS_INVALID_DEVICE_STATE;
|
|||
|
|
|||
|
goto ExitClearChipModeNoChange;
|
|||
|
}
|
|||
|
|
|||
|
// need to find out what mode it was and try to take it out of it
|
|||
|
|
|||
|
// check to see if we used the filter to set the mode
|
|||
|
if ( Fdx->FilterMode ) {
|
|||
|
Status = Fdx->ChipInfo.ParChipClearMode ( Fdx->ChipInfo.Context, ChipMode );
|
|||
|
} else {
|
|||
|
|
|||
|
// If ECP mode check to see if we can clear it
|
|||
|
if ( EcrMode == ECR_ECP_MODE ) {
|
|||
|
Status = PptEcrClearMode( Fdx );
|
|||
|
goto ExitClearChipModeWithChanges;
|
|||
|
}
|
|||
|
|
|||
|
// If EPP mode check to see if we can clear it
|
|||
|
if ( EcrMode == ECR_EPP_MODE ) {
|
|||
|
Status = PptEcrClearMode( Fdx );
|
|||
|
goto ExitClearChipModeWithChanges;
|
|||
|
}
|
|||
|
|
|||
|
// If BYTE mode clear it if use ECR register
|
|||
|
if ( EcrMode == ECR_BYTE_MODE ) {
|
|||
|
Status = PptClearByteMode( Fdx );
|
|||
|
goto ExitClearChipModeWithChanges;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ExitClearChipModeWithChanges:
|
|||
|
|
|||
|
if( NT_SUCCESS(Status) ) {
|
|||
|
Fdx->PnpInfo.CurrentMode = INITIAL_MODE;
|
|||
|
}
|
|||
|
|
|||
|
ExitClearChipModeNoChange:
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptEcrSetMode(
|
|||
|
IN PFDO_EXTENSION Fdx,
|
|||
|
IN UCHAR ChipMode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine enables EPP mode through the ECR register.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the port type was detected.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR ecr;
|
|||
|
PUCHAR Controller;
|
|||
|
PUCHAR wPortECR;
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
|
|||
|
//
|
|||
|
// Store the prior mode.
|
|||
|
//
|
|||
|
wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
|
|||
|
|
|||
|
ecr = P5ReadPortUchar( wPortECR );
|
|||
|
Fdx->EcrPortData = ecr;
|
|||
|
|
|||
|
// get rid of prior mode which is the top three bits
|
|||
|
ecr &= ECR_MODE_MASK;
|
|||
|
|
|||
|
// Write out SPP mode first to the chip
|
|||
|
P5WritePortUchar( wPortECR, (UCHAR)(ecr | ECR_BYTE_MODE) );
|
|||
|
|
|||
|
// Write new mode to ECR register
|
|||
|
P5WritePortUchar( wPortECR, ChipMode );
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptSetByteMode(
|
|||
|
IN PFDO_EXTENSION Fdx,
|
|||
|
IN UCHAR ChipMode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine enables Byte mode either through the ECR register
|
|||
|
(if available). Or just checks it to see if it works
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the port type was detected.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
// Checking to see if ECR register is there and if there use it
|
|||
|
if ( Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {
|
|||
|
Status = PptEcrSetMode( Fdx, ChipMode );
|
|||
|
}
|
|||
|
|
|||
|
Status = PptCheckByteMode( Fdx );
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptClearByteMode(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine Clears Byte mode through the ECR register if there otherwise
|
|||
|
just returns success because nothing needs to be done.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the port type was detected.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
|
|||
|
// Put ECR register back to original if it was there
|
|||
|
if ( Fdx->PnpInfo.HardwareCapabilities & PPT_ECP_PRESENT ) {
|
|||
|
Status = PptEcrClearMode( Fdx );
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptCheckByteMode(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks to make sure we are still Byte capable before doing
|
|||
|
any transfering of data.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension of the device we are
|
|||
|
reporting resources for.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUCHAR Controller;
|
|||
|
UCHAR dcr;
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
|
|||
|
//
|
|||
|
// run the test again to make sure somebody didn't take us out of a
|
|||
|
// bi-directional capable port.
|
|||
|
//
|
|||
|
// 1. put in extended read mode.
|
|||
|
// 2. write data pattern
|
|||
|
// 3. read data pattern
|
|||
|
// 4. if bi-directional capable, then data patterns will be different.
|
|||
|
// 5. if patterns are the same, then check one more pattern.
|
|||
|
// 6. if patterns are still the same, then port is NOT bi-directional.
|
|||
|
//
|
|||
|
|
|||
|
// get the current control port value for later restoration
|
|||
|
dcr = P5ReadPortUchar( Controller + DCR_OFFSET );
|
|||
|
|
|||
|
// put port into extended read mode
|
|||
|
P5WritePortUchar( Controller + DCR_OFFSET, (UCHAR)(dcr | DCR_DIRECTION) );
|
|||
|
|
|||
|
// write the first pattern to the port
|
|||
|
P5WritePortUchar( Controller, (UCHAR)0x55 );
|
|||
|
if ( P5ReadPortUchar( Controller ) == (UCHAR)0x55 ) {
|
|||
|
// same pattern, try the second pattern
|
|||
|
P5WritePortUchar( Controller, (UCHAR)0xaa );
|
|||
|
if ( P5ReadPortUchar( Controller ) == (UCHAR)0xaa ) {
|
|||
|
// the port is NOT bi-directional capable
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// restore the control port to its original value
|
|||
|
P5WritePortUchar( Controller + DCR_OFFSET, (UCHAR)dcr );
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptEcrClearMode(
|
|||
|
IN PFDO_EXTENSION Fdx
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine disables EPP or ECP mode whichever one the chip
|
|||
|
was in through the ECR register.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if it was successful.
|
|||
|
!STATUS_SUCCESS - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR ecr;
|
|||
|
PUCHAR Controller;
|
|||
|
PUCHAR wPortECR;
|
|||
|
|
|||
|
Controller = Fdx->PortInfo.Controller;
|
|||
|
|
|||
|
//
|
|||
|
// Restore the prior mode.
|
|||
|
//
|
|||
|
|
|||
|
// Get original ECR register
|
|||
|
ecr = Fdx->EcrPortData;
|
|||
|
Fdx->EcrPortData = 0;
|
|||
|
|
|||
|
// some chips require to change modes only after
|
|||
|
// you put it into spp mode
|
|||
|
|
|||
|
wPortECR = Fdx->PnpInfo.EcpController + ECR_OFFSET;
|
|||
|
|
|||
|
P5WritePortUchar( wPortECR, (UCHAR)(ecr & ECR_MODE_MASK) );
|
|||
|
|
|||
|
// Back to original mode
|
|||
|
P5WritePortUchar( wPortECR, ecr );
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PptBuildResourceList(
|
|||
|
IN PFDO_EXTENSION Fdx,
|
|||
|
IN ULONG Partial,
|
|||
|
IN PUCHAR *Addresses,
|
|||
|
OUT PCM_RESOURCE_LIST Resources
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine Builds a CM_RESOURCE_LIST with 1 Full Resource
|
|||
|
Descriptor and as many Partial resource descriptors as you want
|
|||
|
with the same parameters for the Full. No Interrupts or anything
|
|||
|
else just IO addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fdx - Supplies the device extension.
|
|||
|
Partial - Number (array size) of partial descriptors in Addresses[]
|
|||
|
Addresses - Pointer to an Array of addresses of the partial descriptors
|
|||
|
Resources - The returned CM_RESOURCE_LIST
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - if the building of the list was successful.
|
|||
|
STATUS_UNSUCCESSFUL - otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR i;
|
|||
|
|
|||
|
//
|
|||
|
// Number of Full Resource descriptors
|
|||
|
//
|
|||
|
Resources->Count = 1;
|
|||
|
|
|||
|
Resources->List[0].InterfaceType = Fdx->InterfaceType;
|
|||
|
Resources->List[0].BusNumber = Fdx->BusNumber;
|
|||
|
Resources->List[0].PartialResourceList.Version = 0;
|
|||
|
Resources->List[0].PartialResourceList.Revision = 0;
|
|||
|
Resources->List[0].PartialResourceList.Count = Partial;
|
|||
|
|
|||
|
//
|
|||
|
// Going through the loop for each partial descriptor
|
|||
|
//
|
|||
|
for ( i = 0; i < Partial ; i++ ) {
|
|||
|
|
|||
|
//
|
|||
|
// Setup port
|
|||
|
//
|
|||
|
Resources->List[0].PartialResourceList.PartialDescriptors[i].Type = CmResourceTypePort;
|
|||
|
Resources->List[0].PartialResourceList.PartialDescriptors[i].ShareDisposition = CmResourceShareDriverExclusive;
|
|||
|
Resources->List[0].PartialResourceList.PartialDescriptors[i].Flags = CM_RESOURCE_PORT_IO;
|
|||
|
Resources->List[0].PartialResourceList.PartialDescriptors[i].u.Port.Start.QuadPart = (ULONG_PTR)Addresses[i];
|
|||
|
Resources->List[0].PartialResourceList.PartialDescriptors[i].u.Port.Length = (ULONG)2;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return ( STATUS_SUCCESS );
|
|||
|
|
|||
|
}
|