1419 lines
34 KiB
C
1419 lines
34 KiB
C
//-----------------------------------------------------------------------
|
|
//
|
|
// EP3C.C
|
|
//
|
|
// Trantor EP3C access file.
|
|
//
|
|
// Revisions:
|
|
// 03-31-93 KJB First.
|
|
// 04-09-93 KJB Changed "in edx,al" and "out edx,al" references to
|
|
// use only the dx register: in al,dx.
|
|
// Changed loop instructions to dec ecx, jnz.
|
|
// 04-21-93 KJB Fixed initialization error for os/2: static
|
|
// variables must be initialized.
|
|
// 05-05-93 KJB Disable Checking for EPP port for debug purposes.
|
|
// TEMPORARY.
|
|
// 05-05-93 KJB Added ReadFifoUni/BiDirSlow routines to do P_BUSY
|
|
// checking to allow bytes to get ready.
|
|
// 05-11-93 KJB Added WriteFifoUniDirSlow routine to do P_BUSY
|
|
// checking to allow bytes to get ready.
|
|
// 05-17-93 JAP Made in-line assemble routines conditionally coded.
|
|
// Only #ifdef WINNT will these routines be read in.
|
|
// Otherwise, look in ep3c2.asm.
|
|
// 05-17-93 KJB Fixed some compiler warnings.
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
|
|
#include CARDTXXX_H
|
|
|
|
// Local Functions
|
|
|
|
VOID EP3CSetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control);
|
|
VOID EP3CSetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control);
|
|
|
|
USHORT EP3CReadBytesFastBiDir(PADAPTER_INFO g, PUCHAR pbytes,
|
|
ULONG len, PULONG pActualLen, UCHAR phase);
|
|
USHORT EP3CReadBytesFastUniDir(PADAPTER_INFO g, PUCHAR pbytes,
|
|
ULONG len, PULONG pActualLen, UCHAR phase);
|
|
VOID EP3CSetRegisterUniDir(PADAPTER_INFO g, UCHAR reg);
|
|
VOID EP3CSetRegisterEPP(PADAPTER_INFO g, UCHAR reg);
|
|
BOOLEAN EP3CCheckAdapterType(PADAPTER_INFO g);
|
|
VOID EP3CSetParallelPortType(PADAPTER_INFO g);
|
|
|
|
VOID EP3CReadFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
|
|
VOID EP3CReadFifoBiDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
|
|
VOID EP3CReadFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
|
|
VOID EP3CWriteFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
|
|
VOID EP3CWriteFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes);
|
|
|
|
// for writes, uni-directional is the same as bi-directional
|
|
|
|
#define EP3CSetRegisterBiDir EP3CSetRegisterUniDir
|
|
#define EP3CWriteFifoBiDir EP3CWriteFifoUniDir
|
|
#define EP3CWriteDataRegisterBiDir EP3CWriteDataRegisterUniDir
|
|
#define EP3CWriteControlRegisterBiDir EP3CWriteControlRegisterUniDir
|
|
|
|
/// for control registers, epp is the same as bi-dir
|
|
|
|
#define EP3CWriteControlRegisterEPP EP3CWriteControlRegisterBiDir
|
|
#define EP3CReadControlRegisterEPP EP3CReadControlRegisterBiDir
|
|
|
|
// local redefinitions
|
|
|
|
#define EP3CPortPut(g, reg, value) \
|
|
(*(g->EP3CWriteControlRegister))(g,reg,value)
|
|
|
|
#define EP3CPortGet(g, reg, value) \
|
|
(*(g->EP3CReadControlRegister))(g, value)
|
|
|
|
//
|
|
// VOID EP3CPortSet
|
|
//
|
|
// Or's bits into an EP3C register.
|
|
//
|
|
VOID EP3CPortSet(PADAPTER_INFO g, UCHAR reg, UCHAR value)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
EP3CPortGet(g,reg,&tmp);
|
|
tmp |= value;
|
|
EP3CPortPut(g,reg,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CPortClear
|
|
//
|
|
// Clears all bits in the EP3C register with value.
|
|
//
|
|
VOID EP3CPortClear(PADAPTER_INFO g, UCHAR reg, UCHAR value)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
EP3CPortGet(g,reg,&tmp);
|
|
tmp &= (value ^ 0xff);
|
|
EP3CPortPut(g,reg,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CPortTest
|
|
//
|
|
// Tests bits in value with the EP3C register.
|
|
//
|
|
BOOLEAN EP3CPortTest(PADAPTER_INFO g, UCHAR reg, UCHAR value)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
EP3CPortGet(g,reg,&tmp);
|
|
return (tmp & value);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CSetRegisterUniDir(PADAPTER_INFO g, UCHAR reg)
|
|
//
|
|
// Sets the register that will be accessed.
|
|
//
|
|
VOID EP3CSetRegisterUniDir(PADAPTER_INFO g, UCHAR reg)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// write to adr reg 1
|
|
|
|
tmp = (reg & EP3C_ADRS);
|
|
EP3CPortPut(g,EP3C_AREG1,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CSetRegisterEPP(PADAPTER_INFO g, UCHAR reg)
|
|
//
|
|
// Sets the register that will be accessed.
|
|
//
|
|
VOID EP3CSetRegisterEPP(PADAPTER_INFO g, UCHAR reg)
|
|
{
|
|
ParallelPortPut(g->BaseIoAddress,EPP_AUTO_ADDRESS,reg);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CWriteControlRegisterUniDir
|
|
//
|
|
// Writes to an adr register of the ep3c using a uni-directional port.
|
|
//
|
|
VOID EP3CWriteControlRegisterUniDir(PADAPTER_INFO g, UCHAR areg,
|
|
UCHAR value)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// output the value and register to the parallel data reg
|
|
tmp = value | areg;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,tmp);
|
|
|
|
// write to ep3c
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp & (0xff ^ P_BUFEN);
|
|
tmp = tmp | P_STB;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
tmp = tmp | P_SLC;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// negate P_STB & P_SLC, to end write
|
|
|
|
tmp = tmp & (0xff ^ (P_STB | P_SLC));
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// note: we leave P_BUFEN asserted.
|
|
}
|
|
|
|
//
|
|
// VOID EP3CReadControlRegisterBiDir
|
|
//
|
|
// Reads from an adr register of the ep3c using a bi-directional port.
|
|
// NOTE: always read areg1 since areg2 is write-only.
|
|
//
|
|
VOID EP3CReadControlRegisterBiDir(PADAPTER_INFO g, PUCHAR value)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// negate P_BUFEN and assert P_SLC
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp | P_BUFEN | P_SLC;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// read data register
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,value);
|
|
|
|
// negate P_BUFEN and negate P_SLC
|
|
|
|
tmp = (tmp & ((P_SLC | P_BUFEN) ^ 0xff));
|
|
// tmp = (tmp & (P_SLC ^ 0xff)) | P_BUFEN;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CReadControlRegisterUniDir
|
|
//
|
|
// Reads from an adr register of the ep3c using a uni-directional port.
|
|
// NOTE: always read areg1 since areg2 is write-only.
|
|
//
|
|
VOID EP3CReadControlRegisterUniDir(PADAPTER_INFO g, PUCHAR value)
|
|
{
|
|
UCHAR tmp;
|
|
UCHAR tmp1;
|
|
|
|
// select high nibble
|
|
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x80);
|
|
|
|
// assert P_BUFEN and assert P_SLC
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp & (P_BUFEN ^ 0xff) | P_SLC;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// read high nibble
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp);
|
|
|
|
// compute high nibble
|
|
tmp = (tmp << 1) & 0xf0;
|
|
|
|
// select low nibble
|
|
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x00);
|
|
|
|
// read low nibble
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp1);
|
|
|
|
// compute low nibble
|
|
|
|
tmp1 = (tmp1 >> 3) & 0x0f;
|
|
|
|
// compute and return byte
|
|
|
|
*value = tmp1 | tmp;
|
|
|
|
// leave P_BUFEN asserted, negate P_SLC
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp & ((P_BUFEN | P_SLC) ^ 0xff);
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CReadDataRegisterUniDir
|
|
//
|
|
// Reads a byte from a register thru the ep3c, using uni-dir mode.
|
|
//
|
|
VOID EP3CReadDataRegisterUniDir(PADAPTER_INFO g,
|
|
UCHAR reg, PUCHAR byte)
|
|
{
|
|
UCHAR tmp;
|
|
UCHAR tmp1;
|
|
|
|
// set the register we want to access
|
|
|
|
(*(g->EP3CSetRegister))(g, reg);
|
|
|
|
// select high nibble
|
|
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x80);
|
|
|
|
// assert P_BUFEN and assert P_AFX
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp & (P_BUFEN ^ 0xff) | P_AFX;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// read high nibble
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp);
|
|
|
|
// compute high nibble
|
|
tmp = (tmp << 1) & 0xf0;
|
|
|
|
// select low nibble
|
|
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0x00);
|
|
|
|
// read low nibble
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_STATUS,&tmp1);
|
|
|
|
// compute low nibble
|
|
|
|
tmp1 = (tmp1 >> 3) & 0x0f;
|
|
|
|
// compute and return byte
|
|
|
|
*byte = tmp1 | tmp;
|
|
|
|
// leave P_BUFEN asserted, negate P_AFX
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp & ((P_BUFEN | P_AFX) ^ 0xff);
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
}
|
|
|
|
//
|
|
// VOID EP3CReadDataRegisterBiDir
|
|
//
|
|
// Reads a byte from a register thru the EP3C, using bi-dir mode.
|
|
//
|
|
VOID EP3CReadDataRegisterBiDir(PADAPTER_INFO g,
|
|
UCHAR reg, PUCHAR byte)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// set the register we want to access
|
|
|
|
(*(g->EP3CSetRegister))(g, reg);
|
|
|
|
// negate P_BUFEN, assert P_AFX
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp | P_BUFEN | P_AFX;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// read the data byte
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,byte);
|
|
|
|
// negate P_BUFEN, and P_AFX
|
|
|
|
tmp = tmp & ((P_BUFEN | P_AFX) ^ 0xff);
|
|
// tmp = tmp | P_BUFEN & (P_AFX ^ 0xff);
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CReadDataRegisterEPP
|
|
//
|
|
// Reads a byte from a register thru the EP3C, using epp mode.
|
|
//
|
|
VOID EP3CReadDataRegisterEPP(PADAPTER_INFO g,
|
|
UCHAR reg, PUCHAR byte)
|
|
{
|
|
// set the register we want to access
|
|
|
|
(*(g->EP3CSetRegister))(g, reg);
|
|
|
|
// read the data byte
|
|
|
|
ParallelPortGet(g->BaseIoAddress,EPP_AUTO_DATA,byte);
|
|
|
|
}
|
|
|
|
//
|
|
// VOID EP3CWriteDataRegisterUniDir
|
|
//
|
|
// Writes the a register thru the EP3C.
|
|
//
|
|
VOID EP3CWriteDataRegisterUniDir(PADAPTER_INFO g,
|
|
UCHAR reg, UCHAR byte)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// set the register we want to access
|
|
|
|
(*(g->EP3CSetRegister))(g, reg);
|
|
|
|
// output the byte on the data lines
|
|
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,byte);
|
|
|
|
// assert P_BUFEN and P_STB
|
|
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,&tmp);
|
|
tmp = tmp & (0xff ^ P_BUFEN) | P_STB;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// assert P_AFX
|
|
|
|
tmp = tmp | P_AFX;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// negate P_STB & P_AFX, to end write
|
|
|
|
tmp = tmp & (0xff ^ (P_STB | P_AFX));
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// negate P_BUFEN
|
|
|
|
// tmp = tmp | P_BUFEN;
|
|
// ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CWriteDataRegisterEPP
|
|
//
|
|
// Writes the a register thru the EP3C.
|
|
//
|
|
VOID EP3CWriteDataRegisterEPP(PADAPTER_INFO g,
|
|
UCHAR reg, UCHAR byte)
|
|
{
|
|
// set the register we want to access
|
|
|
|
(*(g->EP3CSetRegister))(g, reg);
|
|
|
|
// output the byte on the data lines
|
|
|
|
ParallelPortPut(g->BaseIoAddress,EPP_AUTO_DATA,byte);
|
|
|
|
}
|
|
|
|
//
|
|
// VOID EP3CReadFifoEPP
|
|
//
|
|
// Reads bytes for epp parallel port from the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
VOID EP3CReadFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
ScsiPortReadPortBufferUshort (
|
|
(PUSHORT)&(((PUCHAR)baseIoAddress)[EPP_AUTO_DATA]),
|
|
(PUSHORT)pbytes, 64);
|
|
}
|
|
|
|
|
|
//
|
|
// VOID EP3CWriteFifoEPP
|
|
//
|
|
// Writes bytes thru epp parallel port to the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
|
|
VOID EP3CWriteFifoEPP(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
ScsiPortWritePortBufferUshort (
|
|
(PUSHORT)&(((PUCHAR)baseIoAddress)[EPP_AUTO_DATA]),
|
|
(PUSHORT)pbytes, 64);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CDisableInterrupt
|
|
//
|
|
// Disables the interrupt.
|
|
//
|
|
|
|
VOID EP3CDisableInterrupt(PADAPTER_INFO g)
|
|
{
|
|
// set global flag for EP3CSetPrinterMode
|
|
g->EnableInterrupt = FALSE;
|
|
|
|
// see if the EP3C_IRQEN is asserted, if so clear it
|
|
if (EP3CPortTest(g,EP3C_AREG1,EP3C_IRQEN)) {
|
|
|
|
// clear the interrupts
|
|
// NOTE: a positive going edge toggles the state of EP3C_IRQEN
|
|
|
|
EP3CPortSet(g, EP3C_AREG1, EP3C_IRQEN);
|
|
EP3CPortClear(g, EP3C_AREG1, EP3C_IRQEN);
|
|
}
|
|
|
|
// finally, we can disable the core interrupts
|
|
N53C400DisableInterrupt(g);
|
|
}
|
|
|
|
//
|
|
// VOID EP3CEnableInterrupt
|
|
//
|
|
// Enables the interrupt.
|
|
//
|
|
|
|
VOID EP3CEnableInterrupt(PADAPTER_INFO g)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// set global flag for EP3CSetPrinterMode
|
|
|
|
g->EnableInterrupt = TRUE;
|
|
|
|
// see if the EP3C_IRQEN is not asserted, if so assert it
|
|
|
|
EP3CPortGet(g, EP3C_AREG1, &tmp);
|
|
if (!(tmp & EP3C_IRQEN)) {
|
|
|
|
// set the interrupts
|
|
// NOTE: a positive going edge toggles the state of EP3C_IRQEN
|
|
|
|
EP3CPortPut(g, EP3C_AREG1, EP3C_IRQEN);
|
|
EP3CPortPut(g, EP3C_AREG1, 0);
|
|
}
|
|
|
|
// finally, we can disable the core interrupts
|
|
N53C400EnableInterrupt(g);
|
|
}
|
|
|
|
//
|
|
// EP3CSetPrinterMode
|
|
//
|
|
// This routine sets the EP3C to printer pass through mode. This is the
|
|
// default mode and should be set after the brief use of scsi mode.
|
|
//
|
|
VOID EP3CSetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
// restore data register
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
|
|
|
|
// restore control register
|
|
// leave p_init negated, P_BUFEN asserted
|
|
// also set P_IRQEN based on g->EnableInterrupt
|
|
|
|
tmp = control | P_INIT & (P_BUFEN ^ 0xff);
|
|
if (g->EnableInterrupt) {
|
|
tmp = tmp | P_IRQEN;
|
|
} else {
|
|
tmp = tmp & (P_IRQEN ^ 0xff);
|
|
}
|
|
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
}
|
|
|
|
//
|
|
// EP3CSetScsiMode
|
|
//
|
|
// This routine sets the EP3C into scsi mode. Now the parallel port can
|
|
// be used to send commands the the n5380. This mode should be set only
|
|
// briefly during when the scsi command is being executed.
|
|
//
|
|
VOID EP3CSetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control)
|
|
{
|
|
UCHAR tmp;
|
|
USHORT i;
|
|
|
|
// save parallel data
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,data);
|
|
|
|
// zero data register
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0);
|
|
|
|
// save parallel control
|
|
ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,control);
|
|
*control = *control & (P_BUFEN ^ 0xff);
|
|
|
|
// store current interrupt state
|
|
|
|
g->EnableInterrupt = (*control & P_IRQEN);
|
|
|
|
// put our data pattern on the data bus
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,0xf7);
|
|
|
|
// negate P_SLC, P_BUFEN already asserted
|
|
tmp = *control;
|
|
tmp = tmp & (P_SLC ^ 0xff);
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// assert init
|
|
tmp = tmp & (P_INIT ^ 0xff);
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// assert P_SLC
|
|
tmp = tmp | P_SLC;
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// negate P_SLC
|
|
tmp = tmp & (P_SLC ^ 0xff);
|
|
ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
|
|
|
|
// set to the appropriate mode: UNI, BI, etc..
|
|
|
|
if (g->ParallelPortType == PT_UNI) {
|
|
EP3CPortPut(g,(UCHAR)EP3C_AREG2,
|
|
(UCHAR)(EP3C_UNIDIR | g->Delay) );
|
|
} else {
|
|
EP3CPortPut(g,EP3C_AREG2,(UCHAR)(0 | g->Delay));
|
|
}
|
|
|
|
// read in the signature bytes
|
|
|
|
for (i=0;i<2;i++) {
|
|
EP3CPortGet(g, EP3C_AREG1, &g->SignatureBytes[i]);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// EP3CCheckAdapter
|
|
//
|
|
// This routine is used to sense the presense of the EP3C adapter out
|
|
// on the Parallel port. It will only detect the adapter if a device
|
|
// is providing termination power.
|
|
//
|
|
BOOLEAN EP3CCheckAdapter(PADAPTER_INFO g)
|
|
{
|
|
BOOLEAN rval = FALSE;
|
|
static CONST UCHAR ParallelPortType = PT_UNI;
|
|
static CONST UCHAR types[] = { PT_EPP, PT_BI, PT_UNI };
|
|
USHORT i;
|
|
|
|
// default the delay to 2 for now
|
|
g->Delay = 7;
|
|
|
|
if (g->ParallelPortType == PT_UNKNOWN) {
|
|
|
|
// try to locate as all types
|
|
|
|
for (i=0;i<3;i++) {
|
|
|
|
g->ParallelPortType = types[i];
|
|
|
|
// do we have a type[i] port?
|
|
|
|
if (rval = EP3CCheckAdapterType(g)) {
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
} else {
|
|
|
|
// try only the parallel port type specified
|
|
|
|
rval = EP3CCheckAdapterType(g);
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
//
|
|
// VOID EP3CSetParallelType
|
|
//
|
|
// Sets this code to use the type of paralle port given by
|
|
// g->ParallePortType, either PT_UNI, PT_BI, or PT_EPP.
|
|
//
|
|
VOID EP3CSetParallelPortType(PADAPTER_INFO g)
|
|
{
|
|
|
|
switch (g->ParallelPortType) {
|
|
case PT_UNI:
|
|
|
|
// set the port type dependent routines
|
|
|
|
g->EP3CWriteControlRegister = EP3CWriteControlRegisterUniDir;
|
|
g->EP3CReadControlRegister = EP3CReadControlRegisterUniDir;
|
|
g->EP3CReadDataRegister = EP3CReadDataRegisterUniDir;
|
|
g->EP3CWriteDataRegister = EP3CWriteDataRegisterUniDir;
|
|
g->EP3CReadFifo = EP3CReadFifoUniDir;
|
|
// g->EP3CReadFifo = EP3CReadFifoUniDirSlow;
|
|
g->EP3CWriteFifo = EP3CWriteFifoUniDir;
|
|
g->EP3CSetRegister = EP3CSetRegisterUniDir;
|
|
|
|
break;
|
|
case PT_BI:
|
|
|
|
// set the port type dependent routines
|
|
|
|
g->EP3CWriteControlRegister = EP3CWriteControlRegisterBiDir;
|
|
g->EP3CReadControlRegister = EP3CReadControlRegisterBiDir;
|
|
g->EP3CReadDataRegister = EP3CReadDataRegisterBiDir;
|
|
g->EP3CWriteDataRegister = EP3CWriteDataRegisterBiDir;
|
|
g->EP3CReadFifo = EP3CReadFifoBiDir;
|
|
// g->EP3CReadFifo = EP3CReadFifoBiDirSlow;
|
|
g->EP3CWriteFifo = EP3CWriteFifoBiDir;
|
|
g->EP3CSetRegister = EP3CSetRegisterBiDir;
|
|
|
|
break;
|
|
|
|
case PT_EPP:
|
|
// set the port type dependent routines
|
|
|
|
g->EP3CWriteControlRegister = EP3CWriteControlRegisterEPP;
|
|
g->EP3CReadControlRegister = EP3CReadControlRegisterEPP;
|
|
g->EP3CReadDataRegister = EP3CReadDataRegisterEPP;
|
|
g->EP3CWriteDataRegister = EP3CWriteDataRegisterEPP;
|
|
g->EP3CReadFifo = EP3CReadFifoEPP;
|
|
g->EP3CWriteFifo = EP3CWriteFifoEPP;
|
|
g->EP3CSetRegister = EP3CSetRegisterEPP;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// BOOLEAN EP3CCheckAdapterType
|
|
//
|
|
// Checks for an adapter on a parallel port of the given type.
|
|
//
|
|
BOOLEAN EP3CCheckAdapterType(PADAPTER_INFO g)
|
|
{
|
|
UCHAR data;
|
|
UCHAR control;
|
|
|
|
// if epp type, then try to initialize 386sl code
|
|
if (g->ParallelPortType == PT_EPP) {
|
|
if (!SL386EnableEPP()) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// configure for the correct type of parallel port
|
|
|
|
EP3CSetParallelPortType(g);
|
|
|
|
// set scsi mode, reads signature bytes.
|
|
|
|
EP3CSetScsiMode(g,&data,&control);
|
|
|
|
// set parallel port for use by printer
|
|
|
|
EP3CSetPrinterMode(g,data,control);
|
|
|
|
// compare the signature bytes
|
|
|
|
if ((g->SignatureBytes[0] == 0xe8) && (g->SignatureBytes[1] == 0xff) ) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// EP3CDoCommand
|
|
//
|
|
// Called by the main loop to start a scsi command. This functions is the
|
|
// main entry point for all cards. It returns an SRB status code as defined
|
|
// in ..\..\inc\srb.h. A status code of RET_STATUS_PENDING means that the
|
|
// request has been sent to the controller and an interrupt is needed to
|
|
// finish the request. When this interrupt occurs CardFinishCommandInterrupt
|
|
// will be called.
|
|
//
|
|
USHORT EP3CDoCommand(PTSRB t)
|
|
{
|
|
USHORT rval;
|
|
UCHAR data;
|
|
UCHAR control;
|
|
PADAPTER_INFO g = t->pWorkspace;
|
|
|
|
// put the parallel adapter into scsi mode
|
|
|
|
EP3CSetScsiMode(g, &data, &control);
|
|
|
|
// execute the complete command now, without interrupts
|
|
|
|
rval = ScsiDoCommand(t);
|
|
|
|
// put the parallel adapter back to parallel mode
|
|
|
|
EP3CSetPrinterMode(g, data, control);
|
|
return rval;
|
|
}
|
|
|
|
//
|
|
// EP3CStartCommandInterrupt
|
|
//
|
|
// This routines allow the driver to be polled by checking its
|
|
// CardInterrupt by for example using the timer interrupt, since
|
|
// the EP3C does not support interrupts on its own.
|
|
//
|
|
//
|
|
USHORT EP3CStartCommandInterrupt(PTSRB t)
|
|
{
|
|
USHORT rval;
|
|
UCHAR data;
|
|
UCHAR control;
|
|
PADAPTER_INFO g = t->pWorkspace;
|
|
|
|
// put the parallel adapter into scsi mode
|
|
|
|
EP3CSetScsiMode(g, &data, &control);
|
|
|
|
// execute the complete command now, without interrupts
|
|
|
|
rval = ScsiStartCommandInterrupt(t);
|
|
|
|
// put the parallel adapter back to parallel mode
|
|
|
|
EP3CSetPrinterMode(g, data, control);
|
|
|
|
return rval;
|
|
}
|
|
|
|
//
|
|
// EP3CFinishCommandInterrupt
|
|
//
|
|
// This routines allow the driver to be polled by checking its
|
|
// CardInterrupt by for example using the timer interrupt, since
|
|
// the EP3C does not support interrupts on its own.
|
|
//
|
|
//
|
|
USHORT EP3CFinishCommandInterrupt(PTSRB t)
|
|
{
|
|
USHORT rval;
|
|
UCHAR data;
|
|
UCHAR control;
|
|
PADAPTER_INFO g = t->pWorkspace;
|
|
|
|
// put the parallel adapter into scsi mode
|
|
|
|
EP3CSetScsiMode(g, &data, &control);
|
|
|
|
// execute the complete command now, without interrupts
|
|
|
|
rval = ScsiFinishCommandInterrupt(t);
|
|
|
|
// put the parallel adapter back to parallel mode
|
|
|
|
EP3CSetPrinterMode(g, data, control);
|
|
|
|
return rval;
|
|
}
|
|
|
|
//
|
|
// EP3CInterrupt
|
|
//
|
|
// This routines allow the driver to be polled by checking its
|
|
// CardInterrupt by for example using the timer interrupt, since
|
|
// the EP3C does not support interrupts on its own.
|
|
//
|
|
BOOLEAN EP3CInterrupt(PADAPTER_INFO g)
|
|
{
|
|
BOOLEAN rval;
|
|
UCHAR data;
|
|
UCHAR control;
|
|
|
|
// put the parallel adapter into scsi mode
|
|
|
|
EP3CSetScsiMode(g, &data, &control);
|
|
|
|
rval = N5380Interrupt(g);
|
|
|
|
// put the parallel adapter back to parallel mode
|
|
|
|
EP3CSetPrinterMode(g, data, control);
|
|
|
|
return rval;
|
|
}
|
|
|
|
//
|
|
// EP3CResetBus
|
|
//
|
|
// Resets the SCSI Bus
|
|
//
|
|
VOID EP3CResetBus(PADAPTER_INFO g)
|
|
{
|
|
UCHAR data;
|
|
UCHAR control;
|
|
|
|
// reset the EP3C
|
|
|
|
EP3CPortSet(g,EP3C_AREG2,EP3C_RST);
|
|
|
|
// put the parallel adapter into scsi mode
|
|
|
|
EP3CSetScsiMode(g, &data, &control);
|
|
|
|
// execute the complete command now, without interrupts
|
|
|
|
N53C400ResetBus(g);
|
|
|
|
// put the parallel adapter back to parallel mode
|
|
|
|
EP3CSetPrinterMode(g, data, control);
|
|
}
|
|
|
|
//
|
|
// N53C400PortPut
|
|
//
|
|
// This routine is used by the N53C400.C module to write byte to a 53C400
|
|
// controller. This allows the module to be card independent. Other
|
|
// modules that assume a N53C400 may also use this function.
|
|
//
|
|
VOID N53C400PortPut(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
|
|
{
|
|
(*(g->EP3CWriteDataRegister))(g, reg, byte);
|
|
}
|
|
|
|
//
|
|
// N53C400PortGet
|
|
//
|
|
// This routine is used by the N53C400.C module to get a byte from a 53C400
|
|
// controller. This allows the module to be card independent. Other
|
|
// modules that assume a N53C400 may also use this function.
|
|
//
|
|
VOID N53C400PortGet(PADAPTER_INFO g,UCHAR reg,PUCHAR byte)
|
|
{
|
|
(*(g->EP3CReadDataRegister))(g, reg, byte);
|
|
}
|
|
|
|
//
|
|
// VOID N53C400PortSet
|
|
//
|
|
// Sets the bit pattern at the given register.
|
|
//
|
|
VOID N53C400PortSet(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
|
|
{
|
|
UCHAR tmp;
|
|
(*(g->EP3CReadDataRegister))(g, reg, &tmp);
|
|
tmp |= byte;
|
|
(*(g->EP3CWriteDataRegister))(g, reg, tmp);
|
|
}
|
|
|
|
//
|
|
// VOID N53C400PortClear
|
|
//
|
|
// Clears a bit pattern at the given register.
|
|
//
|
|
VOID N53C400PortClear(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
(*(g->EP3CReadDataRegister))(g, reg, &tmp);
|
|
tmp &= (byte ^ 0xff);
|
|
(*(g->EP3CWriteDataRegister))(g, reg, tmp);
|
|
}
|
|
|
|
//
|
|
// BOOLEAN N53C400PortTest
|
|
//
|
|
// Tests for a bit pattern on the given register.
|
|
//
|
|
BOOLEAN N53C400PortTest(PADAPTER_INFO g,UCHAR reg,UCHAR byte)
|
|
{
|
|
UCHAR tmp;
|
|
|
|
(*(g->EP3CReadDataRegister))(g, reg, &tmp);
|
|
return (tmp & byte);
|
|
}
|
|
|
|
|
|
//
|
|
// VOID N53C400PortGetBuffer
|
|
//
|
|
// Gets a buffer of 128 bytes from the n53c400. Note, the len here
|
|
// is ignored.
|
|
//
|
|
VOID N53C400PortGetBuffer(PADAPTER_INFO g, UCHAR reg,
|
|
PUCHAR pbytes, ULONG len)
|
|
{
|
|
// set the 53c400 register to access
|
|
|
|
(*(g->EP3CSetRegister))(g,reg);
|
|
|
|
// read the fifo
|
|
|
|
(*(g->EP3CReadFifo))(g->BaseIoAddress, pbytes);
|
|
}
|
|
|
|
//
|
|
// VOID N53C400PortPutBuffer
|
|
//
|
|
// Puts a buffer of 128 bytes from the n53c400. Note, the len here
|
|
// is ignored.
|
|
//
|
|
VOID N53C400PortPutBuffer(PADAPTER_INFO g, UCHAR reg,
|
|
PUCHAR pbytes, ULONG len)
|
|
{
|
|
// set the 53c400 register to access
|
|
|
|
(*(g->EP3CSetRegister))(g,reg);
|
|
|
|
// read the fifo
|
|
|
|
(*(g->EP3CWriteFifo))(g->BaseIoAddress, pbytes);
|
|
}
|
|
|
|
//======================================================================
|
|
// Conditionally-coded routines using in-line assembler.
|
|
//======================================================================
|
|
|
|
#ifdef WINNT
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
// VOID EP3CReadFifoUniDir
|
|
//
|
|
// Reads bytes for uni-directional parallel port from the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
VOID EP3CReadFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
_asm {
|
|
push ds
|
|
push edi
|
|
|
|
#ifdef MODE_32BIT
|
|
mov edi, pbytes
|
|
mov edx, baseIoAddress
|
|
#else
|
|
mov edi, word ptr pbytes
|
|
mov ds, word ptr pbytes+2
|
|
mov edx, word ptr baseIoAddress
|
|
#endif // MODE_32BIT
|
|
mov ecx, 128
|
|
loop0:
|
|
mov al, 0x80
|
|
out dx,al // select high nibble
|
|
|
|
jmp delay0
|
|
delay0:
|
|
|
|
add edx,2 // DX -> ctl reg
|
|
mov al,P_AFX // assert bufen and afx
|
|
out dx,al // assert dreg read
|
|
|
|
jmp delay1
|
|
delay1:
|
|
|
|
dec edx // DX -> stat reg
|
|
in al,dx // read high nibble
|
|
|
|
jmp delay2
|
|
delay2:
|
|
|
|
mov ah,al
|
|
shl ah,1
|
|
and ah,0f0h // AH -> adj high nibble
|
|
dec edx // DX -> data reg
|
|
sub al,al
|
|
out dx,al // select low nibble
|
|
|
|
jmp delay3
|
|
delay3:
|
|
|
|
inc edx // DX -> stat reg
|
|
in al,dx // read low nibble
|
|
|
|
shr al,1
|
|
shr al,1
|
|
shr al,1
|
|
and al,0fh // AL = adj low nibble
|
|
or al,ah // AL = recombined byte
|
|
|
|
mov [edi],al // store
|
|
inc edi // bump buf ptr
|
|
|
|
inc edx // DX -> ctl reg
|
|
xor al,al // negate afx (bufen stays asserted)
|
|
out dx,al // end read
|
|
|
|
jmp delay4
|
|
delay4:
|
|
|
|
sub edx,2 // DX -> data reg
|
|
dec ecx
|
|
jnz loop0
|
|
|
|
pop edi
|
|
pop ds
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// VOID EP3CReadFifoUniDirSlow
|
|
//
|
|
// Reads bytes for uni-directional parallel port from the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
// USES FULL HANDSHAKING
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
VOID EP3CReadFifoUniDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
_asm {
|
|
push ds
|
|
push edi
|
|
|
|
#ifdef MODE_32BIT
|
|
mov edi, pbytes
|
|
mov edx, baseIoAddress
|
|
#else
|
|
mov edi, word ptr pbytes
|
|
mov ds, word ptr pbytes+2
|
|
mov edx, word ptr baseIoAddress
|
|
#endif // MODE_32BIT
|
|
inc edx // edx - status register
|
|
mov ecx, 128
|
|
loop0:
|
|
|
|
dec edx // edx - data register
|
|
mov al, 0x80
|
|
out dx,al // select high nibble
|
|
|
|
jmp delay0
|
|
delay0:
|
|
|
|
add edx,2 // DX -> ctl reg
|
|
mov al,P_AFX // assert bufen and afx
|
|
out dx,al // assert dreg read
|
|
|
|
// wait till ready, P_BUSY asserted
|
|
dec edx // edx - status register
|
|
loop1:
|
|
in al,dx
|
|
test al, P_BUSY
|
|
jnz loop1
|
|
|
|
// delay to make sure we get high nibble in
|
|
jmp delay01
|
|
delay01:
|
|
in al,dx
|
|
|
|
mov ah,al
|
|
shl ah,1
|
|
and ah,0f0h // AH -> adj high nibble
|
|
dec edx // DX -> data reg
|
|
sub al,al
|
|
out dx,al // select low nibble
|
|
|
|
jmp delay3
|
|
delay3:
|
|
|
|
inc edx // DX -> stat reg
|
|
in al,dx // read low nibble
|
|
|
|
shr al,1
|
|
shr al,1
|
|
shr al,1
|
|
and al,0fh // AL = adj low nibble
|
|
or al,ah // AL = recombined byte
|
|
|
|
mov [edi],al // store
|
|
inc edi // bump buf ptr
|
|
|
|
inc edx // DX -> ctl reg
|
|
xor al,al // negate afx (bufen stays asserted)
|
|
out dx,al // end read
|
|
|
|
dec edx // DX -> status register
|
|
// wait for P_BUSY deasserted
|
|
loop2:
|
|
in al,dx
|
|
test al, P_BUSY
|
|
jz loop2
|
|
|
|
dec ecx
|
|
jnz loop0
|
|
|
|
pop edi
|
|
pop ds
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// VOID EP3CReadFifoBiDir
|
|
//
|
|
// Reads bytes for bi-directional parallel port from the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
VOID EP3CReadFifoBiDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
_asm {
|
|
push ds
|
|
push edi
|
|
|
|
#ifdef MODE_32BIT
|
|
mov edi,pbytes
|
|
mov edx, baseIoAddress
|
|
#else
|
|
mov edi, word ptr pbytes
|
|
mov ds, word ptr pbytes+2
|
|
mov edx, word ptr baseIoAddress
|
|
#endif // MODE_32BIT
|
|
mov ecx, 128
|
|
add edx, 2 // edx - control register
|
|
loop0:
|
|
mov al, P_BUFEN + P_AFX
|
|
out dx, al
|
|
|
|
jmp delay0
|
|
delay0:
|
|
|
|
sub edx,2 // edx - data register
|
|
|
|
in al,dx
|
|
mov [edi], al
|
|
inc edi
|
|
|
|
add edx,2 // edx - control register
|
|
|
|
mov al, P_BUFEN
|
|
out dx, al
|
|
|
|
jmp delay1 // is this needed, there is a loop?
|
|
delay1:
|
|
|
|
dec ecx
|
|
jnz loop0
|
|
|
|
xor al,al // leave control regiser 0'd
|
|
out dx, al
|
|
|
|
pop edi
|
|
pop ds
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// VOID EP3CReadFifoBiDirSlow
|
|
//
|
|
// Reads bytes for bi-directional parallel port from the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
// USES FULL HANDSHAKING
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
VOID EP3CReadFifoBiDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
_asm {
|
|
push ds
|
|
push edi
|
|
|
|
#ifdef MODE_32BIT
|
|
mov edi,pbytes
|
|
mov edx, baseIoAddress
|
|
#else
|
|
mov edi, word ptr pbytes
|
|
mov ds, word ptr pbytes+2
|
|
mov edx, word ptr baseIoAddress
|
|
#endif // MODE_32BIT
|
|
mov ecx, 128
|
|
add edx, 0x02 // edx - control register
|
|
|
|
// wait for data to be ready, P_BUSY asserted
|
|
loop0:
|
|
mov al, P_BUFEN + P_AFX
|
|
out dx, al
|
|
|
|
dec edx // edx - status register
|
|
loop1:
|
|
in al,dx
|
|
test al, P_BUSY
|
|
jnz loop1
|
|
|
|
dec edx // edx - data register
|
|
|
|
in al,dx
|
|
mov [edi], al
|
|
inc edi
|
|
|
|
add edx,2 // edx - control register
|
|
|
|
// end data read cycle
|
|
mov al, P_BUFEN
|
|
out dx, al
|
|
|
|
dec edx // edx - status register
|
|
|
|
// wait for P_BUSY deasserted
|
|
loop2:
|
|
in al,dx
|
|
test al, P_BUSY
|
|
jz loop2
|
|
|
|
inc edx // edx - control register
|
|
|
|
dec ecx
|
|
jnz loop0
|
|
|
|
xor al,al // leave control regiser 0'd
|
|
out dx, al
|
|
|
|
pop edi
|
|
pop ds
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// VOID EP3CWriteFifoUniDir
|
|
//
|
|
// Writes bytes thru uni-directional parallel port to the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
VOID EP3CWriteFifoUniDir(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
_asm {
|
|
push ds
|
|
push edi
|
|
|
|
#ifdef MODE_32BIT
|
|
mov edi,pbytes
|
|
mov edx, baseIoAddress
|
|
#else
|
|
mov edi, word ptr pbytes
|
|
mov ds, word ptr pbytes+2
|
|
mov edx, word ptr baseIoAddress
|
|
#endif // MODE_32BIT
|
|
mov ecx, 128
|
|
|
|
loop0:
|
|
mov al,[edi]
|
|
out dx,al
|
|
inc edi
|
|
|
|
add edx,2 ;DX -> ctl reg
|
|
mov al,P_STB ;assert bufen, stb
|
|
out dx,al
|
|
or al,P_AFX ;assert dreg write
|
|
out dx,al
|
|
|
|
jmp delay0
|
|
delay0:
|
|
;leave bufen asserted
|
|
mov al,0 ; and negate afx, stb
|
|
out dx,al ;end write
|
|
|
|
jmp delay1
|
|
delay1:
|
|
|
|
sub edx,2 ;DX -> data reg
|
|
dec ecx
|
|
jnz loop0
|
|
|
|
// let's leave control register 0'd for all these fifo routines...
|
|
// add edx,2 ;DX -> ctl reg
|
|
// or al,P_BUFEN ;negate bufen
|
|
// out dx,al
|
|
|
|
|
|
jmp delay2
|
|
delay2:
|
|
|
|
pop edi
|
|
pop ds
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// VOID EP3CWriteFifoUniDirSlow
|
|
//
|
|
// Writes bytes thru uni-directional parallel port to the 53c400
|
|
// 128 byte buffer. The register must already be set the the
|
|
// 53c400 buffer register.
|
|
//
|
|
// USES FULL HANDSHAKING
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
VOID EP3CWriteFifoUniDirSlow(PBASE_REGISTER baseIoAddress, PUCHAR pbytes)
|
|
{
|
|
_asm {
|
|
push ds
|
|
push edi
|
|
|
|
#ifdef MODE_32BIT
|
|
mov edi,pbytes
|
|
mov edx, baseIoAddress
|
|
#else
|
|
mov edi, word ptr pbytes
|
|
mov ds, word ptr pbytes+2
|
|
mov edx, word ptr baseIoAddress
|
|
#endif // MODE_32BIT
|
|
mov ecx, 128
|
|
|
|
loop0:
|
|
mov al,[edi]
|
|
out dx,al
|
|
inc edi
|
|
|
|
add edx,2 ;DX -> ctl reg
|
|
mov al,P_STB ;assert bufen, stb
|
|
out dx,al
|
|
or al,P_AFX ;assert dreg write
|
|
out dx,al
|
|
|
|
// wait till ready, P_BUSY asserted
|
|
dec edx // edx - status register
|
|
loop1:
|
|
in al,dx
|
|
test al, P_BUSY
|
|
jnz loop1
|
|
|
|
inc edx // edx - control register
|
|
|
|
;leave bufen asserted
|
|
mov al,0 ; and negate afx, stb
|
|
out dx,al ;end write
|
|
|
|
dec edx // edx - status register
|
|
|
|
// wait for P_BUSY deasserted
|
|
loop2:
|
|
in al,dx
|
|
test al, P_BUSY
|
|
jz loop2
|
|
|
|
dec edx // edx - data register
|
|
|
|
dec ecx
|
|
jnz loop0
|
|
|
|
// let's leave control register 0'd for all these fifo routines...
|
|
// add edx,2 ;DX -> ctl reg
|
|
// or al,P_BUFEN ;negate bufen
|
|
// out dx,al
|
|
|
|
pop edi
|
|
pop ds
|
|
}
|
|
}
|
|
|
|
#endif // #ifdef WINNT
|