/*++

Copyright (C) SCM Micro Systems.

Module Name:

    parstl.c

Abstract:

    This is the module that generates unique device id
    for shuttle adapters, that do not have the capability
    to do so, by themselves.

Author:

    Devanathan NR   21-Jun-1999
    Sudheendran TL

Environment:

    Kernel mode

Revision History :


--*/

#include "pch.h"
#include "shuttle.h"

BOOLEAN
ParStlCheckIfStl(
    IN PPDO_EXTENSION    Extension,
    IN ULONG   ulDaisyIndex
    ) 
/*++

Routine Description:

    This function checks whether the indicated device
    is a shuttle device or not.

Arguments:

    Extension       - Device extension structure.

    ulDaisyIndex    - The daisy index on which to do the check.

Return Value:

    TRUE            - Yes, it was a Shuttle device.
    FALSE           - No, not a shuttle.

--*/
{
    BOOLEAN     bStlNon1284_3Found = FALSE ;

    DD(NULL,DDW,"ParStlCheckIfStl - enter\n");

    Extension->Ieee1284Flags &= ( ~ ( 1 << ulDaisyIndex ) ) ;
    bStlNon1284_3Found = ParStlCheckIfNon1284_3Present( Extension ) ;

    if ( TRUE == ParStlCheckIfStl1284_3 ( Extension, ulDaisyIndex, bStlNon1284_3Found ) ) {
        // this adapter is a Shuttle 1284_3 adapter
        Extension->Ieee1284Flags |= ( 1 << ulDaisyIndex ) ;
        return TRUE ;
    }
    if ( TRUE == bStlNon1284_3Found ) {
        if ( TRUE == ParStlCheckIfStlProductId ( Extension, ulDaisyIndex ) ) {
            // this adapter is Shuttle non-1284_3 adapter
            Extension->Ieee1284Flags |= ( 1 << ulDaisyIndex ) ;
            return TRUE ;
        }
    }
    return FALSE ;
}

BOOLEAN
ParStlCheckIfNon1284_3Present(
    IN PPDO_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->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

    DD(NULL,DDW,"ParStlCheckIfNon1284_3Present - returning %s\n",bReturnValue?"TRUE":"FALSE");

    return bReturnValue ;
} // ParStlCheckIfNon1284_3Present

BOOLEAN
ParStlCheckIfStl1284_3(
    IN PPDO_EXTENSION    Extension,
    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 = Extension->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

    DD(NULL,DDW,"ParStlCheckIfStl1284_3 - returning %s\n",bReturnValue?"TRUE":"FALSE");

    return bReturnValue ;
} // end  ParStlCheckIfStl1284_3()

BOOLEAN
ParStlCheckIfStlProductId(
    IN PPDO_EXTENSION    Extension,
    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 = Extension->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 ;

                // 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

    DD(NULL,DDW,"ParStlCheckIfStlProductId - returning %s\n",bReturnValue?"TRUE":"FALSE");

    return bReturnValue ;
} // end  ParStlCheckIfStlProductId()

PCHAR
ParStlQueryStlDeviceId(
    IN  PPDO_EXTENSION   Extension,
    OUT PCHAR               CallerDeviceIdBuffer,
    IN  ULONG               CallerBufferSize,
    OUT PULONG              DeviceIdSize,
    IN BOOLEAN              bReturnRawString
    )
/*++

Routine Description:

    This routine retrieves/constructs the unique device id
    string from the selected shuttle device on the chain
    and updates the caller's buffer with the same.

Arguments:

    IN  Extension               : The device extension
    OUT CallerDeviceIdBuffer    : Caller's buffer
    IN  CallerBufferSize        : Size of caller's buffer
    OUT DeviceIdSize            : Updated device id's size
    IN  bReturnRawString        : Whether to return raw
                                  string with the first two
                                  bytes or not.

Return Value:

    Pointer to the read device ID string, if successful.

    NULL otherwise.

--*/
{
    PUCHAR              Controller = Extension->Controller;
    NTSTATUS            Status;
    UCHAR               idSizeBuffer[2];
    ULONG               bytesToRead;
    ULONG               bytesRead = 0;
    USHORT              deviceIdSize;
    USHORT              deviceIdBufferSize;
    PCHAR               deviceIdBuffer;
    PCHAR               readPtr;

    DD(NULL,DDW,"ParStlQueryStlDeviceId - enter\n");

    *DeviceIdSize = 0;

    // assert idle state, to recover from undefined state,
    // just in case it gets into
    ParStlAssertIdleState ( Extension ) ;

    //
    // If we are currently connected to the peripheral via any 1284 mode
    //   other than Compatibility/Spp mode (which does not require an IEEE
    //   negotiation), we must first terminate the current mode/connection.
    // 
    // dvdf - RMT - what if we are connected in a reverse mode?
    //
    if( (Extension->Connected) && (afpForward[Extension->IdxForwardProtocol].fnDisconnect) ) {
        afpForward[Extension->IdxForwardProtocol].fnDisconnect (Extension);
    }

    //
    // Negotiate the peripheral into nibble device id mode.
    //
    Status = ParEnterNibbleMode(Extension, REQUEST_DEVICE_ID);
    if( !NT_SUCCESS(Status) ) {
        ParTerminateNibbleMode(Extension);
        goto targetContinue;
    }
    
    
    //
    // Read first two bytes to get the total (including the 2 size bytes) size 
    //   of the Device Id string.
    //
    bytesToRead = 2;
    Status = ParNibbleModeRead(Extension, idSizeBuffer, bytesToRead, &bytesRead);
    if( !NT_SUCCESS( Status ) || ( bytesRead != bytesToRead ) ) {
        goto targetContinue;
    }
    
    
    //
    // Compute size of DeviceId string (including the 2 byte size prefix)
    //
    deviceIdSize = (USHORT)( idSizeBuffer[0]*0x100 + idSizeBuffer[1] );
    
    {
        const USHORT minValidDevId    =   14; // 2 size bytes + "MFG:x;" + "MDL:y;"
        const USHORT maxValidDevId    = 2048; // arbitrary, but we've never seen one > 1024
        
        if( (deviceIdSize < minValidDevId) || (deviceIdSize > maxValidDevId) ) {
            //
            // The device is reporting a 1284 ID string length that is probably bogus.
            //   Ignore the device reported ID and skip to the code below that makes
            //   up a VID/PID based 1284 ID based on the specific SCM Micro chip used
            //   by the device.
            //
            goto targetContinue; 
        }
    }
    
    //
    // Allocate a buffer to hold the DeviceId string and read the DeviceId into it.
    //
    if( bReturnRawString ) {
        //
        // Caller wants the raw string including the 2 size bytes
        //
        *DeviceIdSize      = deviceIdSize;
        deviceIdBufferSize = (USHORT)(deviceIdSize + sizeof(CHAR));     // ID size + ID + terminating NULL
    } else {
        //
        // Caller does not want the 2 byte size prefix
        //
        *DeviceIdSize      = deviceIdSize - 2*sizeof(CHAR);
        deviceIdBufferSize = (USHORT)(deviceIdSize - 2*sizeof(CHAR) + sizeof(CHAR)); //           ID + terminating NULL
    }
    
    deviceIdBuffer = (PCHAR)ExAllocatePool(PagedPool, deviceIdBufferSize);
    if( !deviceIdBuffer ) {
        goto targetContinue;
    }


    //
    // NULL out the ID buffer to be safe
    //
    RtlZeroMemory( deviceIdBuffer, deviceIdBufferSize );
    
    
    //
    // Does the caller want the 2 byte size prefix?
    //
    if( bReturnRawString ) {
        //
        // Yes, caller wants the size prefix. Copy prefix to buffer to return.
        //
        *(deviceIdBuffer+0) = idSizeBuffer[0];
        *(deviceIdBuffer+1) = idSizeBuffer[1];
        readPtr = deviceIdBuffer + 2;
    } else {
        //
        // No, discard size prefix
        //
        readPtr = deviceIdBuffer;
    }
    
    
    //
    // Read remainder of DeviceId from device
    //
    bytesToRead = deviceIdSize -  2; // already have the 2 size bytes
    Status = ParNibbleModeRead(Extension, readPtr, bytesToRead, &bytesRead);
    
    
    ParTerminateNibbleMode( Extension );
    
    if( !NT_SUCCESS(Status) || (bytesRead < 1) ) {
        ExFreePool( deviceIdBuffer );
        goto targetContinue;
    }
    
    if ( strstr ( readPtr, "MFG:" ) == 0 ) {
        ExFreePool( deviceIdBuffer ) ;
        goto targetContinue;
    }
    
    deviceIdSize = (USHORT)strlen(deviceIdBuffer);
    *DeviceIdSize = deviceIdSize;
    if( (NULL != CallerDeviceIdBuffer) && (CallerBufferSize >= deviceIdSize) ) {
        // caller supplied buffer is large enough, use it
        RtlZeroMemory( CallerDeviceIdBuffer, CallerBufferSize );
        RtlCopyMemory( CallerDeviceIdBuffer, deviceIdBuffer, deviceIdSize );
        ExFreePool( deviceIdBuffer );
        return CallerDeviceIdBuffer;
    } 
    return deviceIdBuffer;

 targetContinue:

// Builds later than 2080 fail to terminate in Compatibility mode.
//IEEETerminate1284Mode fails after  Event 23 (Extension->CurrentEvent equals 23)
// with earlier 1284 draft.
//So, we terminate the adapter ourselves, in some cases may be redundant.
    P5WritePortUchar(Controller + DCR_OFFSET, DCR_SELECT_IN | DCR_NOT_INIT);
    KeStallExecutionProcessor( 5 );
    P5WritePortUchar(Controller + DCR_OFFSET, DCR_SELECT_IN | DCR_NOT_INIT | DCR_AUTOFEED);
    KeStallExecutionProcessor( 5 );
    P5WritePortUchar(Controller + DCR_OFFSET, DCR_SELECT_IN | DCR_NOT_INIT);
     
    ParStlAssertIdleState ( Extension ) ;

    deviceIdBuffer = ParBuildStlDeviceId(Extension, bReturnRawString);

    if( !deviceIdBuffer ) {
        return NULL;
    }

    deviceIdSize = (USHORT)strlen(deviceIdBuffer);
    *DeviceIdSize = deviceIdSize;
    if( (NULL != CallerDeviceIdBuffer) && (CallerBufferSize >= deviceIdSize) ) {
        // caller supplied buffer is large enough, use it
        RtlZeroMemory( CallerDeviceIdBuffer, CallerBufferSize );
        RtlCopyMemory( CallerDeviceIdBuffer, deviceIdBuffer, deviceIdSize );
        ExFreePool( deviceIdBuffer );
        return CallerDeviceIdBuffer;
    }
    return deviceIdBuffer;
}

