/*++ 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 "parstl.h" BOOLEAN ParStlCheckIfStl( IN PDEVICE_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. --*/ { NTSTATUS status ; BOOLEAN bStlNon1284_3Found = FALSE ; 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 PDEVICE_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 = READ_PORT_UCHAR( 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); WRITE_PORT_UCHAR( CurrentControl, newvalue ); // make sure we can write // bring nStrobe high WRITE_PORT_UCHAR( 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++ ) { WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[i] ); KeStallExecutionProcessor( Delay ); } // check for correct status status = READ_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[4] ); KeStallExecutionProcessor( Delay ); // check for correct status status = READ_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[5] ); KeStallExecutionProcessor( Delay ); // check for correct status status = READ_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[6] ); } // Second status } // First status WRITE_PORT_UCHAR( CurrentControl, value ); // restore everything return bReturnValue ; } // ParStlCheckIfNon1284_3Present BOOLEAN ParStlCheckIfStl1284_3( IN PDEVICE_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 = READ_PORT_UCHAR( 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); WRITE_PORT_UCHAR( CurrentControl, newvalue ); // make sure we can write // bring nStrobe high WRITE_PORT_UCHAR( 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++ ) { WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[i] ); KeStallExecutionProcessor( Delay ); } // check for correct status status = READ_PORT_UCHAR( CurrentStatus ); if ( (status & (UCHAR)0xb8 ) == ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) { // continue with fifth byte of mode qualifier WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[4] ); KeStallExecutionProcessor( Delay ); // check for correct status status = READ_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[5] ); KeStallExecutionProcessor( Delay ); // check for correct status status = READ_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, (UCHAR) ( 0x88 | ulDaisyIndex ) ); KeStallExecutionProcessor( Delay ); // wait a bit if ( ulDaisyIndex && ( bNoStrobe == FALSE ) ) { WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high KeStallExecutionProcessor( Delay ); // wait a bit } ucExpectedPattern = 0xF0 ; bReturnValue = TRUE ; while ( ucExpectedPattern ) { KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( CurrentPort, (UCHAR) (0x80 | ulDaisyIndex )) ; KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( CurrentPort, (UCHAR) (0x88 | ulDaisyIndex )) ; KeStallExecutionProcessor( Delay ); // wait a bit ucReadValue = READ_PORT_UCHAR( CurrentStatus ) ; ucReadPattern = ( ucReadValue << 1 ) & 0x70 ; ucReadPattern |= ( ucReadValue & 0x80 ) ; if ( ucReadPattern != ucExpectedPattern ) { // not Shuttle 1284_3 behaviour bReturnValue = FALSE ; break ; } ucExpectedPattern -= 0x10 ; } // last byte WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[6] ); } // Third status } // Second status } // First status WRITE_PORT_UCHAR( CurrentControl, value ); // restore everything return bReturnValue ; } // end ParStlCheckIfStl1284_3() BOOLEAN ParStlCheckIfStlProductId( IN PDEVICE_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 = READ_PORT_UCHAR( 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); WRITE_PORT_UCHAR( CurrentControl, newvalue ); // make sure we can write // bring nStrobe high WRITE_PORT_UCHAR( 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++ ) { WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[i] ); KeStallExecutionProcessor( Delay ); } // check for correct status status = READ_PORT_UCHAR( CurrentStatus ); if ( (status & (UCHAR)0xb8 ) == ( DSR_NOT_BUSY | DSR_PERROR | DSR_SELECT | DSR_NOT_FAULT )) { // continue with fifth byte of mode qualifier WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[4] ); KeStallExecutionProcessor( Delay ); // check for correct status status = READ_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[5] ); KeStallExecutionProcessor( Delay ); // check for correct status status = READ_PORT_UCHAR( CurrentStatus ); // if status is valid there is a device out there responding if ((status & (UCHAR) 0x30 ) == ( DSR_PERROR | DSR_SELECT )) { WRITE_PORT_UCHAR ( CurrentPort, (UCHAR) (CPP_QUERY_PRODID | ulDaisyIndex )) ; KeStallExecutionProcessor( Delay ); // Device is out there KeStallExecutionProcessor( Delay ); ucProdIdLoByteHiNibble = READ_PORT_UCHAR( CurrentStatus ) ; ucProdIdLoByteHiNibble &= 0xF0 ; KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high KeStallExecutionProcessor( Delay ); // wait a bit ucProdIdLoByteLoNibble = READ_PORT_UCHAR( CurrentStatus ) ; ucProdIdLoByteLoNibble >>= 4 ; ucProdIdLoByte = ucProdIdLoByteHiNibble | ucProdIdLoByteLoNibble ; KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high KeStallExecutionProcessor( Delay ); // wait a bit ucProdIdHiByteHiNibble = READ_PORT_UCHAR( CurrentStatus ) ; ucProdIdHiByteHiNibble &= 0xF0 ; KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); // bring nStrobe high KeStallExecutionProcessor( Delay ); // wait a bit ucProdIdHiByteLoNibble = READ_PORT_UCHAR( CurrentStatus ) ; ucProdIdHiByteLoNibble >>= 4 ; ucProdIdHiByte = ucProdIdHiByteHiNibble | ucProdIdHiByteLoNibble ; // last strobe KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue & ~DCR_STROBE) ); WRITE_PORT_UCHAR( CurrentControl, (UCHAR)(newvalue | DCR_STROBE) ); // bring nStrobe low KeStallExecutionProcessor( Delay ); // wait a bit WRITE_PORT_UCHAR( 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 WRITE_PORT_UCHAR( CurrentPort, ModeQualifier[6] ); } // Third status } // Second status } // First status WRITE_PORT_UCHAR( CurrentControl, value ); // restore everything return bReturnValue ; } // end ParStlCheckIfStlProductId() PCHAR ParStlQueryStlDeviceId( IN PDEVICE_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; *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); } do { // // Negotiate the peripheral into nibble device id mode. // Status = ParEnterNibbleMode(Extension, REQUEST_DEVICE_ID); if( !NT_SUCCESS(Status) ) { ParTerminateNibbleMode(Extension); break ; } // // 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 ) ) { break ; } // // Compute size of DeviceId string (including the 2 byte size prefix) // deviceIdSize = (USHORT)( idSizeBuffer[0]*0x100 + idSizeBuffer[1] ); // // 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 ) { break; } // // 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 ); break ; } if ( strstr ( readPtr, "MFG:" ) == 0 ) { ExFreePool( deviceIdBuffer ) ; break ; } 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; } while ( FALSE ) ; // 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. WRITE_PORT_UCHAR(Controller + DCR_OFFSET, DCR_SELECT_IN | DCR_NOT_INIT); KeStallExecutionProcessor( 5 ); WRITE_PORT_UCHAR(Controller + DCR_OFFSET, DCR_SELECT_IN | DCR_NOT_INIT | DCR_AUTOFEED); KeStallExecutionProcessor( 5 ); WRITE_PORT_UCHAR(Controller + DCR_OFFSET, DCR_SELECT_IN | DCR_NOT_INIT); ParStlAssertIdleState ( Extension ) ; deviceIdBuffer = ParBuildStlDeviceId(Extension); 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 PDEVICE_EXTENSION Extension ) /*++ 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 ); RtlCopyMemory( id, szDeviceIdString, size - sizeof(NULL) ); return id; } return NULL; } STL_DEVICE_TYPE __cdecl ParStlGetDeviceType ( IN PDEVICE_EXTENSION Extension, IN int nPreferredDeviceType ) { STL_DEVICE_TYPE dtDeviceType = DEVICE_TYPE_NONE ; int nLocalPreferredDeviceType = nPreferredDeviceType ; 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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_EXTENSION Extension, IN OUT PATAPIPARAMS atapiParams, IN int nPreferredDeviceType ) { IMPACT_DEVICE_TYPE idtImpactDeviceType ; STL_DEVICE_TYPE dtDeviceType = DEVICE_TYPE_NONE ; int nLocalPreferredDeviceType = nPreferredDeviceType ; 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 PDEVICE_EXTENSION Extension, IN OUT PATAPIPARAMS atapiParams, IN int nPreferredDeviceType ) { IMPACT_DEVICE_TYPE idtImpactDeviceType ; IMPACT_DEVICE_TYPE idtImpactSDeviceType ; STL_DEVICE_TYPE dtDeviceType = DEVICE_TYPE_NONE ; int nLocalPreferredDeviceType = nPreferredDeviceType ; 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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_EXTENSION Extension ) { BOOLEAN bReturnValue = FALSE; UCHAR byMakerCode = 0x00 , byDeviceCode = 0x00 ; 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 PDEVICE_EXTENSION Extension ) { PUCHAR CurrentPort, CurrentControl ; ULONG Delay = 5 ; CurrentPort = Extension->Controller; CurrentControl = CurrentPort + 2; // place op-code for idle state in port base WRITE_PORT_UCHAR ( CurrentPort, (UCHAR) 0x00 ) ; KeStallExecutionProcessor( Delay ); // bring down DCR_INIT and DCR_STROBE WRITE_PORT_UCHAR ( CurrentControl, (UCHAR) STB_INIT_LOW ) ; KeStallExecutionProcessor( Delay ); // lift DCR_INIT and DCR_STROBE to high WRITE_PORT_UCHAR ( CurrentControl, (UCHAR) STB_INIT_AFXT_HI ) ; KeStallExecutionProcessor( Delay ); } BOOLEAN ParStlCheckAvisionScannerPresence( IN PDEVICE_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 PDEVICE_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 PDEVICE_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 PDEVICE_EXTENSION Extension, IN UCHAR value ) { UCHAR idx; USHORT statusData; 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 PDEVICE_EXTENSION Extension ) { UCHAR idx; USHORT statusData; USHORT controlData; UCHAR eppData; 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 PDEVICE_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 WRITE_PORT_UCHAR ( CurrentPort, (UCHAR)reg ) ; KeStallExecutionProcessor( Delay ); // issue nibble ctl signals to read WRITE_PORT_UCHAR ( CurrentControl, STB_INIT_LOW ) ; KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR ( CurrentControl, STB_INIT_AFXT_LO ) ; KeStallExecutionProcessor( Delay ); // read first nibble byReadNibble = READ_PORT_UCHAR (CurrentStatus); KeStallExecutionProcessor( Delay ); byReadNibble >>= 4 ; // issue nibble ctl signals to read WRITE_PORT_UCHAR ( CurrentControl, STB_INIT_AFXT_HI ) ; KeStallExecutionProcessor( Delay ); // read next nibble byReadNibble |= ( READ_PORT_UCHAR ( CurrentStatus ) & 0xF0 ) ; return (int)byReadNibble ; } int __cdecl ParStlWriteReg ( IN PDEVICE_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 WRITE_PORT_UCHAR ( CurrentPort, (UCHAR)( reg | 0x60 ) ) ; KeStallExecutionProcessor( Delay ); // write to printer ctl port WRITE_PORT_UCHAR ( CurrentControl, STB_INIT_LOW ) ; KeStallExecutionProcessor( Delay ); // write the requested data WRITE_PORT_UCHAR ( CurrentPort, (UCHAR)databyte ) ; KeStallExecutionProcessor( Delay ); // write to printer ctl port WRITE_PORT_UCHAR ( CurrentControl, STB_INIT_AFXT_HI ) ; KeStallExecutionProcessor( Delay ); return SHTL_NO_ERROR ; } int __cdecl ParStlReceiveData ( IN PDEVICE_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 ; 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 WRITE_PORT_UCHAR ( CurrentPort, OP_NIBBLE_BLOCK_READ ) ; KeStallExecutionProcessor( Delay ); // set control ports to correct signals. WRITE_PORT_UCHAR ( CurrentControl, STB_INIT_AFXT_LO ) ; KeStallExecutionProcessor( Delay ); // set data port to 0xFF WRITE_PORT_UCHAR ( CurrentPort, 0xFF ) ; KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR ( CurrentControl, INIT_AFXT_HIGH ) ; KeStallExecutionProcessor( Delay ); do { // low nibble is available in status after // toggling sequences as in EP1284 manual WRITE_PORT_UCHAR ( CurrentControl, AFXT_LO_STB_HI ) ; KeStallExecutionProcessor( Delay ); pchDataBuffer[i] = READ_PORT_UCHAR( CurrentStatus ) >> 4 ; KeStallExecutionProcessor( Delay ); // high nibble is available in status after // toggling sequences as in EP1284 manual WRITE_PORT_UCHAR ( CurrentControl, AFXT_HI_STB_HI ) ; KeStallExecutionProcessor( Delay ); pchDataBuffer[i++] |= ( READ_PORT_UCHAR ( CurrentStatus ) & 0xF0 ) ; KeStallExecutionProcessor( Delay ); if ( count - 1 == i ) { // to read the last byte WRITE_PORT_UCHAR ( CurrentPort, 0xFD ) ; KeStallExecutionProcessor( Delay ); } WRITE_PORT_UCHAR ( CurrentControl, AFXT_LO_STB_LO ) ; KeStallExecutionProcessor( Delay ); pchDataBuffer[i] = READ_PORT_UCHAR ( CurrentStatus ) >> 4 ; KeStallExecutionProcessor( Delay ); WRITE_PORT_UCHAR ( CurrentControl, AFXT_HI_STB_LO ) ; KeStallExecutionProcessor( Delay ); pchDataBuffer[i++] |= ( READ_PORT_UCHAR ( CurrentStatus ) & 0xF0 ) ; KeStallExecutionProcessor( Delay ); } while ( i <= count ) ; // clean up WRITE_PORT_UCHAR ( CurrentPort, 0x00 ) ; KeStallExecutionProcessor( Delay ); // done return SHTL_NO_ERROR ; } int __cdecl ParStlReadIoPort ( IN PDEVICE_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 PDEVICE_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 PDEVICE_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