home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cdrom.zip
/
DDK
/
BASE
/
SRC
/
DEV
/
DASD
/
CDROM
/
MITSUMI
/
drvcmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-18
|
43KB
|
1,151 lines
#define INCL_DOSINFOSEG
#define INCL_NO_SCB
#define INCL_INITRP_ONLY
#include "os2.h" // \DRV6\H
#include "dos.h" // \DRV6\H
#include "sas.h" // \DRV6\H
#include "devcmd.h" // \DRV6\H
#include "iorb.h" // \DRV6\SRC\DEV\DASD\DISKH
#include "reqpkt.h" // \DRV6\SRC\DEV\DASD\DISKH
#include "addcalls.h" // \DRV6\SRC\DEV\DASD\DISKH
#include "dskinit.h"
#include <scsi.h>
#include <cdbscsi.h>
#include "cmd.h"
#include "devhelp.h" // \DRV6\SRC\DEV\DASD\DISKH
#include "cdb.h"
#include "proto.h"
#include <string.h>
#include <memory.h>
#include <rmbase.h>
#include <rmcalls.h>
#define max(x,y) (x<=y?y:x)
BOOL ReadStatusLate=TRUE;
PUCHAR Read_IOBuffer=NULL;
UCHAR Mode=Mode1;
USHORT AdapterBase=0x300;
USHORT StatusRegister=0x301;
USHORT DataStatusRegister=0x302;
USHORT IrqNum=0,IrqMode=NoIrq,OtiChip=Oti12;
BOOL ReadInProgress=FALSE;
BOOL ReaderBlocked=FALSE;
BOOL IrqFired=FALSE;
BOOL InterruptOccured=FALSE;
BOOL IrqTried=FALSE;
ULONG ReadBlockKey=0;
ULONG Timeouts[32]={0,};
ULONG Timers[32]={0,};
ULONG StatusTimeouts=0;
ULONG Reads[32]={0,};
UCHAR wDrvVer[4]="";
BOOL Lu002=FALSE;
PUCHAR YieldFlag=0;
PGINFOSEG PGinfo=0;
#define MaxHoldCPU 3
extern UCHAR near bInfoFlag;
USHORT TickCount=0;
extern USHORT near DrvBlockSize;
ULONG SpinVar=256;
SHORT InterruptCount=-1;
USHORT ReadBlockCount=0;
PUCHAR ReadBuffer=0;
USHORT ReadBufferLen=0;
UCHAR SavePortArray[4]; /*@V89549*/
//
//
// Timer tick routine, used in Polling mode
//
//
VOID _saveregs far TimerTick(void)
{
if(TickCount)
{
TickCount--;
} /* end if */
}
//
//
// Read Sector from drive into buffer, note that we will disable on the last byte of the
// data transfer to close a timing window, but only if in interrupt mode
//
// There is also a small spin loop at the end of each sector to handle slow hardware
// this closes an occasional two byte data loss at the beginning of the next sector
//
VOID ReadData1(PUCHAR Buffer,USHORT Len)
{
if(IrqNum)
{
SHORTWAIT;
} /* end if */
_asm {
push es
push di
mov dx,DataStatusRegister
mov al,ReleaseData
out dx,al
mov dx,AdapterBase
cmp word ptr [bp+8],2048 // if 2352 read, then read all
jne skiprep1
cmp Mode,Mode2 // if 2048 read and mode 2
jne skiprep1 // no
mov cx,8 // yes, skip subheader
dorep1:
in al,dx
loop dorep1
skiprep1:
cld // clear direction flag just in case
les di,[bp+4] // buffer pointer
mov cx,[bp+8] // sector length
rep insb // read in the sector
mov dx,DataStatusRegister // get status regisetr address
mov al,SuspendData // suspend data flow
out dx,al // do it now
mov dx,DataStatusRegister // get status regisetr address
mov al,SuspendData // suspend data flow
out dx,al // do it now
pop di // done
pop es // get out of here
};
}
//
//
//
// Data interrupt handler, used only in Interrupt mode
// while the code handles nesting properly, this
// capability is disabled by the disable for the last
// byte of each sector. The drive apparently gives
// data ready interrupts when its not
//
VOID _saveregs far IrqHandler(void)
{
USHORT Status;
DevHelp_EOI(IrqNum); // EOI now
if(++InterruptCount==0) // if first level interrupt
{
while(InterruptCount>=0) // while some interrupt nest level
{
Enable; // enable interrupts
IrqFired=TRUE; // say the interrupt occured
InterruptOccured=TRUE; // a different one
Status=ReadStatus(); // get the drive status
DevHelp_RAS( 169 ,(ReadBlockCount<<8)|Status , sizeof(PGinfo->msecs),&PGinfo->msecs);
if(ReadInProgress) // ONLY if there is a read in progress
{
if(Status == DTEN) // If Data Available
{
if(ReadBlockCount) // any data still requested to read?
{
ReadData1(ReadBuffer,ReadBufferLen);
ReadBuffer+=ReadBufferLen; // count size of xfer
if(--ReadBlockCount==0) // was this the last requested
{ // data block?
ReadInProgress=FALSE; // turn off flag
if(ReaderBlocked) // application waiting?
{
DevHelp_Run(ReadBlockKey); // unblock it
} /* end if */
} /* end if */
} /* end else */
} /* end if */
else if (Status == STEN) // status change?
{
if(ReaderBlocked) // application waiting?
{
ReadInProgress=FALSE; // turn off flag
DevHelp_Run(ReadBlockKey); // unblock it
} /* end if */
}
} /* end if */
else // no read in progress, so how did we get here?
{
if (Status == STEN) // status change?
{
if(ReaderBlocked) // application waiting?
{
ReadInProgress=FALSE; // turn off flag
DevHelp_Run(ReadBlockKey); // unblock it
} /* end if */
} /* end if */
} /* end else */
Disable; // disable interrupts
--InterruptCount; // decrement the nest count
} /* end while */
} /* end if */
_asm stc ; // say we processed interrupt
}
//
// Get system running millisecond clock, watch out for lower word rollover
//
ULONG GetClock(void) // get ms clock value
{
ULONG timer=0; // initial return value is 0
if(PGinfo) // not set at init time
{ // only do this at init time
timer=PGinfo->msecs; // get timer value
if (HIUSHORT(timer)!=HIUSHORT(PGinfo->msecs)) // if low word forced carry
timer=PGinfo->msecs; // get it again
}
return timer;
}
void ScaleClock(UCHAR CpuType)
{
ULONG temp,temp1;
ULONG Counter=0;
UCHAR saveal,saveah;
temp=PGinfo->msecs; // get current clock value
while(PGinfo->msecs==temp); // spin til end of tick, to get alligned
temp=PGinfo->msecs; // save current tick setting
while(PGinfo->msecs==temp) // spin til clock ticks again
Counter++; // and count while spinning
SpinVar=Counter/170;
DevHelp_RAS( 195 ,0 , sizeof(SpinVar), &SpinVar);
}
//
// check to see if we can get the drive status from user specified address
//
BOOL ChkBaseAddx()
{
BOOL Flag=FALSE; // default is we can't find adapter
USHORT r;
CDROMSTAT s;
r=DriveStatus(SearchCount); // try to get drive status
if(!TIMEOUT(r)) // if it didn't timeout
{
memset(wDrvVer,0,sizeof(wDrvVer));
r=DriveCommand(GetVersion,0,0,&s,sizeof(s.Version));
if(!TIMEOUT(r))
{
switch(s.Version.Code)
{
case 'M':
case 'F':
case 'D':
wDrvVer[0]=s.Version.Code;
wDrvVer[1]=BCD2Bin(s.Version.VerMSN)+48;
wDrvVer[2]=BCD2Bin(s.Version.VerLSN)+48;
Flag=TRUE; // adapter and drive are found
if(!memcmp(wDrvVer,"M02",3)) // if M02 this is an LU002s drive
{
Lu002=TRUE; // say this is an LU002 drive, used in WriteCmd
// Flag=FALSE; // we dont support LU002
} /* end if */
break;
default:
break;
} /* end switch */
} /* end if */
} /* end if */
return Flag;
}
BOOL PortValid(void)
{
UCHAR i;
BOOL rc = FALSE;
for ( i = 0; i < sizeof(SavePortArray); i++ )
{
if ( SavePortArray[i] != 0xff )
{
rc = TRUE;
}
}
return(rc);
}
//
// Try to use Specified IRQ, but just once, returns true if it worked, false
// otherwise, return code not currently used, special global IrqFired is set
// by the interrupt handler to communicate back to this routine
//
// This is only done on mount of a data CD, as audio never supports interrupts
//
BOOL TryIrq(BOOL Testing)
{
BOOL Flag=FALSE;
PSZ p;
HRESOURCE IrqResource;
RESOURCESTRUCT Resource;
extern HDRIVER hDriver;
extern HADAPTER hAdapter;
if(IrqTried==FALSE) // if we haven't tried this already
{
IrqTried=TRUE; // say we have, one time only
if(IrqNum) // are we trying to get into interrupt mode?
{
Resource.ResourceType = RS_TYPE_IRQ;
Resource.IRQResource.IRQLevel = IrqNum;
Resource.IRQResource.PCIIrqPin = RS_PCI_INT_NONE;
Resource.IRQResource.IRQFlags = RS_IRQ_EXCLUSIVE;
if(!RMAllocResource( hDriver, &IrqResource, &Resource ))
{
p=(PSZ)IrqHandler;
if(!DevHelp_SetIRQ(OFFSETOF(p),IrqNum,FALSE)) // can we hook the specified irq?
{
SetIrqMode((UCHAR)(IrqMode|OtiChip)); // yes, set chip in interrupt mode
while(TIMEOUT(DriveCommand( DriveConfig,IRQFLAG ,PreIrq|ErrIrq, 0, 0)))
DUMMYWAIT;
SpecialRead(); // issue the special read
if(IrqFired==FALSE) // if the interrupt handler didn't run
{ // irq can't be working
IrqNum=0; // clear the flag
DevHelp_UnsetIRQ(IrqNum); // unset the irq num
SetIrqMode((UCHAR)(NoIrq|OtiChip)); // reset drive to non-interrupt mode
while(TIMEOUT(DriveCommand( DriveConfig,IRQFLAG ,0, 0, 0)))
DUMMYWAIT;
RMDeallocResource(hDriver, IrqResource);
} /* end if */
else // interrupt handler ran
{
Flag=TRUE; // set flag to tell caller
RMModifyResources(hDriver, hAdapter,RM_MODIFY_ADD,IrqResource);
}
}
else
{
IrqNum=0; // clear the flag
RMDeallocResource(hDriver, IrqResource);
}
}
} /* end if */
} /* end if */
return Flag;
}
void ResetDrive(void)
{
while(TIMEOUT(DriveCommand(Reset,0,0,0,0)))
DUMMYWAIT;
SetDataMode(SuspendData);
DUMMYWAIT;
while(TIMEOUT(DriveCommand( DriveConfig,MODEFLAG ,0, 0, 0)))
DUMMYWAIT;
if(DrvBlockSize==2352)
{
DriveCommand( SetDriveMode,DataLength|EccBit|MuteData ,0, 0, 0);
} /* end if */
else
{
DriveCommand( SetDriveMode,Mode==Mode2?TestMode|MuteData:MuteData ,0, 0, 0);
} /* end else */
while(TIMEOUT(DriveCommand( DriveConfig,BLOCKSIZE ,DrvBlockSize, 0, 0)))
DUMMYWAIT;
while(TIMEOUT(DriveCommand( DriveConfig,IRQFLAG ,IrqNum?PreIrq|ErrIrq:0, 0, 0)))
DUMMYWAIT;
if (wDrvVer[0]=='D')
{
while(TIMEOUT(DriveCommand( DriveConfig,RETRYCOUNT ,3, 0, 0)))
DUMMYWAIT;
}
SpecialRead();
}
BOOL ChkDrive()
{
BOOL Flag=FALSE;
USHORT t;
CDROMSTAT s;
PSZ p;
#if defined(DEBUG) | defined(TEST)
#else
p=(PSZ)TimerTick;
DevHelp_Settimer(OFFSETOF(p));
DevHelp_AllocGdtSel(&FP_SEG(Read_IOBuffer) ,1);
#endif
while(TIMEOUT(DriveCommand(Reset,0,0,0,0)))
DUMMYWAIT;
OtiChip = (wDrvVer[2]&1)?Oti12:0;
if(!strcmp(wDrvVer,"M05"))
{
OtiChip=0;
} /* end if */
else if(!strcmp(wDrvVer,"M06"))
{
OtiChip=Oti12;
} /* end else */
SetDataMode(SuspendData);
DUMMYWAIT;
while(TIMEOUT(DriveCommand( DriveConfig,MODEFLAG ,0, 0, 0)))
DUMMYWAIT;
while(TIMEOUT(DriveCommand( SetDriveMode,TestMode|MuteData ,0, 0, 0)))
DUMMYWAIT;
while(TIMEOUT(DriveCommand( DriveConfig,BLOCKSIZE ,2048, 0, 0)))
DUMMYWAIT;
Flag=TRUE;
return Flag;
}
UCHAR Bin2BCD( UCHAR bBin )
{
UCHAR bBCD ;
bBCD = (UCHAR)( (((bBin/10)<<4)&0xf0) | ((bBin%10)&0x0f) ) ;
return( bBCD ) ;
}
UCHAR BCD2Bin( UCHAR bBin )
{
UCHAR bBCD ;
bBCD = (UCHAR)( ((bBin>>4)*10) + (bBin&0x0f)) ;
return( bBCD ) ;
}
ULONG MayYield(ULONG LastTime) // yield if we've held CPU for MaxHoldCPU ms
{
ULONG Now;
Now=GetClock(); // get current ms clock
if(LastTime) // if last time was specified (not on first time)
{
if ((Now>=LastTime+MaxHoldCPU)) // held CPU long enough?
{ //
if (YieldFlag && *YieldFlag) // pointer not set at init time, need to yield?
DevHelp_Yield(); // yes, yield now
LastTime=GetClock(); // get clock after yield
}
else if(Now<65536L && LastTime>65537L) // watch out for clock rollover
LastTime=GetClock(); // get a new clock value cause of rollover
}
else // no last time specified
LastTime=GetClock(); // get first clock value
return LastTime; // return clock value to caller for next cycle
}
USHORT ReadDataBytes(PUCHAR CmdPtr, USHORT Len, PULONG Count,ULONG tries,BOOL PostStatus)
{
ULONG Clock=0L,i,x,SaveCount;
UCHAR Status=0,b;
USHORT Timeout=0,l,t;
PUCHAR pVirtAddx;
BOOL FirstRecord=TRUE;
SaveCount=*Count; // save incoming block count
if(IrqNum) // handle status in interrupt mode
{
t=ReadBlockCount; // get residual block count, always 0?
b=ReadStatus(); // get current status,
// sb !STEN in late mode,
// STEN| DTEN in Early, but Early has a bug
if(b == STEN) // is it status that dropped?
{
if(ReadStatusLate==FALSE) // oops, shouldn't get this unless
{ // read failed for some reason
Status=ReadError; // say read error so Drivecommand can get
} /* end if */ // status on our return
}
} /* end if */
else
{
DPRINTF(("Read Length=%d Count=%d prestatus=%02X\n",Len,Count,ReadStatus()));
Clock=GetClock(); // get starting clock tick count
for(l=1;*Count;l++) // loop til done
{
#ifdef TRACE
t=(USHORT)*Count;
DevHelp_RAS( 168 ,((t<<8) | 0) , sizeof(PGinfo->msecs),&PGinfo->msecs);
#endif
DPRINTF(("Waiting for !DTEN or !STEN\n"));
Disable;
// watch out for potential yield being gone MAXWAIT seconds
// (maxwait seconds * 1000) + 2 ticks worth / (msec/tick) = ticks
TickCount=((PGinfo->csecMaxWait*1000)+62)/31;
Enable;
x=tries;
while(TickCount) // while some ticks left
{
b=ReadStatus(); // get the current status
if(b) // if either status changed status
{
break;
} /* end if */
// only yield if first record
// and in polled mode
if(IrqNum==0 && FirstRecord)
{
Clock=MayYield(Clock); // yield if possible
FirstRecord=FALSE; // we have at least one record
} /* end if */
for(i=SpinVar; i--; ){}; // don't spin too fast
}
DPRINTF(("Wait over status = %02X\n",b));
if(b==DTEN) // is it Data status that dropped?
{ // yes Data is available
DPRINTF(("Reading data into pre %p Buffer=%d %02X\n",CmdPtr,l,b));
DPRINTF(("Reading data into post %p\n",pVirtAddx));
ReadData1(CmdPtr,Len); // transfer one sector
#ifdef TRACE
b=ReadStatus();
t=*Count;
DevHelp_RAS( 190 ,((t<<8) | b ) , sizeof(PGinfo->msecs), &PGinfo->msecs);
#endif
DPRINTF(("Reading data into post rep %p %02X\n",CmdPtr,b));
CmdPtr+=Len; // adjust the buffer pointer
(*Count)--; // reduce coutn of sectors to read
} /* end if */
else if(b == STEN) // is it Data status that dropped?
{
if(ReadStatusLate==FALSE) // oops, shouldn't get this unless
{ // read failed for some reason
Status=ReadError; // say read error so Drivecommand can get
} /* end if */ // status on our return
else
{
if(*Count)
{
// Status=CommandCheck; // command failed
Status=ReadError; // command failed
// Timeout=TimeOut<<8; // must have timed out waiting
} /* end if */
}
break;
}
else
{
StatusTimeouts++;
Timeout=TimeOut<<8; // must have timed out waiting
break;
}
} /* end while */
#ifdef TRACE
t=*Count;
#endif
} /* end else */
DevHelp_RAS( 168 ,((t<<8) | Status) , sizeof(PGinfo->msecs),&PGinfo->msecs);
return Timeout|Status; // return read status to caller
}
UCHAR WriteData(UCHAR Offset, UCHAR Data)
{
USHORT Addr=AdapterBase+Offset;
_asm {
mov DX,Addr
mov AL,Data
Out Dx,Al
}
}
UCHAR ReadData(void)
{
_asm {
mov DX,AdapterBase
In al,DX
mov ah,0
}
}
void WriteCmd(PUCHAR CmdPtr, USHORT Len)
{
#ifdef DEBUG
USHORT i;
#endif
USHORT j;
DPRINTF(("Write Length=%d\n",Len));
DPRINTF(("Writing data %04X\n",AdapterBase+DataReg));
_asm { pushf }; // save callers flags
#ifdef DEBUG
for(i=0; i<Len;i++ )
{
DPRINTF(("%02X ",CmdPtr[i]));
} /* end for */
DPRINTF(("\n"));
#endif
if(Lu002) // if this is an LU002 drive
{
if((j=ReadStatus()) & DTEN) // if DTEN is on
{
DevHelp_RAS( 170 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
Enable; // make sure to enable interrupts here
TickCount=3; // three clock tick timeout (96 ms max)
while(TickCount) // spin
{
if(!((j=ReadStatus()) & DTEN)) // if DTEN is off
{
DevHelp_RAS( 171 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
break; // break loop
} /* end if */
} /* end while */
DevHelp_RAS( 172 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
} /* end if */
} /* end if */
Disable; // disable interrupts
for(;Len--;CmdPtr++) // send the command bytes
{
WriteData(DataReg,*CmdPtr); // one at a time
} /* end while */
_asm { popf }; // restore callers flags
}
USHORT ReadStatus(void)
{
_asm {
pushf // save callers state
cli // disable
mov dx,StatusRegister // get the register address
in al,dx // get status bits
xor al,255 // flip them
and al, DTEN | STEN // just these two
mov ah,0 // make a word
popf // restore callers flags
};
}
USHORT ReadStatusBytes(PUCHAR CmdPtr, UCHAR Len,ULONG tries)
{
ULONG Clock=0L,i,x;
UCHAR Status=0,b;
USHORT Timeout=0;
DPRINTF(("Read Length=%d\n",Len));
for(;Len--;CmdPtr++) // get status command returned data
{
for(x=tries;x ; x-- ) // spin loop
{
b=ReadStatus(); // read status
if(b==STEN) // a status byte ready?
{
break;
} /* end if */
for(i=SpinVar; i--; ); // don't spin too fast if status not ready
}
if(x) // if status ready before loop expires
{
*CmdPtr=ReadData(); // get the status byte now
} /* end if */
else // oops timed out
{
StatusTimeouts++;
Timeout=TimeOut<<8; // set return code
Status=CommandCheck; // and command check state
break;
} /* end else */
} /* end while */
return Timeout|Status; // return to caller
}
//
// Get driver status on demand
//
USHORT DriveStatus(ULONG tries)
{
ULONG i;
USHORT Timeout=0;
UCHAR data;
DPRINTF(("Requesting status\n"));
WriteData(DataReg,RequestDriveStatus); // send status command to drive
return GetStatus(tries); // get status and return it
}
//
// Get the drive status now, this routine is used after each command that returns status (all)
//
USHORT GetStatus(ULONG tries)
{
ULONG i;
USHORT Timeout=0;
UCHAR data=0;
DPRINTF(("Requesting status\n"));
for(;tries ;tries-- ) // spin loop
{
if(ReadStatus() == STEN) // if status ready
{
break; // break loop
} /* end if */
for(i=SpinVar; i--; ); // don't spin too fast if status not ready
}
if(tries) // if we didn't timeout
{
data=ReadData(); // get the status byte now, only one available
DPRINTF(("Returning status %02X\n",data));
if(!COMMANDCHECK(data))
{
if(DISCCHANGE(data)) // did the disc change states?
{
bInfoFlag &= CLR_VS; // clear the toc cached flag, this state is only available
} /* end if */ // during a SINGLE IN from the status port
} /* end if */
// if(data!=0xff && data!=0x7f && DISCCHANGE(data)) // did the disc change states?
// if(data!=0xff && DISCCHANGE(data)) // did the disc change states?
} /* end if */
else // oops, timed out
{
DPRINTF(("Returning timeout\n"));
StatusTimeouts++;
Timeout=TimeOut<<8; // set timeout flag
data=CommandCheck; // and command check just in case
} /* end else */
DPRINTF(("Status returning\n"));
return Timeout | data; // return to caller
}
//
// Command processor
//
// Note: some commands are fake to differentiate from others
// Seek, Read, & play are the same to the drive, but we have
// three different ones to handle them differently
//
USHORT DriveCommand(UCHAR OpCode, ULONG Addr1, ULONG Addr2, PCDROMSTAT Buffer, USHORT BufferLen)
{
union OutputCommands c;
USHORT len=1,rc=0,x;
USHORT Status,ReadStatusbyte;
UCHAR OldOpCode;
ULONG tries=Spincount;
ULONG ReadStart,ReadStop;
memset(&c,0,sizeof(c)); // clear the command packet
switch(OldOpCode=OpCode) // process based on the pseudo opcode
{
case ReadUPC:
DriveCommand(DriveConfig,UPCFLAG,GetUpc,0,0);
Status=DriveCommand(ReadSubQ,NULL,NULL,Buffer,BufferLen);
DriveCommand(DriveConfig,UPCFLAG,GetSubq,0,0);
DriveCommand(Stop,0,0,0,0);
return Status;
break;
case ReadSubQ:
OpCode=ReadSubQ;
tries=ReadSpinCount;
break;
case Stop:
tries=ReadSpinCount;
break;
case LockUnlock:
c.LockDrawer.Option=LOBYTE(LOUSHORT(Addr1));
len=sizeof(c.LockDrawer);
break;
case Seek:
DPRINTF(("Seeking to %d %d %d size=%d\n",
LOBYTE(HIUSHORT(Addr1)),
HIBYTE(LOUSHORT(Addr1)),
LOBYTE(LOUSHORT(Addr1)),
len=sizeof(c.SeekCmd)));
c.SeekCmd.Min=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
c.SeekCmd.Sec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
c.SeekCmd.Frame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
tries=ReadSpinCount;
len=sizeof(c.SeekCmd);
break;
case Read:
DPRINTF(("Reading at %d %d %d size=%d for %ld blocks\n",
LOBYTE(HIUSHORT(Addr1)),
HIBYTE(LOUSHORT(Addr1)),
LOBYTE(LOUSHORT(Addr1)),
len=sizeof(c.SeekCmd),
Addr2));
DevHelp_RAS( 168 ,1, sizeof(PGinfo->msecs),&PGinfo->msecs);
c.ReadCmd.Min=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
c.ReadCmd.Sec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
c.ReadCmd.Frame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
c.ReadCmd.Length1=LOBYTE(HIUSHORT(Addr2)) | ReadStatusLate? 0 : 0xF0; // read status early/late flag
c.ReadCmd.Length2=HIBYTE(LOUSHORT(Addr2));
c.ReadCmd.Length3=LOBYTE(LOUSHORT(Addr2));
len=sizeof(c.ReadCmd);
if(wDrvVer[0]=='D') // if double speed drive
{
OpCode=ReadFast; // switch to fast read command
} /* end if */
else
{
OpCode=Seek;
} /* end else */
tries=ReadSpinCount;
Disable; // disable interrupts
ReadStart=GetClock();
InterruptOccured=FALSE;
ReadBlockCount=LOUSHORT(Addr2);
ReadBuffer=(PUCHAR)Buffer;
ReadBufferLen=BufferLen;
ReadInProgress=TRUE;
break;
case PlayAudioMSF:
DPRINTF(("Reading from $d %d %d size=%d\n",
LOBYTE(HIUSHORT(Addr1)),
HIBYTE(LOUSHORT(Addr1)),
LOBYTE(LOUSHORT(Addr1)),
len=sizeof(c.SeekCmd)));
c.PlayAudio.StartMin=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
c.PlayAudio.StartSec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
c.PlayAudio.StartFrame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
c.PlayAudio.StopFrame =Bin2BCD(LOBYTE(HIUSHORT(Addr2)));
c.PlayAudio.StopMin =Bin2BCD(HIBYTE(LOUSHORT(Addr2)));
c.PlayAudio.StopSec =Bin2BCD(LOBYTE(LOUSHORT(Addr2)));
tries=ReadSpinCount;
len=sizeof(c.ReadCmd);
OpCode=Seek;
break;
case DriveConfig:
DPRINTF(("Mode =%02x size=%d a1=%08LX a2=%08Lx\n",LOBYTE(LOUSHORT(Addr1)), sizeof(c.DriveConfigCmd), Addr1, Addr2));
c.DriveConfigCmd.Byte1.Byte= LOBYTE(LOUSHORT(Addr1));
if(c.DriveConfigCmd.Byte1.Bits.ByteLength)
{
DPRINTF(("Blocksize mode set\n"));
len=sizeof(c.DriveConfigCmd); // all the data bytes
if(Addr2<2352) // AND its not read-raw
{
if(Mode==Mode2) // if a mode 2 disc
{
Addr2+=8; // add 8 for the subheader size
} /* end if */
else
{
// Addr2+=2; we don't do this anymore, see bit 7 & 6 in Drive mode settings // mode 1, add two dummy bytes
}
}
Addr2--;
c.DriveConfigCmd.Byte2= HIBYTE(LOUSHORT(Addr2));
c.DriveConfigCmd.Byte3= LOBYTE(LOUSHORT(Addr2));
} /* end if */
else
{
DPRINTF(("other mode set\n"));
c.DriveConfigCmd.Byte2= LOBYTE(LOUSHORT(Addr2));
len=sizeof(c.DriveConfigCmd)-sizeof(UCHAR); // one data byte
}
break;
case SetDriveMode:
c.DriveMode.Mode=LOBYTE(LOUSHORT(Addr1));
DPRINTF(("Mode=%02X\n",LOBYTE(LOUSHORT(Addr1))));
len=sizeof(c.DriveMode);
break;
case HoldTime:
c.HoldCmd.UnitsofTenSeconds=LOBYTE(LOUSHORT(Addr1));
len=sizeof(c.HoldCmd);
break;
case SetAudioVolume:
c.AudioLevel.ATT0=LOBYTE(LOUSHORT(Addr1));
c.AudioLevel.ATT1=HIBYTE(LOUSHORT(Addr1));
c.AudioLevel.ATT2=LOBYTE(LOUSHORT(Addr2));
c.AudioLevel.ATT3=HIBYTE(LOUSHORT(Addr2));
len=sizeof(c.AudioLevel);
break;
case ModeSet:
c.DataModeSet.ModeType=LOBYTE(LOUSHORT(Addr1));
len=sizeof(c.DataModeSet);
Mode=c.DataModeSet.ModeType;
break;
case Eject:
case Close:
tries=ReadSpinCount*2;
break;
default:
break;
} /* end switch */
c.Command=OpCode; // set the REAL opecode here
WriteCmd((PUCHAR)&c,len); // send the command to the drive
if(OldOpCode!=Read) // if not read then get command status
{
Status=GetStatus(tries); // now
} /* end if */
else // read comnand handled different ways
{
DPRINTF(("ReadStatus Late =%s\n",ReadStatusLate? "Yes": "No"));
Enable; // we disabled before command issued
if(ReadStatusLate==FALSE) // are we supposed to read status before data appears?
{
while(TIMEOUT(Status=GetStatus(tries))); // get it now, timeouts not allowed, could take LONG time
// if a seek and spinup are involved, keep trying
if(READERROR(Status) || COMMANDCHECK(Status) ) // did the command fail for some reason?
{
rc=3; // say we had a failure, won't block later
ReadInProgress=FALSE; // and kill the read
} /* end if */
DevHelp_RAS( 168 ,(LOBYTE(LOUSHORT(Addr2))<<8)|Status , sizeof(PGinfo->msecs),&PGinfo->msecs);
} /* end if */
else // read status after data
{
Status=0; // clear the status so next phase will work
}
}
//
// Phase 2 of command processing,
//
// if the command didn't fail or timeout, then handle the input data for
// each command that supports it
//
if((!TIMEOUT(Status) && !COMMANDCHECK(Status) && !READERROR(Status)) || OldOpCode==RequestSense)
{
switch(OldOpCode) // on the pseudo opcode again
{
case PlayAudioMSF: // play
DevHelp_RAS( 168 ,3, sizeof(PGinfo->msecs),&PGinfo->msecs);
Status &= 0xFA; // turn off noise bits
break;
case GetVersion:
case GetAudioVolume:
case ReadDriveMode:
case RequestSense:
ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
break;
case LockUnlock:
if(c.LockDrawer.Option==Query) // only if we're querying the state
{
ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
} /* end if */
break;
case ReadToc:
case ReadSubQ:
case ReadUPC:
case ReadDiscInfo:
if(DISCIN(Status)) // if no disc we can't answer these
{
ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
}
break;
case Read: // read data
DevHelp_RAS( 168 ,2, sizeof(PGinfo->msecs),&PGinfo->msecs);
if(IrqNum) // in interrupt mode?
{
Disable; // disable
if(ReadInProgress) // a read still in progress
{
ReaderBlocked=TRUE; // say we're blocked
ReadBlockKey=(ULONG)Buffer; // our block key, PHYSICAL address
rc=DevHelp_Block(ReadBlockKey,3000L,1); // block
Disable; // on return from block we're enabled
ReaderBlocked=FALSE; // say we're not blocked (we aren't)
ReadBlockKey=0; // clear the block key value
} /* end if */
ReadInProgress=FALSE; // turn off read in progress
Enable; // we can enable again
ReadStop=GetClock(); // get current clock value
if(Addr2<32) // was this a <32 sector read?
{
Reads[Addr2]++; // count reads of this sector size
if(!rc) // did the read timeout?
{
Timers[Addr2]=max(Timers[Addr2],ReadStop-ReadStart); // no set max wait time for this size
} /* end if */
else
{
Timeouts[Addr2]++; // oops, timed out, count it for this size read
Timeouts[0]=AdrRed2Hsg(Addr1); // sector addr of read request (debugging)
} /* end else */
} /* end if */
} /* end if */
DevHelp_RAS( 168 ,(rc<<8) +3, sizeof(PGinfo->msecs),&PGinfo->msecs);
// if in polling mode
// OR
// in interrupt mode AND we we're unblocked, or an interrupt has occured
if(IrqNum==0 || (IrqNum && (rc==0 || InterruptOccured)) )
{
// get the data (polled mode) or
// just status (interrupt, post status mode)
// use the GLOBAL GDT virtual pointer for data buffer address, NOT the
// PHYSICAL address passed
ReadStatusbyte=ReadDataBytes((PUCHAR)Buffer,BufferLen, &Addr2,tries*2,ReadStatusLate);
// did the read timeout (polled mode)
if(!TIMEOUT(ReadStatusbyte)) // if no timeout
{
if(ReadStatusLate) // are we supposed to read the status now?
{
Status=GetStatus(tries); // yes, get the read status
} /* end if */
else
{
if(READERROR(ReadStatusbyte)) // oops, Read pre-status lied
{
Status=GetStatus(tries); // get REAL status now
} /* end if */
} /* end else */
} /* end if */
else
{
Status=ReadStatusbyte; // set the timeout return code
} /* end else */
DevHelp_RAS( 168 ,((LOUSHORT(Addr2)<<8) | Status) , sizeof(PGinfo->msecs),&PGinfo->msecs);
} /* end if */
else
{
// Must be in interrupt mode, but check just in case
if(IrqNum)
{
//#ifdef TRACE
while((x=ReadStatus())==DTEN)
{
ReadData();
} /* end if */
DevHelp_RAS( 168 ,(x<<8) +4, sizeof(PGinfo->msecs),&PGinfo->msecs);
if(x == STEN)
{
Status=GetStatus(tries);
if(ReadBlockCount) // not all sectors read
{
Status=CommandCheck; // command failed
} /* end if */
DevHelp_RAS( 168 ,Status, sizeof(PGinfo->msecs),&PGinfo->msecs);
} /* end if */
else
//#endif
Status= CommandCheck; // we either timed out, or had a command failure
// can't tell which, say command failure (worst case)
} /* end if */
} /* end else */
break;
default:
break;
} /* end switch */
} /* end if */
return Status;
}
void SetDataMode(UCHAR data)
{
USHORT addr=AdapterBase+2;
DPRINTF(("Data Mode set %02X\n",data));
_asm {
mov dx,addr
mov al,data
out dx,al
};
}
void SetIrqMode(UCHAR mode)
{
USHORT addr=AdapterBase+3;
DPRINTF(("Irq Mode set %02X\n",mode));
_asm {
mov dx,addr
mov al,mode
out dx,al
};
}
// -------------------------------------------------------------- //
// //
// This routine will change an HSG address to Red book address //
// //
// //
ULONG AdrHsg2Red( ULONG ulHsg )
{
ULONG ulRedBook ;
ulHsg += 150 ;
ulRedBook = MAKEULONG
(
MAKEUSHORT
(
(UCHAR)(ulHsg%75),
(UCHAR)((ulHsg%4500)/75)
),
(UCHAR)(ulHsg/4500)
) ;
return( ulRedBook ) ;
}
ULONG AdrRed2Hsg( ULONG ulRedBook )
{
ULONG ulHsg ;
ulHsg = ((((ULONG)(LOBYTE(HIUSHORT(ulRedBook)))*60)+
(ULONG)(HIBYTE(LOUSHORT(ulRedBook))) )*75)+
(ULONG)(LOBYTE(LOUSHORT(ulRedBook))) - 150 ;
return( ulHsg ) ;
}