mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1291 lines
42 KiB
1291 lines
42 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1993 - 1999
|
|
|
|
Module Name:
|
|
|
|
par12843.c
|
|
|
|
Abstract:
|
|
|
|
This is the main module for 1284.3 functionality. These
|
|
function enable the selection and deselection of 1284.3
|
|
compatable devices on the parallel port.
|
|
|
|
The devices can be selected and deselected IRQL <= DISPATCH_LEVEL
|
|
by calling IOCTL_INTERNAL_SELECT_DEVICE, or 'TrySelectDevice'.
|
|
The first call is the simplest: the IRP will be queued in the
|
|
parallel port driver until the port is free and then it will
|
|
try to select the device with the given ID from the structure
|
|
PARALLEL_1284_COMMAND. If successful it will with a successful
|
|
status, otherwise it will return with an unsuccessful status.
|
|
The class driver may cancel this IRP at any time which serves
|
|
as a mechanism to timeout an allocate request.
|
|
|
|
The 'TrySelectDevice' call returns immediately from the port
|
|
driver with a TRUE status if the port was allocated and the
|
|
device was able to be selected or a FALSE status if the port
|
|
was either busy or the device was not able to be selected.
|
|
|
|
Once the device is selected, the port is owned by the selecting class
|
|
driver until a 'DeselectDevice' call is made. This deselects the
|
|
device and also releases the port and wakes up the next caller.
|
|
|
|
Author:
|
|
|
|
Don E. Redford 3-Mar-1998
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
ULONG
|
|
PptInitiate1284_3(
|
|
IN PVOID Extension
|
|
);
|
|
|
|
NTSTATUS
|
|
PptTrySelectDevice(
|
|
IN PVOID Context,
|
|
IN PVOID TrySelectCommand
|
|
);
|
|
|
|
NTSTATUS
|
|
PptDeselectDevice(
|
|
IN PVOID Context,
|
|
IN PVOID DeselectCommand
|
|
);
|
|
|
|
ULONG
|
|
Ppt1284_3AssignAddress(
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
PptSend1284_3Command(
|
|
IN PUCHAR CurrentPort,
|
|
IN UCHAR Command
|
|
);
|
|
|
|
BOOLEAN
|
|
PptCheckIfStl1284_3(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN ULONG ulDaisyIndex,
|
|
IN BOOLEAN bNoStrobe
|
|
);
|
|
|
|
BOOLEAN
|
|
PptCheckIfNon1284_3Present(
|
|
IN PFDO_EXTENSION Extension
|
|
);
|
|
|
|
BOOLEAN
|
|
PptCheckIfStlProductId(
|
|
IN PFDO_EXTENSION Extension,
|
|
IN ULONG ulDaisyIndex
|
|
);
|
|
//
|
|
// Beginning of functions
|
|
//
|
|
|
|
ULONG
|
|
PptInitiate1284_3(
|
|
IN PVOID Extension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes all of the 1284.3 devices out on the
|
|
given parallel port. It does this by assigning 1284.3 addresses to
|
|
each device on the port.
|
|
|
|
Arguments:
|
|
|
|
Extensioon - Device extension structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG deviceCount1 = 0;
|
|
ULONG deviceCount2 = 0;
|
|
ULONG loopCount = 0;
|
|
ULONG maxTries = 3; // picked 3 out of thin air as a "reasonable" value
|
|
|
|
// Send command to assign addresses and count number of 1284.3 daisy chain devices
|
|
// Try multiple times to make sure we get the same count
|
|
do {
|
|
|
|
KeStallExecutionProcessor( 5 );
|
|
deviceCount1 = Ppt1284_3AssignAddress( Extension );
|
|
|
|
KeStallExecutionProcessor( 5 );
|
|
deviceCount2 = Ppt1284_3AssignAddress( Extension );
|
|
|
|
if( deviceCount1 != deviceCount2 ) {
|
|
DD((PCE)Extension,DDW,"PptInitiate1284_3 - count unstable\n");
|
|
PptAssert(deviceCount1 == deviceCount2);
|
|
}
|
|
|
|
} while( (deviceCount1 != deviceCount2) && (++loopCount < maxTries) );
|
|
|
|
return deviceCount2;
|
|
}
|
|
|
|
NTSTATUS
|
|
PptTrySelectDevice(
|
|
IN PVOID Context,
|
|
IN PVOID TrySelectCommand
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine first tries to allocate the port. If successful
|
|
it will then try to select the device with the ID given.
|
|
|
|
Arguments:
|
|
|
|
Extension - Driver extension.
|
|
Device - 1284.3 Device Id.
|
|
Command - Command to know whether to allocate the port
|
|
|
|
Return Value:
|
|
|
|
TRUE - Able to allocate the port and select the device
|
|
FALSE - 1: Invalid ID 2: Not able to allocate port 3: Not able to select device
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PFDO_EXTENSION Extension = Context;
|
|
PPARALLEL_1284_COMMAND Command = TrySelectCommand;
|
|
BOOLEAN success = FALSE;
|
|
SYNCHRONIZED_COUNT_CONTEXT SyncContext;
|
|
KIRQL CancelIrql;
|
|
UCHAR i, DeviceID;
|
|
|
|
if( ( Command->CommandFlags & PAR_LEGACY_ZIP_DRIVE ) ||
|
|
( Command->ID == DOT3_LEGACY_ZIP_ID )) {
|
|
Status = PptTrySelectLegacyZip(Context, TrySelectCommand);
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - LegacyZip - status=%x\n",Status);
|
|
return Status;
|
|
}
|
|
|
|
// get device ID to select
|
|
DeviceID = Command->ID;
|
|
|
|
// validate parameters - we will accept:
|
|
// - a Dot3 device with a valid DeviceID
|
|
// - an End-of-Chain device indicated by the PAR_END_OF_CHAIN_DEVICE flag, or
|
|
// - an End-of-Chain device indicated by a DeviceID value one past the last Dot3 device
|
|
|
|
if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) && DeviceID > Extension->PnpInfo.Ieee1284_3DeviceCount ) {
|
|
|
|
// Requested device is not flagged as End-of-Chain device and DeviceID
|
|
// is more than one past the end of the Dot3 Devices, so FAIL the IRP
|
|
DD((PCE)Extension,DDE,"PptTrySelectDevice - FAIL - invalid DeviceID parameter\n",DeviceID);
|
|
PptAssertMsg("PptTrySelectDevice - FAIL - invalid DeviceID parameter",FALSE);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Request appears valid
|
|
//
|
|
|
|
// test to see if we need to grab port
|
|
if( Command->CommandFlags & PAR_HAVE_PORT_KEEP_PORT ) {
|
|
|
|
//
|
|
// requester has already acquired port, just do a SELECT
|
|
//
|
|
if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) &&
|
|
DeviceID < Extension->PnpInfo.Ieee1284_3DeviceCount ) {
|
|
|
|
// SELECT the device
|
|
for ( i = 0; i < PptDot3Retries && !success; i++ ) {
|
|
// Send command to to select device in compatability mode
|
|
success = PptSend1284_3Command( Extension->PortInfo.Controller, (UCHAR)(CPP_SELECT | DeviceID) );
|
|
// Stall a little in case we have to retry
|
|
KeStallExecutionProcessor( 5 );
|
|
}
|
|
|
|
if ( success ) {
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - had port - SUCCESS\n");
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
DD((PCE)Extension,DDW,"PptTrySelectDevice - FAIL\n");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
} else {
|
|
// End-of-Chain device, no SELECT required, SUCCEED the request
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - EOC\n");
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
// Don't have the port
|
|
|
|
//
|
|
// Try to acquire port and select device
|
|
//
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
|
|
SyncContext.Count = &Extension->WorkQueueCount;
|
|
|
|
if (Extension->InterruptRefCount) {
|
|
KeSynchronizeExecution(Extension->InterruptObject, PptSynchronizedIncrement, &SyncContext);
|
|
} else {
|
|
PptSynchronizedIncrement(&SyncContext);
|
|
}
|
|
|
|
if (SyncContext.NewCount) {
|
|
// Port is busy, queue request
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - Port Busy - Request Queued\n");
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
Status = STATUS_PENDING;
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
// Port is acquired
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - Port Acquired\n");
|
|
|
|
Extension->WmiPortAllocFreeCounts.PortAllocates++;
|
|
|
|
if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) && DeviceID < Extension->PnpInfo.Ieee1284_3DeviceCount ) {
|
|
|
|
// SELECT the device
|
|
for ( i = 0; i < PptDot3Retries && !success; i++ ) {
|
|
// Send command to to select device in compatability mode
|
|
success = PptSend1284_3Command( Extension->PortInfo.Controller, (UCHAR)(CPP_SELECT | DeviceID) );
|
|
// Stall a little in case we have to retry
|
|
KeStallExecutionProcessor( 5 );
|
|
}
|
|
|
|
if ( success ) {
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - SUCCESS\n");
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
DD((PCE)Extension,DDW,"PptTrySelectDevice - FAILED\n");
|
|
|
|
// RMT - 000831 - do we still have the port locked!?! - did we hang the port?
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
} else {
|
|
// End-of-Chain device, no SELECT required, SUCCEED the request
|
|
DD((PCE)Extension,DDT,"PptTrySelectDevice - EOC2\n");
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} // endif - test for port busy
|
|
|
|
} // endif - test if already have port
|
|
|
|
} // endif - test for valid parameters
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PptDeselectDevice(
|
|
IN PVOID Context,
|
|
IN PVOID DeselectCommand
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deselects the current device and then frees the port
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE - Able to deselect the device and free the port
|
|
FALSE - 1: Invalid ID 2: Not able to deselect the drive
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PFDO_EXTENSION fdx = Context;
|
|
PPARALLEL_1284_COMMAND Command = DeselectCommand;
|
|
BOOLEAN success = FALSE;
|
|
UCHAR i, DeviceID;
|
|
|
|
if( ( Command->CommandFlags & PAR_LEGACY_ZIP_DRIVE ) ||
|
|
( Command->ID == DOT3_LEGACY_ZIP_ID ) ) {
|
|
return PptDeselectLegacyZip( Context, DeselectCommand );
|
|
}
|
|
|
|
// get device ID to deselect
|
|
DeviceID = Command->ID;
|
|
|
|
// validate ID
|
|
if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) && DeviceID > fdx->PnpInfo.Ieee1284_3DeviceCount ) {
|
|
|
|
// not End-of-Chain device and Dot3 DeviceID is invalid
|
|
DD((PCE)fdx,DDE,"PptDeselectDevice - ID=%d - FAIL - invalid parameter\n",DeviceID);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
|
|
// Check for End-of-Chain device
|
|
if ( !(Command->CommandFlags & PAR_END_OF_CHAIN_DEVICE) &&
|
|
DeviceID < fdx->PnpInfo.Ieee1284_3DeviceCount ) {
|
|
|
|
// first deselect the device
|
|
for ( i = 0; i < PptDot3Retries && !success; i++ ) {
|
|
success = PptSend1284_3Command( fdx->PortInfo.Controller, (UCHAR)CPP_DESELECT );
|
|
// Stall a little in case we have to retry
|
|
KeStallExecutionProcessor( 5 );
|
|
}
|
|
|
|
if ( success ) {
|
|
// Deselecting device was a success
|
|
DD((PCE)fdx,DDT,"PptDeselectDevice\n");
|
|
|
|
// check if requester wants to keep port or free port
|
|
if( !(Command->CommandFlags & PAR_HAVE_PORT_KEEP_PORT) ) {
|
|
PptFreePort( fdx );
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
// Unable to deselect device, something went very wrong,
|
|
// port is now in an unknown/blocked state
|
|
DD((PCE)fdx,DDE,"PptDeselectDevice - ID=%d - FAIL\n",DeviceID);
|
|
PptAssertMsg("PptDeselectDevice - FAIL - port in unknown state",FALSE);
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
} else {
|
|
|
|
// this is End-of-Chain device so no deselect neccessary
|
|
DD((PCE)fdx,DDT,"PptDeselectDevice - End-of-Chain - SUCCESS\n",DeviceID);
|
|
|
|
// check if requester wants to keep port or free port
|
|
if( !(Command->CommandFlags & PAR_HAVE_PORT_KEEP_PORT) ) {
|
|
PptFreePort( fdx );
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} // endif - Check if End Of Chain
|
|
|
|
} // endif - Validate ID
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
Ppt1284_3AssignAddress(
|
|
IN PFDO_EXTENSION DeviceExtension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the 1284_3 bus.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Supplies Device Extension structure of the driver.
|
|
|
|
Return Value:
|
|
|
|
Number of 1284.3 devices out there at the given address.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//UCHAR i, ii, value, newvalue, status;
|
|
UCHAR i, value, newvalue, status;
|
|
PUCHAR CurrentPort, CurrentStatus, CurrentControl;
|
|
ULONG Delay = 5;
|
|
UCHAR number = 0;
|
|
BOOLEAN lastdevice = FALSE;
|
|
UCHAR idx;
|
|
|
|
CurrentPort = DeviceExtension->PortInfo.Controller;
|
|
CurrentStatus = CurrentPort + 1;
|
|
CurrentControl = CurrentPort + 2;
|
|
|
|
// get current ctl reg
|
|
value = P5ReadPortUchar( CurrentControl );
|
|
|
|
// make sure 1284.3 devices do not get reseted
|
|
newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
|
|
|
|
// make sure we can write
|
|
newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
|
|
P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
|
|
|
|
// bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
|
|
// send first four bytes of the 1284.3 mode qualifier sequence out
|
|
for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[i] );
|
|
KeStallExecutionProcessor( Delay );
|
|
}
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
if ( (status & (UCHAR)0xb8 )
|
|
== ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
|
|
|
|
// continue with fifth byte of mode qualifier
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[4] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// note busy is high too but is opposite so we see it as a low
|
|
if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
|
|
|
|
// continue with sixth byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[5] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// if status is valid there is a device out there responding
|
|
if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
|
|
|
|
// Device is out there
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
while ( number < 4 && !lastdevice ) {
|
|
|
|
// Asssign address byte
|
|
P5WritePortUchar( CurrentPort, number );
|
|
number = (UCHAR)(number + 1);
|
|
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
if ( (P5ReadPortUchar( CurrentStatus ) & (UCHAR)DSR_NOT_BUSY ) == 0 ) {
|
|
// we saw last device
|
|
lastdevice = TRUE;
|
|
}
|
|
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
}
|
|
|
|
// last byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[6] );
|
|
|
|
if ( number ) {
|
|
BOOLEAN bStlNon1284_3Found ;
|
|
BOOLEAN bStlNon1284_3Valid ;
|
|
bStlNon1284_3Found = PptCheckIfNon1284_3Present(DeviceExtension);
|
|
bStlNon1284_3Valid = FALSE ;
|
|
// as the earlier 1284 spec does not give the
|
|
// lastdevice status is BSY, number needs to
|
|
// be corrected in such cases
|
|
for ( idx = 0 ; idx < number ; idx++ ) {
|
|
if ( TRUE == PptCheckIfStl1284_3(DeviceExtension, idx, bStlNon1284_3Found ) ) {
|
|
continue ;
|
|
}
|
|
if ( TRUE == bStlNon1284_3Found ) {
|
|
if ( TRUE == PptCheckIfStlProductId(DeviceExtension, idx) ) {
|
|
bStlNon1284_3Valid = TRUE ;
|
|
continue ;
|
|
}
|
|
}
|
|
break ;
|
|
}
|
|
if ( TRUE == bStlNon1284_3Valid ) {
|
|
// we alter the count only if old adapters
|
|
// are in the chain
|
|
number = idx;
|
|
}
|
|
}
|
|
|
|
} // Third status
|
|
|
|
} // Second status
|
|
|
|
} // First status
|
|
|
|
P5WritePortUchar( CurrentControl, value ); // restore everything
|
|
|
|
// returns last device ID + 1 or number of devices out there
|
|
return ( (ULONG)number );
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
PptCheckIfNon1284_3Present(
|
|
IN PFDO_EXTENSION Extension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Indicates whether one of the devices of the earlier
|
|
specification is present in the chain.
|
|
|
|
|
|
Arguments:
|
|
|
|
Extension - Device Extension structure
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE : Atleast one of the adapters are of earlier spec.
|
|
FALSE : None of the adapters of the earlier spec.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bReturnValue = FALSE ;
|
|
UCHAR i, value, newvalue, status;
|
|
ULONG Delay = 3;
|
|
PUCHAR CurrentPort, CurrentStatus, CurrentControl;
|
|
UCHAR ucAckStatus ;
|
|
|
|
CurrentPort = Extension->PortInfo.Controller;
|
|
CurrentStatus = CurrentPort + 1;
|
|
CurrentControl = CurrentPort + 2;
|
|
|
|
// get current ctl reg
|
|
value = P5ReadPortUchar( CurrentControl );
|
|
|
|
// make sure 1284.3 devices do not get reseted
|
|
newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
|
|
|
|
// make sure we can write
|
|
newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
|
|
P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
|
|
|
|
// bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
|
|
// send first four bytes of the 1284.3 mode qualifier sequence out
|
|
for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[i] );
|
|
KeStallExecutionProcessor( Delay );
|
|
}
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
if ( (status & (UCHAR)0xb8 )
|
|
== ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
|
|
|
|
ucAckStatus = status & 0x40 ;
|
|
|
|
// continue with fifth byte of mode qualifier
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[4] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// note busy is high too but is opposite so we see it as a low
|
|
if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
|
|
|
|
if ( ucAckStatus != ( status & 0x40 ) ) {
|
|
|
|
// save current ack status
|
|
ucAckStatus = status & 0x40 ;
|
|
|
|
// continue with sixth byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[5] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// if status is valid there is a device out there responding
|
|
if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
|
|
|
|
bReturnValue = TRUE ;
|
|
|
|
} // Third status
|
|
|
|
} // ack of earlier adapters not seen
|
|
|
|
// last byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[6] );
|
|
|
|
} // Second status
|
|
|
|
} // First status
|
|
|
|
P5WritePortUchar( CurrentControl, value ); // restore everything
|
|
|
|
return bReturnValue ;
|
|
} // PptCheckIfNon1284_3Present
|
|
|
|
|
|
// Define 1284 Commands
|
|
#define CPP_QUERY_PRODID 0x10
|
|
|
|
// 1284 related SHTL prod id equates
|
|
#define SHTL_EPAT_PRODID 0xAAFF
|
|
#define SHTL_EPST_PRODID 0xA8FF
|
|
|
|
BOOLEAN
|
|
PptCheckIfStl1284_3(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN ULONG ulDaisyIndex,
|
|
IN BOOLEAN bNoStrobe
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks to see whether the device indicated
|
|
is a Shuttle 1284_3 type of device.
|
|
|
|
Arguments:
|
|
|
|
Extension - Device extension structure.
|
|
|
|
ulDaisyIndex - The daisy chain id of the device that
|
|
this function will check on.
|
|
|
|
bNoStrobe - If set, indicates that the query
|
|
Ep1284 command issued by this function
|
|
need not assert strobe to latch the
|
|
command.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Yes. Device is Shuttle 1284_3 type of device.
|
|
FALSE - No. This may mean that this device is either
|
|
non-shuttle or Shuttle non-1284_3 type of
|
|
device.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bReturnValue = FALSE ;
|
|
UCHAR i, value, newvalue, status;
|
|
ULONG Delay = 3;
|
|
UCHAR ucExpectedPattern ;
|
|
UCHAR ucReadValue, ucReadPattern;
|
|
PUCHAR CurrentPort, CurrentStatus, CurrentControl;
|
|
|
|
CurrentPort = DeviceExtension->PortInfo.Controller;
|
|
CurrentStatus = CurrentPort + 1;
|
|
CurrentControl = CurrentPort + 2;
|
|
|
|
// get current ctl reg
|
|
value = P5ReadPortUchar( CurrentControl );
|
|
|
|
// make sure 1284.3 devices do not get reseted
|
|
newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
|
|
|
|
// make sure we can write
|
|
newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
|
|
P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
|
|
|
|
// bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
|
|
// send first four bytes of the 1284.3 mode qualifier sequence out
|
|
for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[i] );
|
|
KeStallExecutionProcessor( Delay );
|
|
}
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
if ( (status & (UCHAR)0xb8 )
|
|
== ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
|
|
|
|
// continue with fifth byte of mode qualifier
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[4] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// note busy is high too but is opposite so we see it as a low
|
|
if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
|
|
|
|
// continue with sixth byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[5] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// if status is valid there is a device out there responding
|
|
if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
|
|
|
|
// Device is out there
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// issue shuttle specific CPP command
|
|
P5WritePortUchar( CurrentPort, (UCHAR) ( 0x88 | ulDaisyIndex ) );
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
if ( ulDaisyIndex && ( bNoStrobe == FALSE ) ) {
|
|
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
}
|
|
|
|
ucExpectedPattern = 0xF0 ;
|
|
bReturnValue = TRUE ;
|
|
|
|
while ( ucExpectedPattern ) {
|
|
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentPort, (UCHAR) (0x80 | ulDaisyIndex )) ;
|
|
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentPort, (UCHAR) (0x88 | ulDaisyIndex )) ;
|
|
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
ucReadValue = P5ReadPortUchar( CurrentStatus ) ;
|
|
ucReadPattern = ( ucReadValue << 1 ) & 0x70 ;
|
|
ucReadPattern |= ( ucReadValue & 0x80 ) ;
|
|
|
|
if ( ucReadPattern != ucExpectedPattern ) {
|
|
// not Shuttle 1284_3 behaviour
|
|
bReturnValue = FALSE ;
|
|
break ;
|
|
}
|
|
|
|
ucExpectedPattern -= 0x10 ;
|
|
}
|
|
|
|
|
|
// last byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[6] );
|
|
|
|
} // Third status
|
|
|
|
} // Second status
|
|
|
|
} // First status
|
|
|
|
P5WritePortUchar( CurrentControl, value ); // restore everything
|
|
|
|
return bReturnValue ;
|
|
} // end PptCheckIfStl1284_3()
|
|
|
|
BOOLEAN
|
|
PptCheckIfStlProductId(
|
|
IN PFDO_EXTENSION DeviceExtension,
|
|
IN ULONG ulDaisyIndex
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function checks to see whether the device indicated
|
|
is a Shuttle non-1284_3 type of device.
|
|
|
|
Arguments:
|
|
|
|
Extension - Device extension structure.
|
|
|
|
ulDaisyIndex - The daisy chain id of the device that
|
|
this function will check on.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Yes. Device is Shuttle non-1284_3 type of device.
|
|
FALSE - No. This may mean that this device is
|
|
non-shuttle.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bReturnValue = FALSE ;
|
|
UCHAR i, value, newvalue, status;
|
|
ULONG Delay = 3;
|
|
UCHAR ucProdIdHiByteHiNibble, ucProdIdHiByteLoNibble ;
|
|
UCHAR ucProdIdLoByteHiNibble, ucProdIdLoByteLoNibble ;
|
|
UCHAR ucProdIdHiByte, ucProdIdLoByte ;
|
|
USHORT usProdId ;
|
|
PUCHAR CurrentPort, CurrentStatus, CurrentControl;
|
|
|
|
CurrentPort = DeviceExtension->PortInfo.Controller;
|
|
CurrentStatus = CurrentPort + 1;
|
|
CurrentControl = CurrentPort + 2;
|
|
|
|
// get current ctl reg
|
|
value = P5ReadPortUchar( CurrentControl );
|
|
|
|
// make sure 1284.3 devices do not get reseted
|
|
newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
|
|
|
|
// make sure we can write
|
|
newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
|
|
P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
|
|
|
|
// bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
|
|
// send first four bytes of the 1284.3 mode qualifier sequence out
|
|
for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[i] );
|
|
KeStallExecutionProcessor( Delay );
|
|
}
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
if ( (status & (UCHAR)0xb8 )
|
|
== ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) {
|
|
|
|
// continue with fifth byte of mode qualifier
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[4] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// note busy is high too but is opposite so we see it as a low
|
|
if (( status & (UCHAR) 0xb8 ) == (DSR_SELECT | DSR_NOT_FAULT)) {
|
|
|
|
// continue with sixth byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[5] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// check for correct status
|
|
status = P5ReadPortUchar( CurrentStatus );
|
|
|
|
// if status is valid there is a device out there responding
|
|
if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) {
|
|
|
|
P5WritePortUchar ( CurrentPort, (UCHAR) (CPP_QUERY_PRODID | ulDaisyIndex )) ;
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// Device is out there
|
|
KeStallExecutionProcessor( Delay );
|
|
ucProdIdLoByteHiNibble = P5ReadPortUchar( CurrentStatus ) ;
|
|
ucProdIdLoByteHiNibble &= 0xF0 ;
|
|
|
|
KeStallExecutionProcessor( Delay );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
ucProdIdLoByteLoNibble = P5ReadPortUchar( CurrentStatus ) ;
|
|
ucProdIdLoByteLoNibble >>= 4 ;
|
|
ucProdIdLoByte = ucProdIdLoByteHiNibble | ucProdIdLoByteLoNibble ;
|
|
|
|
KeStallExecutionProcessor( Delay );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
ucProdIdHiByteHiNibble = P5ReadPortUchar( CurrentStatus ) ;
|
|
ucProdIdHiByteHiNibble &= 0xF0 ;
|
|
|
|
KeStallExecutionProcessor( Delay );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
ucProdIdHiByteLoNibble = P5ReadPortUchar( CurrentStatus ) ;
|
|
ucProdIdHiByteLoNibble >>= 4 ;
|
|
ucProdIdHiByte = ucProdIdHiByteHiNibble | ucProdIdHiByteLoNibble ;
|
|
|
|
// issue the last strobe
|
|
KeStallExecutionProcessor( Delay );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
usProdId = ( ucProdIdHiByte << 8 ) | ucProdIdLoByte ;
|
|
|
|
if ( ( SHTL_EPAT_PRODID == usProdId ) ||\
|
|
( SHTL_EPST_PRODID == usProdId ) ) {
|
|
// one of the devices that conform to the earlier
|
|
// draft is found
|
|
bReturnValue = TRUE ;
|
|
}
|
|
|
|
// last byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[6] );
|
|
|
|
} // Third status
|
|
|
|
} // Second status
|
|
|
|
} // First status
|
|
|
|
P5WritePortUchar( CurrentControl, value ); // restore everything
|
|
|
|
return bReturnValue ;
|
|
} // end PptCheckIfStlProductId()
|
|
|
|
BOOLEAN
|
|
PptSend1284_3Command(
|
|
IN PUCHAR CurrentPort,
|
|
IN UCHAR Command
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sends the 1284_3 Command given to it
|
|
down the parallel bus.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UCHAR i, value, newvalue, test;//, status;
|
|
ULONG ii;
|
|
PUCHAR CurrentStatus, CurrentControl;
|
|
ULONG Delay = 3;
|
|
BOOLEAN success = FALSE;
|
|
|
|
CurrentStatus = CurrentPort + 1;
|
|
CurrentControl = CurrentPort + 2;
|
|
|
|
// Get Upper 4 bits to see what Command it is
|
|
test = (UCHAR)(Command & (UCHAR)CPP_COMMAND_FILTER);
|
|
|
|
// get current ctl reg
|
|
value = P5ReadPortUchar( CurrentControl );
|
|
|
|
// make sure 1284.3 devices do not get reseted
|
|
newvalue = (UCHAR)((value & ~DCR_SELECT_IN) | DCR_NOT_INIT);
|
|
|
|
// make sure we can write
|
|
newvalue = (UCHAR)(newvalue & ~DCR_DIRECTION);
|
|
P5WritePortUchar( CurrentControl, newvalue ); // make sure we can write
|
|
|
|
// bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// send first four bytes of the 1284.3 mode qualifier sequence out
|
|
for ( i = 0; i < MODE_LEN_1284_3 - 3; i++ ) {
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[i] );
|
|
KeStallExecutionProcessor( Delay );
|
|
}
|
|
|
|
// wait up to 5 us : Spec says about 2 but we will be lienient
|
|
if (CHECK_DSR(CurrentPort, INACTIVE, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, 5 )) {
|
|
|
|
// continue with fifth byte of mode qualifier
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[4] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// wait up to 5 us : Spec says about 2 but we will be lienient
|
|
if (CHECK_DSR(CurrentPort, ACTIVE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, 5 )) {
|
|
|
|
// continue with sixth byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[5] );
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// wait up to 5 us : Spec says about 2 but we will be lienient
|
|
if (CHECK_DSR(CurrentPort, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, 5 )) {
|
|
|
|
// Device is out there
|
|
|
|
KeStallExecutionProcessor( Delay );
|
|
|
|
// Command byte
|
|
P5WritePortUchar( CurrentPort, Command );
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
// NOTE NOTE NOTE
|
|
// Assertion of strobe to be done ONLY after checking for the
|
|
// FAULT feedback, as per the 1284_3 specification.
|
|
|
|
// Selection does not work correctly yet to be able to check for lines
|
|
switch ( test ) {
|
|
|
|
case CPP_SELECT:
|
|
// Check to make sure we are selected
|
|
|
|
// wait for upto 250 micro Secs for for selection time out.
|
|
for ( ii = 25000; ii > 0; ii-- ) {
|
|
|
|
if ( ( P5ReadPortUchar( CurrentStatus ) & DSR_NOT_FAULT ) == DSR_NOT_FAULT ) {
|
|
// selection...
|
|
success = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CPP_DESELECT:
|
|
// Check to make sure we are deselected
|
|
|
|
// wait for upto 250 micro Secs for for deselection time out.
|
|
for ( ii = 25000; ii > 0; ii-- ) {
|
|
|
|
if ( (P5ReadPortUchar( CurrentStatus ) & DSR_NOT_FAULT) != DSR_NOT_FAULT ) {
|
|
// deselection...
|
|
success = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default :
|
|
// there is a device out there and Command completed sucessfully
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
success = TRUE;
|
|
break;
|
|
|
|
} // End Switch
|
|
|
|
// NOTE NOTE NOTE
|
|
// the strobe is de-asserted now and the command is completed here
|
|
P5WritePortUchar( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high
|
|
KeStallExecutionProcessor( Delay ); // wait a bit
|
|
|
|
// last byte
|
|
P5WritePortUchar( CurrentPort, ModeQualifier[6] );
|
|
|
|
} // Third status
|
|
|
|
} // Second status
|
|
|
|
} // First status
|
|
|
|
P5WritePortUchar( CurrentControl, value ); // restore everything
|
|
|
|
// return TRUE if command succeeded, FALSE otherwise
|
|
return success;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ParSelectDevice(
|
|
IN PPDO_EXTENSION Pdx,
|
|
IN BOOLEAN HavePort
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine acquires the ParPort and selects a 1284.3 device
|
|
|
|
Arguments:
|
|
|
|
Pdx - Supplies the device extension.
|
|
|
|
HavePort - TRUE indicates that caller has already acquired port
|
|
so we should only do a SELECT_DEVICE
|
|
- FALSE indicates that caller has not already acquired port
|
|
so we should do a combination ACQUIRE_PORT/SELECT_DEVICE
|
|
|
|
Return Value:
|
|
|
|
TRUE - success - the device was selected (and port acquired if needed)
|
|
FALSE - failure
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT pPortDeviceObject;
|
|
PARALLEL_1284_COMMAND par1284Command;
|
|
LARGE_INTEGER timeOut;
|
|
enum _PdoType pdoType;
|
|
|
|
//
|
|
// Initialize command structure and extract parameters from the DeviceExtension
|
|
//
|
|
|
|
// reserved - always set to 0
|
|
par1284Command.Port = 0;
|
|
|
|
if( HavePort ) {
|
|
par1284Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
|
|
} else {
|
|
par1284Command.CommandFlags = 0;
|
|
}
|
|
|
|
pdoType = Pdx->PdoType;
|
|
switch( pdoType ) {
|
|
case PdoTypeRawPort:
|
|
case PdoTypeEndOfChain:
|
|
par1284Command.ID = 0; // ignored, but set anyway
|
|
par1284Command.CommandFlags |= PAR_END_OF_CHAIN_DEVICE;
|
|
break;
|
|
case PdoTypeLegacyZip:
|
|
par1284Command.ID = DOT3_LEGACY_ZIP_ID;
|
|
break;
|
|
case PdoTypeDaisyChain:
|
|
par1284Command.ID = Pdx->Ieee1284_3DeviceId;
|
|
break;
|
|
default:
|
|
DD((PCE)Pdx,DDE,"Invalid pdoType = %x\n",pdoType);
|
|
PptAssert(FALSE);
|
|
break;
|
|
}
|
|
|
|
pPortDeviceObject = Pdx->PortDeviceObject;
|
|
|
|
//
|
|
// Send the request
|
|
//
|
|
timeOut.QuadPart = -(10*1000*500); // 500ms ( 100ns units )
|
|
|
|
status = ParBuildSendInternalIoctl(IOCTL_INTERNAL_SELECT_DEVICE,
|
|
pPortDeviceObject,
|
|
&par1284Command, sizeof(PARALLEL_1284_COMMAND),
|
|
NULL, 0,
|
|
&timeOut);
|
|
|
|
if( NT_SUCCESS( status ) ) {
|
|
// SELECT succeeded
|
|
DD((PCE)Pdx,DDT,"ParSelectDevice - SUCCESS\n");
|
|
if( !HavePort ) {
|
|
// note in the device extension that we have the port
|
|
Pdx->bAllocated = TRUE;
|
|
}
|
|
return TRUE;
|
|
} else {
|
|
// SELECT failed
|
|
DD((PCE)Pdx,DDT,"ParSelectDevice - FAIL\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
ParDeselectDevice(
|
|
IN PPDO_EXTENSION Pdx,
|
|
IN BOOLEAN KeepPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine deselects a 1284.3 or Legacy Zip device and optionally
|
|
releases the ParPort
|
|
|
|
Arguments:
|
|
|
|
Pdx - Supplies the device extension.
|
|
|
|
KeepPort - TRUE indicates that we should keep the port acquired,
|
|
so we should only do a DESELECT_DEVICE
|
|
- FALSE indicates that we should not keep the port acquired,
|
|
so we should do a combination DESELECT_DEVICE/FREE_PORT
|
|
|
|
Return Value:
|
|
|
|
TRUE - The device was deselected (and the port released if requested)
|
|
|
|
--*/
|
|
{
|
|
PARALLEL_1284_COMMAND par1284Command;
|
|
NTSTATUS status;
|
|
enum _PdoType pdoType;
|
|
PDEVICE_OBJECT fdo = Pdx->Fdo;
|
|
PFDO_EXTENSION fdx = fdo->DeviceExtension;
|
|
|
|
//
|
|
// If we don't have the port, succeed and return
|
|
//
|
|
if( !Pdx->bAllocated ) {
|
|
DD((PCE)Pdx,DDW,"ParDeselectDevice - we do not have the port\n");
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Initialize command structure and extract parameters from the DeviceExtension
|
|
//
|
|
|
|
// reserved - always set to 0
|
|
par1284Command.Port = 0;
|
|
|
|
if( KeepPort ) {
|
|
par1284Command.CommandFlags = PAR_HAVE_PORT_KEEP_PORT;
|
|
} else {
|
|
par1284Command.CommandFlags = 0;
|
|
}
|
|
|
|
pdoType = Pdx->PdoType;
|
|
switch( pdoType ) {
|
|
case PdoTypeRawPort:
|
|
case PdoTypeEndOfChain:
|
|
par1284Command.ID = 0; // ignored, but set anyway
|
|
par1284Command.CommandFlags |= PAR_END_OF_CHAIN_DEVICE;
|
|
break;
|
|
case PdoTypeLegacyZip:
|
|
par1284Command.ID = DOT3_LEGACY_ZIP_ID;
|
|
break;
|
|
case PdoTypeDaisyChain:
|
|
par1284Command.ID = Pdx->Ieee1284_3DeviceId;
|
|
break;
|
|
default:
|
|
DD((PCE)Pdx,DDE,"Invalid pdoType = %x\n",pdoType);
|
|
par1284Command.ID = 0; // choose a 1284.3 type deselect since this is harmless
|
|
PptAssert(FALSE);
|
|
break;
|
|
}
|
|
|
|
status = PptDeselectDevice( fdx, &par1284Command );
|
|
|
|
if( status != STATUS_SUCCESS ) {
|
|
// DESELECT failed?!? - there isn't anything that we can do
|
|
DD((PCE)Pdx,DDE,"ParDeselectDevice - FAILED - nothing we can do - status=%x\n", status);
|
|
} else {
|
|
DD((PCE)Pdx,DDT,"ParDeselectDevice - SUCCESS\n", status);
|
|
}
|
|
|
|
if( !KeepPort ) {
|
|
// note in the device extension that we gave up the port
|
|
DD((PCE)Pdx,DDT,"ParDeselectDevice - gave up port\n");
|
|
Pdx->bAllocated = FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|