363 lines
12 KiB
C
363 lines
12 KiB
C
|
#include "pch.h"
|
||
|
|
||
|
// Register Definitions for National ChipSets
|
||
|
#define REG_CR0 0x00
|
||
|
#define REG_CR1 0x01
|
||
|
#define REG_CR2 0x02
|
||
|
#define REG_CR3 0x03
|
||
|
#define REG_CR4 0x04
|
||
|
#define REG_CR5 0x05
|
||
|
#define REG_CR6 0x06
|
||
|
#define REG_CR7 0x07
|
||
|
#define REG_CR8 0x08
|
||
|
|
||
|
// National Chip ID's
|
||
|
#define PC87303 0x30
|
||
|
#define PC87306 0x70
|
||
|
#define PC87307 0xC0
|
||
|
#define PC87308 0xA0
|
||
|
#define PC87323 0x20
|
||
|
#define PC87332 0x10
|
||
|
#define PC87334 0x50
|
||
|
#define PC87336 0x90
|
||
|
#define PC87338 0xB0
|
||
|
#define PC873xx 0x60
|
||
|
|
||
|
// Additional definitions for National PC87307 and PC87308
|
||
|
#define PC873_LOGICAL_DEV_REG 0x07
|
||
|
#define PC873_PP_LDN 0x04
|
||
|
#define PC873_DEVICE_ID 0x20
|
||
|
#define PC873_PP_MODE_REG 0xF0
|
||
|
#define PC873_ECP_MODE 0xF2
|
||
|
#define PC873_EPP_MODE 0x62
|
||
|
#define PC873_SPP_MODE 0x92
|
||
|
#define PC873_BASE_IO_ADD_MSB 0x60
|
||
|
#define PC873_BASE_IO_ADD_LSB 0x61
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
PptFindNatChip(
|
||
|
IN PFDO_EXTENSION Fdx
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine finds out if there is a National Semiconductor IO chip on
|
||
|
this machine. If it finds a National chip it then determines if this
|
||
|
instance of Parport is using this chips paralle port IO address.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Fdx - Supplies the device extension.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS - if we were able to check for the parallel chip.
|
||
|
STATUS_UNSUCCESSFUL - if we were not able to check for the parallel chip.
|
||
|
|
||
|
Updates:
|
||
|
|
||
|
Fdx->
|
||
|
NationalChecked
|
||
|
NationalChipFound
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
BOOLEAN found = FALSE; // return code, assumed value
|
||
|
BOOLEAN OkToLook = FALSE;
|
||
|
BOOLEAN Conflict;
|
||
|
PUCHAR ChipAddr[4] = { (PUCHAR)0x398, (PUCHAR)0x26e, (PUCHAR)0x15c, (PUCHAR)0x2e }; // list of valid chip addresses
|
||
|
PUCHAR AddrList[4] = { (PUCHAR)0x378, (PUCHAR)0x3bc, (PUCHAR)0x278, (PUCHAR)0x00 }; // List of valid Parallel Port addresses
|
||
|
PUCHAR PortAddr; // Chip Port Address
|
||
|
ULONG_PTR Port; // Chip Port Read Value
|
||
|
UCHAR SaveIdx; // Save the index register value
|
||
|
UCHAR cr; // config register value
|
||
|
UCHAR ii; // loop index
|
||
|
NTSTATUS Status; // Status of success
|
||
|
ULONG ResourceDescriptorCount;
|
||
|
ULONG ResourcesSize;
|
||
|
PCM_RESOURCE_LIST Resources;
|
||
|
ULONG NationalChecked = 0;
|
||
|
ULONG NationalChipFound = 0;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Quick exit if we already know the answer
|
||
|
//
|
||
|
if ( Fdx->NationalChecked == TRUE ) {
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark extension so that we can quick exit the next time we are asked this question
|
||
|
//
|
||
|
Fdx->NationalChecked = TRUE;
|
||
|
|
||
|
//
|
||
|
// Check the registry - we should only need to check this once per installation
|
||
|
//
|
||
|
PptRegGetDeviceParameterDword(Fdx->PhysicalDeviceObject, (PWSTR)L"NationalChecked", &NationalChecked);
|
||
|
if( NationalChecked ) {
|
||
|
//
|
||
|
// We previously performed the NatSemi Check - extract result from registry
|
||
|
//
|
||
|
PptRegGetDeviceParameterDword(Fdx->PhysicalDeviceObject, (PWSTR)L"NationalChipFound", &NationalChipFound);
|
||
|
if( NationalChipFound ) {
|
||
|
Fdx->NationalChipFound = TRUE;
|
||
|
} else {
|
||
|
Fdx->NationalChipFound = FALSE;
|
||
|
}
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This is our first, and hopefully last time that we need to make this check
|
||
|
// for this installation
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Allocate a block of memory for constructing a resource descriptor
|
||
|
//
|
||
|
|
||
|
// number of partial descriptors
|
||
|
ResourceDescriptorCount = sizeof(ChipAddr)/sizeof(ULONG);
|
||
|
|
||
|
// size of resource descriptor list + space for (n-1) more partial descriptors
|
||
|
// (resource descriptor list includes one partial descriptor)
|
||
|
ResourcesSize = sizeof(CM_RESOURCE_LIST) +
|
||
|
(ResourceDescriptorCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
|
|
||
|
Resources = (PCM_RESOURCE_LIST)ExAllocatePool(NonPagedPool, ResourcesSize);
|
||
|
|
||
|
if (Resources == NULL) {
|
||
|
// Error out
|
||
|
return(STATUS_UNSUCCESSFUL);
|
||
|
}
|
||
|
|
||
|
// zero out memory block as a precaution
|
||
|
RtlZeroMemory(Resources, ResourcesSize);
|
||
|
|
||
|
//
|
||
|
// Build the Resource List
|
||
|
//
|
||
|
Status = PptBuildResourceList( Fdx,
|
||
|
sizeof(ChipAddr)/sizeof(ULONG),
|
||
|
&ChipAddr[0],
|
||
|
Resources
|
||
|
);
|
||
|
|
||
|
// Check to see if it was successful
|
||
|
if ( !NT_SUCCESS( Status ) ) {
|
||
|
ExFreePool( Resources );
|
||
|
return ( Status );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check to see if we can use the io addresses where
|
||
|
// national chipsets are located
|
||
|
//
|
||
|
Status = IoReportResourceUsage( NULL,
|
||
|
Fdx->DriverObject,
|
||
|
Resources,
|
||
|
sizeof(Resources),
|
||
|
Fdx->DeviceObject,
|
||
|
NULL,
|
||
|
0,
|
||
|
FALSE,
|
||
|
&Conflict
|
||
|
);
|
||
|
|
||
|
// done with resource list
|
||
|
ExFreePool( Resources );
|
||
|
|
||
|
// Check to see if IoReportResourceUsage was successful
|
||
|
if( !NT_SUCCESS( Status ) ) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Check to see if it was successful
|
||
|
if ( Conflict ) {
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Was successful so now we check each of the addresses that we have
|
||
|
// the resources for
|
||
|
//
|
||
|
// the following for loop is a state machine that checks modes and
|
||
|
// port addresses.
|
||
|
//
|
||
|
// state 0: check for Pc873 at primary port address
|
||
|
// state 1: check for Pc873 at secondary port address
|
||
|
// state 2: check for Pc873 at Ter port address
|
||
|
// state 3: check for Pc873 at Quad port address
|
||
|
|
||
|
for ( ii = 0; !found && ii < 4; ii++ ) {
|
||
|
|
||
|
PortAddr = (PUCHAR)ChipAddr[ii];
|
||
|
|
||
|
// After power up the index register will read back an 0xAA one time only.
|
||
|
// So we'll check for that first.
|
||
|
// Then it should read back a 0 or a valid register number
|
||
|
|
||
|
if(( P5ReadPortUchar( PortAddr ) == 0x88 )
|
||
|
&& ( P5ReadPortUchar( PortAddr ) < 0x20 )) {
|
||
|
|
||
|
OkToLook = TRUE;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
// Or it could read back a 0 or a valid register number
|
||
|
P5ReadPortUchar( PortAddr ); // may read back 0 here
|
||
|
cr = P5ReadPortUchar( PortAddr ); // valid register no.
|
||
|
|
||
|
// is it really valid?
|
||
|
// if( cr < 0x20 ) { - dvdr
|
||
|
if( cr != 0xff ) {
|
||
|
// does it read back the same?
|
||
|
if( P5ReadPortUchar( PortAddr ) == cr)
|
||
|
OkToLook = TRUE;
|
||
|
}
|
||
|
|
||
|
} // end else
|
||
|
|
||
|
// take a closer look by writing to the chip
|
||
|
if ( OkToLook ) {
|
||
|
|
||
|
OkToLook = FALSE;
|
||
|
|
||
|
// setup for ID reg
|
||
|
P5WritePortUchar( PortAddr, REG_CR8 );
|
||
|
|
||
|
// read it back
|
||
|
cr = P5ReadPortUchar( PortAddr );
|
||
|
|
||
|
// does it read back the same?
|
||
|
if( cr == REG_CR8 ) {
|
||
|
|
||
|
// get the ID number.
|
||
|
cr = (UCHAR)( P5ReadPortUchar( PortAddr + 1 ) & 0xf0 );
|
||
|
|
||
|
// if the up. nib. is 1,3,5,6,7,9,A,B,C
|
||
|
if( cr == PC87332 || cr == PC87334 || cr == PC87306 || cr == PC87303 ||
|
||
|
cr == PC87323 || cr == PC87336 || cr == PC87338 || cr == PC873xx ) {
|
||
|
|
||
|
// we found a national chip
|
||
|
found = TRUE;
|
||
|
|
||
|
// setup for Address reg
|
||
|
P5WritePortUchar( PortAddr, REG_CR1 );
|
||
|
|
||
|
// read it back
|
||
|
Port = P5ReadPortUchar( PortAddr + 1 ) & 0x03;
|
||
|
|
||
|
// Check the base address
|
||
|
if ( Fdx->PortInfo.Controller == (PUCHAR)AddrList[ Port ] ) {
|
||
|
|
||
|
//
|
||
|
// it is using the same address that Parport is using
|
||
|
// so we set the flag to not use generic ECP and EPP
|
||
|
//
|
||
|
Fdx->NationalChipFound = TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} // reads back ok
|
||
|
|
||
|
} // end OkToLook
|
||
|
|
||
|
// check to see if we found it
|
||
|
if ( !found ) {
|
||
|
|
||
|
// Check for the 307/308 chips
|
||
|
SaveIdx = P5ReadPortUchar( PortAddr );
|
||
|
|
||
|
// Setup for SID Register
|
||
|
P5WritePortUchar( PortAddr, PC873_DEVICE_ID );
|
||
|
|
||
|
// Zero the ID register to start and because it is read only it will
|
||
|
// let us know whether it is this chip
|
||
|
P5WritePortUchar( PortAddr + 1, REG_CR0 );
|
||
|
|
||
|
// get the ID number.
|
||
|
cr = (UCHAR)( P5ReadPortUchar( PortAddr + 1 ) & 0xf8 );
|
||
|
|
||
|
if ( (cr == PC87307) || (cr == PC87308) ) {
|
||
|
|
||
|
// we found a new national chip
|
||
|
found = TRUE;
|
||
|
|
||
|
// Set the logical device
|
||
|
P5WritePortUchar( PortAddr, PC873_LOGICAL_DEV_REG );
|
||
|
P5WritePortUchar( PortAddr+1, PC873_PP_LDN );
|
||
|
|
||
|
// set up for the base address MSB register
|
||
|
P5WritePortUchar( PortAddr, PC873_BASE_IO_ADD_MSB );
|
||
|
|
||
|
// get the MSB of the base address
|
||
|
Port = (ULONG_PTR)((P5ReadPortUchar( PortAddr + 1 ) << 8) & 0xff00);
|
||
|
|
||
|
// Set up for the base address LSB register
|
||
|
P5WritePortUchar( PortAddr, PC873_BASE_IO_ADD_LSB );
|
||
|
|
||
|
// Get the LSBs of the base address
|
||
|
Port |= P5ReadPortUchar( PortAddr + 1 );
|
||
|
|
||
|
// Check the base address
|
||
|
if ( Fdx->PortInfo.Controller == (PUCHAR)Port ) {
|
||
|
//
|
||
|
// it is using the same address that Parport is using
|
||
|
// so we set the flag to not use generic ECP and EPP
|
||
|
//
|
||
|
Fdx->NationalChipFound = TRUE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
P5WritePortUchar( PortAddr, SaveIdx );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // end of for ii...
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check for NatSemi chip is complete - save results in registry so that we never
|
||
|
// have to make this check again for this port
|
||
|
//
|
||
|
{
|
||
|
PDEVICE_OBJECT pdo = Fdx->PhysicalDeviceObject;
|
||
|
NationalChecked = 1;
|
||
|
NationalChipFound = Fdx->NationalChipFound ? 1 : 0;
|
||
|
|
||
|
// we ignore status here because there is nothing we can do if the calls fail
|
||
|
PptRegSetDeviceParameterDword(pdo, (PWSTR)L"NationalChecked", &NationalChecked);
|
||
|
PptRegSetDeviceParameterDword(pdo, (PWSTR)L"NationalChipFound", &NationalChipFound);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// release the io addresses where we checked for the national chipsets
|
||
|
// we do this by calling IoReportResourceUsage with all NULL parameters
|
||
|
//
|
||
|
Status = IoReportResourceUsage( NULL,
|
||
|
Fdx->DriverObject,
|
||
|
NULL,
|
||
|
0,
|
||
|
Fdx->DeviceObject,
|
||
|
NULL,
|
||
|
0,
|
||
|
FALSE,
|
||
|
&Conflict
|
||
|
);
|
||
|
|
||
|
DD((PCE)Fdx,DDT,"ParMode::PptFindNatChip: return isFound [%x]\n",Fdx->NationalChipFound);
|
||
|
return ( Status );
|
||
|
|
||
|
} // end of ParFindNat()
|