📄 hwecp.c
字号:
Pdx->PortHWMode = HW_MODE_ECP;
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
return nError;
}
BOOLEAN
PptEcpHwHaveReadData (
IN PPDO_EXTENSION Pdx
)
{
Queue *pQueue;
// check shadow buffer
pQueue = &(Pdx->ShadowBuffer);
if (!Queue_IsEmpty(pQueue)) {
return TRUE;
}
// check periph
if (ParEcpHaveReadData(Pdx))
return TRUE;
// Check if FIFO is not empty.
return (BOOLEAN)( (UCHAR)0 == (P5ReadPortUchar(Pdx->EcrController + ECR_OFFSET) & ECR_FIFO_EMPTY) );
}
NTSTATUS
ParEcpHwHostRecoveryPhase(
IN PPDO_EXTENSION Pdx
)
{
NTSTATUS status = STATUS_SUCCESS;
PUCHAR pPortDCR; // I/O address of Device Control Register
PUCHAR pPortDSR; // I/O address of Device Status Register
PUCHAR pPortECR; // I/O address of Extended Control Register
UCHAR bDCR; // Contents of DCR
UCHAR bDSR; // Contents of DSR
if( !Pdx->bIsHostRecoverSupported ) {
return STATUS_SUCCESS;
}
DD((PCE)Pdx,DDT,"ParEcpHwHostRecoveryPhase - enter\n");
// Calculate I/O port addresses for common registers
pPortDCR = Pdx->Controller + OFFSET_DCR;
pPortDSR = Pdx->Controller + OFFSET_DSR;
pPortECR = Pdx->EcrController + ECR_OFFSET;
// Set the ECR to mode 001 (PS2 Mode)
// Don't need to flip to Byte mode. The ECR arbitrator will handle this.
Pdx->PortHWMode = HW_MODE_PS2;
// Set Dir=1 in DCR to disable host bus drive, because the peripheral may
// try to drive the bus during host recovery phase. We are not really going
// to let any data handshake across, because we don't set HostAck low, and
// we don't enable the ECP chip during this phase.
bDCR = P5ReadPortUchar(pPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DIR_READ, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
P5WritePortUchar(pPortDCR, bDCR );
// Check the DCR to see if it has been stomped on
bDCR = P5ReadPortUchar( pPortDCR );
if( TEST_DCR( bDCR, DIR_WRITE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE ) ) {
// DCR ok, now test DSR for valid state, ignoring PeriphAck since it could change
bDSR = P5ReadPortUchar( pPortDSR );
// 11/21/95 LLL, CGM: change test to look for XFlag high
if( TEST_DSR( bDSR, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
// Drop ReverseRequest to initiate host recovery
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE, DONT_CARE );
P5WritePortUchar( pPortDCR, bDCR );
// Wait for nAckReverse response
// 11/21/95 LLL, CGM: tightened test to include PeriphClk and XFlag.
// "ZIP_HRP: state 73, DSR"
if( CHECK_DSR( Pdx->Controller, DONT_CARE, ACTIVE, INACTIVE, ACTIVE, DONT_CARE, IEEE_MAXTIME_TL) ) {
// Yes, raise nReverseRequest, HostClk and HostAck (HostAck high so HW can drive)
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, ACTIVE );
P5WritePortUchar( pPortDCR, bDCR );
// Wait for nAckReverse response
// 11/21/95 LLL, CGM: tightened test to include XFlag and PeriphClk.
// "ZIP_HRP: state 75, DSR"
if( CHECK_DSR( Pdx->Controller, DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE, IEEE_MAXTIME_TL) ) {
// Let the host drive the bus again.
bDCR = P5ReadPortUchar(pPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE );
P5WritePortUchar(pPortDCR, bDCR );
// Recovery is complete, let the caller decide what to do now
status = STATUS_SUCCESS;
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
} else {
status = STATUS_IO_TIMEOUT;
DD((PCE)Pdx,DDW,"ParEcpHwHostRecoveryPhase - error prior to state 75\n");
}
} else {
status = STATUS_IO_TIMEOUT;
DD((PCE)Pdx,DDW,"ParEcpHwHostRecoveryPhase - error prior to state 73\n");
}
} else {
#if DVRH_BUS_RESET_ON_ERROR
BusReset(pPortDCR); // Pass in the dcr address
#endif
DD((PCE)Pdx,DDT, "ParEcpHwHostRecoveryPhase: VE_LINK_FAILURE \n");
status = STATUS_LINK_FAILED;
}
} else {
DD((PCE)Pdx,DDW,"ParEcpHwHostRecoveryPhase: VE_PORT_STOMPED\n");
status = STATUS_DEVICE_PROTOCOL_ERROR;
}
if (!NT_SUCCESS(status)) {
// Make sure both HostAck and HostClk are high before leaving
// Also let the host drive the bus again.
bDCR = P5ReadPortUchar( pPortDCR );
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
P5WritePortUchar( pPortDCR, bDCR );
// [[REVISIT]] pSDCB->wCurrentPhase = PHASE_UNKNOWN;
}
// Set the ECR to ECP mode, disable DMA
status = Pdx->TrySetChipMode ( Pdx->PortContext, ECR_ECP_PIO_MODE );
Pdx->PortHWMode = HW_MODE_ECP;
DD((PCE)Pdx,DDT,"ParEcpHwHostRecoveryPhase - Exit w/status = %x\n", status);
return status;
}
NTSTATUS
ParEcpHwRead(
IN PPDO_EXTENSION Pdx,
IN PVOID Buffer,
IN ULONG BufferSize,
OUT PULONG BytesTransferred
)
/*++
Routine Description:
This routine performs a 1284 ECP mode read under Hardware control
into the given buffer for no more than 'BufferSize' bytes.
Arguments:
Pdx - Supplies the device extension.
Buffer - Supplies the buffer to read into.
BufferSize - Supplies the number of bytes in the buffer.
BytesTransferred - Returns the number of bytes transferred.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PUCHAR lpsBufPtr = (PUCHAR)Buffer; // Pointer to buffer cast to desired data type
ULONG dCount = BufferSize; // Working copy of caller's original request count
UCHAR bDSR; // Contents of DSR
UCHAR bPeriphRequest; // Calculated state of nPeriphReq signal, used in loop
PUCHAR wPortDSR = Pdx->Controller + DSR_OFFSET;
PUCHAR wPortECR = Pdx->EcrController + ECR_OFFSET;
PUCHAR wPortDFIFO = Pdx->EcrController;
LARGE_INTEGER WaitPerByteTimer;
LARGE_INTEGER StartPerByteTimer;
LARGE_INTEGER EndPerByteTimer;
BOOLEAN bResetTimer = TRUE;
ULONG wBurstCount; // Calculated amount of data in FIFO
UCHAR ecrFIFO;
WaitPerByteTimer.QuadPart = (35 * 10 * 1000) + KeQueryTimeIncrement();
//----------------------------------------------------------------------
// Set status byte to indicate Reverse Transfer Phase.
//----------------------------------------------------------------------
P5SetPhase( Pdx, PHASE_REVERSE_XFER );
//----------------------------------------------------------------------
// We've already checked the shadow in ParRead. So go right to the
// Hardware FIFO and pull more data across.
//----------------------------------------------------------------------
KeQueryTickCount(&StartPerByteTimer); // Start the timer
ParEcpHwRead_ReadLoopStart:
//------------------------------------------------------------------
// Determine whether the FIFO has any data and respond accordingly
//------------------------------------------------------------------
ecrFIFO = (UCHAR)(P5ReadPortUchar(wPortECR) & (UCHAR)ECR_FIFO_MASK);
if (ECR_FIFO_FULL == ecrFIFO) {
wBurstCount = ( dCount > Pdx->FifoDepth ? Pdx->FifoDepth : dCount );
dCount -= wBurstCount;
P5ReadPortBufferUchar(wPortDFIFO, lpsBufPtr, wBurstCount);
lpsBufPtr += wBurstCount;
bResetTimer = TRUE;
} else if (ECR_FIFO_SOME_DATA == ecrFIFO) {
// Read just one byte at a time, since we don't know exactly how much is
// in the FIFO.
*lpsBufPtr = P5ReadPortUchar(wPortDFIFO);
lpsBufPtr++;
dCount--;
bResetTimer = TRUE;
} else { // ECR_FIFO_EMPTY
DD((PCE)Pdx,DDW,"ParEcpHwRead - ECR_FIFO_EMPTY - slow or bad periph?\n");
// Nothing to do. We either have a slow peripheral or a bad peripheral.
// We don't have a good way to figure out if its bad. Let's chew up our
// time and hope for the best.
bResetTimer = FALSE;
} // ECR_FIFO_EMPTY a.k.a. else clause of (ECR_FIFO_FULL == ecrFIFO)
if (dCount == 0)
goto ParEcpHwRead_ReadLoopEnd;
else {
// Limit the overall time we spend in this loop.
if (bResetTimer) {
bResetTimer = FALSE;
KeQueryTickCount(&StartPerByteTimer); // Restart the timer
} else {
KeQueryTickCount(&EndPerByteTimer);
if (((EndPerByteTimer.QuadPart - StartPerByteTimer.QuadPart) * KeQueryTimeIncrement()) > WaitPerByteTimer.QuadPart)
goto ParEcpHwRead_ReadLoopEnd;
}
}
goto ParEcpHwRead_ReadLoopStart;
ParEcpHwRead_ReadLoopEnd:
P5SetPhase( Pdx, PHASE_REVERSE_IDLE );
*BytesTransferred = BufferSize - dCount; // Set current count.
Pdx->log.HwEcpReadCount += *BytesTransferred;
if (0 == *BytesTransferred) {
bDSR = P5ReadPortUchar(wPortDSR);
bPeriphRequest = (UCHAR)TEST_DSR( bDSR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE );
// Only flag a timeout error if the device still said it had data to send.
if ( bPeriphRequest ) {
//
// Periph still says that it has data, but we timed out trying to read the data.
//
DD((PCE)Pdx,DDE,"ParEcpHwRead - read timout with nPeriphRequest asserted and no data read - error - STATUS_IO_TIMEOUT\n");
status = STATUS_IO_TIMEOUT;
if ((TRUE == Pdx->P12843DL.bEventActive) ) {
//
// Signal transport that it should try another read
//
KeSetEvent(Pdx->P12843DL.Event, 0, FALSE);
}
}
}
DD((PCE)Pdx,DDT,"ParEcpHwRead: Exit - status=%x, BytesTransferred[%d] dsr[%02x] dcr[%02x] ecr[%02x]\n",
status, *BytesTransferred, P5ReadPortUchar(wPortDSR),
P5ReadPortUchar(Pdx->Controller + OFFSET_DCR), P5ReadPortUchar(wPortECR));
#if 1 == DBG_SHOW_BYTES
if( DbgShowBytes ) {
if( NT_SUCCESS( status ) && (*BytesTransferred > 0) ) {
const ULONG maxBytes = 32;
ULONG i;
PUCHAR bytePtr = (PUCHAR)Buffer;
DbgPrint("R: ");
for( i=0 ; (i < *BytesTransferred) && (i < maxBytes ) ; ++i ) {
DbgPrint("%02x ",*bytePtr++);
}
if( *BytesTransferred > maxBytes ) {
DbgPrint("... ");
}
DbgPrint("zz\n");
}
}
#endif
return status;
} // ParEcpHwRead
NTSTATUS
ParEcpHwRecoverPort(
PPDO_EXTENSION Pdx,
UCHAR bRecoverCode
)
{
NTSTATUS status = STATUS_SUCCESS;
PUCHAR wPortDCR; // IO address of Device Control Register (DCR)
PUCHAR wPortDSR; // IO address of Device Status Register (DSR)
PUCHAR wPortECR; // IO address of Extended Control Register (ECR)
PUCHAR wPortData; // IO address of Data Register
UCHAR bDCR; // Contents of DCR
UCHAR bDSR; // Contents of DSR
UCHAR bDSRmasked; // DSR after masking low order bits
DD((PCE)Pdx,DDT,"ParEcpHwRecoverPort: enter %d\n", bRecoverCode );
// Calculate I/O port addresses for common registers
wPortDCR = Pdx->Controller + OFFSET_DCR;
wPortDSR = Pdx->Controller + OFFSET_DSR;
wPortECR = Pdx->EcrController + ECR_OFFSET;
wPortData = Pdx->Controller + OFFSET_DATA;
//----------------------------------------------------------------------
// Check if port is stomped.
//----------------------------------------------------------------------
bDCR = P5ReadPortUchar(wPortDCR); // Get content of DCR.
if ( ! TEST_DCR( bDCR, DONT_CARE, DONT_CARE, ACTIVE, DONT_CARE, DONT_CARE, DONT_CARE ) )
{
#if DVRH_BUS_RESET_ON_ERROR
BusReset(wPortDCR); // Pass in the dcr address
#endif
DD((PCE)Pdx,DDE,"ParEcpHwRecoverPort - port stomped\n");
status = STATUS_DEVICE_PROTOCOL_ERROR;
}
//----------------------------------------------------------------------
// Attempt a termination phase to get the peripheral recovered.
// Ignore the error return, we've already got that figured out.
//----------------------------------------------------------------------
IeeeTerminate1284Mode(Pdx );
//----------------------------------------------------------------------
// Set the ECR to PS2 Mode so we can change bus direction.
//----------------------------------------------------------------------
Pdx->ClearChipMode( Pdx->PortContext, ECR_ECP_PIO_MODE );
Pdx->PortHWMode = HW_MODE_PS2;
//----------------------------------------------------------------------
// Assert nSelectIn low, nInit high, nStrobe high, and nAutoFd high.
//----------------------------------------------------------------------
bDCR = P5ReadPortUchar(wPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, INACTIVE, ACTIVE, ACTIVE, ACTIVE );
P5WritePortUchar(wPortDCR, bDCR);
P5WritePortUchar(wPortData, bRecoverCode); // Output the error ID
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -