diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/miniport/trantor/source/t338.c | |
download | NT4.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.c | 763 |
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); +} + + |