home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / rmfiles.zip / mitsrc.zip / DRVCMD.C < prev    next >
C/C++ Source or Header  |  1994-09-21  |  44KB  |  1,145 lines

  1.  #define INCL_DOSINFOSEG
  2.  #define INCL_NO_SCB
  3.  #define INCL_INITRP_ONLY
  4.  #include "os2.h"                  // \DRV6\H
  5.  #include "dos.h"                  // \DRV6\H
  6.  #include "sas.h"                  // \DRV6\H
  7.  #include "devcmd.h"               // \DRV6\H
  8.  
  9.  #include "iorb.h"                 // \DRV6\SRC\DEV\DASD\DISKH
  10.  #include "reqpkt.h"               // \DRV6\SRC\DEV\DASD\DISKH
  11.  #include "addcalls.h"             // \DRV6\SRC\DEV\DASD\DISKH
  12.  #include "dskinit.h"
  13.  
  14.  #include <scsi.h>
  15.  #include <cdbscsi.h>
  16.  #include "cmd.h"
  17.  #include "devhelp.h"              // \DRV6\SRC\DEV\DASD\DISKH
  18.  #include "cdb.h"
  19.  #include "proto.h"
  20.  #include <string.h>
  21.  #include <memory.h>
  22.  #include <rmbase.h>
  23.  #include <rmcalls.h>
  24.  #define max(x,y) (x<=y?y:x)
  25.  
  26.   BOOL ReadStatusLate=TRUE;
  27.  
  28.   PUCHAR Read_IOBuffer=NULL;
  29.  
  30.    UCHAR Mode=Mode1;
  31.    USHORT AdapterBase=0x300;
  32.    USHORT StatusRegister=0x301;
  33.    USHORT DataStatusRegister=0x302;
  34.    USHORT IrqNum=0,IrqMode=NoIrq,OtiChip=Oti12;
  35.    BOOL ReadInProgress=FALSE;
  36.    BOOL ReaderBlocked=FALSE;
  37.    BOOL IrqFired=FALSE;
  38.    BOOL InterruptOccured=FALSE;
  39.    BOOL IrqTried=FALSE;
  40.    ULONG ReadBlockKey=0;
  41.    ULONG Timeouts[32]={0,};
  42.    ULONG Timers[32]={0,};
  43.    ULONG StatusTimeouts=0;
  44.    ULONG Reads[32]={0,};
  45.    UCHAR wDrvVer[4]="";
  46.    BOOL Lu002=FALSE;
  47.  
  48.    PUCHAR YieldFlag=0;
  49.    PGINFOSEG PGinfo=0;
  50.    #define MaxHoldCPU 3
  51.    extern UCHAR near bInfoFlag;
  52.    USHORT TickCount=0;
  53.    extern USHORT near DrvBlockSize;
  54.    ULONG SpinVar=256;
  55.    SHORT InterruptCount=-1;
  56.    USHORT ReadBlockCount=0;
  57.    PUCHAR ReadBuffer=0;
  58.    USHORT ReadBufferLen=0;
  59.    UCHAR SavePortArray[4];                                           /*@V89549*/
  60.  
  61. //
  62. //
  63. //      Timer tick routine, used in Polling mode
  64. //
  65. //
  66.  
  67. VOID _saveregs far TimerTick(void)
  68. {
  69.         if(TickCount)
  70.           {
  71.           TickCount--;
  72.           } /* end if */
  73. }
  74.  
  75. //
  76. //
  77. //      Read Sector from drive into buffer, note that we will disable on the last byte of the
  78. //      data transfer to close a timing window, but only if in interrupt mode
  79. //
  80. //      There is also a small spin loop at the end of each sector to handle slow hardware
  81. //      this closes an occasional two byte data loss at the beginning of the next sector
  82. //
  83.  
  84. VOID ReadData1(PUCHAR Buffer,USHORT Len)
  85. {
  86.         if(IrqNum)
  87.           {
  88.           SHORTWAIT;
  89.           } /* end if */
  90.         _asm {
  91.              push   es
  92.              push   di
  93.              mov    dx,DataStatusRegister
  94.              mov    al,ReleaseData
  95.              out    dx,al
  96.              mov    dx,AdapterBase
  97.              cmp    word ptr [bp+8],2048    // if 2352 read, then read all
  98.              jne    skiprep1
  99.              cmp    Mode,Mode2            // if 2048 read and mode 2
  100.              jne    skiprep1              // no
  101.              mov    cx,8                  // yes, skip subheader
  102.         dorep1:
  103.              in     al,dx
  104.              loop   dorep1
  105.         skiprep1:
  106.              cld                                // clear direction flag just in case
  107.              les    di,[bp+4]                   // buffer pointer
  108.              mov    cx,[bp+8]                   // sector length
  109.              rep    insb                        // read in the sector
  110.              mov    dx,DataStatusRegister       // get status regisetr address
  111.              mov    al,SuspendData              // suspend data flow
  112.              out    dx,al                       // do it now
  113.              mov    dx,DataStatusRegister       // get status regisetr address
  114.              mov    al,SuspendData              // suspend data flow
  115.              out    dx,al                       // do it now
  116.              pop    di                          // done
  117.              pop    es                          // get out of here
  118.              };
  119. }
  120.  
  121. //
  122. //
  123. //
  124. //      Data interrupt handler, used only in Interrupt mode
  125. //      while the code handles nesting properly, this
  126. //      capability is disabled by the disable for the last
  127. //      byte of each sector. The drive apparently gives
  128. //      data ready interrupts when its not
  129. //
  130.  
  131. VOID _saveregs far IrqHandler(void)
  132. {
  133. USHORT Status;
  134.  
  135.         DevHelp_EOI(IrqNum);                    // EOI now
  136.         if(++InterruptCount==0)                 // if first level interrupt
  137.           {
  138.           while(InterruptCount>=0)              // while some interrupt nest level
  139.             {
  140.             Enable;                             // enable interrupts
  141.             IrqFired=TRUE;                      // say the interrupt occured
  142.             InterruptOccured=TRUE;              // a different one
  143.             Status=ReadStatus();                // get the drive status
  144.             DevHelp_RAS( 169 ,(ReadBlockCount<<8)|Status , sizeof(PGinfo->msecs),&PGinfo->msecs);
  145.             if(ReadInProgress)                  // ONLY if there is a read in progress
  146.               {
  147.               if(Status == DTEN)                // If Data Available
  148.                 {
  149.                 if(ReadBlockCount)              // any data still requested to read?
  150.                   {
  151.                   ReadData1(ReadBuffer,ReadBufferLen);
  152.                   ReadBuffer+=ReadBufferLen;        // count size of xfer
  153.                   if(--ReadBlockCount==0)           // was this the last requested
  154.                     {                               // data block?
  155.                     ReadInProgress=FALSE;           // turn off flag
  156.                     if(ReaderBlocked)               // application waiting?
  157.                       {
  158.                       DevHelp_Run(ReadBlockKey);    // unblock it
  159.                       } /* end if */
  160.                     } /* end if */
  161.                   } /* end else */
  162.                 } /* end if */
  163.               else if (Status == STEN)              // status change?
  164.                 {
  165.                 if(ReaderBlocked)                   // application waiting?
  166.                   {
  167.                   ReadInProgress=FALSE;             // turn off flag
  168.                   DevHelp_Run(ReadBlockKey);        // unblock it
  169.                   } /* end if */
  170.                 }
  171.               } /* end if */
  172.             else                                    // no read in progress, so how did we get here?
  173.               {
  174.               if (Status == STEN)                   // status change?
  175.                 {
  176.                 if(ReaderBlocked)                   // application waiting?
  177.                   {
  178.                   ReadInProgress=FALSE;             // turn off flag
  179.                   DevHelp_Run(ReadBlockKey);        // unblock it
  180.                   } /* end if */
  181.                 } /* end if */
  182.               } /* end else */
  183.             Disable;                                // disable interrupts
  184.             --InterruptCount;                       // decrement the nest count
  185.             } /* end while */
  186.           } /* end if */
  187.         _asm  stc ;                                 // say we processed interrupt
  188. }
  189.  
  190. //
  191. //      Get system running millisecond clock, watch out for lower word rollover
  192. //
  193.  
  194. ULONG GetClock(void)                                      // get ms clock value
  195. {
  196.    ULONG timer=0;                                         // initial return value is 0
  197.  
  198.    if(PGinfo)                                             // not set at init time
  199.      {                                                    // only do this at init time
  200.      timer=PGinfo->msecs;                                 // get timer value
  201.      if (HIUSHORT(timer)!=HIUSHORT(PGinfo->msecs))        // if low word forced carry
  202.        timer=PGinfo->msecs;                               // get it again
  203.      }
  204.  
  205.    return timer;
  206. }
  207.  
  208. void ScaleClock(UCHAR CpuType)
  209. {
  210. ULONG temp,temp1;
  211. ULONG Counter=0;
  212. UCHAR saveal,saveah;
  213.  
  214.       temp=PGinfo->msecs;                       // get current clock value
  215.       while(PGinfo->msecs==temp);               // spin til end of tick, to get alligned
  216.       temp=PGinfo->msecs;                       // save current tick setting
  217.       while(PGinfo->msecs==temp)                // spin til clock ticks again
  218.         Counter++;                              // and count while spinning
  219.       SpinVar=Counter/170;
  220.       DevHelp_RAS( 195 ,0 , sizeof(SpinVar), &SpinVar);
  221.  
  222. }
  223.  
  224. //
  225. //  check to see if we can get the drive status from user specified address
  226. //
  227.  
  228. BOOL ChkBaseAddx()
  229. {
  230.   BOOL Flag=FALSE;                      // default is we can't find adapter
  231.   USHORT r;
  232.   CDROMSTAT s;
  233.  
  234.   r=DriveStatus(SearchCount);           // try to get drive status
  235.   if(!TIMEOUT(r))                       // if it didn't timeout
  236.     {
  237.     memset(wDrvVer,0,sizeof(wDrvVer));
  238.     r=DriveCommand(GetVersion,0,0,&s,sizeof(s.Version));
  239.     if(!TIMEOUT(r))
  240.       {
  241.       switch(s.Version.Code)
  242.         {
  243.         case 'M':
  244.         case 'F':
  245.         case 'D':
  246.           wDrvVer[0]=s.Version.Code;
  247.           wDrvVer[1]=BCD2Bin(s.Version.VerMSN)+48;
  248.           wDrvVer[2]=BCD2Bin(s.Version.VerLSN)+48;
  249.           Flag=TRUE;                            // adapter and drive are found
  250.           if(!memcmp(wDrvVer,"M02",3))          // if M02 this is an LU002s drive
  251.             {
  252.             Lu002=TRUE;                         // say this is an LU002 drive, used in WriteCmd
  253. //            Flag=FALSE;                         // we dont support LU002
  254.             } /* end if */
  255.           break;
  256.         default:
  257.           break;
  258.         } /* end switch */
  259.       } /* end if */
  260.     } /* end if */
  261.   return Flag;
  262. }
  263.  
  264. BOOL PortValid(void)
  265. {
  266.    UCHAR i;
  267.    BOOL  rc = FALSE;
  268.    for ( i = 0; i < sizeof(SavePortArray); i++ )
  269.    {
  270.       if ( SavePortArray[i] != 0xff )
  271.       {
  272.          rc = TRUE;
  273.       }
  274.    }
  275.    return(rc);
  276. }
  277.  
  278. //
  279. //      Try to use Specified IRQ, but just once, returns true if it worked, false
  280. //      otherwise, return code not currently used, special global IrqFired is set
  281. //      by the interrupt handler to communicate back to this routine
  282. //
  283. //      This is only done on mount of a data CD, as audio never supports interrupts
  284. //
  285.  
  286. BOOL TryIrq(BOOL Testing)
  287. {
  288. BOOL Flag=FALSE;
  289. PSZ p;
  290. HRESOURCE IrqResource;
  291. RESOURCESTRUCT Resource;
  292. extern HDRIVER hDriver;
  293. extern HADAPTER hAdapter;
  294.  
  295.         if(IrqTried==FALSE)                             // if we haven't tried this already
  296.           {
  297.           IrqTried=TRUE;                                // say we have, one time only
  298.           if(IrqNum)                                    // are we trying to get into interrupt mode?
  299.             {
  300.             Resource.ResourceType            = RS_TYPE_IRQ;
  301.             Resource.IRQResource.IRQLevel    = IrqNum;
  302.             Resource.IRQResource.PCIIrqPin   = RS_PCI_INT_NONE;
  303.             Resource.IRQResource.IRQFlags    = RS_IRQ_EXCLUSIVE;
  304.             if(!RMAllocResource( hDriver, &IrqResource, &Resource ))
  305.               {
  306.               p=(PSZ)IrqHandler;
  307.               if(!DevHelp_SetIRQ(OFFSETOF(p),IrqNum,FALSE))               // can we hook the specified irq?
  308.                 {
  309.                 SetIrqMode((UCHAR)(IrqMode|OtiChip));                     // yes, set chip in interrupt mode
  310.                 while(TIMEOUT(DriveCommand( DriveConfig,IRQFLAG ,PreIrq|ErrIrq, 0, 0)))
  311.                    DUMMYWAIT;
  312.                 SpecialRead();                                            // issue the special read
  313.                 if(IrqFired==FALSE)                                       // if the interrupt handler didn't run
  314.                   {                                                       // irq can't be working
  315.                   IrqNum=0;                                               // clear the flag
  316.                   DevHelp_UnsetIRQ(IrqNum);                               // unset the irq num
  317.                   SetIrqMode((UCHAR)(NoIrq|OtiChip));                     // reset drive to non-interrupt mode
  318.                   while(TIMEOUT(DriveCommand( DriveConfig,IRQFLAG ,0, 0, 0)))
  319.                      DUMMYWAIT;
  320.                   RMDeallocResource(hDriver, IrqResource);
  321.                   } /* end if */
  322.                 else                                                      // interrupt handler ran
  323.                   {
  324.                   Flag=TRUE;                                              // set flag to tell caller
  325.                   RMModifyResources(hDriver, hAdapter,RM_MODIFY_ADD,IrqResource);
  326.                   }
  327.                 }
  328.               else
  329.                 {
  330.                 IrqNum=0;                                                 // clear the flag
  331.                 RMDeallocResource(hDriver, IrqResource);
  332.                 }
  333.               }
  334.             } /* end if */
  335.           } /* end if */
  336.   return Flag;
  337. }
  338.  
  339. void ResetDrive(void)
  340. {
  341.  
  342.         while(TIMEOUT(DriveCommand(Reset,0,0,0,0)))
  343.           DUMMYWAIT;
  344.         SetDataMode(SuspendData);
  345.         DUMMYWAIT;
  346.         while(TIMEOUT(DriveCommand( DriveConfig,MODEFLAG ,0, 0, 0)))
  347.           DUMMYWAIT;
  348.         if(DrvBlockSize==2352)
  349.           {
  350.           DriveCommand( SetDriveMode,DataLength|EccBit|MuteData ,0, 0, 0);
  351.           } /* end if */
  352.         else
  353.           {
  354.           DriveCommand( SetDriveMode,Mode==Mode2?TestMode|MuteData:MuteData ,0, 0, 0);
  355.           } /* end else */
  356.         while(TIMEOUT(DriveCommand( DriveConfig,BLOCKSIZE ,DrvBlockSize, 0, 0)))
  357.           DUMMYWAIT;
  358.         while(TIMEOUT(DriveCommand( DriveConfig,IRQFLAG ,IrqNum?PreIrq|ErrIrq:0, 0, 0)))
  359.            DUMMYWAIT;
  360.         SpecialRead();
  361. }
  362.  
  363. BOOL ChkDrive()
  364. {
  365.   BOOL Flag=FALSE;
  366.   USHORT t;
  367.   CDROMSTAT s;
  368.   PSZ p;
  369.  
  370. #if defined(DEBUG) | defined(TEST)
  371. #else
  372.     p=(PSZ)TimerTick;
  373.     DevHelp_Settimer(OFFSETOF(p));
  374.     DevHelp_AllocGdtSel(&FP_SEG(Read_IOBuffer) ,1);
  375. #endif
  376.     while(TIMEOUT(DriveCommand(Reset,0,0,0,0)))
  377.       DUMMYWAIT;
  378.     OtiChip = (wDrvVer[2]&1)?Oti12:0;
  379.     if(!strcmp(wDrvVer,"M05"))
  380.       {
  381.       OtiChip=0;
  382.       } /* end if */
  383.     else if(!strcmp(wDrvVer,"M06"))
  384.       {
  385.       OtiChip=Oti12;
  386.       } /* end else */
  387.     SetDataMode(SuspendData);
  388.     DUMMYWAIT;
  389.     while(TIMEOUT(DriveCommand( DriveConfig,MODEFLAG ,0, 0, 0)))
  390.       DUMMYWAIT;
  391.     while(TIMEOUT(DriveCommand( SetDriveMode,TestMode|MuteData ,0, 0, 0)))
  392.       DUMMYWAIT;
  393.     while(TIMEOUT(DriveCommand( DriveConfig,BLOCKSIZE ,2048, 0, 0)))
  394.       DUMMYWAIT;
  395.     Flag=TRUE;
  396.     return Flag;
  397. }
  398.  
  399. UCHAR Bin2BCD( UCHAR bBin )
  400. {
  401.       UCHAR bBCD ;
  402.  
  403.    bBCD = (UCHAR)( (((bBin/10)<<4)&0xf0) | ((bBin%10)&0x0f) ) ;
  404.  
  405.    return( bBCD ) ;
  406. }
  407.  
  408. UCHAR BCD2Bin( UCHAR bBin )
  409. {
  410.       UCHAR bBCD ;
  411.  
  412.    bBCD = (UCHAR)( ((bBin>>4)*10) + (bBin&0x0f)) ;
  413.  
  414.    return( bBCD ) ;
  415. }
  416.  
  417. ULONG MayYield(ULONG LastTime)                  // yield if we've held CPU for MaxHoldCPU ms
  418. {
  419. ULONG Now;
  420.  
  421.    Now=GetClock();                              // get current ms clock
  422.    if(LastTime)                                 // if last time was specified (not on first time)
  423.      {
  424.      if ((Now>=LastTime+MaxHoldCPU))            // held CPU long enough?
  425.        {                                        //
  426.        if (YieldFlag && *YieldFlag)             // pointer not set at init time, need to yield?
  427.          DevHelp_Yield();                       // yes, yield now
  428.        LastTime=GetClock();                     // get clock after yield
  429.        }
  430.      else if(Now<65536L && LastTime>65537L)     // watch out for clock rollover
  431.        LastTime=GetClock();                     // get a new clock value cause of rollover
  432.      }
  433.    else                                         // no last time specified
  434.      LastTime=GetClock();                       // get first clock value
  435.  
  436.    return LastTime;                             // return clock value to caller for next cycle
  437. }
  438.  
  439. USHORT ReadDataBytes(PUCHAR CmdPtr, USHORT Len, PULONG Count,ULONG tries,BOOL PostStatus)
  440. {
  441. ULONG Clock=0L,i,x,SaveCount;
  442. UCHAR Status=0,b;
  443. USHORT Timeout=0,l,t;
  444. PUCHAR pVirtAddx;
  445. BOOL FirstRecord=TRUE;
  446.  
  447.         SaveCount=*Count;               // save incoming block count
  448.         if(IrqNum)                      // handle status in interrupt mode
  449.           {
  450.           t=ReadBlockCount;             // get residual block count, always 0?
  451.           b=ReadStatus();               // get current status,
  452.                                         // sb !STEN in late mode,
  453.                                         // STEN| DTEN in Early, but Early has a bug
  454.  
  455.           if(b == STEN)                 // is it status that dropped?
  456.             {
  457.             if(ReadStatusLate==FALSE)   // oops, shouldn't get this unless
  458.               {                         // read failed for some reason
  459.               Status=ReadError;         // say read error so Drivecommand can get
  460.               } /* end if */            // status on our return
  461.             }
  462.           } /* end if */
  463.         else
  464.           {
  465.           DPRINTF(("Read Length=%d Count=%d prestatus=%02X\n",Len,Count,ReadStatus()));
  466.  
  467.           Clock=GetClock();                         // get starting clock tick count
  468.  
  469.           for(l=1;*Count;l++)                       // loop til done
  470.             {
  471. #ifdef TRACE
  472.             t=(USHORT)*Count;
  473.             DevHelp_RAS( 168 ,((t<<8) | 0) , sizeof(PGinfo->msecs),&PGinfo->msecs);
  474. #endif
  475.  
  476.             DPRINTF(("Waiting for !DTEN or !STEN\n"));
  477.             Disable;
  478.             // watch out for potential yield being gone MAXWAIT seconds
  479.             // (maxwait seconds * 1000) + 2 ticks worth / (msec/tick) = ticks
  480.             TickCount=((PGinfo->csecMaxWait*1000)+62)/31;
  481.             Enable;
  482.             x=tries;
  483.             while(TickCount)                       // while some ticks left
  484.               {
  485.               b=ReadStatus();                      // get the current status
  486.               if(b)                                // if either status changed status
  487.                 {
  488.                 break;
  489.                 } /* end if */
  490.               // only yield if first record
  491.               // and in polled mode
  492.               if(IrqNum==0 && FirstRecord)
  493.                 {
  494.                 Clock=MayYield(Clock);          // yield if possible
  495.                 FirstRecord=FALSE;              // we have at least one record
  496.                 } /* end if */
  497.               for(i=SpinVar; i--; ){};          // don't spin too fast
  498.  
  499.               }
  500.  
  501.             DPRINTF(("Wait over status = %02X\n",b));
  502.  
  503.             if(b==DTEN)                         // is it Data status that dropped?
  504.               {                                 // yes Data is available
  505.               DPRINTF(("Reading data into pre %p Buffer=%d %02X\n",CmdPtr,l,b));
  506.               DPRINTF(("Reading data into post %p\n",pVirtAddx));
  507.               ReadData1(CmdPtr,Len);            // transfer one sector
  508. #ifdef TRACE
  509.               b=ReadStatus();
  510.               t=*Count;
  511.               DevHelp_RAS( 190 ,((t<<8) | b ) , sizeof(PGinfo->msecs), &PGinfo->msecs);
  512. #endif
  513.               DPRINTF(("Reading data into post rep %p %02X\n",CmdPtr,b));
  514.               CmdPtr+=Len;                      // adjust the buffer pointer
  515.               (*Count)--;                       // reduce coutn of sectors to read
  516.               } /* end if */
  517.             else if(b == STEN)                  // is it Data status that dropped?
  518.               {
  519.               if(ReadStatusLate==FALSE)         // oops, shouldn't get this unless
  520.                 {                               // read failed for some reason
  521.                 Status=ReadError;               // say read error so Drivecommand can get
  522.                 } /* end if */                  // status on our return
  523.               else
  524.                 {
  525.                 if(*Count)
  526.                   {
  527.                   Status=CommandCheck;          // command failed
  528.                   Timeout=TimeOut<<8;           // must have timed out waiting
  529.                   } /* end if */
  530.                 }
  531.               break;
  532.               }
  533.             else
  534.               {
  535.               StatusTimeouts++;
  536.               Timeout=TimeOut<<8;               // must have timed out waiting
  537.               break;
  538.               }
  539.             } /* end while */
  540. #ifdef TRACE
  541.           t=*Count;
  542. #endif
  543.           } /* end else */
  544.         DevHelp_RAS( 168 ,((t<<8) | Status) , sizeof(PGinfo->msecs),&PGinfo->msecs);
  545.         return Timeout|Status;                  // return read status to caller
  546. }
  547.  
  548. UCHAR WriteData(UCHAR Offset, UCHAR Data)
  549. {
  550. USHORT Addr=AdapterBase+Offset;
  551.    _asm {
  552.         mov DX,Addr
  553.         mov AL,Data
  554.         Out Dx,Al
  555.         }
  556. }
  557.  
  558. UCHAR ReadData(void)
  559. {
  560.    _asm {
  561.         mov DX,AdapterBase
  562.         In al,DX
  563.         mov ah,0
  564.         }
  565. }
  566.  
  567. void WriteCmd(PUCHAR CmdPtr, USHORT Len)
  568. {
  569. #ifdef DEBUG
  570. USHORT i;
  571. #endif
  572. USHORT j;
  573.         DPRINTF(("Write Length=%d\n",Len));
  574.         DPRINTF(("Writing data %04X\n",AdapterBase+DataReg));
  575.         _asm { pushf };                 // save callers flags
  576. #ifdef DEBUG
  577.         for(i=0; i<Len;i++ )
  578.           {
  579.           DPRINTF(("%02X ",CmdPtr[i]));
  580.           } /* end for */
  581.         DPRINTF(("\n"));
  582. #endif
  583.         if(Lu002)                       // if this is an LU002 drive
  584.           {
  585.           if((j=ReadStatus()) & DTEN)       // if DTEN is on
  586.             {
  587.             DevHelp_RAS( 170 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
  588.             Enable;                     // make sure to enable interrupts here
  589.             TickCount=3;                // three clock tick timeout (96 ms max)
  590.             while(TickCount)            // spin
  591.               {
  592.               if(!((j=ReadStatus()) & DTEN)) // if DTEN is off
  593.                 {
  594.                 DevHelp_RAS( 171 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
  595.                 break;                  // break loop
  596.                 } /* end if */
  597.               } /* end while */
  598.             DevHelp_RAS( 172 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
  599.             } /* end if */
  600.           } /* end if */
  601.         Disable;                        // disable interrupts
  602.         for(;Len--;CmdPtr++)            // send the command bytes
  603.           {
  604.           WriteData(DataReg,*CmdPtr);   // one at a time
  605.           } /* end while */
  606.         _asm { popf };                  // restore callers flags
  607. }
  608.  
  609. USHORT ReadStatus(void)
  610. {
  611.   _asm {
  612.         pushf                           // save callers state
  613.         cli                             // disable
  614.         mov     dx,StatusRegister       // get the register address
  615.         in      al,dx                   // get status bits
  616.         xor     al,255                  // flip them
  617.         and     al, DTEN | STEN         // just these two
  618.         mov     ah,0                    // make a word
  619.         popf                            // restore callers flags
  620.         };
  621.  
  622. }
  623.  
  624. USHORT ReadStatusBytes(PUCHAR CmdPtr, UCHAR Len,ULONG tries)
  625. {
  626. ULONG Clock=0L,i,x;
  627. UCHAR Status=0,b;
  628. USHORT Timeout=0;
  629.  
  630.         DPRINTF(("Read Length=%d\n",Len));
  631.  
  632.         for(;Len--;CmdPtr++)                            // get status command returned data
  633.           {
  634.           for(x=tries;x ; x-- )                         // spin loop
  635.             {
  636.             b=ReadStatus();                             // read status
  637.             if(b==STEN)                                 // a status byte ready?
  638.               {
  639.               break;
  640.               } /* end if */
  641.             for(i=SpinVar; i--; );                      // don't spin too fast if status not ready
  642.             }
  643.  
  644.           if(x)                                         // if status ready before loop expires
  645.             {
  646.             *CmdPtr=ReadData();                         // get the status byte now
  647.             } /* end if */
  648.           else                                          // oops timed out
  649.             {
  650.             StatusTimeouts++;
  651.             Timeout=TimeOut<<8;                         // set return code
  652.             Status=CommandCheck;                        // and command check state
  653.             break;
  654.             } /* end else */
  655.           } /* end while */
  656.         return Timeout|Status;                          // return to caller
  657. }
  658.  
  659. //
  660. //      Get driver status on demand
  661. //
  662.  
  663. USHORT DriveStatus(ULONG tries)
  664. {
  665. ULONG i;
  666. USHORT Timeout=0;
  667. UCHAR data;
  668.  
  669.         DPRINTF(("Requesting status\n"));
  670.  
  671.         WriteData(DataReg,RequestDriveStatus);          // send status command to drive
  672.  
  673.         return GetStatus(tries);                        // get status and return it
  674.  
  675. }
  676.  
  677. //
  678. //      Get the drive status now, this routine is used after each command that returns status (all)
  679. //
  680.  
  681. USHORT GetStatus(ULONG tries)
  682. {
  683. ULONG i;
  684. USHORT Timeout=0;
  685. UCHAR data=0;
  686.  
  687.         DPRINTF(("Requesting status\n"));
  688.  
  689.         for(;tries ;tries-- )                           // spin loop
  690.           {
  691.           if(ReadStatus() == STEN)                      // if status ready
  692.             {
  693.             break;                                      // break loop
  694.             } /* end if */
  695.           for(i=SpinVar; i--; );                        // don't spin too fast if status not ready
  696.           }
  697.         if(tries)                                       // if we didn't timeout
  698.           {
  699.           data=ReadData();                              // get the status byte now, only one available
  700.           DPRINTF(("Returning status %02X\n",data));
  701.           if(!COMMANDCHECK(data))
  702.             {
  703.             if(DISCCHANGE(data))                          // did the disc change states?
  704.               {
  705.               bInfoFlag &=  CLR_VS;                       // clear the toc cached flag, this state is only available
  706.               } /* end if */                              // during a SINGLE IN from the status port
  707.             } /* end if */
  708. //        if(data!=0xff && data!=0x7f && DISCCHANGE(data)) // did the disc change states?
  709. //        if(data!=0xff && DISCCHANGE(data))            // did the disc change states?
  710.           } /* end if */
  711.         else                                            // oops, timed out
  712.           {
  713.           DPRINTF(("Returning timeout\n"));
  714.           StatusTimeouts++;
  715.           Timeout=TimeOut<<8;                           // set timeout flag
  716.           data=CommandCheck;                            // and command check just in case
  717.           } /* end else */
  718.         DPRINTF(("Status returning\n"));
  719.         return Timeout | data;                          // return to caller
  720. }
  721.  
  722.  
  723. //
  724. //      Command processor
  725. //
  726. //      Note: some commands are fake to differentiate from others
  727. //            Seek, Read, & play are the same to the drive, but we have
  728. //            three different ones to handle them differently
  729. //
  730.  
  731. USHORT DriveCommand(UCHAR OpCode, ULONG Addr1, ULONG Addr2, PCDROMSTAT Buffer, USHORT BufferLen)
  732. {
  733. union  OutputCommands c;
  734. USHORT len=1,rc=0,x;
  735. USHORT Status,ReadStatusbyte;
  736. UCHAR OldOpCode;
  737. ULONG tries=Spincount;
  738. ULONG ReadStart,ReadStop;
  739.  
  740.         memset(&c,0,sizeof(c));                         // clear the command packet
  741.  
  742.         switch(OldOpCode=OpCode)                        // process based on the pseudo opcode
  743.           {
  744.           case ReadUPC:
  745.  
  746.             DriveCommand(DriveConfig,UPCFLAG,GetUpc,0,0);
  747.             Status=DriveCommand(ReadSubQ,NULL,NULL,Buffer,BufferLen);
  748.             DriveCommand(DriveConfig,UPCFLAG,GetSubq,0,0);
  749.             DriveCommand(Stop,0,0,0,0);
  750.             return Status;
  751.             break;
  752.  
  753.           case ReadSubQ:
  754.  
  755.             OpCode=ReadSubQ;
  756.             tries=ReadSpinCount;
  757.             break;
  758.  
  759.           case Stop:
  760.  
  761.             tries=ReadSpinCount;
  762.             break;
  763.  
  764.           case LockUnlock:
  765.  
  766.             c.LockDrawer.Option=LOBYTE(LOUSHORT(Addr1));
  767.             len=sizeof(c.LockDrawer);
  768.             break;
  769.  
  770.           case Seek:
  771.  
  772.             DPRINTF(("Seeking to %d %d %d size=%d\n",
  773.                LOBYTE(HIUSHORT(Addr1)),
  774.                HIBYTE(LOUSHORT(Addr1)),
  775.                LOBYTE(LOUSHORT(Addr1)),
  776.                len=sizeof(c.SeekCmd)));
  777.             c.SeekCmd.Min=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
  778.             c.SeekCmd.Sec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
  779.             c.SeekCmd.Frame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
  780.             tries=ReadSpinCount;
  781.             len=sizeof(c.SeekCmd);
  782.             break;
  783.  
  784.           case Read:
  785.  
  786.             DPRINTF(("Reading at %d %d %d size=%d for %ld blocks\n",
  787.                LOBYTE(HIUSHORT(Addr1)),
  788.                HIBYTE(LOUSHORT(Addr1)),
  789.                LOBYTE(LOUSHORT(Addr1)),
  790.                len=sizeof(c.SeekCmd),
  791.                Addr2));
  792.             DevHelp_RAS( 168 ,1, sizeof(PGinfo->msecs),&PGinfo->msecs);
  793.             c.ReadCmd.Min=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
  794.             c.ReadCmd.Sec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
  795.             c.ReadCmd.Frame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
  796.             c.ReadCmd.Length1=LOBYTE(HIUSHORT(Addr2)) | ReadStatusLate? 0 : 0xF0; // read status early/late flag
  797.             c.ReadCmd.Length2=HIBYTE(LOUSHORT(Addr2));
  798.             c.ReadCmd.Length3=LOBYTE(LOUSHORT(Addr2));
  799.             len=sizeof(c.ReadCmd);
  800.             if(wDrvVer[0]=='D')                 // if double speed drive
  801.               {
  802.               OpCode=ReadFast;                  // switch to fast read command
  803.               } /* end if */
  804.             else
  805.               {
  806.               OpCode=Seek;
  807.               } /* end else */
  808.             tries=ReadSpinCount;
  809.             Disable;                            // disable interrupts
  810.             ReadStart=GetClock();
  811.             InterruptOccured=FALSE;
  812.             ReadBlockCount=LOUSHORT(Addr2);
  813.             ReadBuffer=(PUCHAR)Buffer;
  814.             ReadBufferLen=BufferLen;
  815.             ReadInProgress=TRUE;
  816.             break;
  817.  
  818.           case PlayAudioMSF:
  819.  
  820.             DPRINTF(("Reading from $d %d %d size=%d\n",
  821.                LOBYTE(HIUSHORT(Addr1)),
  822.                HIBYTE(LOUSHORT(Addr1)),
  823.                LOBYTE(LOUSHORT(Addr1)),
  824.                len=sizeof(c.SeekCmd)));
  825.             c.PlayAudio.StartMin=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
  826.             c.PlayAudio.StartSec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
  827.             c.PlayAudio.StartFrame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
  828.             c.PlayAudio.StopFrame =Bin2BCD(LOBYTE(HIUSHORT(Addr2)));
  829.             c.PlayAudio.StopMin   =Bin2BCD(HIBYTE(LOUSHORT(Addr2)));
  830.             c.PlayAudio.StopSec   =Bin2BCD(LOBYTE(LOUSHORT(Addr2)));
  831.             tries=ReadSpinCount;
  832.             len=sizeof(c.ReadCmd);
  833.             OpCode=Seek;
  834.             break;
  835.  
  836.           case DriveConfig:
  837.  
  838.             DPRINTF(("Mode =%02x size=%d a1=%08LX a2=%08Lx\n",LOBYTE(LOUSHORT(Addr1)), sizeof(c.DriveConfigCmd), Addr1, Addr2));
  839.             c.DriveConfigCmd.Byte1.Byte= LOBYTE(LOUSHORT(Addr1));
  840.             if(c.DriveConfigCmd.Byte1.Bits.ByteLength)
  841.               {
  842.               DPRINTF(("Blocksize mode set\n"));
  843.               len=sizeof(c.DriveConfigCmd);                     // all the data bytes
  844.               if(Addr2<2352)            // AND its not read-raw
  845.                 {
  846.                 if(Mode==Mode2)             // if a mode 2 disc
  847.                   {
  848.                   Addr2+=8;                 // add 8 for the subheader size
  849.                   } /* end if */
  850.                 else
  851.                   {
  852. //                Addr2+=2;     we don't do this anymore, see bit 7 & 6 in Drive mode settings  // mode 1, add two dummy bytes
  853.                   }
  854.                 }
  855.               Addr2--;
  856.               c.DriveConfigCmd.Byte2= HIBYTE(LOUSHORT(Addr2));
  857.               c.DriveConfigCmd.Byte3= LOBYTE(LOUSHORT(Addr2));
  858.               } /* end if */
  859.             else
  860.               {
  861.               DPRINTF(("other mode set\n"));
  862.               c.DriveConfigCmd.Byte2= LOBYTE(LOUSHORT(Addr2));
  863.               len=sizeof(c.DriveConfigCmd)-sizeof(UCHAR);       // one data byte
  864.               }
  865.             break;
  866.  
  867.           case SetDriveMode:
  868.  
  869.             c.DriveMode.Mode=LOBYTE(LOUSHORT(Addr1));
  870.             DPRINTF(("Mode=%02X\n",LOBYTE(LOUSHORT(Addr1))));
  871.             len=sizeof(c.DriveMode);
  872.             break;
  873.  
  874.           case HoldTime:
  875.  
  876.             c.HoldCmd.UnitsofTenSeconds=LOBYTE(LOUSHORT(Addr1));
  877.             len=sizeof(c.HoldCmd);
  878.             break;
  879.  
  880.           case SetAudioVolume:
  881.  
  882.             c.AudioLevel.ATT0=LOBYTE(LOUSHORT(Addr1));
  883.             c.AudioLevel.ATT1=HIBYTE(LOUSHORT(Addr1));
  884.             c.AudioLevel.ATT2=LOBYTE(LOUSHORT(Addr2));
  885.             c.AudioLevel.ATT3=HIBYTE(LOUSHORT(Addr2));
  886.             len=sizeof(c.AudioLevel);
  887.             break;
  888.  
  889.           case ModeSet:
  890.  
  891.             c.DataModeSet.ModeType=LOBYTE(LOUSHORT(Addr1));
  892.             len=sizeof(c.DataModeSet);
  893.             Mode=c.DataModeSet.ModeType;
  894.             break;
  895.  
  896.           case Eject:
  897.           case Close:
  898.  
  899.             tries=ReadSpinCount*2;
  900.             break;
  901.  
  902.           default:
  903.             break;
  904.           } /* end switch */
  905.  
  906.         c.Command=OpCode;                                       // set the REAL opecode here
  907.  
  908.         WriteCmd((PUCHAR)&c,len);                               // send the command to the drive
  909.  
  910.         if(OldOpCode!=Read)                                     // if not read then get command status
  911.           {
  912.           Status=GetStatus(tries);                              // now
  913.           } /* end if */
  914.         else                                                    // read comnand handled different ways
  915.           {
  916.           DPRINTF(("ReadStatus Late =%s\n",ReadStatusLate? "Yes": "No"));
  917.           Enable;                                               // we disabled before command issued
  918.           if(ReadStatusLate==FALSE)                             // are we supposed to read status before data appears?
  919.             {
  920.             while(TIMEOUT(Status=GetStatus(tries)));            // get it now, timeouts not allowed, could take LONG time
  921.                                                                 // if a seek and spinup are involved, keep trying
  922.             if(READERROR(Status) || COMMANDCHECK(Status) )      // did the command fail for some reason?
  923.               {
  924.               rc=3;                                             // say we had a failure, won't block later
  925.               ReadInProgress=FALSE;                             // and kill the read
  926.               } /* end if */
  927.             DevHelp_RAS( 168 ,(LOBYTE(LOUSHORT(Addr2))<<8)|Status , sizeof(PGinfo->msecs),&PGinfo->msecs);
  928.             } /* end if */
  929.           else                                                  // read status after data
  930.             {
  931.             Status=0;                                           // clear the status so next phase will work
  932.             }
  933.           }
  934. //
  935. //      Phase 2 of command processing,
  936. //
  937. //      if the command didn't fail or timeout, then handle the input data for
  938. //      each command that supports it
  939. //
  940.  
  941.         if((!TIMEOUT(Status) && !COMMANDCHECK(Status) && !READERROR(Status)) || OldOpCode==RequestSense)
  942.           {
  943.  
  944.           switch(OldOpCode)                                     // on the pseudo opcode again
  945.             {
  946.  
  947.             case PlayAudioMSF:                                  // play
  948.  
  949.                 DevHelp_RAS( 168 ,3, sizeof(PGinfo->msecs),&PGinfo->msecs);
  950.                 Status &= 0xFA;                                 // turn off noise bits
  951.                 break;
  952.  
  953.             case GetVersion:
  954.             case GetAudioVolume:
  955.             case ReadDriveMode:
  956.             case RequestSense:
  957.  
  958.                   ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
  959.                   break;
  960.  
  961.             case LockUnlock:
  962.  
  963.                   if(c.LockDrawer.Option==Query)                // only if we're querying the state
  964.                     {
  965.                     ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
  966.                     } /* end if */
  967.                 break;
  968.  
  969.             case ReadToc:
  970.             case ReadSubQ:
  971.             case ReadUPC:
  972.             case ReadDiscInfo:
  973.  
  974.                 if(DISCIN(Status))                              // if no disc we can't answer these
  975.                   {
  976.                   ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
  977.                   }
  978.                 break;
  979.  
  980.             case Read:                                          // read data
  981.  
  982.                     DevHelp_RAS( 168 ,2, sizeof(PGinfo->msecs),&PGinfo->msecs);
  983.  
  984.                     if(IrqNum)                                  // in interrupt mode?
  985.                       {
  986.                       Disable;                                  // disable
  987.                       if(ReadInProgress)                        // a read still in progress
  988.                         {
  989.                         ReaderBlocked=TRUE;                     // say we're blocked
  990.                         ReadBlockKey=(ULONG)Buffer;             // our block key, PHYSICAL address
  991.                         rc=DevHelp_Block(ReadBlockKey,3000L,1); // block
  992.                         Disable;                                // on return from block we're enabled
  993.                         ReaderBlocked=FALSE;                    // say we're not blocked (we aren't)
  994.                         ReadBlockKey=0;                         // clear the block key value
  995.                         } /* end if */
  996.                       ReadInProgress=FALSE;                     // turn off read in progress
  997.                       Enable;                                   // we can enable again
  998.                       ReadStop=GetClock();                      // get current clock value
  999.                       if(Addr2<32)                              // was this a <32 sector read?
  1000.                         {
  1001.                         Reads[Addr2]++;                         // count reads of this sector size
  1002.                         if(!rc)                                 // did the read timeout?
  1003.                           {
  1004.                           Timers[Addr2]=max(Timers[Addr2],ReadStop-ReadStart); // no set max wait time for this size
  1005.                           } /* end if */
  1006.                         else
  1007.                           {
  1008.                           Timeouts[Addr2]++;                    // oops, timed out, count it for this size read
  1009.                           Timeouts[0]=AdrRed2Hsg(Addr1);        // sector addr of read request (debugging)
  1010.                           } /* end else */
  1011.                         } /* end if */
  1012.                       } /* end if */
  1013.  
  1014.                     DevHelp_RAS( 168 ,(rc<<8) +3, sizeof(PGinfo->msecs),&PGinfo->msecs);
  1015.  
  1016.                     // if in polling mode
  1017.                     // OR
  1018.                     // in interrupt mode AND we we're unblocked, or an interrupt has occured
  1019.  
  1020.                     if(IrqNum==0 || (IrqNum && (rc==0 || InterruptOccured)) )
  1021.                       {
  1022.                       // get the data (polled mode) or
  1023.                       // just status (interrupt, post status mode)
  1024.                       // use the GLOBAL GDT virtual pointer for data buffer address, NOT the
  1025.                       // PHYSICAL address passed
  1026.  
  1027.                       ReadStatusbyte=ReadDataBytes((PUCHAR)Buffer,BufferLen, &Addr2,tries*2,ReadStatusLate);
  1028.  
  1029.                       // did the read timeout (polled mode)
  1030.  
  1031.                       if(!TIMEOUT(ReadStatusbyte))      // if no timeout
  1032.                         {
  1033.                         if(ReadStatusLate)              // are we supposed to read the status now?
  1034.                           {
  1035.                           Status=GetStatus(tries);      // yes, get the read status
  1036.                           } /* end if */
  1037.                         else
  1038.                           {
  1039.                           if(READERROR(ReadStatusbyte)) // oops, Read pre-status lied
  1040.                             {
  1041.                             Status=GetStatus(tries);    // get REAL status now
  1042.                             } /* end if */
  1043.                           } /* end else */
  1044.                         } /* end if */
  1045.                       else
  1046.                         {
  1047.                         Status=ReadStatusbyte;          // set the timeout return code
  1048.                         } /* end else */
  1049.  
  1050.                       DevHelp_RAS( 168 ,((LOUSHORT(Addr2)<<8) | Status) , sizeof(PGinfo->msecs),&PGinfo->msecs);
  1051.  
  1052.                       } /* end if */
  1053.                     else
  1054.                       {
  1055.  
  1056.                       // Must be in interrupt mode, but check just in case
  1057.  
  1058.                       if(IrqNum)
  1059.                         {
  1060. //#ifdef TRACE
  1061.                         while((x=ReadStatus())==DTEN)
  1062.                           {
  1063.                           ReadData();
  1064.                           } /* end if */
  1065.                         DevHelp_RAS( 168 ,(x<<8) +4, sizeof(PGinfo->msecs),&PGinfo->msecs);
  1066.                         if(x == STEN)
  1067.                           {
  1068.                           Status=GetStatus(tries);
  1069.                           if(ReadBlockCount)            // not all sectors read
  1070.                             {
  1071.                             Status=CommandCheck;        // command failed
  1072.                             } /* end if */
  1073.                           DevHelp_RAS( 168 ,Status, sizeof(PGinfo->msecs),&PGinfo->msecs);
  1074.                           } /* end if */
  1075.                         else
  1076. //#endif
  1077.                           Status= CommandCheck;         // we either timed out, or had a command failure
  1078.                                                         // can't tell which, say command failure (worst case)
  1079.                         } /* end if */
  1080.                       } /* end else */
  1081.                 break;
  1082.             default:
  1083.                 break;
  1084.             } /* end switch */
  1085.           } /* end if */
  1086.         return Status;
  1087. }
  1088.  
  1089. void SetDataMode(UCHAR data)
  1090. {
  1091. USHORT addr=AdapterBase+2;
  1092.    DPRINTF(("Data Mode set %02X\n",data));
  1093.    _asm {
  1094.           mov dx,addr
  1095.           mov al,data
  1096.           out dx,al
  1097.           };
  1098. }
  1099.  
  1100. void SetIrqMode(UCHAR mode)
  1101. {
  1102. USHORT addr=AdapterBase+3;
  1103.    DPRINTF(("Irq Mode set %02X\n",mode));
  1104.    _asm {
  1105.           mov dx,addr
  1106.           mov al,mode
  1107.           out dx,al
  1108.           };
  1109. }
  1110. // -------------------------------------------------------------- //
  1111. //                                                                  //
  1112. // This routine will change an HSG address to Red book address          //
  1113. //                                                                  //
  1114. //                                                                  //
  1115.  
  1116. ULONG AdrHsg2Red( ULONG ulHsg )
  1117. {
  1118.       ULONG ulRedBook ;
  1119.  
  1120.    ulHsg    += 150 ;
  1121.  
  1122.    ulRedBook = MAKEULONG
  1123.                (
  1124.                   MAKEUSHORT
  1125.                   (
  1126.                      (UCHAR)(ulHsg%75),
  1127.                      (UCHAR)((ulHsg%4500)/75)
  1128.                   ),
  1129.                   (UCHAR)(ulHsg/4500)
  1130.                ) ;
  1131.  
  1132.    return( ulRedBook ) ;
  1133. }
  1134. ULONG AdrRed2Hsg( ULONG ulRedBook )
  1135. {
  1136.       ULONG ulHsg ;
  1137.  
  1138.    ulHsg = ((((ULONG)(LOBYTE(HIUSHORT(ulRedBook)))*60)+
  1139.               (ULONG)(HIBYTE(LOUSHORT(ulRedBook)))     )*75)+
  1140.               (ULONG)(LOBYTE(LOUSHORT(ulRedBook)))          - 150 ;
  1141.  
  1142.    return( ulHsg ) ;
  1143. }
  1144.  
  1145.