PCHAR
ParBuildStlDeviceId(
    IN  PPDO_EXTENSION   Extension,
    IN  BOOLEAN          bReturnRawString
    )
/*++

Routine Description:

    This function detects the type of shuttle adapter and
    builds an appropriate device id string and returns it
    back.

    It is assumed that the device is already in the 
    selected state.

Arguments:

    Nil. 


Return Value:

    Pointer to the read/built device ID string, if successful.

    NULL otherwise.

--*/
{
    ULONG size = 0x80 ;
    PCHAR id ;
    STL_DEVICE_TYPE dtDeviceType ;
    CHAR szDeviceIdString[0x80] ;
    CHAR szVidPidString[] = "MFG:VID_04E6;CLS:SCSIADAPTER;MDL:PID_" ;
    CHAR szVidPidStringScan[] = "MFG:VID_04E6;CLS:IMAGE;MDL:PID_" ;

    RtlZeroMemory(szDeviceIdString, sizeof(szDeviceIdString));

    // identify the shuttle adapter type by calling
    // Devtype routines here and build an unique id
    // string here.
    dtDeviceType = ParStlGetDeviceType(Extension, DEVICE_TYPE_AUTO_DETECT);

    switch ( dtDeviceType ) {

        case DEVICE_TYPE_NONE :
            return NULL;

        case DEVICE_TYPE_EPP_DEVICE :
            dtDeviceType |= 0x80000000 ;
            sprintf(szDeviceIdString, "%s%08X;", szVidPidStringScan, dtDeviceType);
            break;

        default :
            dtDeviceType |= 0x80000000 ;
            sprintf(szDeviceIdString, "%s%08X;", szVidPidString, dtDeviceType);
            break;

    }

    id = ExAllocatePool(PagedPool, size);
    if( id ) {
        RtlZeroMemory( id, size );
        if( bReturnRawString ) {
            //
            // Yes, caller wants the size prefix. Copy prefix to buffer to return.
            //
            *(id+0) = 0;
            *(id+1) = 0x80-2;
            RtlCopyMemory( id+2, szDeviceIdString, size - sizeof(NULL) - 2 );
        } else {
            RtlCopyMemory( id, szDeviceIdString, size - sizeof(NULL) );
        }
        return id;
    }
    return NULL;
}

STL_DEVICE_TYPE __cdecl 
ParStlGetDeviceType (
    IN PPDO_EXTENSION    Extension,
    IN int                  nPreferredDeviceType
    )
{
    STL_DEVICE_TYPE dtDeviceType    = DEVICE_TYPE_NONE ;
    ATAPIPARAMS atapiParams ;
    int i;

    for ( i=0 ; i<ATAPI_MAX_DRIVES ; i++){
        atapiParams.dsDeviceState[i] = DEVICE_STATE_INVALID ;
    }

    do
    {
        if ( TRUE == ParStlCheckIfScsiDevice(Extension))
        {
// SCSI Device identified.
            dtDeviceType |= DEVICE_TYPE_SCSI_BIT ;
            break ;
        }

        if ( TRUE == NeedToEnableIoPads () )
        {
// in some adapters, the IO pads need to be enabled, before
// doing the device detection
            ParStlWriteReg( Extension, CONFIG_INDEX_REGISTER, EP1284_POWER_CONTROL_REG );
            ParStlWriteReg( Extension, CONFIG_DATA_REGISTER, ENABLE_IOPADS );
        }

        if ( TRUE == IsImpactSPresent() )
        {
// as impact-s has been identified, the device type identification
// can be done through personality configuration info
            dtDeviceType |= ParStlGetImpactSDeviceType( Extension, &atapiParams, nPreferredDeviceType );
            break;
        }

        if ( TRUE == IsImpactPresent() )
        {
// as impact has been identified, the device type identification
// can be done through personality configuration info
            dtDeviceType |= ParStlGetImpactDeviceType( Extension, &atapiParams, nPreferredDeviceType );
            break;
        }

        if (TRUE == ParStlCheckIfEppDevice(Extension))
        {
// epp device identified
            if ( TRUE == ParStlCheckUMAXScannerPresence(Extension) ) {
// umax identified
                dtDeviceType |= DEVICE_TYPE_UMAX_BIT;
                break;
            }
            if ( TRUE == ParStlCheckAvisionScannerPresence(Extension) ) {
// avision identified
                dtDeviceType |= DEVICE_TYPE_AVISION_BIT;
                break;
            }
// generice scanner peripheral detected
            dtDeviceType |= DEVICE_TYPE_EPP_DEVICE_BIT;
            break;
        }

        if (TRUE == ParStlCheckIfSSFDC(Extension))
        {
// SSFDC identified
            dtDeviceType |= DEVICE_TYPE_SSFDC_BIT;
            break;
        }

        if (TRUE == ParStlCheckIfMMC(Extension,&atapiParams))
        {
// MMC device identified
            dtDeviceType |= DEVICE_TYPE_MMC_BIT;
            break;
        }

// set the 16 bit mode of the adapter
        ParStlSet16BitOperation(Extension) ;

        if (TRUE == ParStlCheckIfAtaAtapiDevice(Extension, &atapiParams))
        {
// necessary but not sufficient condition has passed
// proceed for sufficency checks
            if (TRUE == ParStlCheckIfAtapiDevice(Extension, &atapiParams))
            {
// sub-classify between HiFD and LS-120.
                if ( TRUE == ParStlCheckIfLS120(Extension))
                {
// LS Engine is found.            
                    dtDeviceType |= DEVICE_TYPE_LS120_BIT ;
                    break ;
                }
// Check for HiFD.  
                if (TRUE == ParStlCheckIfHiFD(Extension))
                {
// HiFD device identified.
                    dtDeviceType |=   DEVICE_TYPE_HIFD_BIT ;
                    break ;
                }
// OtherWise, it is a generic ATAPI device.
                dtDeviceType |= DEVICE_TYPE_ATAPI_BIT;
                break ;
            }

            if (TRUE == ParStlCheckIfAtaDevice(Extension, &atapiParams))
            {
// ata identified
                dtDeviceType |= DEVICE_TYPE_ATA_BIT;
                break;
            }
        }

        if (TRUE == ParStlCheckIfDazzle(Extension))
        {
// dazzle identified
            dtDeviceType |= DEVICE_TYPE_DAZZLE_BIT;
            break;
        }

        if (TRUE == ParStlCheckIfFlash(Extension))
        {
// flash identified
            dtDeviceType |= DEVICE_TYPE_FLASH_BIT;
            break;
        }
    }
    while ( FALSE ) ;

    return dtDeviceType & nPreferredDeviceType ;
}

VOID
ParStlWaitForMicroSeconds (
    int nMicroSecondsToWait
    ) {
    KeStallExecutionProcessor ( nMicroSecondsToWait ) ;
}

