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 >
C/C++ Source or Header  |  1996-06-18  |  43KB  |  1,151 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.         if (wDrvVer[0]=='D')
  361.           {
  362.           while(TIMEOUT(DriveCommand( DriveConfig,RETRYCOUNT ,3, 0, 0)))
  363.             DUMMYWAIT;
  364.           }
  365.         SpecialRead();
  366. }
  367.  
  368. BOOL ChkDrive()
  369. {
  370.   BOOL Flag=FALSE;
  371.   USHORT t;
  372.   CDROMSTAT s;
  373.   PSZ p;
  374.  
  375. #if defined(DEBUG) | defined(TEST)
  376. #else
  377.     p=(PSZ)TimerTick;
  378.     DevHelp_Settimer(OFFSETOF(p));
  379.     DevHelp_AllocGdtSel(&FP_SEG(Read_IOBuffer) ,1);
  380. #endif
  381.     while(TIMEOUT(DriveCommand(Reset,0,0,0,0)))
  382.       DUMMYWAIT;
  383.     OtiChip = (wDrvVer[2]&1)?Oti12:0;
  384.     if(!strcmp(wDrvVer,"M05"))
  385.       {
  386.       OtiChip=0;
  387.       } /* end if */
  388.     else if(!strcmp(wDrvVer,"M06"))
  389.       {
  390.       OtiChip=Oti12;
  391.       } /* end else */
  392.     SetDataMode(SuspendData);
  393.     DUMMYWAIT;
  394.     while(TIMEOUT(DriveCommand( DriveConfig,MODEFLAG ,0, 0, 0)))
  395.       DUMMYWAIT;
  396.     while(TIMEOUT(DriveCommand( SetDriveMode,TestMode|MuteData ,0, 0, 0)))
  397.       DUMMYWAIT;
  398.     while(TIMEOUT(DriveCommand( DriveConfig,BLOCKSIZE ,2048, 0, 0)))
  399.       DUMMYWAIT;
  400.     Flag=TRUE;
  401.     return Flag;
  402. }
  403.  
  404. UCHAR Bin2BCD( UCHAR bBin )
  405. {
  406.       UCHAR bBCD ;
  407.  
  408.    bBCD = (UCHAR)( (((bBin/10)<<4)&0xf0) | ((bBin%10)&0x0f) ) ;
  409.  
  410.    return( bBCD ) ;
  411. }
  412.  
  413. UCHAR BCD2Bin( UCHAR bBin )
  414. {
  415.       UCHAR bBCD ;
  416.  
  417.    bBCD = (UCHAR)( ((bBin>>4)*10) + (bBin&0x0f)) ;
  418.  
  419.    return( bBCD ) ;
  420. }
  421.  
  422. ULONG MayYield(ULONG LastTime)                  // yield if we've held CPU for MaxHoldCPU ms
  423. {
  424. ULONG Now;
  425.  
  426.    Now=GetClock();                              // get current ms clock
  427.    if(LastTime)                                 // if last time was specified (not on first time)
  428.      {
  429.      if ((Now>=LastTime+MaxHoldCPU))            // held CPU long enough?
  430.        {                                        //
  431.        if (YieldFlag && *YieldFlag)             // pointer not set at init time, need to yield?
  432.          DevHelp_Yield();                       // yes, yield now
  433.        LastTime=GetClock();                     // get clock after yield
  434.        }
  435.      else if(Now<65536L && LastTime>65537L)     // watch out for clock rollover
  436.        LastTime=GetClock();                     // get a new clock value cause of rollover
  437.      }
  438.    else                                         // no last time specified
  439.      LastTime=GetClock();                       // get first clock value
  440.  
  441.    return LastTime;                             // return clock value to caller for next cycle
  442. }
  443.  
  444. USHORT ReadDataBytes(PUCHAR CmdPtr, USHORT Len, PULONG Count,ULONG tries,BOOL PostStatus)
  445. {
  446. ULONG Clock=0L,i,x,SaveCount;
  447. UCHAR Status=0,b;
  448. USHORT Timeout=0,l,t;
  449. PUCHAR pVirtAddx;
  450. BOOL FirstRecord=TRUE;
  451.  
  452.         SaveCount=*Count;               // save incoming block count
  453.         if(IrqNum)                      // handle status in interrupt mode
  454.           {
  455.           t=ReadBlockCount;             // get residual block count, always 0?
  456.           b=ReadStatus();               // get current status,
  457.                                         // sb !STEN in late mode,
  458.                                         // STEN| DTEN in Early, but Early has a bug
  459.  
  460.           if(b == STEN)                 // is it status that dropped?
  461.             {
  462.             if(ReadStatusLate==FALSE)   // oops, shouldn't get this unless
  463.               {                         // read failed for some reason
  464.               Status=ReadError;         // say read error so Drivecommand can get
  465.               } /* end if */            // status on our return
  466.             }
  467.           } /* end if */
  468.         else
  469.           {
  470.           DPRINTF(("Read Length=%d Count=%d prestatus=%02X\n",Len,Count,ReadStatus()));
  471.  
  472.           Clock=GetClock();                         // get starting clock tick count
  473.  
  474.           for(l=1;*Count;l++)                       // loop til done
  475.             {
  476. #ifdef TRACE
  477.             t=(USHORT)*Count;
  478.             DevHelp_RAS( 168 ,((t<<8) | 0) , sizeof(PGinfo->msecs),&PGinfo->msecs);
  479. #endif
  480.  
  481.             DPRINTF(("Waiting for !DTEN or !STEN\n"));
  482.             Disable;
  483.             // watch out for potential yield being gone MAXWAIT seconds
  484.             // (maxwait seconds * 1000) + 2 ticks worth / (msec/tick) = ticks
  485.             TickCount=((PGinfo->csecMaxWait*1000)+62)/31;
  486.             Enable;
  487.             x=tries;
  488.             while(TickCount)                       // while some ticks left
  489.               {
  490.               b=ReadStatus();                      // get the current status
  491.               if(b)                                // if either status changed status
  492.                 {
  493.                 break;
  494.                 } /* end if */
  495.               // only yield if first record
  496.               // and in polled mode
  497.               if(IrqNum==0 && FirstRecord)
  498.                 {
  499.                 Clock=MayYield(Clock);          // yield if possible
  500.                 FirstRecord=FALSE;              // we have at least one record
  501.                 } /* end if */
  502.               for(i=SpinVar; i--; ){};          // don't spin too fast
  503.  
  504.               }
  505.  
  506.             DPRINTF(("Wait over status = %02X\n",b));
  507.  
  508.             if(b==DTEN)                         // is it Data status that dropped?
  509.               {                                 // yes Data is available
  510.               DPRINTF(("Reading data into pre %p Buffer=%d %02X\n",CmdPtr,l,b));
  511.               DPRINTF(("Reading data into post %p\n",pVirtAddx));
  512.               ReadData1(CmdPtr,Len);            // transfer one sector
  513. #ifdef TRACE
  514.               b=ReadStatus();
  515.               t=*Count;
  516.               DevHelp_RAS( 190 ,((t<<8) | b ) , sizeof(PGinfo->msecs), &PGinfo->msecs);
  517. #endif
  518.               DPRINTF(("Reading data into post rep %p %02X\n",CmdPtr,b));
  519.               CmdPtr+=Len;                      // adjust the buffer pointer
  520.               (*Count)--;                       // reduce coutn of sectors to read
  521.               } /* end if */
  522.             else if(b == STEN)                  // is it Data status that dropped?
  523.               {
  524.               if(ReadStatusLate==FALSE)         // oops, shouldn't get this unless
  525.                 {                               // read failed for some reason
  526.                 Status=ReadError;               // say read error so Drivecommand can get
  527.                 } /* end if */                  // status on our return
  528.               else
  529.                 {
  530.                 if(*Count)
  531.                   {
  532. //                  Status=CommandCheck;          // command failed
  533.                   Status=ReadError;             // command failed
  534. //                  Timeout=TimeOut<<8;           // must have timed out waiting
  535.                   } /* end if */
  536.                 }
  537.               break;
  538.               }
  539.             else
  540.               {
  541.               StatusTimeouts++;
  542.               Timeout=TimeOut<<8;               // must have timed out waiting
  543.               break;
  544.               }
  545.             } /* end while */
  546. #ifdef TRACE
  547.           t=*Count;
  548. #endif
  549.           } /* end else */
  550.         DevHelp_RAS( 168 ,((t<<8) | Status) , sizeof(PGinfo->msecs),&PGinfo->msecs);
  551.         return Timeout|Status;                  // return read status to caller
  552. }
  553.  
  554. UCHAR WriteData(UCHAR Offset, UCHAR Data)
  555. {
  556. USHORT Addr=AdapterBase+Offset;
  557.    _asm {
  558.         mov DX,Addr
  559.         mov AL,Data
  560.         Out Dx,Al
  561.         }
  562. }
  563.  
  564. UCHAR ReadData(void)
  565. {
  566.    _asm {
  567.         mov DX,AdapterBase
  568.         In al,DX
  569.         mov ah,0
  570.         }
  571. }
  572.  
  573. void WriteCmd(PUCHAR CmdPtr, USHORT Len)
  574. {
  575. #ifdef DEBUG
  576. USHORT i;
  577. #endif
  578. USHORT j;
  579.         DPRINTF(("Write Length=%d\n",Len));
  580.         DPRINTF(("Writing data %04X\n",AdapterBase+DataReg));
  581.         _asm { pushf };                 // save callers flags
  582. #ifdef DEBUG
  583.         for(i=0; i<Len;i++ )
  584.           {
  585.           DPRINTF(("%02X ",CmdPtr[i]));
  586.           } /* end for */
  587.         DPRINTF(("\n"));
  588. #endif
  589.         if(Lu002)                       // if this is an LU002 drive
  590.           {
  591.           if((j=ReadStatus()) & DTEN)       // if DTEN is on
  592.             {
  593.             DevHelp_RAS( 170 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
  594.             Enable;                     // make sure to enable interrupts here
  595.             TickCount=3;                // three clock tick timeout (96 ms max)
  596.             while(TickCount)            // spin
  597.               {
  598.               if(!((j=ReadStatus()) & DTEN)) // if DTEN is off
  599.                 {
  600.                 DevHelp_RAS( 171 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
  601.                 break;                  // break loop
  602.                 } /* end if */
  603.               } /* end while */
  604.             DevHelp_RAS( 172 ,j , sizeof(PGinfo->msecs),&PGinfo->msecs);
  605.             } /* end if */
  606.           } /* end if */
  607.         Disable;                        // disable interrupts
  608.         for(;Len--;CmdPtr++)            // send the command bytes
  609.           {
  610.           WriteData(DataReg,*CmdPtr);   // one at a time
  611.           } /* end while */
  612.         _asm { popf };                  // restore callers flags
  613. }
  614.  
  615. USHORT ReadStatus(void)
  616. {
  617.   _asm {
  618.         pushf                           // save callers state
  619.         cli                             // disable
  620.         mov     dx,StatusRegister       // get the register address
  621.         in      al,dx                   // get status bits
  622.         xor     al,255                  // flip them
  623.         and     al, DTEN | STEN         // just these two
  624.         mov     ah,0                    // make a word
  625.         popf                            // restore callers flags
  626.         };
  627.  
  628. }
  629.  
  630. USHORT ReadStatusBytes(PUCHAR CmdPtr, UCHAR Len,ULONG tries)
  631. {
  632. ULONG Clock=0L,i,x;
  633. UCHAR Status=0,b;
  634. USHORT Timeout=0;
  635.  
  636.         DPRINTF(("Read Length=%d\n",Len));
  637.  
  638.         for(;Len--;CmdPtr++)                            // get status command returned data
  639.           {
  640.           for(x=tries;x ; x-- )                         // spin loop
  641.             {
  642.             b=ReadStatus();                             // read status
  643.             if(b==STEN)                                 // a status byte ready?
  644.               {
  645.               break;
  646.               } /* end if */
  647.             for(i=SpinVar; i--; );                      // don't spin too fast if status not ready
  648.             }
  649.  
  650.           if(x)                                         // if status ready before loop expires
  651.             {
  652.             *CmdPtr=ReadData();                         // get the status byte now
  653.             } /* end if */
  654.           else                                          // oops timed out
  655.             {
  656.             StatusTimeouts++;
  657.             Timeout=TimeOut<<8;                         // set return code
  658.             Status=CommandCheck;                        // and command check state
  659.             break;
  660.             } /* end else */
  661.           } /* end while */
  662.         return Timeout|Status;                          // return to caller
  663. }
  664.  
  665. //
  666. //      Get driver status on demand
  667. //
  668.  
  669. USHORT DriveStatus(ULONG tries)
  670. {
  671. ULONG i;
  672. USHORT Timeout=0;
  673. UCHAR data;
  674.  
  675.         DPRINTF(("Requesting status\n"));
  676.  
  677.         WriteData(DataReg,RequestDriveStatus);          // send status command to drive
  678.  
  679.         return GetStatus(tries);                        // get status and return it
  680.  
  681. }
  682.  
  683. //
  684. //      Get the drive status now, this routine is used after each command that returns status (all)
  685. //
  686.  
  687. USHORT GetStatus(ULONG tries)
  688. {
  689. ULONG i;
  690. USHORT Timeout=0;
  691. UCHAR data=0;
  692.  
  693.         DPRINTF(("Requesting status\n"));
  694.  
  695.         for(;tries ;tries-- )                           // spin loop
  696.           {
  697.           if(ReadStatus() == STEN)                      // if status ready
  698.             {
  699.             break;                                      // break loop
  700.             } /* end if */
  701.           for(i=SpinVar; i--; );                        // don't spin too fast if status not ready
  702.           }
  703.         if(tries)                                       // if we didn't timeout
  704.           {
  705.           data=ReadData();                              // get the status byte now, only one available
  706.           DPRINTF(("Returning status %02X\n",data));
  707.           if(!COMMANDCHECK(data))
  708.             {
  709.             if(DISCCHANGE(data))                          // did the disc change states?
  710.               {
  711.               bInfoFlag &=  CLR_VS;                       // clear the toc cached flag, this state is only available
  712.               } /* end if */                              // during a SINGLE IN from the status port
  713.             } /* end if */
  714. //        if(data!=0xff && data!=0x7f && DISCCHANGE(data)) // did the disc change states?
  715. //        if(data!=0xff && DISCCHANGE(data))            // did the disc change states?
  716.           } /* end if */
  717.         else                                            // oops, timed out
  718.           {
  719.           DPRINTF(("Returning timeout\n"));
  720.           StatusTimeouts++;
  721.           Timeout=TimeOut<<8;                           // set timeout flag
  722.           data=CommandCheck;                            // and command check just in case
  723.           } /* end else */
  724.         DPRINTF(("Status returning\n"));
  725.         return Timeout | data;                          // return to caller
  726. }
  727.  
  728.  
  729. //
  730. //      Command processor
  731. //
  732. //      Note: some commands are fake to differentiate from others
  733. //            Seek, Read, & play are the same to the drive, but we have
  734. //            three different ones to handle them differently
  735. //
  736.  
  737. USHORT DriveCommand(UCHAR OpCode, ULONG Addr1, ULONG Addr2, PCDROMSTAT Buffer, USHORT BufferLen)
  738. {
  739. union  OutputCommands c;
  740. USHORT len=1,rc=0,x;
  741. USHORT Status,ReadStatusbyte;
  742. UCHAR OldOpCode;
  743. ULONG tries=Spincount;
  744. ULONG ReadStart,ReadStop;
  745.  
  746.         memset(&c,0,sizeof(c));                         // clear the command packet
  747.  
  748.         switch(OldOpCode=OpCode)                        // process based on the pseudo opcode
  749.           {
  750.           case ReadUPC:
  751.  
  752.             DriveCommand(DriveConfig,UPCFLAG,GetUpc,0,0);
  753.             Status=DriveCommand(ReadSubQ,NULL,NULL,Buffer,BufferLen);
  754.             DriveCommand(DriveConfig,UPCFLAG,GetSubq,0,0);
  755.             DriveCommand(Stop,0,0,0,0);
  756.             return Status;
  757.             break;
  758.  
  759.           case ReadSubQ:
  760.  
  761.             OpCode=ReadSubQ;
  762.             tries=ReadSpinCount;
  763.             break;
  764.  
  765.           case Stop:
  766.  
  767.             tries=ReadSpinCount;
  768.             break;
  769.  
  770.           case LockUnlock:
  771.  
  772.             c.LockDrawer.Option=LOBYTE(LOUSHORT(Addr1));
  773.             len=sizeof(c.LockDrawer);
  774.             break;
  775.  
  776.           case Seek:
  777.  
  778.             DPRINTF(("Seeking to %d %d %d size=%d\n",
  779.                LOBYTE(HIUSHORT(Addr1)),
  780.                HIBYTE(LOUSHORT(Addr1)),
  781.                LOBYTE(LOUSHORT(Addr1)),
  782.                len=sizeof(c.SeekCmd)));
  783.             c.SeekCmd.Min=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
  784.             c.SeekCmd.Sec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
  785.             c.SeekCmd.Frame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
  786.             tries=ReadSpinCount;
  787.             len=sizeof(c.SeekCmd);
  788.             break;
  789.  
  790.           case Read:
  791.  
  792.             DPRINTF(("Reading at %d %d %d size=%d for %ld blocks\n",
  793.                LOBYTE(HIUSHORT(Addr1)),
  794.                HIBYTE(LOUSHORT(Addr1)),
  795.                LOBYTE(LOUSHORT(Addr1)),
  796.                len=sizeof(c.SeekCmd),
  797.                Addr2));
  798.             DevHelp_RAS( 168 ,1, sizeof(PGinfo->msecs),&PGinfo->msecs);
  799.             c.ReadCmd.Min=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
  800.             c.ReadCmd.Sec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
  801.             c.ReadCmd.Frame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
  802.             c.ReadCmd.Length1=LOBYTE(HIUSHORT(Addr2)) | ReadStatusLate? 0 : 0xF0; // read status early/late flag
  803.             c.ReadCmd.Length2=HIBYTE(LOUSHORT(Addr2));
  804.             c.ReadCmd.Length3=LOBYTE(LOUSHORT(Addr2));
  805.             len=sizeof(c.ReadCmd);
  806.             if(wDrvVer[0]=='D')                 // if double speed drive
  807.               {
  808.               OpCode=ReadFast;                  // switch to fast read command
  809.               } /* end if */
  810.             else
  811.               {
  812.               OpCode=Seek;
  813.               } /* end else */
  814.             tries=ReadSpinCount;
  815.             Disable;                            // disable interrupts
  816.             ReadStart=GetClock();
  817.             InterruptOccured=FALSE;
  818.             ReadBlockCount=LOUSHORT(Addr2);
  819.             ReadBuffer=(PUCHAR)Buffer;
  820.             ReadBufferLen=BufferLen;
  821.             ReadInProgress=TRUE;
  822.             break;
  823.  
  824.           case PlayAudioMSF:
  825.  
  826.             DPRINTF(("Reading from $d %d %d size=%d\n",
  827.                LOBYTE(HIUSHORT(Addr1)),
  828.                HIBYTE(LOUSHORT(Addr1)),
  829.                LOBYTE(LOUSHORT(Addr1)),
  830.                len=sizeof(c.SeekCmd)));
  831.             c.PlayAudio.StartMin=Bin2BCD(LOBYTE(HIUSHORT(Addr1)));
  832.             c.PlayAudio.StartSec=Bin2BCD(HIBYTE(LOUSHORT(Addr1)));
  833.             c.PlayAudio.StartFrame=Bin2BCD(LOBYTE(LOUSHORT(Addr1)));
  834.             c.PlayAudio.StopFrame =Bin2BCD(LOBYTE(HIUSHORT(Addr2)));
  835.             c.PlayAudio.StopMin   =Bin2BCD(HIBYTE(LOUSHORT(Addr2)));
  836.             c.PlayAudio.StopSec   =Bin2BCD(LOBYTE(LOUSHORT(Addr2)));
  837.             tries=ReadSpinCount;
  838.             len=sizeof(c.ReadCmd);
  839.             OpCode=Seek;
  840.             break;
  841.  
  842.           case DriveConfig:
  843.  
  844.             DPRINTF(("Mode =%02x size=%d a1=%08LX a2=%08Lx\n",LOBYTE(LOUSHORT(Addr1)), sizeof(c.DriveConfigCmd), Addr1, Addr2));
  845.             c.DriveConfigCmd.Byte1.Byte= LOBYTE(LOUSHORT(Addr1));
  846.             if(c.DriveConfigCmd.Byte1.Bits.ByteLength)
  847.               {
  848.               DPRINTF(("Blocksize mode set\n"));
  849.               len=sizeof(c.DriveConfigCmd);                     // all the data bytes
  850.               if(Addr2<2352)            // AND its not read-raw
  851.                 {
  852.                 if(Mode==Mode2)             // if a mode 2 disc
  853.                   {
  854.                   Addr2+=8;                 // add 8 for the subheader size
  855.                   } /* end if */
  856.                 else
  857.                   {
  858. //                Addr2+=2;     we don't do this anymore, see bit 7 & 6 in Drive mode settings  // mode 1, add two dummy bytes
  859.                   }
  860.                 }
  861.               Addr2--;
  862.               c.DriveConfigCmd.Byte2= HIBYTE(LOUSHORT(Addr2));
  863.               c.DriveConfigCmd.Byte3= LOBYTE(LOUSHORT(Addr2));
  864.               } /* end if */
  865.             else
  866.               {
  867.               DPRINTF(("other mode set\n"));
  868.               c.DriveConfigCmd.Byte2= LOBYTE(LOUSHORT(Addr2));
  869.               len=sizeof(c.DriveConfigCmd)-sizeof(UCHAR);       // one data byte
  870.               }
  871.             break;
  872.  
  873.           case SetDriveMode:
  874.  
  875.             c.DriveMode.Mode=LOBYTE(LOUSHORT(Addr1));
  876.             DPRINTF(("Mode=%02X\n",LOBYTE(LOUSHORT(Addr1))));
  877.             len=sizeof(c.DriveMode);
  878.             break;
  879.  
  880.           case HoldTime:
  881.  
  882.             c.HoldCmd.UnitsofTenSeconds=LOBYTE(LOUSHORT(Addr1));
  883.             len=sizeof(c.HoldCmd);
  884.             break;
  885.  
  886.           case SetAudioVolume:
  887.  
  888.             c.AudioLevel.ATT0=LOBYTE(LOUSHORT(Addr1));
  889.             c.AudioLevel.ATT1=HIBYTE(LOUSHORT(Addr1));
  890.             c.AudioLevel.ATT2=LOBYTE(LOUSHORT(Addr2));
  891.             c.AudioLevel.ATT3=HIBYTE(LOUSHORT(Addr2));
  892.             len=sizeof(c.AudioLevel);
  893.             break;
  894.  
  895.           case ModeSet:
  896.  
  897.             c.DataModeSet.ModeType=LOBYTE(LOUSHORT(Addr1));
  898.             len=sizeof(c.DataModeSet);
  899.             Mode=c.DataModeSet.ModeType;
  900.             break;
  901.  
  902.           case Eject:
  903.           case Close:
  904.  
  905.             tries=ReadSpinCount*2;
  906.             break;
  907.  
  908.           default:
  909.             break;
  910.           } /* end switch */
  911.  
  912.         c.Command=OpCode;                                       // set the REAL opecode here
  913.  
  914.         WriteCmd((PUCHAR)&c,len);                               // send the command to the drive
  915.  
  916.         if(OldOpCode!=Read)                                     // if not read then get command status
  917.           {
  918.           Status=GetStatus(tries);                              // now
  919.           } /* end if */
  920.         else                                                    // read comnand handled different ways
  921.           {
  922.           DPRINTF(("ReadStatus Late =%s\n",ReadStatusLate? "Yes": "No"));
  923.           Enable;                                               // we disabled before command issued
  924.           if(ReadStatusLate==FALSE)                             // are we supposed to read status before data appears?
  925.             {
  926.             while(TIMEOUT(Status=GetStatus(tries)));            // get it now, timeouts not allowed, could take LONG time
  927.                                                                 // if a seek and spinup are involved, keep trying
  928.             if(READERROR(Status) || COMMANDCHECK(Status) )      // did the command fail for some reason?
  929.               {
  930.               rc=3;                                             // say we had a failure, won't block later
  931.               ReadInProgress=FALSE;                             // and kill the read
  932.               } /* end if */
  933.             DevHelp_RAS( 168 ,(LOBYTE(LOUSHORT(Addr2))<<8)|Status , sizeof(PGinfo->msecs),&PGinfo->msecs);
  934.             } /* end if */
  935.           else                                                  // read status after data
  936.             {
  937.             Status=0;                                           // clear the status so next phase will work
  938.             }
  939.           }
  940. //
  941. //      Phase 2 of command processing,
  942. //
  943. //      if the command didn't fail or timeout, then handle the input data for
  944. //      each command that supports it
  945. //
  946.  
  947.         if((!TIMEOUT(Status) && !COMMANDCHECK(Status) && !READERROR(Status)) || OldOpCode==RequestSense)
  948.           {
  949.  
  950.           switch(OldOpCode)                                     // on the pseudo opcode again
  951.             {
  952.  
  953.             case PlayAudioMSF:                                  // play
  954.  
  955.                 DevHelp_RAS( 168 ,3, sizeof(PGinfo->msecs),&PGinfo->msecs);
  956.                 Status &= 0xFA;                                 // turn off noise bits
  957.                 break;
  958.  
  959.             case GetVersion:
  960.             case GetAudioVolume:
  961.             case ReadDriveMode:
  962.             case RequestSense:
  963.  
  964.                   ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
  965.                   break;
  966.  
  967.             case LockUnlock:
  968.  
  969.                   if(c.LockDrawer.Option==Query)                // only if we're querying the state
  970.                     {
  971.                     ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
  972.                     } /* end if */
  973.                 break;
  974.  
  975.             case ReadToc:
  976.             case ReadSubQ:
  977.             case ReadUPC:
  978.             case ReadDiscInfo:
  979.  
  980.                 if(DISCIN(Status))                              // if no disc we can't answer these
  981.                   {
  982.                   ReadStatusBytes((PUCHAR)Buffer,(UCHAR)BufferLen,tries);
  983.                   }
  984.                 break;
  985.  
  986.             case Read:                                          // read data
  987.  
  988.                     DevHelp_RAS( 168 ,2, sizeof(PGinfo->msecs),&PGinfo->msecs);
  989.  
  990.                     if(IrqNum)                                  // in interrupt mode?
  991.                       {
  992.                       Disable;                                  // disable
  993.                       if(ReadInProgress)                        // a read still in progress
  994.                         {
  995.                         ReaderBlocked=TRUE;                     // say we're blocked
  996.                         ReadBlockKey=(ULONG)Buffer;             // our block key, PHYSICAL address
  997.                         rc=DevHelp_Block(ReadBlockKey,3000L,1); // block
  998.                         Disable;                                // on return from block we're enabled
  999.                         ReaderBlocked=FALSE;                    // say we're not blocked (we aren't)
  1000.                         ReadBlockKey=0;                         // clear the block key value
  1001.                         } /* end if */
  1002.                       ReadInProgress=FALSE;                     // turn off read in progress
  1003.                       Enable;                                   // we can enable again
  1004.                       ReadStop=GetClock();                      // get current clock value
  1005.                       if(Addr2<32)                              // was this a <32 sector read?
  1006.                         {
  1007.                         Reads[Addr2]++;                         // count reads of this sector size
  1008.                         if(!rc)                                 // did the read timeout?
  1009.                           {
  1010.                           Timers[Addr2]=max(Timers[Addr2],ReadStop-ReadStart); // no set max wait time for this size
  1011.                           } /* end if */
  1012.                         else
  1013.                           {
  1014.                           Timeouts[Addr2]++;                    // oops, timed out, count it for this size read
  1015.                           Timeouts[0]=AdrRed2Hsg(Addr1);        // sector addr of read request (debugging)
  1016.                           } /* end else */
  1017.                         } /* end if */
  1018.                       } /* end if */
  1019.  
  1020.                     DevHelp_RAS( 168 ,(rc<<8) +3, sizeof(PGinfo->msecs),&PGinfo->msecs);
  1021.  
  1022.                     // if in polling mode
  1023.                     // OR
  1024.                     // in interrupt mode AND we we're unblocked, or an interrupt has occured
  1025.  
  1026.                     if(IrqNum==0 || (IrqNum && (rc==0 || InterruptOccured)) )
  1027.                       {
  1028.                       // get the data (polled mode) or
  1029.                       // just status (interrupt, post status mode)
  1030.                       // use the GLOBAL GDT virtual pointer for data buffer address, NOT the
  1031.                       // PHYSICAL address passed
  1032.  
  1033.                       ReadStatusbyte=ReadDataBytes((PUCHAR)Buffer,BufferLen, &Addr2,tries*2,ReadStatusLate);
  1034.  
  1035.                       // did the read timeout (polled mode)
  1036.  
  1037.                       if(!TIMEOUT(ReadStatusbyte))      // if no timeout
  1038.                         {
  1039.                         if(ReadStatusLate)              // are we supposed to read the status now?
  1040.                           {
  1041.                           Status=GetStatus(tries);      // yes, get the read status
  1042.                           } /* end if */
  1043.                         else
  1044.                           {
  1045.                           if(READERROR(ReadStatusbyte)) // oops, Read pre-status lied
  1046.                             {
  1047.                             Status=GetStatus(tries);    // get REAL status now
  1048.                             } /* end if */
  1049.                           } /* end else */
  1050.                         } /* end if */
  1051.                       else
  1052.                         {
  1053.                         Status=ReadStatusbyte;          // set the timeout return code
  1054.                         } /* end else */
  1055.  
  1056.                       DevHelp_RAS( 168 ,((LOUSHORT(Addr2)<<8) | Status) , sizeof(PGinfo->msecs),&PGinfo->msecs);
  1057.  
  1058.                       } /* end if */
  1059.                     else
  1060.                       {
  1061.  
  1062.                       // Must be in interrupt mode, but check just in case
  1063.  
  1064.                       if(IrqNum)
  1065.                         {
  1066. //#ifdef TRACE
  1067.                         while((x=ReadStatus())==DTEN)
  1068.                           {
  1069.                           ReadData();
  1070.                           } /* end if */
  1071.                         DevHelp_RAS( 168 ,(x<<8) +4, sizeof(PGinfo->msecs),&PGinfo->msecs);
  1072.                         if(x == STEN)
  1073.                           {
  1074.                           Status=GetStatus(tries);
  1075.                           if(ReadBlockCount)            // not all sectors read
  1076.                             {
  1077.                             Status=CommandCheck;        // command failed
  1078.                             } /* end if */
  1079.                           DevHelp_RAS( 168 ,Status, sizeof(PGinfo->msecs),&PGinfo->msecs);
  1080.                           } /* end if */
  1081.                         else
  1082. //#endif
  1083.                           Status= CommandCheck;         // we either timed out, or had a command failure
  1084.                                                         // can't tell which, say command failure (worst case)
  1085.                         } /* end if */
  1086.                       } /* end else */
  1087.                 break;
  1088.             default:
  1089.                 break;
  1090.             } /* end switch */
  1091.           } /* end if */
  1092.         return Status;
  1093. }
  1094.  
  1095. void SetDataMode(UCHAR data)
  1096. {
  1097. USHORT addr=AdapterBase+2;
  1098.    DPRINTF(("Data Mode set %02X\n",data));
  1099.    _asm {
  1100.           mov dx,addr
  1101.           mov al,data
  1102.           out dx,al
  1103.           };
  1104. }
  1105.  
  1106. void SetIrqMode(UCHAR mode)
  1107. {
  1108. USHORT addr=AdapterBase+3;
  1109.    DPRINTF(("Irq Mode set %02X\n",mode));
  1110.    _asm {
  1111.           mov dx,addr
  1112.           mov al,mode
  1113.           out dx,al
  1114.           };
  1115. }
  1116. // -------------------------------------------------------------- //
  1117. //                                                                  //
  1118. // This routine will change an HSG address to Red book address          //
  1119. //                                                                  //
  1120. //                                                                  //
  1121.  
  1122. ULONG AdrHsg2Red( ULONG ulHsg )
  1123. {
  1124.       ULONG ulRedBook ;
  1125.  
  1126.    ulHsg    += 150 ;
  1127.  
  1128.    ulRedBook = MAKEULONG
  1129.                (
  1130.                   MAKEUSHORT
  1131.                   (
  1132.                      (UCHAR)(ulHsg%75),
  1133.                      (UCHAR)((ulHsg%4500)/75)
  1134.                   ),
  1135.                   (UCHAR)(ulHsg/4500)
  1136.                ) ;
  1137.  
  1138.    return( ulRedBook ) ;
  1139. }
  1140. ULONG AdrRed2Hsg( ULONG ulRedBook )
  1141. {
  1142.       ULONG ulHsg ;
  1143.  
  1144.    ulHsg = ((((ULONG)(LOBYTE(HIUSHORT(ulRedBook)))*60)+
  1145.               (ULONG)(HIBYTE(LOUSHORT(ulRedBook)))     )*75)+
  1146.               (ULONG)(LOBYTE(LOUSHORT(ulRedBook)))          - 150 ;
  1147.  
  1148.    return( ulHsg ) ;
  1149. }
  1150.  
  1151.