/*++ 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 ; idsDeviceState[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