BOOLEAN
ParStlCheckCardInsertionStatus ( 
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue    = FALSE ;
    UCHAR   byPowerRegData ;
    do
    {
        if ( FALSE == IsEp1284Present() )
        {
            break ;
        }

        ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER , 0x0F ) ;
        byPowerRegData  =  (UCHAR) ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) ;
        
        if ( byPowerRegData & SHTL_CARD_INSERTED_STATUS )
        {
// as the card not inserted status is reported, it is ATA / ATAPI
// possibly, not flash. hence, we break here.
            break ;
        }

        bReturnValue    =   TRUE ;
    }
    while ( FALSE ) ;

    return ( bReturnValue ) ;
}

BOOLEAN
ParStlSelectAdapterSocket (
    IN  PPDO_EXTENSION   Extension,
    IN  int                 nSocketNumber
    )
{
    BOOLEAN bReturnValue    =   FALSE ;
    UCHAR   bySCRControlReg , byISAControlReg ;

    do
    {
        if ( ( nSocketNumber != SOCKET_0 ) &&
             ( nSocketNumber != SOCKET_1 ) )
        {
// as an invalid socket number is provided, we
// break here with error.
            break ;
        } 

        ParStlWriteReg(Extension, CONFIG_INDEX_REGISTER , SOCKET_CONTROL_REGISTER ) ;
        bySCRControlReg = (UCHAR) ParStlReadReg (Extension, CONFIG_DATA_REGISTER ) ;

        ParStlWriteReg(Extension, CONFIG_INDEX_REGISTER , ISA_CONTROL_REGISTER ) ;
        byISAControlReg = (UCHAR) ParStlReadReg (Extension, CONFIG_DATA_REGISTER ) ;

        if ( SOCKET_1 == nSocketNumber )
        {
            bySCRControlReg |=  (UCHAR)SOCKET_1 ;
            bySCRControlReg |=  (UCHAR)PERIPHERAL_RESET_1 ;
            byISAControlReg &=  ~(UCHAR)ISA_IO_SWAP ;
        }
        else
        {
            bySCRControlReg &=  ~(UCHAR)SOCKET_1 ;
            bySCRControlReg &=  ~(UCHAR)PERIPHERAL_RESET_0 ;
        }

        ParStlWriteReg(Extension, CONFIG_INDEX_REGISTER , ISA_CONTROL_REGISTER ) ;
        ParStlWriteReg(Extension, CONFIG_DATA_REGISTER , byISAControlReg ) ;

        ParStlWriteReg(Extension, CONFIG_INDEX_REGISTER , SOCKET_CONTROL_REGISTER ) ;
        ParStlWriteReg(Extension, CONFIG_DATA_REGISTER , bySCRControlReg ) ;

        if ( SOCKET_1 == nSocketNumber )
        {
// Wait for a few milliseconds to provide an optimal puse width
// for reset.
            ParStlWaitForMicroSeconds(1000);
            bySCRControlReg &=  ~(UCHAR)PERIPHERAL_RESET_1 ;
        }
        else
        {
            bySCRControlReg &=  ~(UCHAR)PERIPHERAL_RESET_0 ;
        }
        ParStlWriteReg(Extension, CONFIG_DATA_REGISTER , bySCRControlReg ) ;

        bReturnValue    =   TRUE ;
    }
    while ( FALSE ) ;

    return  bReturnValue ;
}

BOOLEAN 
ParStlCheckIfAtaAtapiDevice (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
        if ( TRUE == ParStlCheckCardInsertionStatus(Extension) )
        {
// as the card insertion status is valid, its probably
// a flash
            break ;
        }
        if ( FALSE == ParStlCheckDrivePresent(Extension, atapiParams) ) 
        {
// as the ATA/ATAPI controller is not present, it cant be
// an ATA/ATAPI device
            break ;
        }
        bReturnValue = TRUE;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfAtapiDevice (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
// return whatever ATAPI initialization module says
        bReturnValue = ParStlAtapiInitialize(Extension, atapiParams) ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfAtaDevice (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
// return whatever ATA initialization module says
        bReturnValue = ParStlAtaInitialize(Extension, atapiParams) ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN
ParStlCheckDrivePresent (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue    = FALSE ;
    UCHAR   byOrgCylHigh, byOrgCylLow ;
    int     nCurrentDrive = 0 , i ;
    UCHAR   nDrvHdArray[]={ATAPI_MASTER, ATAPI_SLAVE};

    do
    {
        if ( atapiParams->dsDeviceState[nCurrentDrive] == DEVICE_STATE_VALID )
        {
// this means that the MMC module had detected the presence
// of an ATA/ATAPI device. So, we make use of that and break out
            bReturnValue = TRUE ;
            break ;
        }

        ParStlWriteIoPort(Extension, ATA_DRVHD_REG, nDrvHdArray[nCurrentDrive]);

//  The Atapi Fuji MO drive is found to de-assert BSY and still
//  does not respond to reg. r/w when configured as slave with no media.
//  However, after a delay, it works ok.
        if ( nCurrentDrive )
        {
            ParStlWaitForMicroSeconds ( DELAY_1SECOND ) ;
        }

// this dummy write of 0 is to zero out a possible 
// floating bus
        for ( i = 0 ; i < 16 ; i++ )
        {
            ParStlWriteReg(Extension, CONFIG_INDEX_REGISTER, i) ;
            if ( !( ParStlReadIoPort (Extension, ATA_TASK_STAT_REG ) & ATA_ST_BUSY ) )
            {
                break ;
            }
        }

        if ( FALSE == ParStlWaitForBusyToClear(Extension, ATA_TASK_STAT_REG) )
        {
// as the busy has been found permanently set, we check
// for the slave also
            continue;
        }

// as the drive head setup might have been performed in a busy state,
// we set it up again after busy clears.
        ParStlWriteIoPort(Extension, ATA_DRVHD_REG, nDrvHdArray[nCurrentDrive]);

        if ( ( ParStlReadIoPort(Extension, ATA_DRVHD_REG) & ATAPI_SLAVE ) != nDrvHdArray[nCurrentDrive] )
        {
            continue ;
        }

// read original contents of the cyl ATA high/low registers
        byOrgCylLow  = (UCHAR) ParStlReadIoPort(Extension, ATA_CYLLOW_REG);
        byOrgCylHigh = (UCHAR) ParStlReadIoPort(Extension, ATA_CYLHIGH_REG);

// write a test pattern in the cyl ATA high/low registers
        ParStlWriteIoPort(Extension, ATA_CYLLOW_REG, TEST_PATTERN_1);
        ParStlWriteIoPort(Extension, ATA_CYLHIGH_REG, TEST_PATTERN_2);

// read the test pattern in the cyl ATA high/low registers
        if ( ( TEST_PATTERN_1 != ParStlReadIoPort(Extension, ATA_CYLLOW_REG) ) ||\
             ( TEST_PATTERN_2 != ParStlReadIoPort(Extension, ATA_CYLHIGH_REG) ) )
        {
// as we were not able to read back the written values
// we break out here, indicating the absence of the device
            continue ;
        }

// write back original contents in the cyl ATA high/low registers
        ParStlWriteIoPort(Extension, ATA_CYLLOW_REG, byOrgCylLow);
        ParStlWriteIoPort(Extension, ATA_CYLHIGH_REG, byOrgCylHigh);
        bReturnValue = TRUE ;
        atapiParams->dsDeviceState[nCurrentDrive] = DEVICE_STATE_VALID ;
    }
    while ( ++nCurrentDrive < ATAPI_MAX_DRIVES );

// reset back to master state, as check drive present
// will be called successively
    ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_MASTER);

    return bReturnValue ;
}

BOOLEAN
ParStlAtapiInitialize ( 
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue    = FALSE ;
    int     nCurrentDrive   = 0, i ;
    UCHAR   byTempValue ;
    UCHAR   chAtapiIdentifyBuffer [ ATAPI_IDENTIFY_LENGTH ] ;
    do
    {
        if ( DEVICE_STATE_VALID != atapiParams->dsDeviceState[nCurrentDrive] )
        {
// the device is absent
            continue ;
        }

        if ( nCurrentDrive ) 
        {
// as it is the next drive, choose the slave
            ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_SLAVE);
        }
        else
        {
// choose the master
            ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_MASTER);
        }

        if ( FALSE == ParStlWaitForBusyToClear(Extension, ATA_TASK_STAT_REG) )
        {
// as busy has permanently set after master/slave, we fail
// the detection process
            continue ;
        }

// check if the ATAPI signature is present in the cyl hi/lo
// registers. If present, it is definitely an ATAPI device
        if ( ( ParStlReadIoPort(Extension, ATA_CYLLOW_REG) == ATAPI_SIGN_LOW ) &&\
             ( ParStlReadIoPort(Extension, ATA_CYLHIGH_REG) == ATAPI_SIGN_HI ) )
        {
// as ATAPI signature is present, it is ATAPI type
            bReturnValue = TRUE ;

// set this flag so that, ATA initialize will skip this
// target
            atapiParams->dsDeviceState[nCurrentDrive] = DEVICE_STATE_ATAPI ;
// for Impact, since Ls120 engine is always present,
// issuing ATAPI_IDENTIFY is mandatory. 
            if ( !IsImpactPresent())
            {
                continue ;
            }
        }

// issue the ata nop command
        ParStlWriteIoPort(Extension, ATA_TASK_CMD_REG, ATA_NOP_COMMAND) ;

        if ( FALSE == ParStlWaitForIrq(Extension) )
        {
// ATAPI devices are expected to give interrrupt on NOP command
// mandatorily.
            continue ;
        }
        if ( FALSE == ParStlWaitForBusyToClear(Extension, ATA_TASK_STAT_REG) )
        {
// as busy has permanently set, we proceed with the next
// drive
            continue ;
        }

// issue the atapi packet command
        ParStlWriteIoPort(Extension, ATA_TASK_CMD_REG, ATAPI_IDENTIFY) ;

        if ( FALSE == ParStlWaitForIrq(Extension) )
        {
// ATAPI devices are expected to give interrrupt on 0xA1 command
// mandatorily.
            continue ;
        }
        if ( FALSE == ParStlWaitForBusyToClear(Extension, ATA_TASK_STAT_REG) )
        {
// as busy has permanently set, we proceed with the next
// drive
            continue ;
        }

        byTempValue = (UCHAR) ParStlReadIoPort ( Extension, ATA_TASK_STAT_REG ) ;
        if ( ! ( byTempValue & ATA_ST_ERROR ) )
        {
// as the drive has passed the packet command, this is an atapi
// drive
// Wait for DRQ to be sit, as some drives are known
// to remove busy too early and set DRQ after some time.
            if ( FALSE == ParStlWaitForDrq(Extension) )
            {
// as there was no DRQ set, we proceed with the next
// drive
                continue ;
            }
            bReturnValue = TRUE ;
// as the DRQ is still asserted, quell it, as certain ATA/ATAPI-4
// spec. dictates it so
// There is a need to check the device identifier returned in the 
// ATAPI Identify cmd. to determine the presence of Ls-120.
            ParStlReceiveData ( Extension, chAtapiIdentifyBuffer , SKIP_MEMORY_ADDRESS , ATAPI_IDENTIFY_LENGTH ) ;
            for ( i = 0 ; i < ATAPI_NAME_LENGTH ; i++ )
            {
                atapiParams->szAtapiNameString[i] = chAtapiIdentifyBuffer[ ATAPI_NAME_OFFSET + i ] ;
            }

// set this flag so that, ATA initialize will skip this
// target
            atapiParams->dsDeviceState[nCurrentDrive] = DEVICE_STATE_ATAPI ;
        }
    }
    while ( ++nCurrentDrive < ATAPI_MAX_DRIVES );

// reset back to master state, as check drive present
// will be called successively
    ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_MASTER);

    return ( bReturnValue ) ;
}

