📄 hwecp.c
字号:
KeStallExecutionProcessor(100); // Hold long enough to capture
P5WritePortUchar(wPortData, 0); // Now clear the data lines.
//----------------------------------------------------------------------
// Set the ECR to mode 000 (Compatibility Mode).
//----------------------------------------------------------------------
// Nothing needs to be done here.
Pdx->PortHWMode = HW_MODE_COMPATIBILITY;
//----------------------------------------------------------------------
// Check for any link errors if nothing bad found yet.
//----------------------------------------------------------------------
bDSR = P5ReadPortUchar(wPortDSR); // Get content of DSR.
bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
if( NT_SUCCESS(status) ) {
if (bDSRmasked != 0xDF) {
DD((PCE)Pdx,DDE,"ParEcpHwRecoverPort - DSR Exp value: 0xDF, Act value: 0x%X\n",bDSRmasked);
// Get DSR again just to make sure...
bDSR = P5ReadPortUchar(wPortDSR); // Get content of DSR.
bDSRmasked = (UCHAR)(bDSR | 0x07); // Set first 3 bits (don't cares).
if( (CHKPRNOFF1 == bDSRmasked ) || (CHKPRNOFF2 == bDSRmasked ) ) { // Check for printer off.
DD((PCE)Pdx,DDW,"ParEcpHwRecoverPort - DSR value: 0x%X, Printer Off\n", bDSRmasked);
status = STATUS_DEVICE_POWERED_OFF;
} else {
if( CHKNOCABLE == bDSRmasked ) { // Check for cable unplugged.
DD((PCE)Pdx,DDW,"ParEcpHwRecoverPort - DSR value: 0x%X, Cable Unplugged\n",bDSRmasked);
status = STATUS_DEVICE_NOT_CONNECTED;
} else {
DD((PCE)Pdx,DDW,"ParEcpHwRecoverPort - DSR value: 0x%X, Unknown error\n",bDSRmasked);
status = STATUS_LINK_FAILED;
}
}
}
}
//----------------------------------------------------------------------
// Set status byte to indicate Compatibility Mode.
//----------------------------------------------------------------------
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
return status;
} // ParEcpHwRecoverPort
NTSTATUS
ParEcpHwSetAddress(
IN PPDO_EXTENSION Pdx,
IN UCHAR Address
)
/*++
Routine Description:
Sets the ECP Address.
Arguments:
Pdx - Supplies the device extension.
Address - The bus address to be set.
Return Value:
None.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PUCHAR wPortDSR; // IO address of Device Status Register
PUCHAR wPortECR; // IO address of Extended Control Register
PUCHAR wPortAFIFO; // IO address of ECP Address FIFO
UCHAR bDSR; // Contents of DSR
UCHAR bECR; // Contents of ECR
BOOLEAN bDone;
DD((PCE)Pdx,DDT,"ParEcpHwSetAddress, Start\n");
// Calculate I/O port addresses for common registers
wPortDSR = Pdx->Controller + DSR_OFFSET;
wPortECR = Pdx->EcrController + ECR_OFFSET;
wPortAFIFO = Pdx->Controller + AFIFO_OFFSET;
//----------------------------------------------------------------------
// Check for any link errors.
//----------------------------------------------------------------------
//ZIP_CHECK_PORT( DONT_CARE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE,
// "ZIP_SCA: init DCR", RECOVER_40, errorExit );
//ZIP_CHECK_LINK( DONT_CARE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
// "ZIP_SCA: init DSR", RECOVER_41, errorExit );
// Set state to indicate ECP forward transfer phase
P5SetPhase( Pdx, PHASE_FORWARD_XFER );
//----------------------------------------------------------------------
// Send ECP channel address to AFIFO.
//----------------------------------------------------------------------
if ( ! ( TEST_ECR_FIFO( P5ReadPortUchar( wPortECR), ECR_FIFO_EMPTY ) ? TRUE :
CheckPort( wPortECR, ECR_FIFO_MASK, ECR_FIFO_EMPTY, IEEE_MAXTIME_TL ) ) ) {
status = ParEcpHwHostRecoveryPhase(Pdx);
DD((PCE)Pdx,DDT,"ParEcpHwSetAddress: FIFO full, timeout sending ECP channel address\n");
status = STATUS_IO_DEVICE_ERROR;
} else {
// Send the address byte. The most significant bit must be set to distinquish
// it as an address (as opposed to a run-length compression count).
P5WritePortUchar(wPortAFIFO, (UCHAR)(Address | 0x80));
}
if ( NT_SUCCESS(status) ) {
// If there have been no previous errors, and synchronous writes
// have been requested, wait for the FIFO to empty and the device to
// complete the last PeriphAck handshake before returning success.
if ( Pdx->bSynchWrites ) {
LARGE_INTEGER Wait;
LARGE_INTEGER Start;
LARGE_INTEGER End;
// we wait up to 35 milliseconds.
Wait.QuadPart = (IEEE_MAXTIME_TL * 10 * 1000) + KeQueryTimeIncrement(); // 35ms
KeQueryTickCount(&Start);
bDone = FALSE;
while ( ! bDone )
{
bECR = P5ReadPortUchar( wPortECR );
bDSR = P5ReadPortUchar( wPortDSR );
// LLL/CGM 10/9/95: Tighten up link test - PeriphClk high
if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) &&
TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
bDone = TRUE;
} else {
KeQueryTickCount(&End);
if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart) {
DD((PCE)Pdx,DDT,"ParEcpHwSetAddress, timeout during synch\n");
bDone = TRUE;
status = ParEcpHwHostRecoveryPhase(Pdx);
status = STATUS_IO_DEVICE_ERROR;
}
}
} // of while...
} // if bSynchWrites...
}
if ( NT_SUCCESS(status) ) {
// Update the state to reflect that we are back in an idle phase
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
} else if ( status == STATUS_IO_DEVICE_ERROR ) {
// Update the state to reflect that we are back in an idle phase
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
}
return status;
}
NTSTATUS
ParEcpHwSetupPhase(
IN PPDO_EXTENSION Pdx
)
/*++
Routine Description:
This routine performs 1284 Setup Phase.
Arguments:
Controller - Supplies the port address.
Return Value:
STATUS_SUCCESS - Successful negotiation.
otherwise - Unsuccessful negotiation.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PUCHAR pPortDCR; // IO address of Device Control Register (DCR)
PUCHAR pPortDSR; // IO address of Device Status Register (DSR)
PUCHAR pPortECR; // IO address of Extended Control Register (ECR)
UCHAR bDCR; // Contents of DCR
// Calculate I/O port addresses for common registers
pPortDCR = Pdx->Controller + OFFSET_DCR;
pPortDSR = Pdx->Controller + OFFSET_DSR;
pPortECR = Pdx->EcrController + ECR_OFFSET;
// Get the DCR and make sure port hasn't been stomped
//ZIP_CHECK_PORT( DIR_WRITE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, DONT_CARE,
// "ZIP_SP: init DCR", RECOVER_44, exit1 );
// Set HostAck low
bDCR = P5ReadPortUchar(pPortDCR); // Get content of DCR.
bDCR = UPDATE_DCR( bDCR, DONT_CARE, DONT_CARE, DONT_CARE, DONT_CARE, INACTIVE, DONT_CARE );
P5WritePortUchar( pPortDCR, bDCR );
// for some reason dvdr doesn't want an extra check in UNSAFE_MODE
if ( Pdx->ModeSafety == SAFE_MODE ) {
// Wait for nAckReverse to go high
// LLL/CGM 10/9/95: look for PeriphAck low, PeriphClk high as per 1284 spec.
if ( !CHECK_DSR(Pdx->Controller, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE,
IEEE_MAXTIME_TL ) )
{
// Any failure leaves us in an unknown state to recover from.
P5SetPhase( Pdx, PHASE_UNKNOWN );
Status = STATUS_IO_DEVICE_ERROR;
goto HWECP_SetupPhaseExitLabel;
}
}
//----------------------------------------------------------------------
// Set the ECR to mode 001 (PS2 Mode).
//----------------------------------------------------------------------
Status = Pdx->TrySetChipMode ( Pdx->PortContext, ECR_ECP_PIO_MODE );
// Set DCR: DIR=0 for output, HostAck and HostClk high so HW can drive
bDCR = UPDATE_DCR( bDCR, DIR_WRITE, DONT_CARE, DONT_CARE, DONT_CARE, ACTIVE, ACTIVE );
P5WritePortUchar( pPortDCR, bDCR );
// Set the ECR to ECP mode, disable DMA
Pdx->PortHWMode = HW_MODE_ECP;
// If setup was successful, mark the new ECP phase.
P5SetPhase( Pdx, PHASE_FORWARD_IDLE );
Status = STATUS_SUCCESS;
HWECP_SetupPhaseExitLabel:
DD((PCE)Pdx,DDT,"ParEcpHwSetupPhase - exit w/status=%x\n",Status);
return Status;
}
NTSTATUS ParEcpHwWaitForEmptyFIFO(IN PPDO_EXTENSION Pdx)
/*++
Routine Description:
This routine will babysit the Fifo.
Arguments:
Pdx - The device extension.
Return Value:
NTSTATUS.
--*/
{
UCHAR bDSR; // Contents of DSR
UCHAR bECR; // Contents of ECR
UCHAR bDCR; // Contents of ECR
BOOLEAN bDone = FALSE;
PUCHAR wPortDSR;
PUCHAR wPortECR;
PUCHAR wPortDCR;
LARGE_INTEGER Wait;
LARGE_INTEGER Start;
LARGE_INTEGER End;
NTSTATUS status = STATUS_SUCCESS;
// Calculate I/O port addresses for common registers
wPortDSR = Pdx->Controller + OFFSET_DSR;
wPortECR = Pdx->EcrController + ECR_OFFSET;
wPortDCR = Pdx->Controller + OFFSET_DCR;
Wait.QuadPart = (330 * 10 * 1000) + KeQueryTimeIncrement(); // 330ms
KeQueryTickCount(&Start);
//--------------------------------------------------------------------
// wait for the FIFO to empty and the last
// handshake of PeriphAck to complete before returning success.
//--------------------------------------------------------------------
while ( ! bDone )
{
bECR = P5ReadPortUchar(wPortECR);
bDSR = P5ReadPortUchar(wPortDSR);
bDCR = P5ReadPortUchar(wPortDCR);
#if 0 // one bit differs - keep alternate around until we know which to really use
if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) &&
TEST_DCR( bDCR, INACTIVE, ***INACTIVE***, ACTIVE, ACTIVE, DONT_CARE, ACTIVE ) &&
TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
#else
if ( TEST_ECR_FIFO( bECR, ECR_FIFO_EMPTY ) &&
TEST_DCR( bDCR, INACTIVE, DONT_CARE, ACTIVE, ACTIVE, DONT_CARE, ACTIVE ) &&
TEST_DSR( bDSR, INACTIVE, ACTIVE, ACTIVE, ACTIVE, DONT_CARE ) ) {
#endif
// FIFO is empty, exit without error.
bDone = TRUE;
} else {
KeQueryTickCount(&End);
if ((End.QuadPart - Start.QuadPart) * KeQueryTimeIncrement() > Wait.QuadPart) {
// FIFO not empty, timeout occurred, exit with error.
// NOTE: There is not a good way to determine how many bytes
// are stuck in the fifo
DD((PCE)Pdx,DDT,"ParEcpHwWaitForEmptyFIFO: timeout during synch\n");
status = STATUS_IO_TIMEOUT;
bDone = TRUE;
}
}
} // of while...
return status;
}
NTSTATUS
ParEcpHwWrite(
IN PPDO_EXTENSION Pdx,
IN PVOID Buffer,
IN ULONG BufferSize,
OUT PULONG BytesTransferred
)
/*++
Routine Description:
Writes data to the peripheral using the ECP protocol under hardware
control.
Arguments:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -