summaryrefslogtreecommitdiffstats
path: root/private/ntos/miniport/trantor/source/t338.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/miniport/trantor/source/t338.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/miniport/trantor/source/t338.c')
-rw-r--r--private/ntos/miniport/trantor/source/t338.c763
1 files changed, 763 insertions, 0 deletions
diff --git a/private/ntos/miniport/trantor/source/t338.c b/private/ntos/miniport/trantor/source/t338.c
new file mode 100644
index 000000000..e36bf3c12
--- /dev/null
+++ b/private/ntos/miniport/trantor/source/t338.c
@@ -0,0 +1,763 @@
+//---------------------------------------------------------------------
+//
+// T338.C
+//
+// Trantor T338 Logic Module. Contains functions to access the T338
+// adapter.
+//
+// Revisions:
+// 02-01-93 KJB First.
+// 02-23-93 KJB Reorganized, supports dataunderrun with long delay
+// for under run on large xfers. Can we fix this?
+// 03-11-93 JAP Changed retcode equates to reflect new names.
+// 03-11-93 KJB Changed to use N5380Enable/DisableDmaRead/Write
+// routines.
+// 03-12-93 KJB Now supports polling thru CardInterrupt and
+// StartCommandInterrupt/FinishCommandInterrupt.
+// 03-19-93 JAP Implemented condition build FAR and NEAR pointers
+// 03-22-93 KJB Added support for scatter gather: T338DoIo.
+// 03-24-93 KJB Fixed SetScsiMode so it does not reset the n5380!
+// 05-14-93 KJB Added CardParseCommandString for card specific
+// standard string parsing across platforms.
+// Changed CardCheckAdapter to accept an
+// Initialization info from command line, ie
+// force bi-directional ports, etc.
+// All functions that used to take an PBASE_REGISTER
+// parameter now take PWORKSPACE. CardCheckAdapter
+// takes the both a PINIT and a PWORKSPACE parameters.
+// 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
+// 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
+// 05-16-93 KJB Fixed parameter bugs introduced while doing the
+// PWORKSPACE changes.
+// 05-17-93 KJB Fixed compiler warnings.
+//
+//---------------------------------------------------------------------
+
+#include CARDTXXX_H
+
+// Local Functions
+
+VOID T338PutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg);
+VOID T338SetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control);
+VOID T338SetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control);
+
+//
+// T338PutControl
+//
+// Puts a control byte to the T338 style adapter. This sets the mode
+// to IOR or IOW and the address byte of the N5380 register.
+//
+VOID T338PutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg)
+{
+ UCHAR tmp;
+
+ // the following bits are active low: IOW, IOR, MR
+
+ tmp = reg | (mode ^ (T338_MR | T338_IOW | T338_IOR));
+
+ // put the control byte on the data lines
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,tmp);
+
+ // assert slc to indicate byte is there
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC);
+
+ // clear slc
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
+}
+
+//
+// T338SetPrinterMode
+//
+// This routine sets the T338 to printer pass through mode. This is the
+// default mode and should be set after the brief use of scsi mode.
+//
+VOID T338SetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control)
+{
+ UCHAR tmp;
+
+ // do we have to disable interrupts?
+
+ // negate all control signals...
+
+ T338PutControl(g,0,0);
+
+ // restore data register
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // leave p_init negated (1)
+
+ tmp = control | P_INIT;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// T338SetScsiMode
+//
+// This routine sets the T338 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 T338SetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control)
+{
+ UCHAR tmp;
+
+ // save parallel data
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,data);
+
+ // zero data register
+ // note: the signals IOW,IOR,MR are active low, so assert them..
+
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,
+ T338_MR | T338_IOW | T338_IOR);
+
+ // save parallel control
+
+ ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,control);
+ *control = *control & (P_BUFEN ^ 0xff);
+
+ // clear p_init and set p_slc
+
+ tmp = (*control & (P_INIT ^ 0xff) ) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // clear p_init and set p_slc
+
+ tmp = (*control & (P_INIT ^ 0xff) ) | P_SLC;
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+
+ // clear slc, leave p_init asserted (0)
+
+ tmp = tmp & (P_SLC ^ 0xff);
+ ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
+}
+
+//
+// T338CheckAdapter
+//
+// This routine is used to sense the presense of the T338 adapter out
+// on the Parallel port. It will only detect the adapter if a device
+// is providing termination power.
+//
+BOOLEAN T338CheckAdapter(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+ BOOLEAN rval;
+
+ // set scsi mode
+
+ T338SetScsiMode(g,&data,&control);
+
+ // reset the 5380
+
+ T338PutControl(g,T338_MR,0);
+ T338PutControl(g,0,0);
+
+ // check to see if a 5380 is there
+
+ rval = N5380CheckAdapter(g);
+
+ // set parallel port for use by printer
+
+ T338SetPrinterMode(g,data,control);
+
+ return rval;
+}
+
+//
+// T338DoCommand
+//
+// 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 T338DoCommand(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiDoCommand(t);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// T338StartCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the T338 does not support interrupts on its own.
+//
+//
+USHORT T338StartCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiStartCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// T338FinishCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the T338 does not support interrupts on its own.
+//
+//
+USHORT T338FinishCommandInterrupt(PTSRB t)
+{
+ USHORT rval;
+ UCHAR data;
+ UCHAR control;
+ PADAPTER_INFO g = t->pWorkspace;
+
+ // put the T338 into ScsiMode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ rval = ScsiFinishCommandInterrupt(t);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+// T338StartCommandInterrupt
+//
+// This routines allow the driver to be polled by checking its
+// CardInterrupt by for example using the timer interrupt, since
+// the T338 does not support interrupts on its own.
+//
+BOOLEAN T338Interrupt(PADAPTER_INFO g)
+{
+ BOOLEAN rval;
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ rval = N5380Interrupt(g);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+
+ return rval;
+}
+
+//
+//
+// T338ResetBus
+//
+// Resets the SCSI Bus
+//
+VOID T338ResetBus(PADAPTER_INFO g)
+{
+ UCHAR data;
+ UCHAR control;
+
+ // put the parallel adapter into scsi mode
+
+ T338SetScsiMode(g, &data, &control);
+
+ // execute the complete command now, without interrupts
+
+ N5380ResetBus(g);
+
+ // put the parallel adapter back to parallel mode
+
+ T338SetPrinterMode(g, data, control);
+}
+
+//
+// T338WriteBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiWriteBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+USHORT T338WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // use slow mode for odd xfers (inquiry type commands) & audio
+
+ if (len % 512) {
+ return ScsiWriteBytesSlow (g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ // start dma mode
+
+ N5380EnableDmaWrite (g);
+
+ // put the T338 into write dma mode
+
+ T338PutControl (g,T338_IOW,0);
+
+ {
+ ULONG xfer_count = len;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx,baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+
+ add dx,2 // dx points to control reg
+
+ get_bytes:
+ dec dx // dx points to status register
+ in al,dx
+ test al,P_BUSY
+ jnz big_wait
+
+ ready:
+ dec dx // dx points to parallel data reg
+ mov al,[esi]
+ out dx,al
+
+ // assert DACK
+
+ add dx,2 // dx points to control reg
+ mov al, P_AFX
+ out dx,al
+
+ // deassert DACK
+
+ mov al,0
+ out dx,al
+
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ jmp short ready
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // clear the dma bit of 5380
+
+ N5380DisableDmaWrite (g);
+
+ // if data underrun, return the under/over run error message
+
+ if (rval) {
+ UCHAR tmp;
+
+ // phase mismatch means data under/over run
+
+ N5380GetPhase (g,&tmp);
+
+ if (tmp == PHASE_STATUS) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ return rval;
+}
+
+//
+// T338ReadBytesFast
+//
+// This routine is used by the ScsiFnc routines to write bytes to the scsi
+// bus quickly. The ScsiFnc routines don't know how to do this quickly for
+// a particular card, so they call this. This routine can be mapped to the
+// slower ScsiReadBytesSlow routine for small transferrs or if this routine
+// is not supported.
+//
+#pragma optimize("",off)
+USHORT T338ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
+ ULONG len, PULONG pActualLen, UCHAR phase)
+{
+ USHORT rval = 0;
+
+ // use slow mode for small xfers (inquiry type commands) and audio
+
+ if (len % 512) {
+ return ScsiReadBytesSlow (g, pbytes, len,
+ pActualLen, phase);
+ }
+
+ // start dma read
+
+ N5380EnableDmaRead (g);
+
+ // put the t338 into read mode
+
+ T338PutControl (g,T338_IOR,0);
+
+ // to be fast, for 386 machines, this must be coded in assembly
+ // for inline assembly, we don't have to save eax-edx registers
+ {
+ ULONG xfer_count = len;
+ PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
+
+ _asm {
+ push esi
+ push ds
+#ifdef MODE_32BIT
+ mov edx, baseIoAddress
+ mov esi,pbytes
+ mov ecx,len
+#else
+ mov dx, word ptr baseIoAddress
+ mov si, word ptr pbytes
+ mov cx, word ptr len
+ mov ds, word ptr pbytes+2
+#endif // MODE_32BIT
+ inc dx // dx points to status register
+
+ get_bytes:
+ in al,dx
+ test al,P_BUSY
+ jnz big_wait
+
+ ready:
+
+ // assert DACK, the P_AFX bit
+
+ inc dx // dx points to control register
+ mov al,P_AFX
+ out dx,al
+
+ // select high nibble
+
+ sub dx,2 // dx points to data register
+ mov al,0x80
+ out dx,al
+
+ // get high nibble
+
+ inc dx // dx points to status register
+ in al,dx
+ mov ah,al
+
+ // select lower nibble
+
+ dec dx // dx points to data register
+ xor al,al
+ out dx,al
+
+ // calculate high nibble
+
+ shl ah,1
+ and ah,0f0h
+
+ // get lower nibble
+
+ inc dx // dx points to status register
+ in al,dx
+ mov bh,al
+
+ // deassert DACK, clear P_AFX
+
+ inc dx // dx points to control register
+ xor al,al
+ out dx,al
+
+ dec dx // dx points to status register
+
+ // compute low nibble and the whole byte
+
+ shr bh,1
+ shr bh,1
+ shr bh,1
+ and bh,0fh
+ or ah,bh
+ mov al,ah
+
+
+ // store data and loop
+
+ mov [esi],al
+ inc esi
+ dec ecx
+ jnz get_bytes
+ }
+ goto done_asm;
+ _asm {
+big_wait:
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ in al,dx
+ test al,P_BUSY
+ jz ready
+
+ // wait for a while before going to a bigger timeout
+ push ecx
+ push ebx
+ mov ebx,TIMEOUT_READWRITE_LOOP
+ loop0:
+ mov ecx,0x10000
+ loop1:
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+ in al,dx
+ test al,P_BUSY
+ jz ready1
+
+ dec ecx
+ jnz loop1
+ dec ebx
+ jnz loop0
+ pop ebx
+ pop ecx
+ jmp short error
+ ready1:
+ pop ebx
+ pop ecx
+ }
+ goto ready;
+ _asm {
+ error:
+ mov rval,RET_STATUS_TIMEOUT
+ done_asm:
+ pop ds
+ pop esi
+#ifdef MODE_32BIT
+ mov xfer_count,ecx
+#else
+ mov word ptr xfer_count,ecx
+#endif
+ }
+
+ // compute actual xfer len
+
+ *pActualLen = len - xfer_count;
+ }
+
+ // zero control register, disable read dma mode
+ ParallelPortPut (g->BaseIoAddress,PARALLEL_CONTROL,0);
+
+ // clear the dma read mode
+ N5380DisableDmaRead (g);
+
+ // if data underrun, return the under/over run error message
+
+ if (rval) {
+ UCHAR tmp;
+
+ // phase mismatch means data under/over run
+
+ N5380GetPhase (g,&tmp);
+
+ if (tmp == PHASE_STATUS) {
+ rval = RET_STATUS_DATA_OVERRUN;
+ }
+ }
+
+ return rval;
+}
+
+#pragma optimize("",on)
+
+//
+// N5380PortPut
+//
+// This routine is used by the N5380.C module to write byte to a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+VOID N5380PortPut (PADAPTER_INFO g,UCHAR reg,UCHAR byte)
+{
+
+ // set T338 logic into data write mode
+
+ T338PutControl (g, T338_IOW, reg);
+
+ // write the byte
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, byte);
+
+ // toggle the strobe line
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, P_STB);
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, 0);
+
+ // clear data write mode
+
+ T338PutControl (g, 0, 0);
+}
+
+
+//
+// N5380PortGet
+//
+// This routine is used by the N5380.C module to get a byte from a 5380
+// controller. This allows the module to be card independent. Other
+// modules that assume a N5380 may also use this function.
+//
+
+VOID N5380PortGet (PADAPTER_INFO g, UCHAR reg, PUCHAR byte)
+{
+ UCHAR tmp,tmp1;
+
+ // set T338 logic to read mode
+
+ T338PutControl (g, T338_IOR, reg);
+
+ // select high nibble
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, 0x80);
+
+ // assert stb
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, P_STB);
+
+ // 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;
+
+ // clear slc
+
+ ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, 0);
+
+ // clear data read mode
+
+ T338PutControl (g, 0, 0);
+}
+
+