BOOLEAN
ParStlAtaInitialize ( 
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue    = FALSE ;
    UCHAR   byTempValue ;
    int     nCurrentDrive   = 0 ;
    do
    {
        if ( DEVICE_STATE_VALID != atapiParams->dsDeviceState[nCurrentDrive] )
        {
// atapi module has marked its presence or the device is absent
            continue ;
        }

// select the possibly present device
        if ( nCurrentDrive ) 
        {
            ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_SLAVE ) ;
        }
        else
        {
            ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_MASTER ) ;
        }

        if ( FALSE == ParStlWaitForBusyToClear(Extension, ATA_TASK_STAT_REG) )
        {
// as busy has permanently set after master/slave, we fail the
// detection process
            continue ;
        }

// issue the ata NOP command
        ParStlWriteIoPort(Extension, ATA_TASK_CMD_REG, ATA_NOP_COMMAND) ;

        if ( FALSE == ParStlWaitForBusyToClear(Extension, ATA_TASK_STAT_REG) )
        {
// as busy has permanently set, we fail the detection process
            continue ;
        }

        byTempValue = (UCHAR) ParStlReadIoPort ( Extension, ATA_TASK_STAT_REG ) ;
        if ( ( byTempValue != BUS_LINES_IN_HIGH_IMPEDANCE ) &&\
             ( byTempValue & ATA_ST_ERROR ) )
        {
// as the bus is not reading 0xFF and the status register
// indicates an error, this is likely to be an ATA device
            if ( ATA_ERROR_ABORTED_COMMAND == ( (UCHAR) ParStlReadIoPort ( Extension, ATA_ERROR_REG ) & 0x0F ) )
            {
// as the error register, contains the ata aborted error 
// in response to our ATA NOP command, we conclude that
// it is ATA! as it is already known that it is not ATAPI
                bReturnValue = TRUE ;
                break;
            }
        }
    }
    while ( ++nCurrentDrive < ATAPI_MAX_DRIVES );

// reset back to master state, as check drive present
// will be called successively
    ParStlWriteIoPort(Extension, ATA_DRVHD_REG, ATAPI_MASTER);

    return ( bReturnValue ) ;
}

BOOLEAN
ParStlWaitForBusyToClear (
    IN  PPDO_EXTENSION   Extension,
    IN  int                 nRegisterToWaitOn 
    ) 
{
// The default timeout increased to 10secs as Fujitsu MO is found to set
// BUSY for >5secs for 0xA1 command.
    int nMaxRetrials  = MAX_RETRIES_FOR_10_SECS ;
    BOOLEAN    bRetVal =   FALSE ;

    while ( nMaxRetrials-- )
    {
// the following service will be implemented by the caller
// the driver can use the STLMPORT service.
        ParStlWaitForMicroSeconds ( DELAY_1MILLISECONDS ) ;
        if ( ! ( ParStlReadIoPort ( Extension, nRegisterToWaitOn ) & ATA_ST_BUSY ) )
        {
// as busy has cleared, we return clear here
            bRetVal = TRUE ;
            break ;
        }
    }
    return  bRetVal ;
}

BOOLEAN
ParStlWaitForDrq (
    IN  PPDO_EXTENSION   Extension
    ) 
{
    int nMaxRetrials  = MAX_RETRIES_FOR_5_SECS ;
    BOOLEAN    bRetVal =   FALSE ;
    while ( nMaxRetrials-- )
    {
        if ( ParStlReadIoPort ( Extension, ATA_TASK_STAT_REG ) & ATA_ST_DRQ )
        {
// as busy has cleared, we return clear here
            bRetVal = TRUE ;
            break ;
        }
// the following service will be implemented by the caller
// the driver can use the STLMPORT service.
        ParStlWaitForMicroSeconds ( DELAY_1MILLISECONDS ) ;
    }
    return  bRetVal ;
}

BOOLEAN
ParStlWaitForIrq (
    IN  PPDO_EXTENSION   Extension
    ) 
{
    int nMaxRetrials  = MAX_RETRIES_FOR_10_SECS ;
    BOOLEAN    bRetVal =   FALSE ;
    while ( nMaxRetrials-- )
    {
        if ( ParStlReadReg ( Extension, EP1284_TRANSFER_CONTROL_REG ) & XFER_IRQ_BIT )
        {
// as Irq has asserted, we return true here
            bRetVal = TRUE ;
            break ;
        }
        ParStlWaitForMicroSeconds ( DELAY_1MILLISECONDS ) ;
    }
    return  bRetVal ;
}

VOID
ParStlSet16BitOperation (
    IN  PPDO_EXTENSION   Extension
    ) 
{
    int nModeReg ;

    nModeReg = ParStlReadReg ( Extension, EP1284_MODE_REGISTER ) ;

    if ( 0 == ( nModeReg & EP1284_ENABLE_16BIT ) )
    {
// as the bit is not already set, this needs to be set now
        ParStlWriteReg ( Extension, EP1284_MODE_REGISTER, nModeReg | EP1284_ENABLE_16BIT ) ; 
    }
}

BOOLEAN 
ParStlCheckIfEppDevice (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
        if ( FALSE == IsEp1284Present() )
        {
// as EPPDEVs live only on EP1284 we break here
            break;
        }

        bReturnValue = ParStlCheckPersonalityForEppDevice(Extension) ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN
ParStlCheckPersonalityForEppDevice (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE ;

    ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER, EP1284_PERSONALITY_REG ) ;
    if ( EPPDEV_SIGN == ( ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) & PERSONALITY_MASK ) )
    {
// as the EPPDEV sign is found in the personality
// we break with success here
        bReturnValue   = TRUE ;
    }

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfFlash (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN    bReturnValue = FALSE ;

    do 
    {
        if ( !IsEp1284Present() && !IsImpactPresent() && !IsEpatPlusPresent() )
        {
// Check the sign-on version checks for the existence of Shuttle
// adapter. If nothing is found, we break here.
            break ;
        }

// Perform a ATA-16bit check just in case, it turns out to be something else
        bReturnValue = ParStlCheckFlashPersonality(Extension) ;
    }
    while ( FALSE ) ;

    return  bReturnValue ;
}

BOOLEAN
ParStlCheckFlashPersonality (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE ;

    if ( IsEp1284Present() )
    {
// as the personality configuration check only works for
// Ep1284, confim its presence before the actual check.
        ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER, EP1284_PERSONALITY_REG ) ;
        if ( FLASH_SIGN == ( ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) & FLASH_PERSONALITY_MASK ) )
        {
// as the flash sign ATA-16bit device is found in the personality
// we break with success here
            bReturnValue   = TRUE ;
        }
    }
    else
    {
// always return true, if a shuttle adapter other than ep1284 is
// identified and assume it might be flash!
        bReturnValue    =   TRUE ;
    }

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfDazzle (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue = FALSE ;
    UCHAR   ucSignature ;

    do 
    {
        if ( !IsEp1284Present() )
        {
// Check for EP1284 presence, as Dazzle is ONLY on EP1284
// adapters. If the adapter is not EP1284, we break.
            break ;
        }

// Check whether any card insertion is detected, to eliminate
// possible flash adapters with the card in
        if ( TRUE == ParStlCheckCardInsertionStatus( Extension ) ) {
            break ;
        }

// code to read the pulled up pattern present on dazzle
// adapters.
        ParStlWriteReg( Extension, DAZ_SELECT_BLK, DAZ_BLK0 ) ;
        ucSignature = (UCHAR) ParStlReadReg( Extension, DAZ_REG1 ) ;

        if ( ( ucSignature == DAZ_CONFIGURED ) ||\
             ( ucSignature == DAZ_NOT_CONFIGURED ) ) {
            // the pulled up pattern generally found ONLY
            // on the DAZZLE adapter is found. So, we
            // conclude that it is a Dazzle adapter 
                bReturnValue = TRUE ;
        }

    }
    while ( FALSE ) ;

    return  bReturnValue ;
}

BOOLEAN 
ParStlCheckIfHiFD (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE;

    do
    {
        if ( FALSE == ParStlSelectAdapterSocket(Extension, SOCKET_1) )
        {
// as the socket 1 selection failed,
// we break out here.
            break ;
        }

// check for the ready status of the floppy controller,
// after clearing the reset bit of the floppy controller.

        if ( FALSE == ParStlHIFDCheckIfControllerReady(Extension) )
        {
// since the controller didnot wake up after the
// reset pin was asserted, we break here.

            break ;
        }

        if ( FALSE == ParStlHIFDCheckSMCController(Extension) )
        {
// as the SMC ID retrieval failed,
// we break out here.
            break ;
        }

        bReturnValue = TRUE ;

    }
    while ( FALSE ) ;
// Reset the socket to zero.
    ParStlSelectAdapterSocket(Extension, SOCKET_0);
    return bReturnValue ;
}

BOOLEAN
ParStlHIFDCheckIfControllerReady (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue    =   FALSE ;
    UCHAR   bySCRControlReg ;
    do
    {
        ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER , SOCKET_CONTROL_REGISTER ) ;
        bySCRControlReg = (UCHAR) ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) ;
        bySCRControlReg |=  (UCHAR)PERIPHERAL_RESET_1 ;
        ParStlWriteReg ( Extension, CONFIG_DATA_REGISTER , bySCRControlReg ) ;
        ParStlWaitForMicroSeconds ( HIFD_WAIT_10_MILLISEC ) ;

        ParStlWriteIoPort ( Extension, HIFD_DIGITAL_OUTPUT_REGISTER ,
                              0x00 ) ;
        ParStlWaitForMicroSeconds ( HIFD_WAIT_1_MILLISEC ) ;

        ParStlWriteIoPort ( Extension, HIFD_DIGITAL_OUTPUT_REGISTER ,
                              HIFD_DOR_RESET_BIT | HIFD_ENABLE_DMA_BIT ) ;
        ParStlWaitForMicroSeconds ( HIFD_WAIT_10_MILLISEC ) ;

        if ( HIFD_CONTROLLER_READY_STATUS == ParStlReadIoPort ( Extension, HIFD_MAIN_STATUS_REGISTER ) )
        {
            bReturnValue = TRUE ;
        }

        bySCRControlReg     &= ~(UCHAR)PERIPHERAL_RESET_1 ;
        ParStlWriteReg ( Extension, CONFIG_DATA_REGISTER , bySCRControlReg ) ;

    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN
ParStlHIFDCheckSMCController (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN    bReturnValue = FALSE ;
    do
    {
        ParStlWriteIoPort ( Extension, HIFD_STATUS_REGISTER_A , HIFD_COMMAND_TO_CONTROLLER ) ;
        ParStlWriteIoPort ( Extension, HIFD_STATUS_REGISTER_A , HIFD_COMMAND_TO_CONTROLLER ) ;
        ParStlWriteIoPort ( Extension, HIFD_STATUS_REGISTER_A , HIFD_CTL_REG_0D ) ;
        if ( SMC_DEVICE_ID == ParStlReadIoPort ( Extension, HIFD_STATUS_REGISTER_B ) )
        {
            bReturnValue = TRUE ;
            ParStlWriteIoPort ( Extension, HIFD_STATUS_REGISTER_A , HIFD_CTL_REG_03 ) ;
            ParStlWriteIoPort ( Extension, HIFD_STATUS_REGISTER_B , SMC_ENABLE_MODE2 ) ;        
        }
        ParStlWriteReg ( Extension, HIFD_STATUS_REGISTER_A , HIFD_TERMINATE_SEQUENCE ) ;

    }
    while ( FALSE ) ;

    return bReturnValue ;
}

STL_DEVICE_TYPE
ParStlGetImpactDeviceType (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams,
    IN  int                 nPreferredDeviceType
    )
{
    IMPACT_DEVICE_TYPE      idtImpactDeviceType ;
    STL_DEVICE_TYPE         dtDeviceType = DEVICE_TYPE_NONE ;

    ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER, IMPACT_PERSONALITY_REG ) ;
    idtImpactDeviceType    = ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) >> 4 ;

    switch ( idtImpactDeviceType )
    {
        case IMPACT_DEVICE_TYPE_ATA_ATAPI:

            // set the 16 bit mode of the adapter
            ParStlSet16BitOperation(Extension) ;

            if (TRUE == ParStlCheckIfAtaAtapiDevice(Extension,atapiParams))
            {
// necessary but not sufficient condition has passed
// proceed for sufficency checks
                if (TRUE == ParStlCheckIfAtapiDevice(Extension,atapiParams))
                {
// atapi identified
// Check for Impact LS-120 device
                    if ( TRUE == ParStlCheckIfImpactLS120(Extension, atapiParams))
                    {
                        dtDeviceType |= DEVICE_TYPE_LS120_BIT ;
                        break ;
                    }
                    dtDeviceType |= DEVICE_TYPE_ATAPI_BIT;
                    break ;
                }

                if (TRUE == ParStlCheckIfAtaDevice(Extension, atapiParams))
                {
// ata identified
                    dtDeviceType |= DEVICE_TYPE_ATA_BIT;
                    break;
                }
            }
            break ;

        case IMPACT_DEVICE_TYPE_CF:
            dtDeviceType |= DEVICE_TYPE_FLASH_BIT;
            break ;

        case IMPACT_DEVICE_TYPE_PCMCIA_CF:
            dtDeviceType |= DEVICE_TYPE_PCMCIA_CF_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_SSFDC:
            dtDeviceType |= DEVICE_TYPE_SSFDC_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_MMC:
            dtDeviceType |= DEVICE_TYPE_MMC_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_HIFD:
            dtDeviceType |= DEVICE_TYPE_HIFD_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_SOUND:
            dtDeviceType |= DEVICE_TYPE_SOUND_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_FLP_TAPE_DSK:
            dtDeviceType |= DEVICE_TYPE_FLP_TAPE_DSK_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_ATA_ATAPI_8BIT:
            dtDeviceType |= DEVICE_TYPE_ATA_ATAPI_8BIT_BIT ;
            break;

        default:
            break;
    }

    return dtDeviceType & nPreferredDeviceType ;
}

STL_DEVICE_TYPE
ParStlGetImpactSDeviceType (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams,
    IN  int                 nPreferredDeviceType
    )
{
    IMPACT_DEVICE_TYPE      idtImpactDeviceType ;
    IMPACT_DEVICE_TYPE      idtImpactSDeviceType ;
    STL_DEVICE_TYPE         dtDeviceType = DEVICE_TYPE_NONE ;

    ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER, IMPACT_PERSONALITY_REG ) ;
    idtImpactDeviceType    = ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) >> 4 ;

    switch ( idtImpactDeviceType )
    {
        case IMPACT_DEVICE_TYPE_ATA_ATAPI:

            // set the 16 bit mode of the adapter
            ParStlSet16BitOperation(Extension) ;

            if (TRUE == ParStlCheckIfAtaAtapiDevice(Extension,atapiParams))
            {
// necessary but not sufficient condition has passed
// proceed for sufficency checks
                if (TRUE == ParStlCheckIfAtapiDevice(Extension,atapiParams))
                {
// atapi identified
                    dtDeviceType |= DEVICE_TYPE_ATAPI_BIT;
                    break ;
                }

                if (TRUE == ParStlCheckIfAtaDevice(Extension,atapiParams))
                {
// ata identified
                    dtDeviceType |= DEVICE_TYPE_ATA_BIT;
                    break;
                }
            }
            break ;

        case IMPACT_DEVICE_TYPE_CF:
            dtDeviceType |= DEVICE_TYPE_FLASH_BIT;
            break ;

        case IMPACT_DEVICE_TYPE_PCMCIA_CF:
            dtDeviceType |= DEVICE_TYPE_PCMCIA_CF_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_SSFDC:
            dtDeviceType |= DEVICE_TYPE_SSFDC_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_MMC:
            dtDeviceType |= DEVICE_TYPE_MMC_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_HIFD:
            dtDeviceType |= DEVICE_TYPE_HIFD_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_SOUND:
            dtDeviceType |= DEVICE_TYPE_SOUND_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_FLP_TAPE_DSK:
            dtDeviceType |= DEVICE_TYPE_FLP_TAPE_DSK_BIT ;
            break;

        case IMPACT_DEVICE_TYPE_ATA_ATAPI_8BIT:
            dtDeviceType |= DEVICE_TYPE_ATA_ATAPI_8BIT_BIT ;
            break;

        case IMPACTS_EXT_PERSONALITY_PRESENT:
            ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER, IMPACTS_EXT_PERSONALITY_XREG ) ;
            idtImpactSDeviceType    = ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) ;
            dtDeviceType = DEVICE_TYPE_EXT_HWDETECT ;
            dtDeviceType |= idtImpactSDeviceType ;
            break ;

        default:
            break;
    }

    return dtDeviceType & nPreferredDeviceType ;
}

BOOLEAN 
ParStlCheckIfLS120 (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
        if ( FALSE == ParStlSelectAdapterSocket(Extension, SOCKET_1) )
        {
// as the socket 1 selection failed,
// we break out here.
            break ;
        }

// check for engine version.                    

        if ( LS120_ENGINE_VERSION == ParStlReadIoPort( Extension, LS120_ENGINE_VERSION_REGISTER ) )
        {
// if the ls120 engine version is correct, we have
// found LS120.

            bReturnValue    =   TRUE ;
        }

// Reset the socket to zero.
        ParStlSelectAdapterSocket ( Extension, SOCKET_0 ) ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfImpactLS120 (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue   = FALSE ;
    BOOLEAN bLs120NameFound= TRUE ;
    char chLs120Name[] = "HU DlFpoyp";
    char *pszAtapiName = atapiParams->szAtapiNameString ;
    int  i , nMemoryOnBoard ;

    do
    {
        for ( i = 0 ;i < sizeof(chLs120Name)-1 ; i++ )
        {
            if ( pszAtapiName[i] != chLs120Name[i] )
            {
                bLs120NameFound = FALSE ;
                break ;
            }
        }
        if ( TRUE != bLs120NameFound )
        {
// as LS-120 name string is not found, we conclude that it is
// not LS-120
            break ;
        }
        nMemoryOnBoard =  ParStlGetMemorySize(Extension) ;
        if ( ( !IsShtlError ( nMemoryOnBoard ) ) && \
             ( nMemoryOnBoard ) )
        {
// there is memory on-board.
// hence, we return ls120 here
            bReturnValue = TRUE ;
            break ;
        }
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfMMC (
    IN  PPDO_EXTENSION   Extension,
    IN  OUT  PATAPIPARAMS   atapiParams
    )
{
    BOOLEAN bReturnValue   = FALSE;

    do
    {
        if ( FALSE == IsEpatPlusPresent() )
        {
// as mmc device can exist only on EPAT Plus adapter only
// we break out of here
            break;
        }
        if ( TRUE == ParStlCheckIfAtaAtapiDevice (Extension,atapiParams) )
        {
// as an ATA/ATAPI device is probably present,
// we break out of here
            break;
        }
        bReturnValue = ParStlIsMMCEnginePresent(Extension) ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlIsMMCEnginePresent(
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE;

    do
    {
// check if the ATAPI signature is present in the cyl hi/lo
// registers. If present, it is definitely an ATAPI device
        if ( ( ParStlReadIoPort(Extension, CYLLOW_REG) == ATAPI_SIGN_LOW ) &&\
             ( ParStlReadIoPort(Extension, CYLHIGH_REG) == ATAPI_SIGN_HI ) )
        {
// as ATAPI signature is present, it cant be MMC
            break ;
        }

// write a zero pattern ( which will be a NOP for ATA/ATAPI devices ) 
// in the block size / possible ATA/ATAPI command register
        ParStlWriteReg(Extension, MMC_ENGINE_INDEX, MMC_BLOCK_SIZE_REG);
        ParStlWriteReg(Extension, MMC_ENGINE_DATA, MMC_TEST_PATTERN_1);
        if ( MMC_TEST_PATTERN_1 != ParStlReadReg(Extension, MMC_ENGINE_DATA) )
        {
// as the written value is not available, it means device present
// has responded to the written value, in a way different from
// how an MMC would have.
            break ;
        }

// write a test pattern in the freq register
        ParStlWriteReg(Extension, MMC_ENGINE_INDEX, MMC_FREQ_SELECT_REG);
        ParStlWriteReg(Extension, MMC_ENGINE_DATA, MMC_TEST_PATTERN_2);

// write another in the block size register
        ParStlWriteReg(Extension, MMC_ENGINE_INDEX, MMC_BLOCK_SIZE_REG);
        ParStlWriteReg(Extension, MMC_ENGINE_DATA, MMC_TEST_PATTERN_3);

        ParStlWriteReg(Extension, MMC_ENGINE_INDEX, MMC_FREQ_SELECT_REG);
        if ( MMC_TEST_PATTERN_2 != ParStlReadReg(Extension, MMC_ENGINE_DATA) )
        {
// as we were not able to read back the written value
// we quit here
            break;
        }

        ParStlWriteReg(Extension, MMC_ENGINE_INDEX, MMC_BLOCK_SIZE_REG);
        if ( MMC_TEST_PATTERN_3 != ParStlReadReg(Extension, MMC_ENGINE_DATA) )
        {
// as we were not able to read back the written value
// we quit here
            break;
        }
// as all tests have passed, engine presence is confirmed
// here
        bReturnValue = TRUE ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfScsiDevice (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
        if ( FALSE == IsEpstPresent() )
        {
// as SCSI devices live only on EPST we break here
            break;
        }

        bReturnValue = TRUE ;
    }
    while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN 
ParStlCheckIfSSFDC (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN bReturnValue   = FALSE;
    do
    {
        if ( FALSE == IsEp1284Present() )
        {
// SSFDC lives on EP1284 alone, other than impact
// which is already taken care
            break;
        }

//check to see if the loop back of the EPCS and EPDO pins
//of the INDEX 00 register read the same. If so, it is 
//SSFDC board characteristic
        ParStlWriteReg ( Extension, CONFIG_INDEX_REGISTER , 0x00 ) ;
        ParStlWriteReg ( Extension, CONFIG_DATA_REGISTER , 0x10 ) ;
        ParStlWriteReg ( Extension, CONFIG_DATA_REGISTER , 0x12 ) ;
        if ( 0x1A == ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) )
        {
            ParStlWriteReg ( Extension, CONFIG_DATA_REGISTER , 0x10 ) ;
            if ( ! ( ParStlReadReg ( Extension, CONFIG_DATA_REGISTER ) & 0x08 ) )
            {
//as they are equal, SSFDC present
                bReturnValue    =   TRUE ;
                break ;
            }
        }

    }
    while ( FALSE ) ;

    return bReturnValue ;
}

VOID
ParStlAssertIdleState (
    IN  PPDO_EXTENSION   Extension
    )
{
    PUCHAR  CurrentPort, CurrentControl ;
    ULONG   Delay = 5 ;

    CurrentPort = Extension->Controller;
    CurrentControl = CurrentPort + 2;

// place op-code for idle state in port base
    P5WritePortUchar ( CurrentPort, (UCHAR) 0x00 ) ;
    KeStallExecutionProcessor( Delay );

// bring down DCR_INIT and DCR_STROBE
    P5WritePortUchar ( CurrentControl, (UCHAR) STB_INIT_LOW ) ;
    KeStallExecutionProcessor( Delay );

// lift DCR_INIT and DCR_STROBE to high
    P5WritePortUchar ( CurrentControl, (UCHAR) STB_INIT_AFXT_HI ) ;
    KeStallExecutionProcessor( Delay );
}

BOOLEAN
ParStlCheckAvisionScannerPresence(
        IN PPDO_EXTENSION Extension
    )
{
    BOOLEAN bReturnValue = FALSE ;
    UCHAR   data;

    do {

        data = (UCHAR) ParStlReadReg( Extension, STATUSPORT);
        if((data & 0x80) == 0) {
            break ;
        }

        ParStlWriteReg( Extension, CONTROLPORT, 0x08 ) ;
        ParStlWriteReg( Extension, CONTROLPORT, 0x08 ) ;

        data = (UCHAR) ParStlReadReg( Extension, STATUSPORT);
        if((data & 0x80) != 0) {
            break ;
        }

        ParStlWriteReg( Extension, CONTROLPORT, 0x00 ) ;
        ParStlWriteReg( Extension, CONTROLPORT, 0x00 ) ;

        data = (UCHAR) ParStlReadReg( Extension, STATUSPORT);
        if((data & 0x80) == 0) {
            break ;
        }

        ParStlWriteReg( Extension, CONTROLPORT, 0x02 ) ;
        ParStlWriteReg( Extension, CONTROLPORT, 0x02 ) ;

        data = (UCHAR) ParStlReadReg( Extension, STATUSPORT);
        if((data & 0x80) != 0) {
            break ;
        }

        ParStlWriteReg( Extension, CONTROLPORT, 0x00 ) ;
        ParStlWriteReg( Extension, CONTROLPORT, 0x00 ) ;

        data = (UCHAR) ParStlReadReg( Extension, STATUSPORT);
        if((data & 0x80) == 0) {
            break ;
        }

        bReturnValue = TRUE ;

    } while ( FALSE ) ;

    return bReturnValue ;
}

BOOLEAN
ParStlCheckUMAXScannerPresence(
    IN PPDO_EXTENSION    Extension
    )
{
    UCHAR   commandPacket_[6] = {0x55,0xaa,0,0,0,0} ;
    PUCHAR  commandPacket ;
    USHORT  status;
    UCHAR   idx;
    PUCHAR  saveCommandPacket;
    ULONG   dataLength;

    ParStlWriteReg ( Extension, CONTROLPORT, 0 ) ;  // scannner reset
    KeStallExecutionProcessor ( 2000 ) ;            // 2 m.secs delay
    ParStlWriteReg ( Extension, CONTROLPORT, 0x0C ) ;

    commandPacket = commandPacket_ ;
    saveCommandPacket = commandPacket;

    if ( TRUE == ParStlSetEPPMode(Extension) ) {

        commandPacket+=2;
        dataLength = *(ULONG*)commandPacket;
        dataLength &= 0xffffff; //data bytes ordering (msb to lsb) will
                                // wrong .What we need here is whether the
                                // dataLength is 0 or not.

        commandPacket = saveCommandPacket;

        //Command phase

        status = ParStlEPPWrite(Extension, *(commandPacket)++);
        if((status & 0x700) != 0){
            return FALSE;      //TIMEOUT_ERROR);
        }

        status = ParStlEPPWrite(Extension, *(commandPacket)++);
        if((status & 0x700 ) != 0){
            return FALSE;     //TIMEOUT_ERROR);
        }

        for(idx=0; idx<= 6 ;idx++){

            if(status & 0x800){
                break;
            }

            status = ParStlEPPRead(Extension);
        }

        if(idx == 7){

            status = (status & 0xf800)  | 0x100; 
            if ( status & 0x700 )
                return FALSE;
        }

        status = ParStlEPPWrite(Extension, *(commandPacket)++);
        if((status & 0x700 ) != 0){
            return FALSE;          //TIMEOUT_ERROR);
        }

        status = ParStlEPPWrite(Extension, *(commandPacket)++);
        if((status & 0x700 ) != 0){
            return FALSE;         //TIMEOUT_ERROR);
        }

        status = ParStlEPPWrite(Extension, *(commandPacket)++);
        if((status & 0x700 ) != 0){
            return FALSE;         //TIMEOUT_ERROR);
        }

        status = ParStlEPPWrite(Extension, *commandPacket);
        if((status & 0x700 ) != 0){
            return FALSE;         //TIMEOUT_ERROR);
        }

        //Response phase

        status    =    ParStlEPPRead(Extension);
        commandPacket = saveCommandPacket;

        if((status & 0x700) == 0){

            if((commandPacket[5] == 0xc2)&& (dataLength == 0)){

                status = ParStlEPPRead(Extension);

                if((status & 0x0700) != 0){
                    return FALSE;  //TIMEOUT_ERROR);
                }
            }
        }
    
        return  TRUE;
    }
    return FALSE;
}

BOOLEAN
ParStlSetEPPMode(
    IN PPDO_EXTENSION    Extension
    )
{
    UCHAR   idx;
    BOOLEAN timeout = TRUE ;

    ParStlWriteReg( Extension, CONTROLPORT, 0x0C ) ;
    ParStlWriteReg( Extension, DATAPORT, 0x40 ) ;
    ParStlWriteReg( Extension, CONTROLPORT, 0x06 ) ;

    for(idx=0; idx<10; idx++){

        if((ParStlReadReg(Extension, STATUSPORT) & 0x78) == 0x38){

            timeout = FALSE;
            break;

        }

    }

    if(timeout == FALSE){

        ParStlWriteReg( Extension, CONTROLPORT,0x7 );
        timeout = TRUE;

        for(idx=0; idx<10; idx++){

            if((ParStlReadReg( Extension, STATUSPORT) & 0x78) == 0x38){
                timeout = FALSE;
                break;
            }

        }

        if(timeout == FALSE){

            ParStlWriteReg( Extension, CONTROLPORT,0x4 ) ;
            timeout = TRUE;

            for(idx=0; idx<10; idx++){

                if((ParStlReadReg( Extension, STATUSPORT) & 0xf8) == 0xf8){
                    timeout = FALSE;
                    break;
                }

            }

            if(timeout == FALSE){

                timeout = TRUE;

                ParStlWriteReg( Extension, CONTROLPORT, 0x5 );

                for(idx=0; idx<10; idx++){

                    if( ParStlReadReg( Extension, CONTROLPORT ) == 0x5){

                        timeout = FALSE;
                        break;

                    }
                }

                if(timeout == FALSE){

                    ParStlWriteReg( Extension, CONTROLPORT, 0x84) ;
                    return TRUE ;

                } // final check

            } // third check

        } // second check

    } // first check

    return(FALSE);
}

USHORT
ParStlEPPWrite(
    IN PPDO_EXTENSION    Extension,
    IN UCHAR                value
    )
{
    UCHAR   idx;
    USHORT  statusData = 0;
    BOOLEAN timeout;

    timeout = TRUE;

    for(idx=0; idx<10; idx++){

        if( !( (statusData = (USHORT)ParStlReadReg( Extension, STATUSPORT)) & BUSY)){
            timeout = FALSE;
            break;
        }

    }

    if(timeout == TRUE){

        return(((statusData<<8) & 0xf800)|0x100);

    }

    ParStlWriteReg( Extension, EPPDATA0PORT,value );
    return(((statusData & 0xf8) << 8)|value);
}

USHORT
ParStlEPPRead(
    IN PPDO_EXTENSION Extension
    )
{
    UCHAR   idx;
    UCHAR   eppData;
    USHORT  statusData = 0;
    BOOLEAN timeout    = TRUE ;

    for(idx=0; idx<10; idx++){

        if(!( (statusData = (USHORT)ParStlReadReg( Extension, STATUSPORT)) & PE)){
            timeout = FALSE;
            break;
        }

    }

    if(timeout == TRUE){

        return(((statusData<<8) & 0xf800)|0x100);

    }

    eppData = (UCHAR)ParStlReadReg( Extension, EPPDATA0PORT) ;
    return(((statusData & 0x00f8)<<8) | eppData );
}

int  __cdecl
ParStlReadReg (
    IN  PPDO_EXTENSION   Extension,
    IN  unsigned            reg
    )
{
    UCHAR   byReadNibble ;
    PUCHAR  CurrentPort, CurrentStatus, CurrentControl ;
    ULONG   Delay = 5 ;

    CurrentPort = Extension->Controller;
    CurrentStatus  = CurrentPort + 1;
    CurrentControl = CurrentPort + 2;

// select the register to read
    P5WritePortUchar ( CurrentPort, (UCHAR)reg ) ;
    KeStallExecutionProcessor( Delay );

// issue nibble ctl signals to read
    P5WritePortUchar ( CurrentControl, STB_INIT_LOW ) ;
    KeStallExecutionProcessor( Delay );
    P5WritePortUchar ( CurrentControl, STB_INIT_AFXT_LO ) ;
    KeStallExecutionProcessor( Delay );

// read first nibble
    byReadNibble = P5ReadPortUchar (CurrentStatus);
    KeStallExecutionProcessor( Delay );
    byReadNibble >>= 4 ;

// issue nibble ctl signals to read
    P5WritePortUchar ( CurrentControl, STB_INIT_AFXT_HI ) ;
    KeStallExecutionProcessor( Delay );

// read next nibble
    byReadNibble |= ( P5ReadPortUchar ( CurrentStatus ) & 0xF0 ) ;

    return (int)byReadNibble ;
}

int  __cdecl
ParStlWriteReg ( 
    IN  PPDO_EXTENSION   Extension,
    IN  unsigned            reg, 
    IN  int                 databyte 
    )
{
    PUCHAR  CurrentPort, CurrentStatus, CurrentControl ;
    ULONG   Delay = 5 ;

    CurrentPort = Extension->Controller;
    CurrentStatus  = CurrentPort + 1;
    CurrentControl = CurrentPort + 2;

// select the register to write
    P5WritePortUchar ( CurrentPort, (UCHAR)( reg | 0x60 ) ) ;
    KeStallExecutionProcessor( Delay );

// write to printer ctl port
    P5WritePortUchar ( CurrentControl, STB_INIT_LOW ) ;
    KeStallExecutionProcessor( Delay );

// write the requested data
    P5WritePortUchar ( CurrentPort, (UCHAR)databyte ) ;
    KeStallExecutionProcessor( Delay );

// write to printer ctl port
    P5WritePortUchar ( CurrentControl, STB_INIT_AFXT_HI ) ;
    KeStallExecutionProcessor( Delay );

    return SHTL_NO_ERROR ;
}

int __cdecl
ParStlReceiveData (
    IN  PPDO_EXTENSION   Extension,
    IN  VOID                *hostBufferPointer,
    IN  long                shuttleMemoryAddress,
    IN  unsigned            count
    )
{
    PCHAR   pchDataBuffer = (PCHAR) hostBufferPointer ;
    unsigned int i = 0 ;
    PUCHAR  CurrentPort, CurrentStatus, CurrentControl ;
    ULONG   Delay = 5 ;

    UNREFERENCED_PARAMETER( shuttleMemoryAddress );

    CurrentPort = Extension->Controller;
    CurrentStatus  = CurrentPort + 1;
    CurrentControl = CurrentPort + 2;

// set the block address register to ATA/ATAPI data register,
// as this function is currently used ONLY for ATA/ATAPI devices
// ATA/ATAPI data register 0x1F0 corresponds to 0x18 value
    ParStlWriteReg ( Extension, EP1284_BLK_ADDR_REGISTER, 0x18 ) ;

// do the nibble block read sequence
// write the nibble block read op-code
    P5WritePortUchar ( CurrentPort, OP_NIBBLE_BLOCK_READ ) ;
    KeStallExecutionProcessor( Delay );

// set control ports to correct signals.
    P5WritePortUchar ( CurrentControl, STB_INIT_AFXT_LO ) ;
    KeStallExecutionProcessor( Delay );

// set data port to 0xFF
    P5WritePortUchar ( CurrentPort, 0xFF ) ;
    KeStallExecutionProcessor( Delay );
    P5WritePortUchar ( CurrentControl, INIT_AFXT_HIGH ) ;
    KeStallExecutionProcessor( Delay );

    do
    {
// low nibble is available in status after
// toggling sequences as in EP1284 manual
        P5WritePortUchar ( CurrentControl, AFXT_LO_STB_HI ) ;
        KeStallExecutionProcessor( Delay );
        pchDataBuffer[i] = P5ReadPortUchar( CurrentStatus ) >> 4 ;
        KeStallExecutionProcessor( Delay );

// high nibble is available in status after
// toggling sequences as in EP1284 manual
        P5WritePortUchar ( CurrentControl, AFXT_HI_STB_HI ) ;
        KeStallExecutionProcessor( Delay );

        pchDataBuffer[i++] |= ( P5ReadPortUchar ( CurrentStatus ) & 0xF0 ) ;
        KeStallExecutionProcessor( Delay );
        if ( count - 1 == i )
        {
// to read the last byte 
            P5WritePortUchar ( CurrentPort, 0xFD ) ;
            KeStallExecutionProcessor( Delay );
        }

        P5WritePortUchar ( CurrentControl, AFXT_LO_STB_LO ) ;
        KeStallExecutionProcessor( Delay );

        pchDataBuffer[i] = P5ReadPortUchar ( CurrentStatus ) >> 4 ;
        KeStallExecutionProcessor( Delay );

        P5WritePortUchar ( CurrentControl, AFXT_HI_STB_LO ) ;
        KeStallExecutionProcessor( Delay );
        pchDataBuffer[i++] |= ( P5ReadPortUchar ( CurrentStatus ) & 0xF0 ) ;
        KeStallExecutionProcessor( Delay );
    }
    while ( i <= count ) ;

// clean up
    P5WritePortUchar ( CurrentPort, 0x00 ) ;
    KeStallExecutionProcessor( Delay );

// done
    return SHTL_NO_ERROR ;
}

int  __cdecl
ParStlReadIoPort (
    IN  PPDO_EXTENSION   Extension,
    IN  unsigned            reg 
    )
{
    switch ( reg )
    {
    case 0x08 :
        reg = 0x16 ;
        break ;
    case 0x09 :
        reg = 0x17 ;
        break ;
    default :
        reg |= 0x18 ;
        break;
    }
    return ParStlReadReg ( Extension, reg ) ;
}

int  __cdecl
ParStlWriteIoPort (
    IN  PPDO_EXTENSION   Extension,
    IN  unsigned            reg,
    IN  int                 databyte
    )
{
    switch ( reg )
    {
    case 0x08 :
        reg = 0x16 ;
        break ;
    case 0x09 :
        reg = 0x17 ;
        break ;
    default :
        reg |= 0x18 ;
        break;
    }
    return ParStlWriteReg ( Extension, reg, databyte ) ;
}

int  __cdecl
ParStlGetMemorySize (
    IN  PPDO_EXTENSION   Extension
    )
{
    BOOLEAN    bReturnValue = FALSE ;
    UCHAR      byTempValue ;
    do
    {
// Issue reset through control register
// first try on DRAM
        byTempValue = (UCHAR) ParStlReadReg ( Extension, EP1284_CONTROL_REG ) ;
        byTempValue |= ENABLE_MEM|SELECT_DRAM|RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;
        byTempValue &= ~RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;

// write to the first location in the memory
        ParStlWriteReg ( Extension, EP1284_BUFFER_DATA_REG, TEST_PATTERN_1 ) ;
// write to the next location in the memory
        ParStlWriteReg ( Extension, EP1284_BUFFER_DATA_REG, TEST_PATTERN_2 ) ;

        byTempValue = (UCHAR) ParStlReadReg ( Extension, EP1284_CONTROL_REG ) ;
        byTempValue |= ENABLE_MEM|SELECT_DRAM|RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;
        byTempValue &= ~RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;

// read from the first and next location in the memory
        if ( ( TEST_PATTERN_1 == (UCHAR) ParStlReadReg ( Extension, EP1284_BUFFER_DATA_REG ) ) &&\
             ( TEST_PATTERN_2 == (UCHAR) ParStlReadReg ( Extension, EP1284_BUFFER_DATA_REG ) ) )
        {
            bReturnValue = TRUE ;
            break ;
        }
        
        if ( !IsImpactPresent () )
        {
// as only DRAM can be present on non-impact adapters
            break ;
        }
// Issue reset through control register
// and next try on SRAM
        byTempValue = (UCHAR) ParStlReadReg ( Extension, EP1284_CONTROL_REG ) ;
        byTempValue |= ENABLE_MEM|RESET_PTR ;
        byTempValue &= SELECT_SRAM ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;
        byTempValue &= ~RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;

// write to the first location in the memory
        ParStlWriteReg ( Extension, EP1284_BUFFER_DATA_REG, TEST_PATTERN_1 ) ;
// write to the next location in the memory
        ParStlWriteReg ( Extension, EP1284_BUFFER_DATA_REG, TEST_PATTERN_2 ) ;

        byTempValue = (UCHAR) ParStlReadReg ( Extension, EP1284_CONTROL_REG ) ;
        byTempValue |= ENABLE_MEM|RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;
        byTempValue &= ~RESET_PTR ;
        ParStlWriteReg ( Extension, EP1284_CONTROL_REG, byTempValue ) ;

// read from the first location in the memory
        if ( ( TEST_PATTERN_1 == (UCHAR) ParStlReadReg ( Extension, EP1284_BUFFER_DATA_REG ) ) &&\
             ( TEST_PATTERN_2 == (UCHAR) ParStlReadReg ( Extension, EP1284_BUFFER_DATA_REG ) ) )
        {
            bReturnValue = TRUE ;
            break ;
        }
    }
    while ( FALSE ) ;
    return bReturnValue ;
}
// end of file